// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #include ZEN_THIRD_PARTY_INCLUDES_START #include ZEN_THIRD_PARTY_INCLUDES_END #include namespace zen { class HttpRequestParserCallbacks { public: virtual ~HttpRequestParserCallbacks() = default; virtual void HandleRequest() = 0; virtual void TerminateConnection() = 0; }; struct HttpRequestParser { explicit HttpRequestParser(HttpRequestParserCallbacks& Connection); ~HttpRequestParser(); 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; }; HttpRequestParserCallbacks& 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 m_Headers; int8_t m_ContentLengthHeaderIndex; int8_t m_AcceptHeaderIndex; int8_t m_ContentTypeHeaderIndex; int8_t m_RangeHeaderIndex; HttpVerb m_RequestVerb; std::atomic_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(Parser->data); } static http_parser_settings s_ParserSettings; }; } // namespace zen