aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/httpparser.h
blob: cce51fccaac11edd797b03233ca4f420a0636aab (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
// 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