HTTP -> Http

This commit is contained in:
sha512sum 2024-06-27 01:12:31 +00:00
parent 0d77aa7e3c
commit 61a7e85e52
10 changed files with 55 additions and 55 deletions

View file

@ -2,15 +2,15 @@
#include <cserver/engine/basic/task_processor.hpp> #include <cserver/engine/basic/task_processor.hpp>
#include <cserver/server/handlers/http_handler_base.hpp> #include <cserver/server/handlers/http_handler_base.hpp>
struct SomeComponent : public cserver::server::handlers::HTTPHandlerBaseWithAdder<SomeComponent> { struct SomeComponent : public cserver::server::handlers::HttpHandlerBaseWithAdder<SomeComponent> {
static constexpr utempl::ConstexprString kPath = "/v1/some/"; static constexpr utempl::ConstexprString kPath = "/v1/some/";
static constexpr utempl::ConstexprString kName = "name"; static constexpr utempl::ConstexprString kName = "name";
static constexpr utempl::ConstexprString kHandlerManagerName = "server"; static constexpr utempl::ConstexprString kHandlerManagerName = "server";
inline constexpr SomeComponent(auto name, auto& context) : inline constexpr SomeComponent(auto name, auto& context) :
HTTPHandlerBaseWithAdder(name, context) {}; HttpHandlerBaseWithAdder(name, context) {};
inline auto HandleRequestThrow(const cserver::server::http::HTTPRequest& request) -> cserver::Task<cserver::server::http::HTTPResponse> { inline auto HandleRequestThrow(const cserver::server::http::HttpRequest& request) -> cserver::Task<cserver::server::http::HttpResponse> {
co_return cserver::server::http::HTTPResponse{.body = request.url.data()}; co_return cserver::server::http::HttpResponse{.body = request.url.data()};
}; };
}; };

View file

@ -52,16 +52,16 @@ private:
std::unreachable(); std::unreachable();
}(); }();
} else { } else {
return [] -> server::http::HTTPResponse { return [] -> server::http::HttpResponse {
std::unreachable(); std::unreachable();
}(); }();
}; };
}; };
template <typename Socket> template <typename Socket>
inline auto ReadHeaders(Socket&& socket, auto&&...) const -> cserver::Task<server::http::HTTPResponse> { inline auto ReadHeaders(Socket&& socket, auto&&...) const -> cserver::Task<server::http::HttpResponse> {
std::string serverResponse; std::string serverResponse;
co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(serverResponse), "\r\n\r\n", boost::asio::use_awaitable); co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(serverResponse), "\r\n\r\n", boost::asio::use_awaitable);
server::http::HTTPResponse response; server::http::HttpResponse response;
std::istringstream responseStream(std::move(serverResponse)); std::istringstream responseStream(std::move(serverResponse));
std::string httpVersion; std::string httpVersion;
responseStream >> httpVersion >> response.statusCode; responseStream >> httpVersion >> response.statusCode;

View file

@ -7,7 +7,7 @@ namespace cserver::clients::http {
template <typename HttpClient> template <typename HttpClient>
struct Request { struct Request {
HttpClient& client; HttpClient& client;
server::http::HTTPRequest request; server::http::HttpRequest request;
Request(HttpClient& client) : Request(HttpClient& client) :
client(client) { client(client) {
this->AddHeader("User-Agent", "cserver/1"); this->AddHeader("User-Agent", "cserver/1");

View file

@ -6,7 +6,7 @@
namespace cserver::clients::http { namespace cserver::clients::http {
template <typename HttpClient, typename Socket> template <typename HttpClient, typename Socket>
class Response : public server::http::HTTPResponse { class Response : public server::http::HttpResponse {
HttpClient& client; HttpClient& client;
Socket socket; Socket socket;
@ -25,10 +25,10 @@ public:
}; };
inline constexpr Response(Response&&) = default; inline constexpr Response(Response&&) = default;
inline constexpr Response(const Response&) = default; inline constexpr Response(const Response&) = default;
inline constexpr Response(HttpClient& client, Socket socket, server::http::HTTPResponse response) : inline constexpr Response(HttpClient& client, Socket socket, server::http::HttpResponse response) :
client(client), client(client),
socket(std::move(socket)), socket(std::move(socket)),
HTTPResponse(std::move(response)) {}; HttpResponse(std::move(response)) {};
}; };
} // namespace cserver::clients::http } // namespace cserver::clients::http

View file

@ -7,16 +7,16 @@
namespace cserver::server::handlers { namespace cserver::server::handlers {
struct HTTPHandlerBase { struct HttpHandlerBase {
template <typename T, utempl::ConstexprString name, Options Options> template <typename T, utempl::ConstexprString name, Options Options>
static consteval auto Adder(const auto& context) { static consteval auto HttpHandlerAdder(const auto& context) {
return context.TransformComponents([]<typename TT>(const ComponentConfig<T::kHandlerManagerName, TT, Options>) { return context.TransformComponents([]<typename TT>(const ComponentConfig<T::kHandlerManagerName, TT, Options>) {
return ComponentConfig<T::kHandlerManagerName, typename TT::template AddHandler<ComponentConfig<name, T, Options>>, Options>{}; return ComponentConfig<T::kHandlerManagerName, typename TT::template AddHandler<ComponentConfig<name, T, Options>>, Options>{};
}); });
}; };
template <typename Self> template <typename Self>
inline auto HandleRequest(this Self&& self, http::HTTPRequest&& request inline auto HandleRequest(this Self&& self, http::HttpRequest&& request
) -> Task<http::HTTPResponse> requires requires{self.HandleRequestThrow(std::move(request));} { ) -> Task<http::HttpResponse> requires requires{self.HandleRequestThrow(std::move(request));} {
using T = std::remove_cvref_t<Self>; using T = std::remove_cvref_t<Self>;
try { try {
co_return co_await std::forward<Self>(self).HandleRequestThrow(std::move(request)); co_return co_await std::forward<Self>(self).HandleRequestThrow(std::move(request));
@ -25,11 +25,11 @@ struct HTTPHandlerBase {
} catch(...) { } catch(...) {
fmt::println("Error in handler with default name {}: Unknown Error", T::kName); fmt::println("Error in handler with default name {}: Unknown Error", T::kName);
}; };
co_return http::HTTPResponse{.statusCode = 500, .statusMessage = "Internal Server Error", .body = "Internal Server Error"}; co_return http::HttpResponse{.statusCode = 500, .statusMessage = "Internal Server Error", .body = "Internal Server Error"};
}; };
template <typename Self> template <typename Self>
inline auto HandleRequestStream(this Self&& self, cserver::server::http::HTTPRequest&& request, inline auto HandleRequestStream(this Self&& self, cserver::server::http::HttpRequest&& request,
cserver::server::http::HTTPStream& stream) -> Task<void> requires requires{self.HandleRequestStreamThrow(std::move(request), stream);} { cserver::server::http::HttpStream& stream) -> Task<void> requires requires{self.HandleRequestStreamThrow(std::move(request), stream);} {
using T = std::remove_cvref_t<Self>; using T = std::remove_cvref_t<Self>;
try { try {
co_await std::forward<Self>(self).HandleRequestStreamThrow(std::move(request), stream); co_await std::forward<Self>(self).HandleRequestStreamThrow(std::move(request), stream);
@ -40,20 +40,20 @@ struct HTTPHandlerBase {
}; };
co_await stream.Close(); co_await stream.Close();
}; };
inline constexpr HTTPHandlerBase(auto, auto&) {}; inline constexpr HttpHandlerBase(auto, auto&) {};
}; };
template <typename T> template <typename T>
struct HTTPHandlerAdder { struct HttpHandlerAdderType {
template <utempl::ConstexprString Name, Options Options> template <utempl::ConstexprString Name, Options Options>
static consteval auto Adder(const auto& context) { static consteval auto Adder(const auto& context) {
return HTTPHandlerBase::template Adder<T, Name, Options>(context); return HttpHandlerBase::template HttpHandlerAdder<T, Name, Options>(context);
}; };
}; };
template <typename T> template <typename T>
struct HTTPHandlerBaseWithAdder : HTTPHandlerBase, HTTPHandlerAdder<T> { struct HttpHandlerBaseWithAdder : HttpHandlerBase, HttpHandlerAdderType<T> {
inline constexpr HTTPHandlerBaseWithAdder(auto name, auto& context) : inline constexpr HttpHandlerBaseWithAdder(auto name, auto& context) :
HTTPHandlerBase(name, context), HttpHandlerBase(name, context),
HTTPHandlerAdder<T>{} {}; HttpHandlerAdderType<T>{} {};
}; };
} // namespace cserver::server::handlers } // namespace cserver::server::handlers

View file

@ -6,14 +6,14 @@
namespace cserver::server::http { namespace cserver::server::http {
struct HTTPRequest { struct HttpRequest {
std::string method = {}; std::string method = {};
boost::urls::url url = {}; boost::urls::url url = {};
std::unordered_map<std::string, std::string> headers = {}; std::unordered_map<std::string, std::string> headers = {};
std::string body = {}; std::string body = {};
inline auto ToString() const -> std::string { inline auto ToString() const -> std::string {
std::ostringstream stream; std::ostringstream stream;
stream << fmt::format("{} {} HTTP/1.1\r\n", this->method, this->url.path()); stream << fmt::format("{} {} Http/1.1\r\n", this->method, this->url.path());
for(const auto& header : this->headers) { for(const auto& header : this->headers) {
stream << fmt::format("{}: {}\r\n", header.first, header.second); stream << fmt::format("{}: {}\r\n", header.first, header.second);
}; };

View file

@ -4,65 +4,65 @@
namespace cserver::server::http { namespace cserver::server::http {
struct HTTPRequestParser : private llhttp_t, public HTTPRequest { struct HttpRequestParser : private llhttp_t, public HttpRequest {
bool err = false; bool err = false;
bool done = false; bool done = false;
std::string headerField = {}; std::string headerField = {};
std::string headerValue = {}; std::string headerValue = {};
std::string urlString = {}; std::string urlString = {};
inline HTTPRequestParser(std::string_view data) { inline HttpRequestParser(std::string_view data) {
llhttp_settings_t settings; llhttp_settings_t settings;
llhttp_settings_init(&settings); llhttp_settings_init(&settings);
settings.on_method = HTTPRequestParser::OnMethod; settings.on_method = HttpRequestParser::OnMethod;
settings.on_url = HTTPRequestParser::OnUrl; settings.on_url = HttpRequestParser::OnUrl;
settings.on_url_complete = HTTPRequestParser::OnUrlComplete; settings.on_url_complete = HttpRequestParser::OnUrlComplete;
settings.on_header_field = HTTPRequestParser::OnHeaderField; settings.on_header_field = HttpRequestParser::OnHeaderField;
settings.on_header_value = HTTPRequestParser::OnHeaderValue; settings.on_header_value = HttpRequestParser::OnHeaderValue;
settings.on_headers_complete = HTTPRequestParser::OnHeaderComplete; settings.on_headers_complete = HttpRequestParser::OnHeaderComplete;
settings.on_body = HTTPRequestParser::OnBody; settings.on_body = HttpRequestParser::OnBody;
settings.on_message_complete = HTTPRequestParser::OnMessageComplete; settings.on_message_complete = HttpRequestParser::OnMessageComplete;
llhttp_init(this, HTTP_BOTH, &settings); llhttp_init(this, HTTP_BOTH, &settings);
llhttp_execute(this, data.data(), data.size()); llhttp_execute(this, data.data(), data.size());
}; };
static inline auto OnMethod(llhttp_t* parser, const char* data, std::size_t size) -> int { static inline auto OnMethod(llhttp_t* parser, const char* data, std::size_t size) -> int {
auto* self = static_cast<HTTPRequest*>(static_cast<HTTPRequestParser*>(parser)); auto* self = static_cast<HttpRequest*>(static_cast<HttpRequestParser*>(parser));
self->method.append(data, size); self->method.append(data, size);
return 0; return 0;
}; };
static inline auto OnUrl(llhttp_t* parser, const char* data, std::size_t size) -> int { static inline auto OnUrl(llhttp_t* parser, const char* data, std::size_t size) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->urlString.append(data, size); self->urlString.append(data, size);
return 0; return 0;
}; };
static inline auto OnUrlComplete(llhttp_t* parser) -> int { static inline auto OnUrlComplete(llhttp_t* parser) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->url = boost::urls::url(self->urlString); self->url = boost::urls::url(self->urlString);
return 0; return 0;
}; };
static inline auto OnHeaderField(llhttp_t* parser, const char* data, std::size_t size) -> int { static inline auto OnHeaderField(llhttp_t* parser, const char* data, std::size_t size) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->headerField.append(data, size); self->headerField.append(data, size);
return 0; return 0;
}; };
static inline auto OnHeaderValue(llhttp_t* parser, const char* data, std::size_t size) -> int { static inline auto OnHeaderValue(llhttp_t* parser, const char* data, std::size_t size) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->headerValue.append(data, size); self->headerValue.append(data, size);
return 0; return 0;
}; };
static inline auto OnHeaderComplete(llhttp_t* parser) -> int { static inline auto OnHeaderComplete(llhttp_t* parser) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->headers.emplace(std::move(self->headerField), std::move(self->headerValue)); self->headers.emplace(std::move(self->headerField), std::move(self->headerValue));
self->headerValue.clear(); self->headerValue.clear();
self->headerField.clear(); self->headerField.clear();
return 0; return 0;
}; };
static inline auto OnBody(llhttp_t* parser, const char* data, std::size_t size) -> int { static inline auto OnBody(llhttp_t* parser, const char* data, std::size_t size) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->body.append(data, size); self->body.append(data, size);
return 0; return 0;
}; };
static inline auto OnMessageComplete(llhttp_t* parser) -> int { static inline auto OnMessageComplete(llhttp_t* parser) -> int {
auto* self = static_cast<HTTPRequestParser*>(parser); auto* self = static_cast<HttpRequestParser*>(parser);
self->done = true; self->done = true;
return 0; return 0;
}; };

View file

@ -5,14 +5,14 @@
namespace cserver::server::http { namespace cserver::server::http {
struct HTTPResponse { struct HttpResponse {
unsigned short statusCode = 200; unsigned short statusCode = 200;
std::string statusMessage = "OK"; std::string statusMessage = "OK";
std::unordered_map<std::string, std::string> headers = {}; std::unordered_map<std::string, std::string> headers = {};
std::string body = {}; std::string body = {};
inline auto ToString() const -> std::string { inline auto ToString() const -> std::string {
std::ostringstream stream; std::ostringstream stream;
stream << fmt::format("HTTP/1.1 {} {}\r\n", this->statusCode, this->statusMessage); stream << fmt::format("Http/1.1 {} {}\r\n", this->statusCode, this->statusMessage);
for(const auto& header : this->headers) { for(const auto& header : this->headers) {
stream << fmt::format("{}: {}\r\n", header.first, header.second); stream << fmt::format("{}: {}\r\n", header.first, header.second);
}; };

View file

@ -5,7 +5,7 @@
namespace cserver::server::http { namespace cserver::server::http {
struct HTTPStream { struct HttpStream {
boost::asio::ip::tcp::socket socket; boost::asio::ip::tcp::socket socket;
std::stringstream stream = {}; std::stringstream stream = {};
inline auto SetMethod(std::string method) -> Task<void> { inline auto SetMethod(std::string method) -> Task<void> {
@ -13,7 +13,7 @@ struct HTTPStream {
co_await boost::asio::async_write(this->socket, boost::asio::buffer(method.data(), method.size()), boost::asio::transfer_all(), boost::asio::use_awaitable); co_await boost::asio::async_write(this->socket, boost::asio::buffer(method.data(), method.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
}; };
inline auto SetStatus(std::string status) -> Task<void> { inline auto SetStatus(std::string status) -> Task<void> {
status = fmt::format("HTTP/1.1 {}\r\n", std::move(status)); status = fmt::format("Http/1.1 {}\r\n", std::move(status));
co_await boost::asio::async_write(this->socket, boost::asio::buffer(status.data(), status.size()), boost::asio::transfer_all(), boost::asio::use_awaitable); co_await boost::asio::async_write(this->socket, boost::asio::buffer(status.data(), status.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
}; };

View file

@ -49,13 +49,13 @@ struct Server : StopBlocker {
Server(std::index_sequence_for<Ts...>{}, name, context) { Server(std::index_sequence_for<Ts...>{}, name, context) {
}; };
template<auto I, typename Socket> template<auto I, typename Socket>
auto ProcessHandler(Socket&& socket, http::HTTPRequest request) -> Task<void> { auto ProcessHandler(Socket&& socket, http::HttpRequest request) -> Task<void> {
if constexpr(requires(http::HTTPStream& stream){Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);}) { if constexpr(requires(http::HttpStream& stream){Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);}) {
http::HTTPStream stream{std::move(socket)}; http::HttpStream stream{std::move(socket)};
co_await Get<I>(this->handlers).HandleRequestStream(std::move(request), stream); co_await Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);
co_return; co_return;
} else { } else {
http::HTTPResponse response = co_await Get<I>(this->handlers).HandleRequest(std::move(request)); http::HttpResponse response = co_await Get<I>(this->handlers).HandleRequest(std::move(request));
response.headers["Content-Length"] = std::to_string(response.body.size()); response.headers["Content-Length"] = std::to_string(response.body.size());
response.headers["Server"] = "cserver/1"; response.headers["Server"] = "cserver/1";
auto data = response.ToString(); auto data = response.ToString();
@ -67,7 +67,7 @@ struct Server : StopBlocker {
std::string buffer; std::string buffer;
buffer.reserve(socket.available()); buffer.reserve(socket.available());
co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(buffer), "\r\n\r\n", boost::asio::use_awaitable); co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(buffer), "\r\n\r\n", boost::asio::use_awaitable);
http::HTTPRequest request = http::HTTPRequestParser{buffer}; http::HttpRequest request = http::HttpRequestParser{buffer};
bool flag = false; bool flag = false;
co_await [&]<auto... Is>(std::index_sequence<Is...>) -> cserver::Task<void> { co_await [&]<auto... Is>(std::index_sequence<Is...>) -> cserver::Task<void> {
(co_await [&] -> cserver::Task<void> { (co_await [&] -> cserver::Task<void> {
@ -76,7 +76,7 @@ struct Server : StopBlocker {
}; };
}(), ...); }(), ...);
}(std::index_sequence_for<Ts...>()); }(std::index_sequence_for<Ts...>());
constexpr std::string_view error404 = "HTTP/1.1 404 Not Found\r\n" constexpr std::string_view error404 = "Http/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n" "Content-Length: 0\r\n"
"\r\n"; "\r\n";
if(!flag) { if(!flag) {