REGISTER_URLHANDLER("/v1/actions", ActionsHandler);
bool ActionsHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ActionsHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler);
bool ConfigFilesHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ConfigFilesHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler);
bool ConfigPackagesHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ConfigPackagesHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
private:
REGISTER_URLHANDLER("/v1/config/stages", ConfigStagesHandler);
bool ConfigStagesHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ConfigStagesHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
private:
}
bool ConsoleHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ConsoleHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
static std::vector<String> GetAutocompletionSuggestions(const String& word, ScriptFrame& frame);
REGISTER_URLHANDLER("/v1/objects", CreateObjectHandler);
bool CreateObjectHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(CreateObjectHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
REGISTER_URLHANDLER("/v1/objects", DeleteObjectHandler);
bool DeleteObjectHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(DeleteObjectHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
#include "remote/filterutility.hpp"
#include "config/configcompiler.hpp"
#include "config/expression.hpp"
+#include "base/defer.hpp"
#include "base/objectlock.hpp"
#include "base/json.hpp"
+#include <boost/asio/buffer.hpp>
#include <boost/algorithm/string/replace.hpp>
using namespace icinga;
REGISTER_URLHANDLER("/v1/events", EventsHandler);
bool EventsHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
+ namespace asio = boost::asio;
namespace http = boost::beast::http;
if (url->GetPath().size() != 2)
queue->AddClient(&request);
+ Defer removeClient ([&queue, &request, &queueName]() {
+ queue->RemoveClient(&request);
+ EventQueue::UnregisterIfUnused(queueName, queue);
+ });
+
+ hasStartedStreaming = true;
+
response.result(http::status::ok);
response.set(http::field::content_type, "application/json");
+ http::async_write(stream, response, yc);
+ stream.async_flush(yc);
+
+ asio::const_buffer newLine ("\n", 1);
+
for (;;) {
Dictionary::Ptr result = queue->WaitForEvent(&request);
- if (!response.IsPeerConnected()) {
- queue->RemoveClient(&request);
- EventQueue::UnregisterIfUnused(queueName, queue);
- return true;
- }
-
if (!result)
continue;
boost::algorithm::replace_all(body, "\n", "");
- try {
- response.WriteBody(body.CStr(), body.GetLength());
- response.WriteBody("\n", 1);
- } catch (const std::exception&) {
- queue->RemoveClient(&request);
- EventQueue::UnregisterIfUnused(queueName, queue);
- throw;
- }
+ asio::const_buffer payload (body.CStr(), body.GetLength());
+
+ stream.async_write_some(payload, yc);
+ stream.async_write_some(newLine, yc);
+ stream.async_flush(yc);
}
}
DECLARE_PTR_TYPEDEFS(EventsHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
}
void HttpHandler::ProcessRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
- boost::beast::http::response<boost::beast::http::string_body>& response
+ boost::beast::http::response<boost::beast::http::string_body>& response,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
Dictionary::Ptr node = m_UrlTree;
bool processed = false;
for (const HttpHandler::Ptr& handler : handlers) {
- if (handler->HandleRequest(user, request, url, response, params)) {
+ if (handler->HandleRequest(stream, user, request, url, response, params, yc, hasStartedStreaming)) {
processed = true;
break;
}
#include "remote/httpresponse.hpp"
#include "remote/apiuser.hpp"
#include "base/registry.hpp"
+#include "base/tlsstream.hpp"
#include <vector>
+#include <boost/asio/spawn.hpp>
#include <boost/beast/http.hpp>
namespace icinga
DECLARE_PTR_TYPEDEFS(HttpHandler);
virtual bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) = 0;
static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler);
static void ProcessRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
- boost::beast::http::response<boost::beast::http::string_body>& response
+ boost::beast::http::response<boost::beast::http::string_body>& response,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
);
private:
}
static inline
-void ProcessRequest(
+bool ProcessRequest(
AsioTlsStream& stream,
boost::beast::http::request<boost::beast::http::string_body>& request,
ApiUser::Ptr& authenticatedUser,
{
namespace http = boost::beast::http;
+ bool hasStartedStreaming = false;
+
try {
CpuBoundWork handlingRequest (yc);
- HttpHandler::ProcessRequest(authenticatedUser, request, response);
+ HttpHandler::ProcessRequest(stream, authenticatedUser, request, response, yc, hasStartedStreaming);
} catch (const std::exception& ex) {
+ if (hasStartedStreaming) {
+ return false;
+ }
+
http::response<http::string_body> response;
HttpUtility::SendJsonError(response, nullptr, 500, "Unhandled exception" , DiagnosticInformation(ex));
http::async_write(stream, response, yc);
stream.async_flush(yc);
- return;
+ return true;
+ }
+
+ if (hasStartedStreaming) {
+ return false;
}
http::async_write(stream, response, yc);
stream.async_flush(yc);
+
+ return true;
}
void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
break;
}
- ProcessRequest(*m_Stream, request, authenticatedUser, response, yc);
+ if (!ProcessRequest(*m_Stream, request, authenticatedUser, response, yc)) {
+ break;
+ }
if (request.version() != 11 || request[http::field::connection] == "close") {
break;
REGISTER_URLHANDLER("/", InfoHandler);
bool InfoHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(InfoHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
REGISTER_URLHANDLER("/v1/objects", ModifyObjectHandler);
bool ModifyObjectHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ModifyObjectHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
}
bool ObjectQueryHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(ObjectQueryHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
private:
};
bool StatusHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(StatusHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
};
bool TemplateQueryHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(TemplateQueryHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
};
bool TypeQueryHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(TypeQueryHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};
};
bool VariableQueryHandler::HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
)
{
namespace http = boost::beast::http;
DECLARE_PTR_TYPEDEFS(VariableQueryHandler);
bool HandleRequest(
+ AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
- const Dictionary::Ptr& params
+ const Dictionary::Ptr& params,
+ boost::asio::yield_context& yc,
+ bool& hasStartedStreaming
) override;
};