]> granicus.if.org Git - icinga2/commitdiff
HttpServerConnection: actually handle requests
authorAlexander A. Klimov <alexander.klimov@icinga.com>
Thu, 14 Feb 2019 16:27:17 +0000 (17:27 +0100)
committerAlexander A. Klimov <alexander.klimov@icinga.com>
Mon, 1 Apr 2019 09:40:14 +0000 (11:40 +0200)
lib/remote/httphandler.cpp
lib/remote/httphandler.hpp
lib/remote/httpserverconnection.cpp
lib/remote/httputility.cpp
lib/remote/httputility.hpp

index bf8bed37d685f826e66603224803ff8d0ecb9d4f..d6ea3426ba55295cae0409f40246933639a6ac49 100644 (file)
@@ -5,6 +5,7 @@
 #include "base/singleton.hpp"
 #include "base/exception.hpp"
 #include <boost/algorithm/string/join.hpp>
+#include <boost/beast/http.hpp>
 
 using namespace icinga;
 
@@ -44,11 +45,17 @@ void HttpHandler::Register(const Url::Ptr& url, const HttpHandler::Ptr& handler)
        handlers->Add(handler);
 }
 
-void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+void HttpHandler::ProcessRequest(
+       const ApiUser::Ptr& user,
+       boost::beast::http::request<boost::beast::http::string_body>& request,
+       boost::beast::http::response<boost::beast::http::string_body>& response
+)
 {
        Dictionary::Ptr node = m_UrlTree;
        std::vector<HttpHandler::Ptr> handlers;
-       const std::vector<String>& path = request.RequestUrl->GetPath();
+
+       Url::Ptr url = new Url(request.target().to_string());
+       auto& path (url->GetPath());
 
        for (std::vector<String>::size_type i = 0; i <= path.size(); i++) {
                Array::Ptr current_handlers = node->Get("handlers");
@@ -81,7 +88,7 @@ void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request,
        Dictionary::Ptr params;
 
        try {
-               params = HttpUtility::FetchRequestParameters(request);
+               params = HttpUtility::FetchRequestParameters(url, request.body());
        } catch (const std::exception& ex) {
                HttpUtility::SendJsonError(response, params, 400, "Invalid request body: " + DiagnosticInformation(ex, false));
                return;
@@ -89,16 +96,15 @@ void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request,
 
        bool processed = false;
        for (const HttpHandler::Ptr& handler : handlers) {
-               if (handler->HandleRequest(user, request, response, params)) {
+               if (handler->HandleRequest(user, request, url, response, params)) {
                        processed = true;
                        break;
                }
        }
 
        if (!processed) {
-               String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
-               HttpUtility::SendJsonError(response, params, 404, "The requested path '" + path +
-                               "' could not be found or the request method is not valid for this path.");
+               HttpUtility::SendJsonError(response, params, 404, "The requested path '" + boost::algorithm::join(path, "/") +
+                       "' could not be found or the request method is not valid for this path.");
                return;
        }
 }
index 95ddd0b49dff7ff2a4d2bdf5ec12039fbfb2e0c1..7e74329e0ccf1d9b45b7610d597d44cffa89eac4 100644 (file)
@@ -4,10 +4,12 @@
 #define HTTPHANDLER_H
 
 #include "remote/i2-remote.hpp"
+#include "remote/url.hpp"
 #include "remote/httpresponse.hpp"
 #include "remote/apiuser.hpp"
 #include "base/registry.hpp"
 #include <vector>
+#include <boost/beast/http.hpp>
 
 namespace icinga
 {
@@ -22,10 +24,20 @@ class HttpHandler : public Object
 public:
        DECLARE_PTR_TYPEDEFS(HttpHandler);
 
-       virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) = 0;
+       virtual bool HandleRequest(
+               const ApiUser::Ptr& user,
+               boost::beast::http::request<boost::beast::http::string_body>& request,
+               const Url::Ptr& url,
+               boost::beast::http::response<boost::beast::http::string_body>& response,
+               const Dictionary::Ptr& params
+       ) = 0;
 
        static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler);
-       static void ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+       static void ProcessRequest(
+               const ApiUser::Ptr& user,
+               boost::beast::http::request<boost::beast::http::string_body>& request,
+               boost::beast::http::response<boost::beast::http::string_body>& response
+       );
 
 private:
        static Dictionary::Ptr m_UrlTree;
index 707c1a6351d3791b41290073251e9800f77e0f0e..87db3da5c481001a908bbd61105c137234aa295b 100644 (file)
@@ -321,7 +321,20 @@ void ProcessRequest(
 {
        namespace http = boost::beast::http;
 
-       HttpUtility::SendJsonError(response, nullptr, 503, "Unhandled exception" , "");
+       try {
+               CpuBoundWork handlingRequest (yc);
+
+               HttpHandler::ProcessRequest(authenticatedUser, request, response);
+       } catch (const std::exception& ex) {
+               http::response<http::string_body> response;
+
+               HttpUtility::SendJsonError(response, nullptr, 500, "Unhandled exception" , DiagnosticInformation(ex));
+
+               http::async_write(stream, response, yc);
+               stream.async_flush(yc);
+
+               return;
+       }
 
        http::async_write(stream, response, yc);
        stream.async_flush(yc);
index fa54d9c8945b16d6864e8d0a31822b97db4de38f..c97297cd0eef6451fa8f42ef55456611db443144 100644 (file)
@@ -1,28 +1,23 @@
 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
 
 #include "remote/httputility.hpp"
+#include "remote/url.hpp"
 #include "base/json.hpp"
 #include "base/logger.hpp"
 #include <map>
+#include <string>
 #include <vector>
 #include <boost/beast/http.hpp>
 
 using namespace icinga;
 
-Dictionary::Ptr HttpUtility::FetchRequestParameters(HttpRequest& request)
+Dictionary::Ptr HttpUtility::FetchRequestParameters(const Url::Ptr& url, const std::string& body)
 {
        Dictionary::Ptr result;
 
-       String body;
-       char buffer[1024];
-       size_t count;
-
-       while ((count = request.ReadBody(buffer, sizeof(buffer))) > 0)
-               body += String(buffer, buffer + count);
-
-       if (!body.IsEmpty()) {
+       if (!body.empty()) {
                Log(LogDebug, "HttpUtility")
-                       << "Request body: '" << body << "'";
+                       << "Request body: '" << body << '\'';
 
                result = JsonDecode(body);
        }
@@ -31,7 +26,7 @@ Dictionary::Ptr HttpUtility::FetchRequestParameters(HttpRequest& request)
                result = new Dictionary();
 
        std::map<String, std::vector<String>> query;
-       for (const auto& kv : request.RequestUrl->GetQuery()) {
+       for (const auto& kv : url->GetQuery()) {
                query[kv.first].emplace_back(kv.second);
        }
 
index 7122e3e7167137d063ded0028b986dd5434ba3ec..e9f44b3aa7931967fed3cad62be0457043613bc7 100644 (file)
@@ -5,7 +5,9 @@
 
 #include "remote/httprequest.hpp"
 #include "remote/httpresponse.hpp"
+#include "remote/url.hpp"
 #include "base/dictionary.hpp"
+#include <string>
 #include <boost/beast/http.hpp>
 
 namespace icinga
@@ -20,7 +22,7 @@ class HttpUtility
 {
 
 public:
-       static Dictionary::Ptr FetchRequestParameters(HttpRequest& request);
+       static Dictionary::Ptr FetchRequestParameters(const Url::Ptr& url, const std::string& body);
        static void SendJsonBody(HttpResponse& response, const Dictionary::Ptr& params, const Value& val);
        static void SendJsonBody(boost::beast::http::response<boost::beast::http::string_body>& response, const Dictionary::Ptr& params, const Value& val);
        static Value GetLastParameter(const Dictionary::Ptr& params, const String& key);