// Project Includes #include "http.hpp" // Standard Library Includes #include #include #include #include #include #include #include HttpRequestParser::HttpRequestParser() { llhttp_settings_init(&m_settings); /*1*/ m_settings.on_message_complete = HttpRequestParser::on_message_complete; /*2*/ m_settings.on_url = HttpRequestParser::on_url; /*3*/ m_settings.on_method = HttpRequestParser::on_method; /*4*/ m_settings.on_version = HttpRequestParser::on_version; /*5*/ m_settings.on_header_field = HttpRequestParser::on_header_field; /*6*/ m_settings.on_header_value = HttpRequestParser::on_header_value; /*7*/ m_settings.on_body = HttpRequestParser::on_body; llhttp_init(&m_parser, HTTP_REQUEST, &m_settings); m_parser.data = this; m_state = State::Idle; } void HttpRequestParser::reset() { llhttp_reset(&m_parser); m_parser.data = this; m_completed_requests.clear(); m_current_request = HttpRequest{}; m_current_header_field.clear(); m_current_header_value.clear(); m_header_state = HeaderState::None; m_state = State::Idle; } std::expected HttpRequestParser::parse(std::span data) { if (m_state == State::Error) { std::println(std::cerr, "Parser in error state, resetting"); reset(); } if (data.empty()) { if (!m_completed_requests.empty()) { m_state = State::Completed; } return {}; } auto data_ptr = std::bit_cast(data.data()); auto data_len = data.size(); llhttp_errno_t status = llhttp_execute(&m_parser, data_ptr, data_len); if (status != HPE_OK && status != HPE_PAUSED && status != HPE_PAUSED_UPGRADE) { const char *reason = llhttp_get_error_reason(&m_parser); std::string error_message = reason ? reason : "Unknown parsing error"; reset(); m_state = State::Error; return std::unexpected(error_message); } if (!m_completed_requests.empty()) { m_state = State::Completed; return {}; } m_state = State::Parsing; return {}; } HttpRequestParser &HttpRequestParser::from_llhttp(llhttp_t *parser) { return *static_cast(parser->data); } void HttpRequestParser::commit_pending_header() { if (m_header_state == HeaderState::Value && !m_current_header_field.empty()) { m_current_request.headers.emplace_back(std::move(m_current_header_field), std::move(m_current_header_value)); m_current_header_field.clear(); m_current_header_value.clear(); m_header_state = HeaderState::None; } } int HttpRequestParser::on_message_complete(llhttp_t *parser) { auto &self = from_llhttp(parser); self.commit_pending_header(); self.m_current_request.http_major = parser->http_major; self.m_current_request.http_minor = parser->http_minor; self.m_completed_requests.emplace_back(std::move(self.m_current_request)); self.m_current_request = HttpRequest{}; self.m_current_header_field.clear(); self.m_current_header_value.clear(); self.m_header_state = HeaderState::None; self.m_state = State::Completed; return HPE_OK; } int HttpRequestParser::on_url(llhttp_t *parser, const char *ptr, size_t length) { auto &self = from_llhttp(parser); self.m_current_request.url.append(ptr, length); return HPE_OK; } int HttpRequestParser::on_method(llhttp_t *parser, const char *ptr, size_t length) { auto &self = from_llhttp(parser); self.m_current_request.method.append(ptr, length); return HPE_OK; } int HttpRequestParser::on_version(llhttp_t *parser, const char *ptr, size_t length) { static_cast(ptr); static_cast(length); auto &self = from_llhttp(parser); self.m_current_request.http_major = parser->http_major; self.m_current_request.http_minor = parser->http_minor; return HPE_OK; } int HttpRequestParser::on_header_field(llhttp_t *parser, const char *ptr, size_t length) { auto &self = from_llhttp(parser); if (self.m_header_state == HeaderState::Value) { self.commit_pending_header(); } self.m_current_header_field.append(ptr, length); self.m_header_state = HeaderState::Field; return HPE_OK; } int HttpRequestParser::on_header_value(llhttp_t *parser, const char *ptr, size_t length) { auto &self = from_llhttp(parser); self.m_current_header_value.append(ptr, length); self.m_header_state = HeaderState::Value; return HPE_OK; } int HttpRequestParser::on_body(llhttp_t *parser, const char *ptr, size_t length) { auto &self = from_llhttp(parser); self.commit_pending_header(); const auto *data_begin = std::bit_cast(ptr); self.m_current_request.body.insert(self.m_current_request.body.end(), data_begin, data_begin + length); return HPE_OK; } void HttpResponse::serialize_into(std::vector &out_bytes) const { if (out_bytes.capacity() < out_bytes.size() + 128 + body.size()) { out_bytes.reserve(out_bytes.size() + 128 + body.size()); } std::string status_line = std::format("HTTP/{}.{} {} {}\r\n", http_major, http_minor, status_code, reason_phrase); std::ranges::copy(std::bit_cast(status_line.data()), std::bit_cast(status_line.data() + status_line.size()), std::back_inserter(out_bytes)); for (const auto &[header_name, header_value] : headers) { std::string header_line = std::format("{}: {}\r\n", header_name, header_value); std::ranges::copy(std::bit_cast(header_line.data()), std::bit_cast(header_line.data() + header_line.size()), std::back_inserter(out_bytes)); } constexpr std::string_view crlf = "\r\n"; std::ranges::copy(std::bit_cast(crlf.data()), std::bit_cast(crlf.data() + crlf.size()), std::back_inserter(out_bytes)); std::ranges::copy(body, std::back_inserter(out_bytes)); }