diff --git a/lib/remote/actionshandler.cpp b/lib/remote/actionshandler.cpp
index 5ae5fdc80..47fdd9b3b 100644
--- a/lib/remote/actionshandler.cpp
+++ b/lib/remote/actionshandler.cpp
@@ -18,29 +18,26 @@ REGISTER_URLHANDLER("/v1/actions", ActionsHandler);
bool ActionsHandler::HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() != 3)
+ if (request.Url()->GetPath().size() != 3)
return false;
if (request.method() != http::verb::post)
return false;
- String actionName = url->GetPath()[2];
+ String actionName = request.Url()->GetPath()[2];
ApiAction::Ptr action = ApiAction::GetByName(actionName);
if (!action) {
- HttpUtility::SendJsonError(response, params, 404, "Action '" + actionName + "' does not exist.");
+ response.SendJsonError(request.Params(), 404, "Action '" + actionName + "' does not exist.");
return true;
}
@@ -56,21 +53,21 @@ bool ActionsHandler::HandleRequest(
qd.Permission = permission;
try {
- objs = FilterUtility::GetFilterTargets(qd, params, user);
+ objs = FilterUtility::GetFilterTargets(qd, request.Params(), request.User());
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 404,
+ response.SendJsonError(request.Params(), 404,
"No objects found.",
DiagnosticInformation(ex));
return true;
}
if (objs.empty()) {
- HttpUtility::SendJsonError(response, params, 404,
+ response.SendJsonError(request.Params(), 404,
"No objects found.");
return true;
}
} else {
- FilterUtility::CheckPermission(user, permission);
+ FilterUtility::CheckPermission(request.User(), permission);
objs.emplace_back(nullptr);
}
@@ -79,19 +76,16 @@ bool ActionsHandler::HandleRequest(
Log(LogNotice, "ApiActionHandler")
<< "Running action " << actionName;
- bool verbose = false;
+ bool verbose = request.IsVerbose();
- ActionsHandler::AuthenticatedApiUser = user;
+ ActionsHandler::AuthenticatedApiUser = request.User();
Defer a ([]() {
ActionsHandler::AuthenticatedApiUser = nullptr;
});
- if (params)
- verbose = HttpUtility::GetLastParameter(params, "verbose");
-
std::shared_lock wgLock{*waitGroup, std::try_to_lock};
if (!wgLock) {
- HttpUtility::SendJsonError(response, params, 503, "Shutting down.");
+ response.SendJsonError(request.Params(), 503, "Shutting down.");
return true;
}
@@ -112,7 +106,7 @@ bool ActionsHandler::HandleRequest(
}
try {
- results.emplace_back(action->Invoke(obj, params));
+ results.emplace_back(action->Invoke(obj, request.Params()));
} catch (const std::exception& ex) {
Dictionary::Ptr fail = new Dictionary({
{ "code", 500 },
@@ -161,7 +155,7 @@ bool ActionsHandler::HandleRequest(
{ "results", new Array(std::move(results)) }
});
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
return true;
}
diff --git a/lib/remote/actionshandler.hpp b/lib/remote/actionshandler.hpp
index fbf716797..83132eeec 100644
--- a/lib/remote/actionshandler.hpp
+++ b/lib/remote/actionshandler.hpp
@@ -18,11 +18,8 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
diff --git a/lib/remote/configfileshandler.cpp b/lib/remote/configfileshandler.cpp
index 6c390e804..f91a48330 100644
--- a/lib/remote/configfileshandler.cpp
+++ b/lib/remote/configfileshandler.cpp
@@ -16,11 +16,8 @@ REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler);
bool ConfigFilesHandler::HandleRequest(
const WaitGroup::Ptr&,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
@@ -30,50 +27,50 @@ bool ConfigFilesHandler::HandleRequest(
if (request.method() != http::verb::get)
return false;
- const std::vector& urlPath = url->GetPath();
+ const std::vector& urlPath = request.Url()->GetPath();
if (urlPath.size() >= 4)
- params->Set("package", urlPath[3]);
+ request.Params()->Set("package", urlPath[3]);
if (urlPath.size() >= 5)
- params->Set("stage", urlPath[4]);
+ request.Params()->Set("stage", urlPath[4]);
if (urlPath.size() >= 6) {
std::vector tmpPath(urlPath.begin() + 5, urlPath.end());
- params->Set("path", boost::algorithm::join(tmpPath, "/"));
+ request.Params()->Set("path", boost::algorithm::join(tmpPath, "/"));
}
if (request[http::field::accept] == "application/json") {
- HttpUtility::SendJsonError(response, params, 400, "Invalid Accept header. Either remove the Accept header or set it to 'application/octet-stream'.");
+ response.SendJsonError(request.Params(), 400, "Invalid Accept header. Either remove the Accept header or set it to 'application/octet-stream'.");
return true;
}
- FilterUtility::CheckPermission(user, "config/query");
+ FilterUtility::CheckPermission(request.User(), "config/query");
- String packageName = HttpUtility::GetLastParameter(params, "package");
- String stageName = HttpUtility::GetLastParameter(params, "stage");
+ String packageName = request.GetLastParameter("package");
+ String stageName = request.GetLastParameter("stage");
if (!ConfigPackageUtility::ValidatePackageName(packageName)) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
+ response.SendJsonError(request.Params(), 400, "Invalid package name.");
return true;
}
if (!ConfigPackageUtility::ValidateStageName(stageName)) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid stage name.");
+ response.SendJsonError(request.Params(), 400, "Invalid stage name.");
return true;
}
- String relativePath = HttpUtility::GetLastParameter(params, "path");
+ String relativePath = request.GetLastParameter("path");
if (ConfigPackageUtility::ContainsDotDot(relativePath)) {
- HttpUtility::SendJsonError(response, params, 400, "Path contains '..' (not allowed).");
+ response.SendJsonError(request.Params(), 400, "Path contains '..' (not allowed).");
return true;
}
String path = ConfigPackageUtility::GetPackageDir() + "/" + packageName + "/" + stageName + "/" + relativePath;
if (!Utility::PathExists(path)) {
- HttpUtility::SendJsonError(response, params, 404, "Path not found.");
+ response.SendJsonError(request.Params(), 404, "Path not found.");
return true;
}
@@ -81,13 +78,11 @@ bool ConfigFilesHandler::HandleRequest(
std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary);
fp.exceptions(std::ifstream::badbit);
- String content((std::istreambuf_iterator(fp)), std::istreambuf_iterator());
response.result(http::status::ok);
response.set(http::field::content_type, "application/octet-stream");
- response.body() = content;
- response.content_length(response.body().size());
+ response.body() << fp.rdbuf();
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 500, "Could not read file.",
+ response.SendJsonError(request.Params(), 500, "Could not read file.",
DiagnosticInformation(ex));
}
diff --git a/lib/remote/configfileshandler.hpp b/lib/remote/configfileshandler.hpp
index a8826d8c1..0bb12488d 100644
--- a/lib/remote/configfileshandler.hpp
+++ b/lib/remote/configfileshandler.hpp
@@ -16,11 +16,8 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
diff --git a/lib/remote/configpackageshandler.cpp b/lib/remote/configpackageshandler.cpp
index 7987092bc..619e88b8a 100644
--- a/lib/remote/configpackageshandler.cpp
+++ b/lib/remote/configpackageshandler.cpp
@@ -13,50 +13,41 @@ REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler);
bool ConfigPackagesHandler::HandleRequest(
const WaitGroup::Ptr&,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() > 4)
+ if (request.Url()->GetPath().size() > 4)
return false;
if (request.method() == http::verb::get)
- HandleGet(user, request, url, response, params);
+ HandleGet(request, response);
else if (request.method() == http::verb::post)
- HandlePost(user, request, url, response, params);
+ HandlePost(request, response);
else if (request.method() == http::verb::delete_)
- HandleDelete(user, request, url, response, params);
+ HandleDelete(request, response);
else
return false;
return true;
}
-void ConfigPackagesHandler::HandleGet(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigPackagesHandler::HandleGet(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/query");
+ FilterUtility::CheckPermission(request.User(), "config/query");
std::vector packages;
try {
packages = ConfigPackageUtility::GetPackages();
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 500, "Could not retrieve packages.",
+ response.SendJsonError(request.Params(), 500, "Could not retrieve packages.",
DiagnosticInformation(ex));
return;
}
@@ -86,28 +77,22 @@ void ConfigPackagesHandler::HandleGet(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
-void ConfigPackagesHandler::HandlePost(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigPackagesHandler::HandlePost(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/modify");
+ FilterUtility::CheckPermission(request.User(), "config/modify");
- if (url->GetPath().size() >= 4)
- params->Set("package", url->GetPath()[3]);
+ if (request.Url()->GetPath().size() >= 4)
+ request.Params()->Set("package", request.Url()->GetPath()[3]);
- String packageName = HttpUtility::GetLastParameter(params, "package");
+ String packageName = request.GetLastParameter("package");
if (!ConfigPackageUtility::ValidatePackageName(packageName)) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
+ response.SendJsonError(request.Params(), 400, "Invalid package name '" + packageName + "'.");
return;
}
@@ -116,7 +101,7 @@ void ConfigPackagesHandler::HandlePost(
ConfigPackageUtility::CreatePackage(packageName);
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 500, "Could not create package '" + packageName + "'.",
+ response.SendJsonError(request.Params(), 500, "Could not create package '" + packageName + "'.",
DiagnosticInformation(ex));
return;
}
@@ -132,35 +117,29 @@ void ConfigPackagesHandler::HandlePost(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
-void ConfigPackagesHandler::HandleDelete(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigPackagesHandler::HandleDelete(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/modify");
+ FilterUtility::CheckPermission(request.User(), "config/modify");
- if (url->GetPath().size() >= 4)
- params->Set("package", url->GetPath()[3]);
+ if (request.Url()->GetPath().size() >= 4)
+ request.Params()->Set("package", request.Url()->GetPath()[3]);
- String packageName = HttpUtility::GetLastParameter(params, "package");
+ String packageName = request.GetLastParameter("package");
if (!ConfigPackageUtility::ValidatePackageName(packageName)) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
+ response.SendJsonError(request.Params(), 400, "Invalid package name '" + packageName + "'.");
return;
}
try {
ConfigPackageUtility::DeletePackage(packageName);
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 500, "Failed to delete package '" + packageName + "'.",
+ response.SendJsonError(request.Params(), 500, "Failed to delete package '" + packageName + "'.",
DiagnosticInformation(ex));
return;
}
@@ -176,5 +155,5 @@ void ConfigPackagesHandler::HandleDelete(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
diff --git a/lib/remote/configpackageshandler.hpp b/lib/remote/configpackageshandler.hpp
index 2bae0e265..95bcfacbc 100644
--- a/lib/remote/configpackageshandler.hpp
+++ b/lib/remote/configpackageshandler.hpp
@@ -16,37 +16,16 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
private:
- void HandleGet(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
- void HandlePost(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
- void HandleDelete(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
+ void HandleGet(const HttpRequest& request, HttpResponse& response);
+ void HandlePost(const HttpRequest& request, HttpResponse& response);
+ void HandleDelete(const HttpRequest& request, HttpResponse& response);
};
diff --git a/lib/remote/configstageshandler.cpp b/lib/remote/configstageshandler.cpp
index 0dee5f25f..98baf1bb7 100644
--- a/lib/remote/configstageshandler.cpp
+++ b/lib/remote/configstageshandler.cpp
@@ -17,58 +17,49 @@ std::atomic ConfigStagesHandler::m_RunningPackageUpdates (false);
bool ConfigStagesHandler::HandleRequest(
const WaitGroup::Ptr&,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() > 5)
+ if (request.Url()->GetPath().size() > 5)
return false;
if (request.method() == http::verb::get)
- HandleGet(user, request, url, response, params);
+ HandleGet(request, response);
else if (request.method() == http::verb::post)
- HandlePost(user, request, url, response, params);
+ HandlePost(request, response);
else if (request.method() == http::verb::delete_)
- HandleDelete(user, request, url, response, params);
+ HandleDelete(request, response);
else
return false;
return true;
}
-void ConfigStagesHandler::HandleGet(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigStagesHandler::HandleGet(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/query");
+ FilterUtility::CheckPermission(request.User(), "config/query");
- if (url->GetPath().size() >= 4)
- params->Set("package", url->GetPath()[3]);
+ if (request.Url()->GetPath().size() >= 4)
+ request.Params()->Set("package", request.Url()->GetPath()[3]);
- if (url->GetPath().size() >= 5)
- params->Set("stage", url->GetPath()[4]);
+ if (request.Url()->GetPath().size() >= 5)
+ request.Params()->Set("stage", request.Url()->GetPath()[4]);
- String packageName = HttpUtility::GetLastParameter(params, "package");
- String stageName = HttpUtility::GetLastParameter(params, "stage");
+ String packageName = request.GetLastParameter("package");
+ String stageName = request.GetLastParameter("stage");
if (!ConfigPackageUtility::ValidatePackageName(packageName))
- return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
+ return response.SendJsonError(request.Params(), 400, "Invalid package name '" + packageName + "'.");
if (!ConfigPackageUtility::ValidateStageName(stageName))
- return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name '" + stageName + "'.");
+ return response.SendJsonError(request.Params(), 400, "Invalid stage name '" + stageName + "'.");
ArrayData results;
@@ -88,40 +79,34 @@ void ConfigStagesHandler::HandleGet(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
-void ConfigStagesHandler::HandlePost(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigStagesHandler::HandlePost(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/modify");
+ FilterUtility::CheckPermission(request.User(), "config/modify");
- if (url->GetPath().size() >= 4)
- params->Set("package", url->GetPath()[3]);
+ if (request.Url()->GetPath().size() >= 4)
+ request.Params()->Set("package", request.Url()->GetPath()[3]);
- String packageName = HttpUtility::GetLastParameter(params, "package");
+ String packageName = request.GetLastParameter("package");
if (!ConfigPackageUtility::ValidatePackageName(packageName))
- return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
+ return response.SendJsonError(request.Params(), 400, "Invalid package name '" + packageName + "'.");
bool reload = true;
- if (params->Contains("reload"))
- reload = HttpUtility::GetLastParameter(params, "reload");
+ if (request.Params()->Contains("reload"))
+ reload = request.GetLastParameter("reload");
bool activate = true;
- if (params->Contains("activate"))
- activate = HttpUtility::GetLastParameter(params, "activate");
+ if (request.Params()->Contains("activate"))
+ activate = request.GetLastParameter("activate");
- Dictionary::Ptr files = params->Get("files");
+ Dictionary::Ptr files = request.Params()->Get("files");
String stageName;
@@ -133,7 +118,7 @@ void ConfigStagesHandler::HandlePost(
BOOST_THROW_EXCEPTION(std::invalid_argument("Parameter 'reload' must be false when 'activate' is false."));
if (m_RunningPackageUpdates.exchange(true)) {
- return HttpUtility::SendJsonError(response, params, 423,
+ return response.SendJsonError(request.Params(), 423,
"Conflicting request, there is already an ongoing package update in progress. Please try it again later.");
}
@@ -146,7 +131,7 @@ void ConfigStagesHandler::HandlePost(
/* validate the config. on success, activate stage and reload */
ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName, activate, reload, resetPackageUpdates);
} catch (const std::exception& ex) {
- return HttpUtility::SendJsonError(response, params, 500,
+ return response.SendJsonError(request.Params(), 500,
"Stage creation failed.",
DiagnosticInformation(ex));
}
@@ -171,40 +156,34 @@ void ConfigStagesHandler::HandlePost(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
-void ConfigStagesHandler::HandleDelete(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
-)
+void ConfigStagesHandler::HandleDelete(const HttpRequest& request, HttpResponse& response)
{
namespace http = boost::beast::http;
- FilterUtility::CheckPermission(user, "config/modify");
+ FilterUtility::CheckPermission(request.User(), "config/modify");
- if (url->GetPath().size() >= 4)
- params->Set("package", url->GetPath()[3]);
+ if (request.Url()->GetPath().size() >= 4)
+ request.Params()->Set("package", request.Url()->GetPath()[3]);
- if (url->GetPath().size() >= 5)
- params->Set("stage", url->GetPath()[4]);
+ if (request.Url()->GetPath().size() >= 5)
+ request.Params()->Set("stage", request.Url()->GetPath()[4]);
- String packageName = HttpUtility::GetLastParameter(params, "package");
- String stageName = HttpUtility::GetLastParameter(params, "stage");
+ String packageName = request.GetLastParameter("package");
+ String stageName = request.GetLastParameter("stage");
if (!ConfigPackageUtility::ValidatePackageName(packageName))
- return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
+ return response.SendJsonError(request.Params(), 400, "Invalid package name '" + packageName + "'.");
if (!ConfigPackageUtility::ValidateStageName(stageName))
- return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name '" + stageName + "'.");
+ return response.SendJsonError(request.Params(), 400, "Invalid stage name '" + stageName + "'.");
try {
ConfigPackageUtility::DeleteStage(packageName, stageName);
} catch (const std::exception& ex) {
- return HttpUtility::SendJsonError(response, params, 500,
+ return response.SendJsonError(request.Params(), 500,
"Failed to delete stage '" + stageName + "' in package '" + packageName + "'.",
DiagnosticInformation(ex));
}
@@ -221,5 +200,5 @@ void ConfigStagesHandler::HandleDelete(
});
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
}
diff --git a/lib/remote/configstageshandler.hpp b/lib/remote/configstageshandler.hpp
index a26ddc49c..6dd644f05 100644
--- a/lib/remote/configstageshandler.hpp
+++ b/lib/remote/configstageshandler.hpp
@@ -17,37 +17,16 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
private:
- void HandleGet(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
- void HandlePost(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
- void HandleDelete(
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params
- );
+ void HandleGet(const HttpRequest& request, HttpResponse& response);
+ void HandlePost(const HttpRequest& request, HttpResponse& response);
+ void HandleDelete(const HttpRequest& request, HttpResponse& response);
static std::atomic m_RunningPackageUpdates;
};
diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp
index c48821aae..6c4abcb25 100644
--- a/lib/remote/consolehandler.cpp
+++ b/lib/remote/consolehandler.cpp
@@ -56,18 +56,15 @@ static void EnsureFrameCleanupTimer()
bool ConsoleHandler::HandleRequest(
const WaitGroup::Ptr&,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() != 3)
+ if (request.Url()->GetPath().size() != 3)
return false;
if (request.method() != http::verb::post)
@@ -75,38 +72,37 @@ bool ConsoleHandler::HandleRequest(
QueryDescription qd;
- String methodName = url->GetPath()[2];
+ String methodName = request.Url()->GetPath()[2];
- FilterUtility::CheckPermission(user, "console");
+ FilterUtility::CheckPermission(request.User(), "console");
- String session = HttpUtility::GetLastParameter(params, "session");
+ String session = request.GetLastParameter("session");
if (session.IsEmpty())
session = Utility::NewUniqueID();
- String command = HttpUtility::GetLastParameter(params, "command");
+ String command = request.GetLastParameter("command");
- bool sandboxed = HttpUtility::GetLastParameter(params, "sandboxed");
+ bool sandboxed = request.GetLastParameter("sandboxed");
ConfigObjectsSharedLock lock (std::try_to_lock);
if (!lock) {
- HttpUtility::SendJsonError(response, params, 503, "Icinga is reloading.");
+ response.SendJsonError(request.Params(), 503, "Icinga is reloading.");
return true;
}
if (methodName == "execute-script")
- return ExecuteScriptHelper(request, response, params, command, session, sandboxed);
+ return ExecuteScriptHelper(request, response, command, session, sandboxed);
else if (methodName == "auto-complete-script")
- return AutocompleteScriptHelper(request, response, params, command, session, sandboxed);
+ return AutocompleteScriptHelper(request, response, command, session, sandboxed);
- HttpUtility::SendJsonError(response, params, 400, "Invalid method specified: " + methodName);
+ response.SendJsonError(request.Params(), 400, "Invalid method specified: " + methodName);
return true;
}
-bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::request& request,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params, const String& command, const String& session, bool sandboxed)
+bool ConsoleHandler::ExecuteScriptHelper(const HttpRequest& request, HttpResponse& response,
+ const String& command, const String& session, bool sandboxed)
{
namespace http = boost::beast::http;
@@ -174,14 +170,13 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::request& request,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params, const String& command, const String& session, bool sandboxed)
+bool ConsoleHandler::AutocompleteScriptHelper(const HttpRequest& request, HttpResponse& response,
+ const String& command, const String& session, bool sandboxed)
{
namespace http = boost::beast::http;
@@ -213,7 +208,7 @@ bool ConsoleHandler::AutocompleteScriptHelper(boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
@@ -37,12 +34,10 @@ public:
static std::vector GetAutocompletionSuggestions(const String& word, ScriptFrame& frame);
private:
- static bool ExecuteScriptHelper(boost::beast::http::request& request,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params, const String& command, const String& session, bool sandboxed);
- static bool AutocompleteScriptHelper(boost::beast::http::request& request,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params, const String& command, const String& session, bool sandboxed);
+ static bool ExecuteScriptHelper(const HttpRequest& request, HttpResponse& response,
+ const String& command, const String& session, bool sandboxed);
+ static bool AutocompleteScriptHelper(const HttpRequest& request, HttpResponse& response,
+ const String& command, const String& session, bool sandboxed);
};
diff --git a/lib/remote/createobjecthandler.cpp b/lib/remote/createobjecthandler.cpp
index 119be1cd9..b12e2bf91 100644
--- a/lib/remote/createobjecthandler.cpp
+++ b/lib/remote/createobjecthandler.cpp
@@ -18,35 +18,32 @@ REGISTER_URLHANDLER("/v1/objects", CreateObjectHandler);
bool CreateObjectHandler::HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() != 4)
+ if (request.Url()->GetPath().size() != 4)
return false;
if (request.method() != http::verb::put)
return false;
- Type::Ptr type = FilterUtility::TypeFromPluralName(url->GetPath()[2]);
+ Type::Ptr type = FilterUtility::TypeFromPluralName(request.Url()->GetPath()[2]);
if (!type) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid type specified.");
+ response.SendJsonError(request.Params(), 400, "Invalid type specified.");
return true;
}
- FilterUtility::CheckPermission(user, "objects/create/" + type->GetName());
+ FilterUtility::CheckPermission(request.User(), "objects/create/" + type->GetName());
- String name = url->GetPath()[3];
- Array::Ptr templates = params->Get("templates");
- Dictionary::Ptr attrs = params->Get("attrs");
+ String name = request.Url()->GetPath()[3];
+ Array::Ptr templates = request.Params()->Get("templates");
+ Dictionary::Ptr attrs = request.Params()->Get("attrs");
/* Put created objects into the local zone if not explicitly defined.
* This allows additional zone members to sync the
@@ -82,8 +79,8 @@ bool CreateObjectHandler::HandleRequest(
bool ignoreOnError = false;
- if (params->Contains("ignore_on_error"))
- ignoreOnError = HttpUtility::GetLastParameter(params, "ignore_on_error");
+ if (request.Params()->Contains("ignore_on_error"))
+ ignoreOnError = request.GetLastParameter("ignore_on_error");
Dictionary::Ptr result = new Dictionary({
{ "results", new Array({ result1 }) }
@@ -91,21 +88,18 @@ bool CreateObjectHandler::HandleRequest(
String config;
- bool verbose = false;
-
- if (params)
- verbose = HttpUtility::GetLastParameter(params, "verbose");
+ bool verbose = request.IsVerbose();
ConfigObjectsSharedLock lock (std::try_to_lock);
if (!lock) {
- HttpUtility::SendJsonError(response, params, 503, "Icinga is reloading");
+ response.SendJsonError(request.Params(), 503, "Icinga is reloading");
return true;
}
std::shared_lock wgLock{*waitGroup, std::try_to_lock};
if (!wgLock) {
- HttpUtility::SendJsonError(response, params, 503, "Shutting down.");
+ response.SendJsonError(request.Params(), 503, "Shutting down.");
return true;
}
@@ -126,7 +120,7 @@ bool CreateObjectHandler::HandleRequest(
result1->Set("status", "Object could not be created.");
response.result(http::status::internal_server_error);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
return true;
}
@@ -143,7 +137,7 @@ bool CreateObjectHandler::HandleRequest(
result1->Set("diagnostic_information", diagnosticInformation);
response.result(http::status::internal_server_error);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
return true;
}
@@ -159,7 +153,7 @@ bool CreateObjectHandler::HandleRequest(
result1->Set("status", "Object was not created but 'ignore_on_error' was set to true");
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
return true;
}
diff --git a/lib/remote/createobjecthandler.hpp b/lib/remote/createobjecthandler.hpp
index 3f6a705c2..317cf023c 100644
--- a/lib/remote/createobjecthandler.hpp
+++ b/lib/remote/createobjecthandler.hpp
@@ -16,11 +16,8 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
diff --git a/lib/remote/deleteobjecthandler.cpp b/lib/remote/deleteobjecthandler.cpp
index 54d31f13d..253a73f16 100644
--- a/lib/remote/deleteobjecthandler.cpp
+++ b/lib/remote/deleteobjecthandler.cpp
@@ -18,27 +18,24 @@ REGISTER_URLHANDLER("/v1/objects", DeleteObjectHandler);
bool DeleteObjectHandler::HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
namespace http = boost::beast::http;
- if (url->GetPath().size() < 3 || url->GetPath().size() > 4)
+ if (request.Url()->GetPath().size() < 3 || request.Url()->GetPath().size() > 4)
return false;
if (request.method() != http::verb::delete_)
return false;
- Type::Ptr type = FilterUtility::TypeFromPluralName(url->GetPath()[2]);
+ Type::Ptr type = FilterUtility::TypeFromPluralName(request.Url()->GetPath()[2]);
if (!type) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid type specified.");
+ response.SendJsonError(request.Params(), 400, "Invalid type specified.");
return true;
}
@@ -46,32 +43,32 @@ bool DeleteObjectHandler::HandleRequest(
qd.Types.insert(type->GetName());
qd.Permission = "objects/delete/" + type->GetName();
- params->Set("type", type->GetName());
+ request.Params()->Set("type", type->GetName());
- if (url->GetPath().size() >= 4) {
+ if (request.Url()->GetPath().size() >= 4) {
String attr = type->GetName();
boost::algorithm::to_lower(attr);
- params->Set(attr, url->GetPath()[3]);
+ request.Params()->Set(attr, request.Url()->GetPath()[3]);
}
std::vector objs;
try {
- objs = FilterUtility::GetFilterTargets(qd, params, user);
+ objs = FilterUtility::GetFilterTargets(qd, request.Params(), request.User());
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 404,
+ response.SendJsonError(request.Params(), 404,
"No objects found.",
DiagnosticInformation(ex));
return true;
}
- bool cascade = HttpUtility::GetLastParameter(params, "cascade");
- bool verbose = HttpUtility::GetLastParameter(params, "verbose");
+ bool cascade = request.GetLastParameter("cascade");
+ bool verbose = request.IsVerbose();
ConfigObjectsSharedLock lock (std::try_to_lock);
if (!lock) {
- HttpUtility::SendJsonError(response, params, 503, "Icinga is reloading");
+ response.SendJsonError(request.Params(), 503, "Icinga is reloading");
return true;
}
@@ -81,7 +78,7 @@ bool DeleteObjectHandler::HandleRequest(
std::shared_lock wgLock{*waitGroup, std::try_to_lock};
if (!wgLock) {
- HttpUtility::SendJsonError(response, params, 503, "Shutting down.");
+ response.SendJsonError(request.Params(), 503, "Shutting down.");
return true;
}
@@ -143,7 +140,7 @@ bool DeleteObjectHandler::HandleRequest(
else
response.result(http::status::ok);
- HttpUtility::SendJsonBody(response, params, result);
+ response.SendJsonBody(result, request.IsPretty());
return true;
}
diff --git a/lib/remote/deleteobjecthandler.hpp b/lib/remote/deleteobjecthandler.hpp
index 0f9643277..076f76704 100644
--- a/lib/remote/deleteobjecthandler.hpp
+++ b/lib/remote/deleteobjecthandler.hpp
@@ -16,11 +16,8 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
diff --git a/lib/remote/eventshandler.cpp b/lib/remote/eventshandler.cpp
index 2cbee92f3..56fce0037 100644
--- a/lib/remote/eventshandler.cpp
+++ b/lib/remote/eventshandler.cpp
@@ -42,11 +42,8 @@ const String l_ApiQuery ("");
bool EventsHandler::HandleRequest(
const WaitGroup::Ptr&,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
@@ -54,35 +51,35 @@ bool EventsHandler::HandleRequest(
namespace asio = boost::asio;
namespace http = boost::beast::http;
- if (url->GetPath().size() != 2)
+ if (request.Url()->GetPath().size() != 2)
return false;
if (request.method() != http::verb::post)
return false;
if (request.version() == 10) {
- HttpUtility::SendJsonError(response, params, 400, "HTTP/1.0 not supported for event streams.");
+ response.SendJsonError(request.Params(), 400, "HTTP/1.0 not supported for event streams.");
return true;
}
- Array::Ptr types = params->Get("types");
+ Array::Ptr types = request.Params()->Get("types");
if (!types) {
- HttpUtility::SendJsonError(response, params, 400, "'types' query parameter is required.");
+ response.SendJsonError(request.Params(), 400, "'types' query parameter is required.");
return true;
}
{
ObjectLock olock(types);
for (String type : types) {
- FilterUtility::CheckPermission(user, "events/" + type);
+ FilterUtility::CheckPermission(request.User(), "events/" + type);
}
}
- String queueName = HttpUtility::GetLastParameter(params, "queue");
+ String queueName = request.GetLastParameter("queue");
if (queueName.IsEmpty()) {
- HttpUtility::SendJsonError(response, params, 400, "'queue' query parameter is required.");
+ response.SendJsonError(request.Params(), 400, "'queue' query parameter is required.");
return true;
}
@@ -99,7 +96,7 @@ bool EventsHandler::HandleRequest(
}
}
- EventsSubscriber subscriber (std::move(eventTypes), HttpUtility::GetLastParameter(params, "filter"), l_ApiQuery);
+ EventsSubscriber subscriber (std::move(eventTypes), request.GetLastParameter("filter"), l_ApiQuery);
server.StartStreaming();
diff --git a/lib/remote/eventshandler.hpp b/lib/remote/eventshandler.hpp
index 49229733a..68a1f9844 100644
--- a/lib/remote/eventshandler.hpp
+++ b/lib/remote/eventshandler.hpp
@@ -17,11 +17,8 @@ public:
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) override;
diff --git a/lib/remote/httphandler.cpp b/lib/remote/httphandler.cpp
index 79571d760..5292123a5 100644
--- a/lib/remote/httphandler.cpp
+++ b/lib/remote/httphandler.cpp
@@ -49,9 +49,8 @@ void HttpHandler::Register(const Url::Ptr& url, const HttpHandler::Ptr& handler)
void HttpHandler::ProcessRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- boost::beast::http::response& response,
+ HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
@@ -59,8 +58,8 @@ void HttpHandler::ProcessRequest(
Dictionary::Ptr node = m_UrlTree;
std::vector handlers;
- Url::Ptr url = new Url(std::string(request.target()));
- auto& path (url->GetPath());
+ request.DecodeUrl();
+ auto& path (request.Url()->GetPath());
for (std::vector::size_type i = 0; i <= path.size(); i++) {
Array::Ptr current_handlers = node->Get("handlers");
@@ -90,12 +89,10 @@ void HttpHandler::ProcessRequest(
std::reverse(handlers.begin(), handlers.end());
- Dictionary::Ptr params;
-
try {
- params = HttpUtility::FetchRequestParameters(url, request.body());
+ request.DecodeParams();
} catch (const std::exception& ex) {
- HttpUtility::SendJsonError(response, params, 400, "Invalid request body: " + DiagnosticInformation(ex, false));
+ response.SendJsonError(nullptr, 400, "Invalid request body: " + DiagnosticInformation(ex, false));
return;
}
@@ -109,12 +106,20 @@ void HttpHandler::ProcessRequest(
*/
try {
for (const HttpHandler::Ptr& handler : handlers) {
- if (handler->HandleRequest(waitGroup, stream, user, request, url, response, params, yc, server)) {
+ if (handler->HandleRequest(waitGroup, stream, request, response, yc, server)) {
processed = true;
break;
}
}
} catch (const std::exception& ex) {
+ /* This means we can't send an error response because the exception was thrown
+ * in the middle of a streaming response. We can't send any error response, so the
+ * only thing we can do is propagate it up.
+ */
+ if (response.HasSerializationStarted()) {
+ throw;
+ }
+
Log(LogWarning, "HttpServerConnection")
<< "Error while processing HTTP request: " << ex.what();
@@ -122,7 +127,7 @@ void HttpHandler::ProcessRequest(
}
if (!processed) {
- HttpUtility::SendJsonError(response, params, 404, "The requested path '" + boost::algorithm::join(path, "/") +
+ response.SendJsonError(request.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 ec67ae8a4..0d6bd12b8 100644
--- a/lib/remote/httphandler.hpp
+++ b/lib/remote/httphandler.hpp
@@ -4,8 +4,10 @@
#define HTTPHANDLER_H
#include "remote/i2-remote.hpp"
+#include "base/io-engine.hpp"
#include "remote/url.hpp"
#include "remote/httpserverconnection.hpp"
+#include "remote/httpmessage.hpp"
#include "remote/apiuser.hpp"
#include "base/registry.hpp"
#include "base/tlsstream.hpp"
@@ -29,11 +31,8 @@ public:
virtual bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- const Url::Ptr& url,
- boost::beast::http::response& response,
- const Dictionary::Ptr& params,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
) = 0;
@@ -42,9 +41,8 @@ public:
static void ProcessRequest(
const WaitGroup::Ptr& waitGroup,
AsioTlsStream& stream,
- const ApiUser::Ptr& user,
- boost::beast::http::request& request,
- boost::beast::http::response& response,
+ HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc,
HttpServerConnection& server
);
diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp
index 17e61f160..617515822 100644
--- a/lib/remote/httpserverconnection.cpp
+++ b/lib/remote/httpserverconnection.cpp
@@ -129,10 +129,9 @@ bool HttpServerConnection::Disconnected()
static inline
bool EnsureValidHeaders(
- AsioTlsStream& stream,
boost::beast::flat_buffer& buf,
- boost::beast::http::parser& parser,
- boost::beast::http::response& response,
+ HttpRequest& request,
+ HttpResponse& response,
bool& shuttingDown,
boost::asio::yield_context& yc
)
@@ -147,7 +146,7 @@ bool EnsureValidHeaders(
boost::system::error_code ec;
- http::async_read_header(stream, buf, parser, yc[ec]);
+ request.ParseHeader(buf, yc[ec]);
if (ec) {
if (ec == boost::asio::error::operation_aborted)
@@ -156,7 +155,7 @@ bool EnsureValidHeaders(
errorMsg = ec.message();
httpError = true;
} else {
- switch (parser.get().version()) {
+ switch (request.version()) {
case 10:
case 11:
break;
@@ -168,21 +167,16 @@ bool EnsureValidHeaders(
if (!errorMsg.IsEmpty() || httpError) {
response.result(http::status::bad_request);
- if (!httpError && parser.get()[http::field::accept] == "application/json") {
- HttpUtility::SendJsonBody(response, nullptr, new Dictionary({
- { "error", 400 },
- { "status", String("Bad Request: ") + errorMsg }
- }));
+ if (!httpError && request[http::field::accept] == "application/json") {
+ response.SendJsonError(400, "Bad Request: " + errorMsg);
} else {
response.set(http::field::content_type, "text/html");
- response.body() = String("Bad Request
") + errorMsg + "
";
- response.content_length(response.body().size());
+ response.body() << "Bad Request
" << errorMsg << "
\r\n";
}
response.set(http::field::connection, "close");
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
return false;
}
@@ -192,28 +186,24 @@ bool EnsureValidHeaders(
static inline
void HandleExpect100(
- AsioTlsStream& stream,
- boost::beast::http::request& request,
+ const Shared::Ptr& stream,
+ const HttpRequest& request,
boost::asio::yield_context& yc
)
{
namespace http = boost::beast::http;
if (request[http::field::expect] == "100-continue") {
- http::response response;
-
+ HttpResponse response{stream};
response.result(http::status::continue_);
-
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
}
}
static inline
bool HandleAccessControl(
- AsioTlsStream& stream,
- boost::beast::http::request& request,
- boost::beast::http::response& response,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc
)
{
@@ -240,12 +230,10 @@ bool HandleAccessControl(
response.result(http::status::ok);
response.set(http::field::access_control_allow_methods, "GET, POST, PUT, DELETE");
response.set(http::field::access_control_allow_headers, "Authorization, Content-Type, X-HTTP-Method-Override");
- response.body() = "Preflight OK";
- response.content_length(response.body().size());
+ response.body() << "Preflight OK";
response.set(http::field::connection, "close");
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
return false;
}
@@ -258,9 +246,8 @@ bool HandleAccessControl(
static inline
bool EnsureAcceptHeader(
- AsioTlsStream& stream,
- boost::beast::http::request& request,
- boost::beast::http::response& response,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc
)
{
@@ -269,12 +256,10 @@ bool EnsureAcceptHeader(
if (request.method() != http::verb::get && request[http::field::accept] != "application/json") {
response.result(http::status::bad_request);
response.set(http::field::content_type, "text/html");
- response.body() = "Accept header is missing or not set to 'application/json'.
";
- response.content_length(response.body().size());
+ response.body() << "Accept header is missing or not set to 'application/json'.
\r\n";
response.set(http::field::connection, "close");
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
return false;
}
@@ -284,16 +269,14 @@ bool EnsureAcceptHeader(
static inline
bool EnsureAuthenticatedUser(
- AsioTlsStream& stream,
- boost::beast::http::request& request,
- ApiUser::Ptr& authenticatedUser,
- boost::beast::http::response& response,
+ const HttpRequest& request,
+ HttpResponse& response,
boost::asio::yield_context& yc
)
{
namespace http = boost::beast::http;
- if (!authenticatedUser) {
+ if (!request.User()) {
Log(LogWarning, "HttpServerConnection")
<< "Unauthorized request: " << request.method_string() << ' ' << request.target();
@@ -302,18 +285,13 @@ bool EnsureAuthenticatedUser(
response.set(http::field::connection, "close");
if (request[http::field::accept] == "application/json") {
- HttpUtility::SendJsonBody(response, nullptr, new Dictionary({
- { "error", 401 },
- { "status", "Unauthorized. Please check your user credentials." }
- }));
+ response.SendJsonError(401, "Unauthorized. Please check your user credentials.");
} else {
response.set(http::field::content_type, "text/html");
- response.body() = "Unauthorized. Please check your user credentials.
";
- response.content_length(response.body().size());
+ response.body() << "Unauthorized. Please check your user credentials.
\r\n";
}
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
return false;
}
@@ -323,11 +301,9 @@ bool EnsureAuthenticatedUser(
static inline
bool EnsureValidBody(
- AsioTlsStream& stream,
boost::beast::flat_buffer& buf,
- boost::beast::http::parser& parser,
- ApiUser::Ptr& authenticatedUser,
- boost::beast::http::response& response,
+ HttpRequest& request,
+ HttpResponse& response,
bool& shuttingDown,
boost::asio::yield_context& yc
)
@@ -336,7 +312,7 @@ bool EnsureValidBody(
{
size_t maxSize = 1024 * 1024;
- Array::Ptr permissions = authenticatedUser->GetPermissions();
+ Array::Ptr permissions = request.User()->GetPermissions();
if (permissions) {
ObjectLock olock(permissions);
@@ -366,7 +342,7 @@ bool EnsureValidBody(
}
}
- parser.body_limit(maxSize);
+ request.Parser().body_limit(maxSize);
}
if (shuttingDown)
@@ -374,7 +350,7 @@ bool EnsureValidBody(
boost::system::error_code ec;
- http::async_read(stream, buf, parser, yc[ec]);
+ request.ParseBody(buf, yc[ec]);
if (ec) {
if (ec == boost::asio::error::operation_aborted)
@@ -389,21 +365,16 @@ bool EnsureValidBody(
response.result(http::status::bad_request);
- if (parser.get()[http::field::accept] == "application/json") {
- HttpUtility::SendJsonBody(response, nullptr, new Dictionary({
- { "error", 400 },
- { "status", String("Bad Request: ") + ec.message() }
- }));
+ if (request[http::field::accept] == "application/json") {
+ response.SendJsonError(400, "Bad Request: " + ec.message());
} else {
response.set(http::field::content_type, "text/html");
- response.body() = String("Bad Request
") + ec.message() + "
";
- response.content_length(response.body().size());
+ response.body() << "Bad Request
" << ec.message() << "
\r\n";
}
response.set(http::field::connection, "close");
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.Flush(yc);
return false;
}
@@ -414,9 +385,8 @@ bool EnsureValidBody(
static inline
bool ProcessRequest(
AsioTlsStream& stream,
- boost::beast::http::request& request,
- ApiUser::Ptr& authenticatedUser,
- boost::beast::http::response& response,
+ HttpRequest& request,
+ HttpResponse& response,
HttpServerConnection& server,
bool& hasStartedStreaming,
const WaitGroup::Ptr& waitGroup,
@@ -424,42 +394,29 @@ bool ProcessRequest(
boost::asio::yield_context& yc
)
{
- namespace http = boost::beast::http;
-
try {
// Cache the elapsed time to acquire a CPU semaphore used to detect extremely heavy workloads.
auto start (std::chrono::steady_clock::now());
CpuBoundWork handlingRequest (yc);
cpuBoundWorkTime = std::chrono::steady_clock::now() - start;
- HttpHandler::ProcessRequest(waitGroup, stream, authenticatedUser, request, response, yc, server);
+ HttpHandler::ProcessRequest(waitGroup, stream, request, response, yc, server);
} catch (const std::exception& ex) {
- if (hasStartedStreaming) {
- return false;
- }
-
- auto sysErr (dynamic_cast(&ex));
-
- if (sysErr && sysErr->code() == boost::asio::error::operation_aborted) {
+ /* This means we can't do anything with the connection anymore, so we can't send
+ * an error response. And since we don't know the state the stream is in, we have to
+ * just cause a disconnect here.
+ */
+ if (response.HasSerializationStarted()) {
throw;
}
- http::response response;
-
- HttpUtility::SendJsonError(response, nullptr, 500, "Unhandled exception" , DiagnosticInformation(ex));
-
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
-
- return true;
- }
-
- if (hasStartedStreaming) {
+ response.SendJsonError(request.Params(), 500, "Unhandled exception", DiagnosticInformation(ex));
+ response.Flush(yc);
return false;
}
- http::async_write(stream, response, yc);
- stream.async_flush(yc);
+ response.body().Finish();
+ response.Flush(yc);
return true;
}
@@ -481,23 +438,21 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
while (m_WaitGroup->IsLockable()) {
m_Seen = Utility::GetTime();
- http::parser parser;
- http::response response;
+ HttpRequest request(m_Stream);
+ HttpResponse response(m_Stream);
- parser.header_limit(1024 * 1024);
- parser.body_limit(-1);
+ request.Parser().header_limit(1024 * 1024);
+ request.Parser().body_limit(-1);
response.set(http::field::server, l_ServerHeader);
- if (!EnsureValidHeaders(*m_Stream, buf, parser, response, m_ShuttingDown, yc)) {
+ if (!EnsureValidHeaders(buf, request, response, m_ShuttingDown, yc)) {
break;
}
m_Seen = Utility::GetTime();
auto start (ch::steady_clock::now());
- auto& request (parser.get());
-
{
auto method (http::string_to_verb(request["X-Http-Method-Override"]));
@@ -506,19 +461,20 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
}
}
- HandleExpect100(*m_Stream, request, yc);
+ HandleExpect100(m_Stream, request, yc);
- auto authenticatedUser (m_ApiUser);
-
- if (!authenticatedUser) {
- authenticatedUser = ApiUser::GetByAuthHeader(std::string(request[http::field::authorization]));
+ if (m_ApiUser) {
+ request.User(m_ApiUser);
+ } else {
+ auto user = ApiUser::GetByAuthHeader(std::string(request[http::field::authorization]));
+ request.User(user);
}
Log logMsg (LogInformation, "HttpServerConnection");
logMsg << "Request " << request.method_string() << ' ' << request.target()
<< " (from " << m_PeerAddress
- << ", user: " << (authenticatedUser ? authenticatedUser->GetName() : "")
+ << ", user: " << (request.User() ? request.User()->GetName() : "")
<< ", agent: " << request[http::field::user_agent]; //operator[] - Returns the value for a field, or "" if it does not exist.
ch::steady_clock::duration cpuBoundWorkTime(0);
@@ -531,29 +487,29 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
logMsg << " took total " << ch::duration_cast(ch::steady_clock::now() - start).count() << "ms.";
});
- if (!HandleAccessControl(*m_Stream, request, response, yc)) {
+ if (!HandleAccessControl(request, response, yc)) {
break;
}
- if (!EnsureAcceptHeader(*m_Stream, request, response, yc)) {
+ if (!EnsureAcceptHeader(request, response, yc)) {
break;
}
- if (!EnsureAuthenticatedUser(*m_Stream, request, authenticatedUser, response, yc)) {
+ if (!EnsureAuthenticatedUser(request, response, yc)) {
break;
}
- if (!EnsureValidBody(*m_Stream, buf, parser, authenticatedUser, response, m_ShuttingDown, yc)) {
+ if (!EnsureValidBody(buf, request, response, m_ShuttingDown, yc)) {
break;
}
m_Seen = std::numeric_limits::max();
- if (!ProcessRequest(*m_Stream, request, authenticatedUser, response, *this, m_HasStartedStreaming, m_WaitGroup, cpuBoundWorkTime, yc)) {
+ if (!ProcessRequest(*m_Stream, request, response, *this, m_HasStartedStreaming, m_WaitGroup, cpuBoundWorkTime, yc)) {
break;
}
- if (request.version() != 11 || request[http::field::connection] == "close") {
+ if (!request.keep_alive()) {
break;
}
}
diff --git a/lib/remote/httputility.cpp b/lib/remote/httputility.cpp
index a2142e5d8..a1a0a855a 100644
--- a/lib/remote/httputility.cpp
+++ b/lib/remote/httputility.cpp
@@ -3,40 +3,10 @@
#include "remote/httputility.hpp"
#include "remote/url.hpp"
#include "base/json.hpp"
-#include "base/logger.hpp"
-#include