HttpServerConnection: actually handle requests

This commit is contained in:
Alexander A. Klimov 2019-02-14 17:27:17 +01:00
parent 7fe0431ada
commit 9ae1d732af
5 changed files with 50 additions and 22 deletions

View 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;
}
}

View 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;

View 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);

View 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);
}

View 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);