// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #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() ? GetHeaderSubString(m_UrlRange) : m_NormalizedUrl; } std::string_view QueryString() const { return GetHeaderSubString(m_QueryStringRange); } IoBuffer Body() { return m_BodyBuffer; } inline HttpContentType ContentType() { return ParseContentType(GetHeaderValue(m_ContentTypeHeaderIndex)); } inline HttpContentType AcceptType() { return ParseContentType(GetHeaderValue(m_AcceptHeaderIndex)); } Oid SessionId() const { return m_SessionId; } int RequestId() const { return m_RequestId; } std::string_view RangeHeader() const { return GetHeaderValue(m_RangeHeaderIndex); } std::string_view AuthorizationHeader() const { return GetHeaderValue(m_AuthorizationHeaderIndex); } private: struct HeaderRange { uint32_t Offset = 0; uint32_t Length = 0; }; struct HeaderEntry { HeaderRange NameRange; HeaderRange ValueRange; }; inline std::string_view GetHeaderValue(int8_t HeaderIndex) const { if (HeaderIndex == -1) { return {}; } ZEN_ASSERT(size_t(HeaderIndex) < m_HeaderEntries.size()); return GetHeaderSubString(m_HeaderEntries[HeaderIndex].ValueRange); } std::string_view GetHeaderSubString(const HeaderRange& Range) const { ZEN_ASSERT_SLOW(Range.Offset + Range.Length <= m_HeaderData.size()); return std::string_view(m_HeaderData.begin(), m_HeaderData.size()).substr(Range.Offset, Range.Length); } HttpRequestParserCallbacks& m_Connection; HeaderRange m_UrlRange; HeaderRange m_QueryStringRange; eastl::fixed_vector m_HeaderEntries; int8_t m_ContentLengthHeaderIndex; int8_t m_AcceptHeaderIndex; int8_t m_ContentTypeHeaderIndex; int8_t m_RangeHeaderIndex; int8_t m_AuthorizationHeaderIndex; 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; eastl::fixed_vector m_HeaderData; std::string m_NormalizedUrl; void ParseCurrentHeader(); 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