diff options
| author | Stefan Boberg <[email protected]> | 2023-10-03 18:15:35 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-03 18:15:35 +0200 |
| commit | c10f6ce83c4460fa162641a22243faed27abe541 (patch) | |
| tree | eb32786f786e8ec50ba7c6f86f231128ef5df10e /src/zenhttp/httpparser.h | |
| parent | faster accesstime save restore (#439) (diff) | |
| download | zen-c10f6ce83c4460fa162641a22243faed27abe541.tar.xz zen-c10f6ce83c4460fa162641a22243faed27abe541.zip | |
factored out http parser from asio into separate files (#444)
factored out http request parsing from httpasio into separate files to enable code to be reused for different transports
Diffstat (limited to 'src/zenhttp/httpparser.h')
| -rw-r--r-- | src/zenhttp/httpparser.h | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/zenhttp/httpparser.h b/src/zenhttp/httpparser.h new file mode 100644 index 000000000..cce51fcca --- /dev/null +++ b/src/zenhttp/httpparser.h @@ -0,0 +1,113 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/uid.h> +#include <zenhttp/httpcommon.h> + +ZEN_THIRD_PARTY_INCLUDES_START +#include <http_parser.h> +ZEN_THIRD_PARTY_INCLUDES_END + +namespace zen { + +class HttpConnectionBase +{ +public: + virtual ~HttpConnectionBase() = default; + virtual void HandleNewRequest() = 0; + virtual void TerminateConnection() = 0; + virtual void HandleRequest() = 0; +}; + +struct HttpRequestParser +{ + explicit HttpRequestParser(HttpConnectionBase& Connection) : m_Connection(Connection) {} + + void Initialize(); + size_t ConsumeData(const char* InputData, size_t DataSize); + void ResetState(); + + HttpVerb RequestVerb() const { return m_RequestVerb; } + bool IsKeepAlive() const { return m_KeepAlive; } + std::string_view Url() const { return m_NormalizedUrl.empty() ? std::string_view(m_Url, m_UrlLength) : m_NormalizedUrl; } + std::string_view QueryString() const { return std::string_view(m_QueryString, m_QueryLength); } + IoBuffer Body() { return m_BodyBuffer; } + + inline HttpContentType ContentType() + { + if (m_ContentTypeHeaderIndex < 0) + { + return HttpContentType::kUnknownContentType; + } + + return ParseContentType(m_Headers[m_ContentTypeHeaderIndex].Value); + } + + inline HttpContentType AcceptType() + { + if (m_AcceptHeaderIndex < 0) + { + return HttpContentType::kUnknownContentType; + } + + return ParseContentType(m_Headers[m_AcceptHeaderIndex].Value); + } + + Oid SessionId() const { return m_SessionId; } + int RequestId() const { return m_RequestId; } + + std::string_view RangeHeader() const { return m_RangeHeaderIndex != -1 ? m_Headers[m_RangeHeaderIndex].Value : std::string_view(); } + +private: + struct HeaderEntry + { + HeaderEntry() = default; + + HeaderEntry(std::string_view InName, std::string_view InValue) : Name(InName), Value(InValue) {} + + std::string_view Name; + std::string_view Value; + }; + + HttpConnectionBase& m_Connection; + char* m_HeaderCursor = m_HeaderBuffer; + char* m_Url = nullptr; + size_t m_UrlLength = 0; + char* m_QueryString = nullptr; + size_t m_QueryLength = 0; + char* m_CurrentHeaderName = nullptr; // Used while parsing headers + size_t m_CurrentHeaderNameLength = 0; + char* m_CurrentHeaderValue = nullptr; // Used while parsing headers + size_t m_CurrentHeaderValueLength = 0; + std::vector<HeaderEntry> m_Headers; + int8_t m_ContentLengthHeaderIndex; + int8_t m_AcceptHeaderIndex; + int8_t m_ContentTypeHeaderIndex; + int8_t m_RangeHeaderIndex; + HttpVerb m_RequestVerb; + bool m_KeepAlive = false; + bool m_Expect100Continue = false; + int m_RequestId = -1; + Oid m_SessionId{}; + IoBuffer m_BodyBuffer; + uint64_t m_BodyPosition = 0; + http_parser m_Parser; + char m_HeaderBuffer[1024]; + std::string m_NormalizedUrl; + + void AppendCurrentHeader(); + + int OnMessageBegin(); + int OnUrl(const char* Data, size_t Bytes); + int OnHeader(const char* Data, size_t Bytes); + int OnHeaderValue(const char* Data, size_t Bytes); + int OnHeadersComplete(); + int OnBody(const char* Data, size_t Bytes); + int OnMessageComplete(); + + static HttpRequestParser* GetThis(http_parser* Parser) { return reinterpret_cast<HttpRequestParser*>(Parser->data); } + static http_parser_settings s_ParserSettings; +}; + +} // namespace zen |