From 9ae1d732af3052865c8bd2b4d1bafd90df0ee682 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 14 Feb 2019 17:27:17 +0100 Subject: [PATCH] HttpServerConnection: actually handle requests --- lib/remote/httphandler.cpp | 20 +++++++++++++------- lib/remote/httphandler.hpp | 16 ++++++++++++++-- lib/remote/httpserverconnection.cpp | 15 ++++++++++++++- lib/remote/httputility.cpp | 17 ++++++----------- lib/remote/httputility.hpp | 4 +++- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/lib/remote/httphandler.cpp b/lib/remote/httphandler.cpp index bf8bed37d..d6ea3426b 100644 --- a/lib/remote/httphandler.cpp +++ b/lib/remote/httphandler.cpp @@ -5,6 +5,7 @@ #include "base/singleton.hpp" #include "base/exception.hpp" #include +#include 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& request, + boost::beast::http::response& response +) { Dictionary::Ptr node = m_UrlTree; std::vector handlers; - const std::vector& path = request.RequestUrl->GetPath(); + + Url::Ptr url = new Url(request.target().to_string()); + auto& path (url->GetPath()); for (std::vector::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; } } diff --git a/lib/remote/httphandler.hpp b/lib/remote/httphandler.hpp index 95ddd0b49..7e74329e0 100644 --- a/lib/remote/httphandler.hpp +++ b/lib/remote/httphandler.hpp @@ -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 +#include 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& request, + const Url::Ptr& url, + boost::beast::http::response& 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& request, + boost::beast::http::response& response + ); private: static Dictionary::Ptr m_UrlTree; diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp index 707c1a635..87db3da5c 100644 --- a/lib/remote/httpserverconnection.cpp +++ b/lib/remote/httpserverconnection.cpp @@ -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 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); diff --git a/lib/remote/httputility.cpp b/lib/remote/httputility.cpp index fa54d9c89..c97297cd0 100644 --- a/lib/remote/httputility.cpp +++ b/lib/remote/httputility.cpp @@ -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 +#include #include #include 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> query; - for (const auto& kv : request.RequestUrl->GetQuery()) { + for (const auto& kv : url->GetQuery()) { query[kv.first].emplace_back(kv.second); } diff --git a/lib/remote/httputility.hpp b/lib/remote/httputility.hpp index 7122e3e71..e9f44b3aa 100644 --- a/lib/remote/httputility.hpp +++ b/lib/remote/httputility.hpp @@ -5,7 +5,9 @@ #include "remote/httprequest.hpp" #include "remote/httpresponse.hpp" +#include "remote/url.hpp" #include "base/dictionary.hpp" +#include #include 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& response, const Dictionary::Ptr& params, const Value& val); static Value GetLastParameter(const Dictionary::Ptr& params, const String& key);