aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/httpparser.h
blob: d40a5aeb02a14ff4d0f328410432a88f3afd43d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/uid.h>
#include <zenhttp/httpcommon.h>

#include <EASTL/fixed_vector.h>

ZEN_THIRD_PARTY_INCLUDES_START
#include <http_parser.h>
ZEN_THIRD_PARTY_INCLUDES_END

#include <atomic>

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); }

	std::string_view UpgradeHeader() const { return GetHeaderValue(m_UpgradeHeaderIndex); }
	std::string_view SecWebSocketKey() const { return GetHeaderValue(m_SecWebSocketKeyHeaderIndex); }
	bool			 IsWebSocketUpgrade() const;

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<HeaderEntry, 16> m_HeaderEntries;
	int8_t								 m_ContentLengthHeaderIndex;
	int8_t								 m_AcceptHeaderIndex;
	int8_t								 m_ContentTypeHeaderIndex;
	int8_t								 m_RangeHeaderIndex;
	int8_t								 m_AuthorizationHeaderIndex;
	int8_t								 m_UpgradeHeaderIndex;
	int8_t								 m_SecWebSocketKeyHeaderIndex;
	int8_t								 m_SecWebSocketVersionHeaderIndex;
	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<char, 512>		 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<HttpRequestParser*>(Parser->data); }
	static http_parser_settings s_ParserSettings;
};

}  // namespace zen