diff options
| author | Stefan Boberg <[email protected]> | 2023-10-13 09:55:27 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-13 09:55:27 +0200 |
| commit | 74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d (patch) | |
| tree | acae59dac67b4d051403f35e580201c214ec4fda /src/zenhttp/httpparser.cpp | |
| parent | faster oplog iteration (#471) (diff) | |
| download | zen-74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d.tar.xz zen-74d104d4eb3735e0881f0e1fccc2df8aa4d3f57d.zip | |
restructured zenhttp (#472)
separating the http server implementations into a directory and moved diagsvcs into zenserver since it's somewhat hard-coded for it
Diffstat (limited to 'src/zenhttp/httpparser.cpp')
| -rw-r--r-- | src/zenhttp/httpparser.cpp | 370 |
1 files changed, 0 insertions, 370 deletions
diff --git a/src/zenhttp/httpparser.cpp b/src/zenhttp/httpparser.cpp deleted file mode 100644 index 6b987151a..000000000 --- a/src/zenhttp/httpparser.cpp +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "httpparser.h" - -#include <zencore/logging.h> -#include <zencore/string.h> - -namespace zen { - -using namespace std::literals; - -static constinit uint32_t HashContentLength = HashStringAsLowerDjb2("Content-Length"sv); -static constinit uint32_t HashContentType = HashStringAsLowerDjb2("Content-Type"sv); -static constinit uint32_t HashAccept = HashStringAsLowerDjb2("Accept"sv); -static constinit uint32_t HashExpect = HashStringAsLowerDjb2("Expect"sv); -static constinit uint32_t HashSession = HashStringAsLowerDjb2("UE-Session"sv); -static constinit uint32_t HashRequest = HashStringAsLowerDjb2("UE-Request"sv); -static constinit uint32_t HashRange = HashStringAsLowerDjb2("Range"sv); - -////////////////////////////////////////////////////////////////////////// -// -// HttpRequestParser -// - -http_parser_settings HttpRequestParser::s_ParserSettings{ - .on_message_begin = [](http_parser* p) { return GetThis(p)->OnMessageBegin(); }, - .on_url = [](http_parser* p, const char* Data, size_t ByteCount) { return GetThis(p)->OnUrl(Data, ByteCount); }, - .on_status = - [](http_parser* p, const char* Data, size_t ByteCount) { - ZEN_UNUSED(p, Data, ByteCount); - return 0; - }, - .on_header_field = [](http_parser* p, const char* Data, size_t ByteCount) { return GetThis(p)->OnHeader(Data, ByteCount); }, - .on_header_value = [](http_parser* p, const char* Data, size_t ByteCount) { return GetThis(p)->OnHeaderValue(Data, ByteCount); }, - .on_headers_complete = [](http_parser* p) { return GetThis(p)->OnHeadersComplete(); }, - .on_body = [](http_parser* p, const char* Data, size_t ByteCount) { return GetThis(p)->OnBody(Data, ByteCount); }, - .on_message_complete = [](http_parser* p) { return GetThis(p)->OnMessageComplete(); }, - .on_chunk_header{}, - .on_chunk_complete{}}; - -HttpRequestParser::HttpRequestParser(HttpRequestParserCallbacks& Connection) : m_Connection(Connection) -{ - http_parser_init(&m_Parser, HTTP_REQUEST); - m_Parser.data = this; - - ResetState(); -} - -HttpRequestParser::~HttpRequestParser() -{ -} - -size_t -HttpRequestParser::ConsumeData(const char* InputData, size_t DataSize) -{ - const size_t ConsumedBytes = http_parser_execute(&m_Parser, &s_ParserSettings, InputData, DataSize); - - http_errno HttpErrno = HTTP_PARSER_ERRNO((&m_Parser)); - - if (HttpErrno && HttpErrno != HPE_INVALID_EOF_STATE) - { - ZEN_WARN("HTTP parser error {} ('{}'). Closing connection", http_errno_name(HttpErrno), http_errno_description(HttpErrno)); - return ~0ull; - } - - return ConsumedBytes; -} - -int -HttpRequestParser::OnUrl(const char* Data, size_t Bytes) -{ - if (!m_Url) - { - ZEN_ASSERT_SLOW(m_UrlLength == 0); - m_Url = m_HeaderCursor; - } - - const size_t RemainingBufferSpace = sizeof m_HeaderBuffer + m_HeaderBuffer - m_HeaderCursor; - - if (RemainingBufferSpace < Bytes) - { - ZEN_WARN("HTTP parser does not have enough space for incoming request, need {} more bytes", Bytes - RemainingBufferSpace); - return 1; - } - - memcpy(m_HeaderCursor, Data, Bytes); - m_HeaderCursor += Bytes; - m_UrlLength += Bytes; - - return 0; -} - -int -HttpRequestParser::OnHeader(const char* Data, size_t Bytes) -{ - if (m_CurrentHeaderValueLength) - { - AppendCurrentHeader(); - - m_CurrentHeaderNameLength = 0; - m_CurrentHeaderValueLength = 0; - m_CurrentHeaderName = m_HeaderCursor; - } - else if (m_CurrentHeaderName == nullptr) - { - m_CurrentHeaderName = m_HeaderCursor; - } - - const size_t RemainingBufferSpace = sizeof m_HeaderBuffer + m_HeaderBuffer - m_HeaderCursor; - if (RemainingBufferSpace < Bytes) - { - ZEN_WARN("HTTP parser does not have enough space for incoming header name, need {} more bytes", Bytes - RemainingBufferSpace); - return 1; - } - - memcpy(m_HeaderCursor, Data, Bytes); - m_HeaderCursor += Bytes; - m_CurrentHeaderNameLength += Bytes; - - return 0; -} - -void -HttpRequestParser::AppendCurrentHeader() -{ - std::string_view HeaderName(m_CurrentHeaderName, m_CurrentHeaderNameLength); - std::string_view HeaderValue(m_CurrentHeaderValue, m_CurrentHeaderValueLength); - - const uint32_t HeaderHash = HashStringAsLowerDjb2(HeaderName); - - if (HeaderHash == HashContentLength) - { - m_ContentLengthHeaderIndex = (int8_t)m_Headers.size(); - } - else if (HeaderHash == HashAccept) - { - m_AcceptHeaderIndex = (int8_t)m_Headers.size(); - } - else if (HeaderHash == HashContentType) - { - m_ContentTypeHeaderIndex = (int8_t)m_Headers.size(); - } - else if (HeaderHash == HashSession) - { - m_SessionId = Oid::FromHexString(HeaderValue); - } - else if (HeaderHash == HashRequest) - { - std::from_chars(HeaderValue.data(), HeaderValue.data() + HeaderValue.size(), m_RequestId); - } - else if (HeaderHash == HashExpect) - { - if (HeaderValue == "100-continue"sv) - { - // We don't currently do anything with this - m_Expect100Continue = true; - } - else - { - ZEN_INFO("Unexpected expect - Expect: {}", HeaderValue); - } - } - else if (HeaderHash == HashRange) - { - m_RangeHeaderIndex = (int8_t)m_Headers.size(); - } - - m_Headers.emplace_back(HeaderName, HeaderValue); -} - -int -HttpRequestParser::OnHeaderValue(const char* Data, size_t Bytes) -{ - if (m_CurrentHeaderValueLength == 0) - { - m_CurrentHeaderValue = m_HeaderCursor; - } - - const size_t RemainingBufferSpace = sizeof m_HeaderBuffer + m_HeaderBuffer - m_HeaderCursor; - if (RemainingBufferSpace < Bytes) - { - ZEN_WARN("HTTP parser does not have enough space for incoming header value, need {} more bytes", Bytes - RemainingBufferSpace); - return 1; - } - - memcpy(m_HeaderCursor, Data, Bytes); - m_HeaderCursor += Bytes; - m_CurrentHeaderValueLength += Bytes; - - return 0; -} - -static void -NormalizeUrlPath(const char* Url, size_t UrlLength, std::string& NormalizedUrl) -{ - bool LastCharWasSeparator = false; - for (std::string_view::size_type UrlIndex = 0; UrlIndex < UrlLength; ++UrlIndex) - { - const char UrlChar = Url[UrlIndex]; - const bool IsSeparator = (UrlChar == '/'); - - if (IsSeparator && LastCharWasSeparator) - { - if (NormalizedUrl.empty()) - { - NormalizedUrl.reserve(UrlLength); - NormalizedUrl.append(Url, UrlIndex); - } - - if (!LastCharWasSeparator) - { - NormalizedUrl.push_back('/'); - } - } - else if (!NormalizedUrl.empty()) - { - NormalizedUrl.push_back(UrlChar); - } - - LastCharWasSeparator = IsSeparator; - } -} - -int -HttpRequestParser::OnHeadersComplete() -{ - try - { - if (m_CurrentHeaderValueLength) - { - AppendCurrentHeader(); - } - - m_KeepAlive = !!http_should_keep_alive(&m_Parser); - - switch (m_Parser.method) - { - case HTTP_GET: - m_RequestVerb = HttpVerb::kGet; - break; - - case HTTP_POST: - m_RequestVerb = HttpVerb::kPost; - break; - - case HTTP_PUT: - m_RequestVerb = HttpVerb::kPut; - break; - - case HTTP_DELETE: - m_RequestVerb = HttpVerb::kDelete; - break; - - case HTTP_HEAD: - m_RequestVerb = HttpVerb::kHead; - break; - - case HTTP_COPY: - m_RequestVerb = HttpVerb::kCopy; - break; - - case HTTP_OPTIONS: - m_RequestVerb = HttpVerb::kOptions; - break; - - default: - ZEN_WARN("invalid HTTP method: '{}'", http_method_str((http_method)m_Parser.method)); - break; - } - - std::string_view Url(m_Url, m_UrlLength); - - if (auto QuerySplit = Url.find_first_of('?'); QuerySplit != std::string_view::npos) - { - m_UrlLength = QuerySplit; - m_QueryString = m_Url + QuerySplit + 1; - m_QueryLength = Url.size() - QuerySplit - 1; - } - - NormalizeUrlPath(m_Url, m_UrlLength, m_NormalizedUrl); - - if (m_ContentLengthHeaderIndex >= 0) - { - std::string_view& Value = m_Headers[m_ContentLengthHeaderIndex].Value; - uint64_t ContentLength = 0; - std::from_chars(Value.data(), Value.data() + Value.size(), ContentLength); - - if (ContentLength) - { - m_BodyBuffer = IoBuffer(ContentLength); - } - - m_BodyBuffer.SetContentType(ContentType()); - - m_BodyPosition = 0; - } - } - catch (const std::exception& Ex) - { - ZEN_WARN("HttpRequestParser::OnHeadersComplete failed. Reason '{}'", Ex.what()); - return -1; - } - return 0; -} - -int -HttpRequestParser::OnBody(const char* Data, size_t Bytes) -{ - if (m_BodyPosition + Bytes > m_BodyBuffer.Size()) - { - ZEN_WARN("HTTP parser incoming body is larger than content size, need {} more bytes", - (m_BodyPosition + Bytes) - m_BodyBuffer.Size()); - return 1; - } - memcpy(reinterpret_cast<uint8_t*>(m_BodyBuffer.MutableData()) + m_BodyPosition, Data, Bytes); - m_BodyPosition += Bytes; - - if (http_body_is_final(&m_Parser)) - { - if (m_BodyPosition != m_BodyBuffer.Size()) - { - ZEN_WARN("Body mismatch! {} != {}", m_BodyPosition, m_BodyBuffer.Size()); - return 1; - } - } - - return 0; -} - -void -HttpRequestParser::ResetState() -{ - m_HeaderCursor = m_HeaderBuffer; - m_CurrentHeaderName = nullptr; - m_CurrentHeaderNameLength = 0; - m_CurrentHeaderValue = nullptr; - m_CurrentHeaderValueLength = 0; - m_CurrentHeaderName = nullptr; - m_Url = nullptr; - m_UrlLength = 0; - m_QueryString = nullptr; - m_QueryLength = 0; - m_ContentLengthHeaderIndex = -1; - m_AcceptHeaderIndex = -1; - m_ContentTypeHeaderIndex = -1; - m_RangeHeaderIndex = -1; - m_Expect100Continue = false; - m_BodyBuffer = {}; - m_BodyPosition = 0; - m_Headers.clear(); - m_NormalizedUrl.clear(); -} - -int -HttpRequestParser::OnMessageBegin() -{ - return 0; -} - -int -HttpRequestParser::OnMessageComplete() -{ - m_Connection.HandleRequest(); - - ResetState(); - - return 0; -} - -} // namespace zen |