1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 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 <boost/algorithm/string/join.hpp>
#include <boost/beast/http.hpp>
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(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
boost::beast::http::response<boost::beast::http::string_body>& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
Dictionary::Ptr node = m_UrlTree;
std::vector<HttpHandler::Ptr> handlers;
Url::Ptr url = new Url(std::string(request.target()));
auto& path (url->GetPath());
for (std::vector<String>::size_type i = 0; i <= path.size(); i++) {
Array::Ptr current_handlers = node->Get("handlers");
if (current_handlers) {
ObjectLock olock(current_handlers);
for (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(waitGroup, 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;
}
}
|