From 0915b3ef56dfac3113cce55a59a5765dc94976be Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 14:34:54 +0200 Subject: Adding upstream version 2.13.6. Signed-off-by: Daniel Baumann --- lib/remote/httphandler.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 lib/remote/httphandler.cpp (limited to 'lib/remote/httphandler.cpp') diff --git a/lib/remote/httphandler.cpp b/lib/remote/httphandler.cpp new file mode 100644 index 0000000..e1bb4f4 --- /dev/null +++ b/lib/remote/httphandler.cpp @@ -0,0 +1,129 @@ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ + +#include "base/logger.hpp" +#include "remote/httphandler.hpp" +#include "remote/httputility.hpp" +#include "base/singleton.hpp" +#include "base/exception.hpp" +#include +#include + +using namespace icinga; + +Dictionary::Ptr HttpHandler::m_UrlTree; + +void HttpHandler::Register(const Url::Ptr& url, const HttpHandler::Ptr& handler) +{ + if (!m_UrlTree) + m_UrlTree = new Dictionary(); + + Dictionary::Ptr node = m_UrlTree; + + for (const String& elem : url->GetPath()) { + Dictionary::Ptr children = node->Get("children"); + + if (!children) { + children = new Dictionary(); + node->Set("children", children); + } + + Dictionary::Ptr sub_node = children->Get(elem); + if (!sub_node) { + sub_node = new Dictionary(); + children->Set(elem, sub_node); + } + + node = sub_node; + } + + Array::Ptr handlers = node->Get("handlers"); + + if (!handlers) { + handlers = new Array(); + node->Set("handlers", handlers); + } + + handlers->Add(handler); +} + +void HttpHandler::ProcessRequest( + AsioTlsStream& stream, + const ApiUser::Ptr& user, + boost::beast::http::request& request, + boost::beast::http::response& response, + boost::asio::yield_context& yc, + HttpServerConnection& server +) +{ + Dictionary::Ptr node = m_UrlTree; + std::vector handlers; + + 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"); + + if (current_handlers) { + ObjectLock olock(current_handlers); + for (const HttpHandler::Ptr& current_handler : current_handlers) { + handlers.push_back(current_handler); + } + } + + Dictionary::Ptr children = node->Get("children"); + + if (!children) { + node.reset(); + break; + } + + if (i == path.size()) + break; + + node = children->Get(path[i]); + + if (!node) + break; + } + + std::reverse(handlers.begin(), handlers.end()); + + Dictionary::Ptr params; + + try { + params = HttpUtility::FetchRequestParameters(url, request.body()); + } catch (const std::exception& ex) { + HttpUtility::SendJsonError(response, params, 400, "Invalid request body: " + DiagnosticInformation(ex, false)); + return; + } + + bool processed = false; + + /* + * HandleRequest may throw a permission exception. + * DO NOT return a specific permission error. This + * allows attackers to guess from words which objects + * do exist. + */ + try { + for (const HttpHandler::Ptr& handler : handlers) { + if (handler->HandleRequest(stream, user, request, url, response, params, yc, server)) { + processed = true; + break; + } + } + } catch (const std::exception& ex) { + Log(LogWarning, "HttpServerConnection") + << "Error while processing HTTP request: " << ex.what(); + + processed = false; + } + + if (!processed) { + 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; + } +} + -- cgit v1.2.3