mirror of
https://github.com/Icinga/icinga2.git
synced 2026-02-03 20:40:17 -05:00
Merge pull request #10692 from Icinga/refactor-httpmessage-more-general
Some checks are pending
Container Image / Container Image (push) Waiting to run
Linux / alpine:bash (push) Waiting to run
Linux / amazonlinux:2 (push) Waiting to run
Linux / amazonlinux:2023 (push) Waiting to run
Linux / debian:11 (linux/386) (push) Waiting to run
Linux / debian:11 (push) Waiting to run
Linux / debian:12 (linux/386) (push) Waiting to run
Linux / debian:12 (push) Waiting to run
Linux / debian:13 (push) Waiting to run
Linux / fedora:41 (push) Waiting to run
Linux / fedora:42 (push) Waiting to run
Linux / fedora:43 (push) Waiting to run
Linux / opensuse/leap:15.6 (push) Waiting to run
Linux / opensuse/leap:16.0 (push) Waiting to run
Linux / registry.suse.com/bci/bci-base:16.0 (push) Waiting to run
Linux / registry.suse.com/suse/sle15:15.6 (push) Waiting to run
Linux / registry.suse.com/suse/sle15:15.7 (push) Waiting to run
Linux / rockylinux/rockylinux:10 (push) Waiting to run
Linux / rockylinux:8 (push) Waiting to run
Linux / rockylinux:9 (push) Waiting to run
Linux / ubuntu:22.04 (push) Waiting to run
Linux / ubuntu:24.04 (push) Waiting to run
Linux / ubuntu:25.04 (push) Waiting to run
Linux / ubuntu:25.10 (push) Waiting to run
Windows / Windows (push) Waiting to run
Some checks are pending
Container Image / Container Image (push) Waiting to run
Linux / alpine:bash (push) Waiting to run
Linux / amazonlinux:2 (push) Waiting to run
Linux / amazonlinux:2023 (push) Waiting to run
Linux / debian:11 (linux/386) (push) Waiting to run
Linux / debian:11 (push) Waiting to run
Linux / debian:12 (linux/386) (push) Waiting to run
Linux / debian:12 (push) Waiting to run
Linux / debian:13 (push) Waiting to run
Linux / fedora:41 (push) Waiting to run
Linux / fedora:42 (push) Waiting to run
Linux / fedora:43 (push) Waiting to run
Linux / opensuse/leap:15.6 (push) Waiting to run
Linux / opensuse/leap:16.0 (push) Waiting to run
Linux / registry.suse.com/bci/bci-base:16.0 (push) Waiting to run
Linux / registry.suse.com/suse/sle15:15.6 (push) Waiting to run
Linux / registry.suse.com/suse/sle15:15.7 (push) Waiting to run
Linux / rockylinux/rockylinux:10 (push) Waiting to run
Linux / rockylinux:8 (push) Waiting to run
Linux / rockylinux:9 (push) Waiting to run
Linux / ubuntu:22.04 (push) Waiting to run
Linux / ubuntu:24.04 (push) Waiting to run
Linux / ubuntu:25.04 (push) Waiting to run
Linux / ubuntu:25.10 (push) Waiting to run
Windows / Windows (push) Waiting to run
Refactor HttpMessage into generalized templated types
This commit is contained in:
commit
aa0e7b6c7d
42 changed files with 369 additions and 238 deletions
|
|
@ -13,6 +13,7 @@
|
|||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <boost/asio/buffered_stream.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
|
@ -122,9 +123,9 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
typedef boost::asio::buffered_stream<boost::asio::ip::tcp::socket> AsioTcpStream;
|
||||
typedef std::pair<Shared<AsioTlsStream>::Ptr, Shared<AsioTcpStream>::Ptr> OptionalTlsStream;
|
||||
|
||||
using AsioTcpStream = boost::asio::buffered_stream<boost::asio::ip::tcp::socket>;
|
||||
using OptionalTlsStream = std::pair<Shared<AsioTlsStream>::Ptr, Shared<AsioTcpStream>::Ptr>;
|
||||
using AsioTlsOrTcpStream = std::variant<Shared<AsioTlsStream>::Ptr, Shared<AsioTcpStream>::Ptr>;
|
||||
}
|
||||
|
||||
#endif /* TLSSTREAM_H */
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ REGISTER_URLHANDLER("/v1/actions", ActionsHandler);
|
|||
|
||||
bool ActionsHandler::HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler);
|
|||
|
||||
bool ConfigFilesHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler);
|
|||
|
||||
bool ConfigPackagesHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -39,7 +39,7 @@ bool ConfigPackagesHandler::HandleRequest(
|
|||
return true;
|
||||
}
|
||||
|
||||
void ConfigPackagesHandler::HandleGet(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigPackagesHandler::HandleGet(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ void ConfigPackagesHandler::HandleGet(const HttpRequest& request, HttpResponse&
|
|||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
||||
void ConfigPackagesHandler::HandlePost(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigPackagesHandler::HandlePost(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ void ConfigPackagesHandler::HandlePost(const HttpRequest& request, HttpResponse&
|
|||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
||||
void ConfigPackagesHandler::HandleDelete(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigPackagesHandler::HandleDelete(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,15 +15,15 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
|
||||
private:
|
||||
void HandleGet(const HttpRequest& request, HttpResponse& response);
|
||||
void HandlePost(const HttpRequest& request, HttpResponse& response);
|
||||
void HandleDelete(const HttpRequest& request, HttpResponse& response);
|
||||
void HandleGet(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
void HandlePost(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
void HandleDelete(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ static std::mutex l_RunningPackageUpdatesMutex; // Protects the above two variab
|
|||
|
||||
bool ConfigStagesHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -46,7 +46,7 @@ bool ConfigStagesHandler::HandleRequest(
|
|||
return true;
|
||||
}
|
||||
|
||||
void ConfigStagesHandler::HandleGet(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigStagesHandler::HandleGet(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ void ConfigStagesHandler::HandleGet(const HttpRequest& request, HttpResponse& re
|
|||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
||||
void ConfigStagesHandler::HandlePost(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigStagesHandler::HandlePost(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ void ConfigStagesHandler::HandlePost(const HttpRequest& request, HttpResponse& r
|
|||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
||||
void ConfigStagesHandler::HandleDelete(const HttpRequest& request, HttpResponse& response)
|
||||
void ConfigStagesHandler::HandleDelete(const HttpApiRequest& request, HttpApiResponse& response)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,15 +15,15 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
|
||||
private:
|
||||
void HandleGet(const HttpRequest& request, HttpResponse& response);
|
||||
void HandlePost(const HttpRequest& request, HttpResponse& response);
|
||||
void HandleDelete(const HttpRequest& request, HttpResponse& response);
|
||||
void HandleGet(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
void HandlePost(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
void HandleDelete(const HttpApiRequest& request, HttpApiResponse& response);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ static void EnsureFrameCleanupTimer()
|
|||
|
||||
bool ConsoleHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -102,7 +102,7 @@ bool ConsoleHandler::HandleRequest(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleHandler::ExecuteScriptHelper(const HttpRequest& request, HttpResponse& response,
|
||||
bool ConsoleHandler::ExecuteScriptHelper(const HttpApiRequest& request, HttpApiResponse& response,
|
||||
const String& command, const String& session, bool sandboxed)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
|
@ -176,7 +176,7 @@ bool ConsoleHandler::ExecuteScriptHelper(const HttpRequest& request, HttpRespons
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleHandler::AutocompleteScriptHelper(const HttpRequest& request, HttpResponse& response,
|
||||
bool ConsoleHandler::AutocompleteScriptHelper(const HttpApiRequest& request, HttpApiResponse& response,
|
||||
const String& command, const String& session, bool sandboxed)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
|
|
|||
|
|
@ -24,17 +24,17 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
|
||||
static std::vector<String> GetAutocompletionSuggestions(const String& word, ScriptFrame& frame);
|
||||
|
||||
private:
|
||||
static bool ExecuteScriptHelper(const HttpRequest& request, HttpResponse& response,
|
||||
static bool ExecuteScriptHelper(const HttpApiRequest& request, HttpApiResponse& response,
|
||||
const String& command, const String& session, bool sandboxed);
|
||||
static bool AutocompleteScriptHelper(const HttpRequest& request, HttpResponse& response,
|
||||
static bool AutocompleteScriptHelper(const HttpApiRequest& request, HttpApiResponse& response,
|
||||
const String& command, const String& session, bool sandboxed);
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ REGISTER_URLHANDLER("/v1/objects", CreateObjectHandler);
|
|||
|
||||
bool CreateObjectHandler::HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ REGISTER_URLHANDLER("/v1/objects", DeleteObjectHandler);
|
|||
|
||||
bool DeleteObjectHandler::HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ const String l_ApiQuery ("<API query>");
|
|||
|
||||
bool EventsHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ void HttpHandler::Register(const Url::Ptr& url, const HttpHandler::Ptr& handler)
|
|||
|
||||
void HttpHandler::ProcessRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,16 +30,16 @@ public:
|
|||
|
||||
virtual bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) = 0;
|
||||
|
||||
static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler);
|
||||
static void ProcessRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/* Icinga 2 | (c) 2025 Icinga GmbH | GPLv2+ */
|
||||
|
||||
#include "remote/httpmessage.hpp"
|
||||
#include "base/io-engine.hpp"
|
||||
#include "base/json.hpp"
|
||||
#include "remote/httputility.hpp"
|
||||
#include "remote/url.hpp"
|
||||
|
|
@ -27,10 +26,15 @@ constexpr std::size_t l_FlushThreshold = 128UL * 1024UL;
|
|||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<typename Message>
|
||||
class HttpResponseJsonWriter : public AsyncJsonWriter
|
||||
{
|
||||
public:
|
||||
explicit HttpResponseJsonWriter(HttpResponse& msg) : m_Message{msg}
|
||||
HttpResponseJsonWriter(const HttpResponseJsonWriter&) = delete;
|
||||
HttpResponseJsonWriter(HttpResponseJsonWriter&&) = delete;
|
||||
HttpResponseJsonWriter& operator=(const HttpResponseJsonWriter&) = delete;
|
||||
HttpResponseJsonWriter& operator=(HttpResponseJsonWriter&&) = delete;
|
||||
explicit HttpResponseJsonWriter(Message& msg) : m_Message{msg}
|
||||
{
|
||||
m_Message.body().Start();
|
||||
#if BOOST_VERSION >= 107000
|
||||
|
|
@ -59,51 +63,65 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
HttpResponse& m_Message;
|
||||
Message& m_Message;
|
||||
};
|
||||
|
||||
HttpRequest::HttpRequest(Shared<AsioTlsStream>::Ptr stream) : m_Stream(std::move(stream))
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
IncomingHttpMessage<isRequest, Body, StreamVariant>::IncomingHttpMessage(StreamVariant stream)
|
||||
: m_Stream(std::move(stream))
|
||||
{
|
||||
}
|
||||
|
||||
void HttpRequest::ParseHeader(boost::beast::flat_buffer& buf, boost::asio::yield_context yc)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void IncomingHttpMessage<isRequest, Body, StreamVariant>::ParseHeader(
|
||||
boost::beast::flat_buffer& buf,
|
||||
boost::asio::yield_context yc
|
||||
)
|
||||
{
|
||||
boost::beast::http::async_read_header(*m_Stream, buf, m_Parser, yc);
|
||||
base() = m_Parser.get().base();
|
||||
std::visit([&](auto& stream) { boost::beast::http::async_read_header(*stream, buf, m_Parser, yc); }, m_Stream);
|
||||
Base::base() = m_Parser.get().base();
|
||||
}
|
||||
|
||||
void HttpRequest::ParseBody(boost::beast::flat_buffer& buf, boost::asio::yield_context yc)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void IncomingHttpMessage<isRequest, Body, StreamVariant>::ParseBody(
|
||||
boost::beast::flat_buffer& buf,
|
||||
boost::asio::yield_context yc
|
||||
)
|
||||
{
|
||||
boost::beast::http::async_read(*m_Stream, buf, m_Parser, yc);
|
||||
body() = std::move(m_Parser.release().body());
|
||||
std::visit([&](auto& stream) { boost::beast::http::async_read(*stream, buf, m_Parser, yc); }, m_Stream);
|
||||
Base::body() = std::move(m_Parser.release().body());
|
||||
}
|
||||
|
||||
ApiUser::Ptr HttpRequest::User() const
|
||||
HttpApiRequest::HttpApiRequest(Shared<AsioTlsStream>::Ptr stream) : IncomingHttpMessage(std::move(stream))
|
||||
{
|
||||
}
|
||||
|
||||
ApiUser::Ptr HttpApiRequest::User() const
|
||||
{
|
||||
return m_User;
|
||||
}
|
||||
|
||||
void HttpRequest::User(const ApiUser::Ptr& user)
|
||||
void HttpApiRequest::User(const ApiUser::Ptr& user)
|
||||
{
|
||||
m_User = user;
|
||||
}
|
||||
|
||||
Url::Ptr HttpRequest::Url() const
|
||||
Url::Ptr HttpApiRequest::Url() const
|
||||
{
|
||||
return m_Url;
|
||||
}
|
||||
|
||||
void HttpRequest::DecodeUrl()
|
||||
void HttpApiRequest::DecodeUrl()
|
||||
{
|
||||
m_Url = new icinga::Url(std::string(target()));
|
||||
}
|
||||
|
||||
Dictionary::Ptr HttpRequest::Params() const
|
||||
Dictionary::Ptr HttpApiRequest::Params() const
|
||||
{
|
||||
return m_Params;
|
||||
}
|
||||
|
||||
void HttpRequest::DecodeParams()
|
||||
void HttpApiRequest::DecodeParams()
|
||||
{
|
||||
if (!m_Url) {
|
||||
DecodeUrl();
|
||||
|
|
@ -111,49 +129,72 @@ void HttpRequest::DecodeParams()
|
|||
m_Params = HttpUtility::FetchRequestParameters(m_Url, body());
|
||||
}
|
||||
|
||||
HttpResponse::HttpResponse(Shared<AsioTlsStream>::Ptr stream, HttpServerConnection::Ptr server)
|
||||
: m_Server(std::move(server)), m_Stream(std::move(stream))
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
OutgoingHttpMessage<isRequest, Body, StreamVariant>::OutgoingHttpMessage(StreamVariant stream)
|
||||
: m_Stream(std::move(stream))
|
||||
{
|
||||
}
|
||||
|
||||
void HttpResponse::Clear()
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void OutgoingHttpMessage<isRequest, Body, StreamVariant>::Clear()
|
||||
{
|
||||
ASSERT(!m_SerializationStarted);
|
||||
boost::beast::http::response<body_type>::operator=({});
|
||||
Base::operator=({});
|
||||
}
|
||||
|
||||
void HttpResponse::Flush(boost::asio::yield_context yc)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void OutgoingHttpMessage<isRequest, Body, StreamVariant>::Flush(boost::asio::yield_context yc, bool finish)
|
||||
{
|
||||
if (!chunked() && !has_content_length()) {
|
||||
if (!Base::chunked() && !Base::has_content_length()) {
|
||||
ASSERT(!m_SerializationStarted);
|
||||
prepare_payload();
|
||||
Base::prepare_payload();
|
||||
}
|
||||
|
||||
m_SerializationStarted = true;
|
||||
std::visit(
|
||||
[&](auto& stream) {
|
||||
m_SerializationStarted = true;
|
||||
|
||||
if (!m_Serializer.is_header_done()) {
|
||||
boost::beast::http::write_header(*m_Stream, m_Serializer);
|
||||
}
|
||||
if (!m_Serializer.is_header_done()) {
|
||||
boost::beast::http::write_header(*stream, m_Serializer);
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::beast::http::async_write(*m_Stream, m_Serializer, yc[ec]);
|
||||
if (ec && ec != boost::beast::http::error::need_buffer) {
|
||||
if (yc.ec_) {
|
||||
*yc.ec_ = ec;
|
||||
return;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
|
||||
}
|
||||
m_Stream->async_flush(yc);
|
||||
if (finish) {
|
||||
Base::body().Finish();
|
||||
}
|
||||
|
||||
ASSERT(m_Serializer.is_done() || !body().Finished());
|
||||
boost::system::error_code ec;
|
||||
boost::beast::http::async_write(*stream, m_Serializer, yc[ec]);
|
||||
if (ec && ec != boost::beast::http::error::need_buffer) {
|
||||
if (yc.ec_) {
|
||||
*yc.ec_ = ec;
|
||||
return;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
|
||||
}
|
||||
stream->async_flush(yc);
|
||||
|
||||
ASSERT(m_Serializer.is_done() || !Base::body().Finished());
|
||||
},
|
||||
m_Stream
|
||||
);
|
||||
}
|
||||
|
||||
void HttpResponse::StartStreaming(bool checkForDisconnect)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void OutgoingHttpMessage<isRequest, Body, StreamVariant>::StartStreaming()
|
||||
{
|
||||
ASSERT(body().Size() == 0 && !m_SerializationStarted);
|
||||
body().Start();
|
||||
chunked(true);
|
||||
ASSERT(Base::body().Size() == 0 && !m_SerializationStarted);
|
||||
Base::body().Start();
|
||||
Base::chunked(true);
|
||||
}
|
||||
|
||||
HttpApiResponse::HttpApiResponse(Shared<AsioTlsStream>::Ptr stream, HttpServerConnection::Ptr server)
|
||||
: OutgoingHttpMessage(std::move(stream)), m_Server(std::move(server))
|
||||
{
|
||||
}
|
||||
|
||||
void HttpApiResponse::StartStreaming(bool checkForDisconnect)
|
||||
{
|
||||
OutgoingHttpMessage::StartStreaming();
|
||||
|
||||
if (checkForDisconnect) {
|
||||
ASSERT(m_Server);
|
||||
|
|
@ -161,13 +202,17 @@ void HttpResponse::StartStreaming(bool checkForDisconnect)
|
|||
}
|
||||
}
|
||||
|
||||
bool HttpResponse::IsClientDisconnected() const
|
||||
bool HttpApiResponse::IsClientDisconnected() const
|
||||
{
|
||||
ASSERT(m_Server);
|
||||
return m_Server->Disconnected();
|
||||
}
|
||||
|
||||
void HttpResponse::SendFile(const String& path, const boost::asio::yield_context& yc)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
void OutgoingHttpMessage<isRequest, Body, StreamVariant>::SendFile(
|
||||
const String& path,
|
||||
const boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
fp.exceptions(std::ifstream::badbit | std::ifstream::eofbit);
|
||||
|
|
@ -175,22 +220,44 @@ void HttpResponse::SendFile(const String& path, const boost::asio::yield_context
|
|||
std::uint64_t remaining = fp.tellg();
|
||||
fp.seekg(0);
|
||||
|
||||
content_length(remaining);
|
||||
body().Start();
|
||||
Base::content_length(remaining);
|
||||
Base::body().Start();
|
||||
|
||||
while (remaining) {
|
||||
auto maxTransfer = std::min(remaining, static_cast<std::uint64_t>(l_FlushThreshold));
|
||||
|
||||
auto buf = *body().Buffer().prepare(maxTransfer).begin();
|
||||
using BodyBuffer = std::decay_t<decltype(std::declval<typename Body::value_type>().Buffer())>;
|
||||
using BufferOrSequence = typename BodyBuffer::mutable_buffers_type;
|
||||
|
||||
boost::asio::mutable_buffer buf;
|
||||
|
||||
if constexpr (!std::is_same_v<BufferOrSequence, boost::asio::mutable_buffer>) {
|
||||
buf = *Base::body().Buffer().prepare(maxTransfer).begin();
|
||||
} else {
|
||||
buf = Base::body().Buffer().prepare(maxTransfer);
|
||||
}
|
||||
fp.read(static_cast<char*>(buf.data()), buf.size());
|
||||
body().Buffer().commit(buf.size());
|
||||
Base::body().Buffer().commit(buf.size());
|
||||
|
||||
remaining -= buf.size();
|
||||
Flush(yc);
|
||||
}
|
||||
}
|
||||
|
||||
JsonEncoder HttpResponse::GetJsonEncoder(bool pretty)
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
JsonEncoder OutgoingHttpMessage<isRequest, Body, StreamVariant>::GetJsonEncoder(bool pretty)
|
||||
{
|
||||
return JsonEncoder{std::make_shared<HttpResponseJsonWriter>(*this), pretty};
|
||||
return JsonEncoder{
|
||||
std::make_shared<HttpResponseJsonWriter<OutgoingHttpMessage<isRequest, Body, StreamVariant>>>(*this), pretty
|
||||
};
|
||||
}
|
||||
|
||||
// More general instantiations
|
||||
template class icinga::OutgoingHttpMessage<true, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
template class icinga::OutgoingHttpMessage<false, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
template class icinga::IncomingHttpMessage<true, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
template class icinga::IncomingHttpMessage<false, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
|
||||
// Instantiations specifically for HttpApi(Request|Response)
|
||||
template class icinga::IncomingHttpMessage<true, boost::beast::http::string_body, std::variant<Shared<AsioTlsStream>::Ptr>>;
|
||||
template class icinga::OutgoingHttpMessage<false, SerializableMultiBufferBody, std::variant<Shared<AsioTlsStream>::Ptr>>;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "remote/url.hpp"
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace icinga {
|
||||
|
||||
|
|
@ -143,17 +144,17 @@ struct SerializableBody
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper class for a boost::beast HTTP request
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
class HttpRequest : public boost::beast::http::request<boost::beast::http::string_body>
|
||||
{
|
||||
public:
|
||||
using ParserType = boost::beast::http::request_parser<body_type>;
|
||||
using SerializableMultiBufferBody = SerializableBody<boost::beast::multi_buffer>;
|
||||
using SerializableFlatBufferBody = SerializableBody<boost::beast::flat_buffer>;
|
||||
|
||||
explicit HttpRequest(Shared<AsioTlsStream>::Ptr stream);
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
class IncomingHttpMessage : public boost::beast::http::message<isRequest, Body>
|
||||
{
|
||||
using ParserType = boost::beast::http::parser<isRequest, Body>;
|
||||
using Base = boost::beast::http::message<isRequest, Body>;
|
||||
|
||||
public:
|
||||
explicit IncomingHttpMessage(StreamVariant stream);
|
||||
|
||||
/**
|
||||
* Parse the header of the response using the internal parser object.
|
||||
|
|
@ -176,34 +177,23 @@ public:
|
|||
|
||||
ParserType& Parser() { return m_Parser; }
|
||||
|
||||
[[nodiscard]] ApiUser::Ptr User() const;
|
||||
void User(const ApiUser::Ptr& user);
|
||||
|
||||
[[nodiscard]] icinga::Url::Ptr Url() const;
|
||||
void DecodeUrl();
|
||||
|
||||
[[nodiscard]] Dictionary::Ptr Params() const;
|
||||
void DecodeParams();
|
||||
|
||||
private:
|
||||
ApiUser::Ptr m_User;
|
||||
Url::Ptr m_Url;
|
||||
Dictionary::Ptr m_Params;
|
||||
|
||||
ParserType m_Parser;
|
||||
|
||||
Shared<AsioTlsStream>::Ptr m_Stream;
|
||||
StreamVariant m_Stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper class for a boost::beast HTTP response
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
class HttpResponse : public boost::beast::http::response<SerializableBody<boost::beast::multi_buffer>>
|
||||
using IncomingHttpRequest = IncomingHttpMessage<true, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
using IncomingHttpResponse = IncomingHttpMessage<false, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
|
||||
template<bool isRequest, typename Body, typename StreamVariant>
|
||||
class OutgoingHttpMessage : public boost::beast::http::message<isRequest, Body>
|
||||
{
|
||||
using Serializer = boost::beast::http::serializer<isRequest, Body>;
|
||||
using Base = boost::beast::http::message<isRequest, Body>;
|
||||
|
||||
public:
|
||||
explicit HttpResponse(Shared<AsioTlsStream>::Ptr stream, HttpServerConnection::Ptr server = nullptr);
|
||||
explicit OutgoingHttpMessage(StreamVariant stream);
|
||||
|
||||
/* Delete the base class clear() which is inherited from the fields<> class and doesn't
|
||||
* clear things like the body or obviously our own members.
|
||||
|
|
@ -217,6 +207,32 @@ public:
|
|||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Commits the specified number of bytes (previously obtained via @c prepare()) for reading.
|
||||
*
|
||||
* This function makes the specified number of bytes available in the body buffer for reading.
|
||||
*
|
||||
* @param size The number of bytes to commit
|
||||
*/
|
||||
void Commit(std::size_t size) { Base::body().Buffer().commit(size); }
|
||||
|
||||
/**
|
||||
* Prepare a buffer of the specified size for writing.
|
||||
*
|
||||
* The returned buffer serves just as a view onto the internal buffer sequence but does not actually
|
||||
* own the memory. Thus, destroying the returned buffer will not free any memory it represents.
|
||||
*
|
||||
* @param size The size of the buffer to prepare
|
||||
*
|
||||
* @return A mutable buffer representing the prepared space
|
||||
*/
|
||||
auto Prepare(std::size_t size) { return Base::body().Buffer().prepare(size); }
|
||||
|
||||
/**
|
||||
* Enables chunked encoding.
|
||||
*/
|
||||
void StartStreaming();
|
||||
|
||||
/**
|
||||
* Writes as much of the response as is currently available.
|
||||
*
|
||||
|
|
@ -228,31 +244,10 @@ public:
|
|||
*
|
||||
* @param yc The yield_context for this operation
|
||||
*/
|
||||
void Flush(boost::asio::yield_context yc);
|
||||
void Flush(boost::asio::yield_context yc, bool finish = false);
|
||||
|
||||
[[nodiscard]] bool HasSerializationStarted() const { return m_SerializationStarted; }
|
||||
|
||||
/**
|
||||
* Enables chunked encoding.
|
||||
*
|
||||
* Optionally starts a coroutine that reads from the stream and checks for client-side
|
||||
* disconnects. In this case, the stream can not be reused after the response has been
|
||||
* sent and any further requests sent over the connections will be discarded, even if
|
||||
* no client-side disconnect occurs. This requires that this object has been constructed
|
||||
* with a valid HttpServerConnection::Ptr.
|
||||
*
|
||||
* @param checkForDisconnect Whether to start a coroutine to detect disconnects
|
||||
*/
|
||||
void StartStreaming(bool checkForDisconnect = false);
|
||||
|
||||
/**
|
||||
* Check if the server has initiated a disconnect.
|
||||
*
|
||||
* @note This requires that the message has been constructed with a pointer to the
|
||||
* @c HttpServerConnection.
|
||||
*/
|
||||
[[nodiscard]] bool IsClientDisconnected() const;
|
||||
|
||||
/**
|
||||
* Sends the contents of a file.
|
||||
*
|
||||
|
|
@ -270,12 +265,80 @@ public:
|
|||
JsonEncoder GetJsonEncoder(bool pretty = false);
|
||||
|
||||
private:
|
||||
using Serializer = boost::beast::http::response_serializer<HttpResponse::body_type>;
|
||||
Serializer m_Serializer{*this};
|
||||
bool m_SerializationStarted = false;
|
||||
|
||||
HttpServerConnection::Ptr m_Server;
|
||||
Shared<AsioTlsStream>::Ptr m_Stream;
|
||||
StreamVariant m_Stream;
|
||||
};
|
||||
|
||||
using OutgoingHttpRequest = OutgoingHttpMessage<true, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
using OutgoingHttpResponse = OutgoingHttpMessage<false, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
|
||||
class HttpApiRequest
|
||||
: public IncomingHttpMessage<true, boost::beast::http::string_body, std::variant<Shared<AsioTlsStream>::Ptr>>
|
||||
{
|
||||
public:
|
||||
explicit HttpApiRequest(Shared<AsioTlsStream>::Ptr stream);
|
||||
|
||||
[[nodiscard]] ApiUser::Ptr User() const;
|
||||
void User(const ApiUser::Ptr& user);
|
||||
|
||||
[[nodiscard]] icinga::Url::Ptr Url() const;
|
||||
void DecodeUrl();
|
||||
|
||||
[[nodiscard]] Dictionary::Ptr Params() const;
|
||||
void DecodeParams();
|
||||
|
||||
private:
|
||||
ApiUser::Ptr m_User;
|
||||
Url::Ptr m_Url;
|
||||
Dictionary::Ptr m_Params;
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper class for a boost::beast HTTP response for the Icinga 2 API
|
||||
*
|
||||
* @ingroup remote
|
||||
*/
|
||||
class HttpApiResponse
|
||||
: public OutgoingHttpMessage<false, SerializableMultiBufferBody, std::variant<Shared<AsioTlsStream>::Ptr>>
|
||||
{
|
||||
public:
|
||||
explicit HttpApiResponse(Shared<AsioTlsStream>::Ptr stream, HttpServerConnection::Ptr server = nullptr);
|
||||
|
||||
/**
|
||||
* Enables chunked encoding.
|
||||
*
|
||||
* Optionally starts a coroutine that reads from the stream and checks for client-side
|
||||
* disconnects. In this case, the stream can not be reused after the response has been
|
||||
* sent and any further requests sent over the connections will be discarded, even if
|
||||
* no client-side disconnect occurs. This requires that this object has been constructed
|
||||
* with a valid HttpServerConnection::Ptr.
|
||||
*
|
||||
* @param checkForDisconnect Whether to start a coroutine to detect disconnects
|
||||
*/
|
||||
void StartStreaming(bool checkForDisconnect);
|
||||
|
||||
/**
|
||||
* Check if the server has initiated a disconnect.
|
||||
*
|
||||
* @note This requires that the message has been constructed with a pointer to the
|
||||
* @c HttpServerConnection.
|
||||
*/
|
||||
[[nodiscard]] bool IsClientDisconnected() const;
|
||||
|
||||
private:
|
||||
HttpServerConnection::Ptr m_Server;
|
||||
};
|
||||
|
||||
// More general instantiations
|
||||
extern template class OutgoingHttpMessage<true, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
extern template class OutgoingHttpMessage<false, SerializableFlatBufferBody, AsioTlsOrTcpStream>;
|
||||
extern template class IncomingHttpMessage<true, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
extern template class IncomingHttpMessage<false, boost::beast::http::string_body, AsioTlsOrTcpStream>;
|
||||
|
||||
// Instantiations specifically for HttpApi(Request|Response)
|
||||
extern template class IncomingHttpMessage<true, boost::beast::http::string_body, std::variant<Shared<AsioTlsStream>::Ptr>>;
|
||||
extern template class OutgoingHttpMessage<false, SerializableMultiBufferBody, std::variant<Shared<AsioTlsStream>::Ptr>>;
|
||||
|
||||
} // namespace icinga
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ void HttpServerConnection::StartDetectClientSideShutdown()
|
|||
* If this async_fill() then buffers more application data and not an immediate eof, we could
|
||||
* attempt to read another message before disconnecting.
|
||||
*
|
||||
* This could either be done at the level of the handlers, via the @c HttpResponse class, or
|
||||
* This could either be done at the level of the handlers, via the @c HttpApiResponse class, or
|
||||
* generally as a separate coroutine here in @c HttpServerConnection, both (mostly) side-effect
|
||||
* free and without affecting the state of the connection.
|
||||
*
|
||||
|
|
@ -159,8 +159,8 @@ void HttpServerConnection::SetLivenessTimeout(std::chrono::milliseconds timeout)
|
|||
static inline
|
||||
bool EnsureValidHeaders(
|
||||
boost::beast::flat_buffer& buf,
|
||||
HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
bool& shuttingDown,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
|
|
@ -216,14 +216,14 @@ bool EnsureValidHeaders(
|
|||
static inline
|
||||
void HandleExpect100(
|
||||
const Shared<AsioTlsStream>::Ptr& stream,
|
||||
const HttpRequest& request,
|
||||
const HttpApiRequest& request,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
if (request[http::field::expect] == "100-continue") {
|
||||
HttpResponse response{stream};
|
||||
HttpApiResponse response{stream};
|
||||
response.result(http::status::continue_);
|
||||
response.Flush(yc);
|
||||
}
|
||||
|
|
@ -231,8 +231,8 @@ void HandleExpect100(
|
|||
|
||||
static inline
|
||||
bool HandleAccessControl(
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -275,8 +275,8 @@ bool HandleAccessControl(
|
|||
|
||||
static inline
|
||||
bool EnsureAcceptHeader(
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -298,8 +298,8 @@ bool EnsureAcceptHeader(
|
|||
|
||||
static inline
|
||||
bool EnsureAuthenticatedUser(
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -331,8 +331,8 @@ bool EnsureAuthenticatedUser(
|
|||
static inline
|
||||
bool EnsureValidBody(
|
||||
boost::beast::flat_buffer& buf,
|
||||
HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
bool& shuttingDown,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
|
|
@ -413,8 +413,8 @@ bool EnsureValidBody(
|
|||
|
||||
static inline
|
||||
void ProcessRequest(
|
||||
HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
std::chrono::steady_clock::duration& cpuBoundWorkTime,
|
||||
boost::asio::yield_context& yc
|
||||
|
|
@ -459,8 +459,8 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
|
|||
while (m_WaitGroup->IsLockable()) {
|
||||
m_Seen = ch::steady_clock::now();
|
||||
|
||||
HttpRequest request(m_Stream);
|
||||
HttpResponse response(m_Stream, this);
|
||||
HttpApiRequest request(m_Stream);
|
||||
HttpApiResponse response(m_Stream, this);
|
||||
|
||||
request.Parser().header_limit(1024 * 1024);
|
||||
request.Parser().body_limit(-1);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ Value HttpUtility::GetLastParameter(const Dictionary::Ptr& params, const String&
|
|||
return arr->Get(arr->GetLength() - 1);
|
||||
}
|
||||
|
||||
void HttpUtility::SendJsonBody(HttpResponse& response, const Dictionary::Ptr& params, const Value& val)
|
||||
void HttpUtility::SendJsonBody(HttpApiResponse& response, const Dictionary::Ptr& params, const Value& val)
|
||||
{
|
||||
namespace http = boost::beast::http;
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ void HttpUtility::SendJsonBody(HttpResponse& response, const Dictionary::Ptr& pa
|
|||
response.GetJsonEncoder(params && GetLastParameter(params, "pretty")).Encode(val);
|
||||
}
|
||||
|
||||
void HttpUtility::SendJsonError(HttpResponse& response,
|
||||
void HttpUtility::SendJsonError(HttpApiResponse& response,
|
||||
const Dictionary::Ptr& params, int code, const String& info, const String& diagnosticInformation)
|
||||
{
|
||||
Dictionary::Ptr result = new Dictionary({ { "error", code } });
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ public:
|
|||
static Dictionary::Ptr FetchRequestParameters(const Url::Ptr& url, const std::string& body);
|
||||
static Value GetLastParameter(const Dictionary::Ptr& params, const String& key);
|
||||
|
||||
static void SendJsonBody(HttpResponse& response, const Dictionary::Ptr& params, const Value& val);
|
||||
static void SendJsonError(HttpResponse& response, const Dictionary::Ptr& params, const int code,
|
||||
static void SendJsonBody(HttpApiResponse& response, const Dictionary::Ptr& params, const Value& val);
|
||||
static void SendJsonError(HttpApiResponse& response, const Dictionary::Ptr& params, const int code,
|
||||
const String& info = {}, const String& diagnosticInformation = {});
|
||||
|
||||
static bool IsValidHeaderName(std::string_view name);
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ REGISTER_URLHANDLER("/", InfoHandler);
|
|||
|
||||
bool InfoHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ REGISTER_URLHANDLER("/v1/debug/malloc_info", MallocInfoHandler);
|
|||
|
||||
bool MallocInfoHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context&
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ REGISTER_URLHANDLER("/v1/objects", ModifyObjectHandler);
|
|||
|
||||
bool ModifyObjectHandler::HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ Dictionary::Ptr ObjectQueryHandler::SerializeObjectAttrs(const Object::Ptr& obje
|
|||
|
||||
bool ObjectQueryHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
@ -328,7 +328,7 @@ bool ObjectQueryHandler::HandleRequest(
|
|||
|
||||
response.result(http::status::ok);
|
||||
response.set(http::field::content_type, "application/json");
|
||||
response.StartStreaming();
|
||||
response.StartStreaming(false);
|
||||
|
||||
Dictionary::Ptr results = new Dictionary{{"results", new ValueGenerator{generatorFunc}}};
|
||||
results->Freeze();
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ public:
|
|||
|
||||
bool StatusHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ public:
|
|||
|
||||
bool TemplateQueryHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ public:
|
|||
|
||||
bool TypeQueryHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ public:
|
|||
|
||||
bool VariableQueryHandler::HandleRequest(
|
||||
const WaitGroup::Ptr&,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public:
|
|||
|
||||
bool HandleRequest(
|
||||
const WaitGroup::Ptr& waitGroup,
|
||||
const HttpRequest& request,
|
||||
HttpResponse& response,
|
||||
const HttpApiRequest& request,
|
||||
HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc
|
||||
) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(request_parse)
|
|||
|
||||
auto future = SpawnSynchronizedCoroutine([this, &requestOut](boost::asio::yield_context yc) {
|
||||
boost::beast::flat_buffer buf;
|
||||
HttpRequest request(server);
|
||||
HttpApiRequest request(server);
|
||||
BOOST_REQUIRE_NO_THROW(request.ParseHeader(buf, yc));
|
||||
|
||||
for (const auto& field : requestOut.base()) {
|
||||
|
|
@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(request_parse)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(request_params)
|
||||
{
|
||||
HttpRequest request(client);
|
||||
HttpApiRequest request(client);
|
||||
// clang-format off
|
||||
request.body() = JsonEncode(
|
||||
new Dictionary{
|
||||
|
|
@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(request_params)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(response_clear)
|
||||
{
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::bad_request);
|
||||
response.version(10);
|
||||
response.set(http::field::content_type, "text/html");
|
||||
|
|
@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(response_clear)
|
|||
BOOST_AUTO_TEST_CASE(response_flush_nothrow)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](const boost::asio::yield_context& yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
|
||||
server->lowest_layer().close();
|
||||
|
|
@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(response_flush_nothrow)
|
|||
BOOST_AUTO_TEST_CASE(response_flush_throw)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](const boost::asio::yield_context& yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
|
||||
server->lowest_layer().close();
|
||||
|
|
@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(response_flush_throw)
|
|||
BOOST_AUTO_TEST_CASE(response_write_empty)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
|
||||
BOOST_REQUIRE_NO_THROW(response.Flush(yc));
|
||||
|
|
@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(response_write_empty)
|
|||
BOOST_AUTO_TEST_CASE(response_write_fixed)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
response.body() << "test";
|
||||
|
||||
|
|
@ -225,10 +225,10 @@ BOOST_AUTO_TEST_CASE(response_write_chunked)
|
|||
{
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
|
||||
response.StartStreaming();
|
||||
response.StartStreaming(false);
|
||||
BOOST_REQUIRE_NO_THROW(response.Flush(yc));
|
||||
BOOST_REQUIRE(response.HasSerializationStarted());
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(response_write_chunked)
|
|||
BOOST_AUTO_TEST_CASE(response_sendjsonbody)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
response.result(http::status::ok);
|
||||
|
||||
HttpUtility::SendJsonBody(response, nullptr, new Dictionary{{"test", 1}});
|
||||
|
|
@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(response_sendjsonbody)
|
|||
BOOST_AUTO_TEST_CASE(response_sendjsonerror)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
|
||||
// This has to be overwritten in SendJsonError.
|
||||
response.result(http::status::ok);
|
||||
|
|
@ -324,7 +324,7 @@ BOOST_AUTO_TEST_CASE(response_sendjsonerror)
|
|||
BOOST_AUTO_TEST_CASE(response_sendfile)
|
||||
{
|
||||
auto future = SpawnSynchronizedCoroutine([this](boost::asio::yield_context yc) {
|
||||
HttpResponse response(server);
|
||||
HttpApiResponse response(server);
|
||||
|
||||
response.result(http::status::ok);
|
||||
BOOST_REQUIRE_NO_THROW(response.SendFile(m_CaCrtFile.string(), yc));
|
||||
|
|
|
|||
|
|
@ -67,12 +67,12 @@ struct HttpServerConnectionFixture : TlsStreamFixture, ConfigurationCacheDirFixt
|
|||
class UnitTestHandler final : public HttpHandler
|
||||
{
|
||||
public:
|
||||
using TestFn = std::function<void(HttpResponse& response, const boost::asio::yield_context&)>;
|
||||
using TestFn = std::function<void(HttpApiResponse& response, const boost::asio::yield_context&)>;
|
||||
|
||||
static void RegisterTestFn(std::string handle, TestFn fn) { testFns[std::move(handle)] = std::move(fn); }
|
||||
|
||||
private:
|
||||
bool HandleRequest(const WaitGroup::Ptr&, const HttpRequest& request, HttpResponse& response,
|
||||
bool HandleRequest(const WaitGroup::Ptr&, const HttpApiRequest& request, HttpApiResponse& response,
|
||||
boost::asio::yield_context& yc) override
|
||||
{
|
||||
response.result(boost::beast::http::status::ok);
|
||||
|
|
@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(wg_abort)
|
|||
CreateTestUsers();
|
||||
SetupHttpServerConnection(true);
|
||||
|
||||
UnitTestHandler::RegisterTestFn("wgjoin", [this](HttpResponse& response, const boost::asio::yield_context&) {
|
||||
UnitTestHandler::RegisterTestFn("wgjoin", [this](HttpApiResponse& response, const boost::asio::yield_context&) {
|
||||
response.body() << "test";
|
||||
m_WaitGroup->Join();
|
||||
});
|
||||
|
|
@ -421,8 +421,8 @@ BOOST_AUTO_TEST_CASE(client_shutdown)
|
|||
CreateTestUsers();
|
||||
SetupHttpServerConnection(true);
|
||||
|
||||
UnitTestHandler::RegisterTestFn("stream", [](HttpResponse& response, const boost::asio::yield_context& yc) {
|
||||
response.StartStreaming();
|
||||
UnitTestHandler::RegisterTestFn("stream", [](HttpApiResponse& response, const boost::asio::yield_context& yc) {
|
||||
response.StartStreaming(false);
|
||||
response.Flush(yc);
|
||||
|
||||
boost::asio::deadline_timer dt{IoEngine::Get().GetIoContext()};
|
||||
|
|
@ -470,8 +470,8 @@ BOOST_AUTO_TEST_CASE(handler_throw_error)
|
|||
CreateTestUsers();
|
||||
SetupHttpServerConnection(true);
|
||||
|
||||
UnitTestHandler::RegisterTestFn("throw", [](HttpResponse& response, const boost::asio::yield_context&) {
|
||||
response.StartStreaming();
|
||||
UnitTestHandler::RegisterTestFn("throw", [](HttpApiResponse& response, const boost::asio::yield_context&) {
|
||||
response.StartStreaming(false);
|
||||
response.body() << "test";
|
||||
|
||||
boost::system::error_code ec{};
|
||||
|
|
@ -508,8 +508,8 @@ BOOST_AUTO_TEST_CASE(handler_throw_streaming)
|
|||
CreateTestUsers();
|
||||
SetupHttpServerConnection(true);
|
||||
|
||||
UnitTestHandler::RegisterTestFn("throw", [](HttpResponse& response, const boost::asio::yield_context& yc) {
|
||||
response.StartStreaming();
|
||||
UnitTestHandler::RegisterTestFn("throw", [](HttpApiResponse& response, const boost::asio::yield_context& yc) {
|
||||
response.StartStreaming(false);
|
||||
response.body() << "test";
|
||||
|
||||
response.Flush(yc);
|
||||
|
|
|
|||
Loading…
Reference in a new issue