summaryrefslogtreecommitdiffstats
path: root/src/HTTPServer/TransferEncodingParser.cpp
blob: 8b703fd422c33043d616a8abc7620c849f643bff (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
122
123
124
125
126
127
128
129
130
131
132

// TransferEncodingParser.cpp

// Implements the cTransferEncodingParser class and its descendants representing the parser for the various transfer encodings (chunked etc.)

#include "Globals.h"
#include "TransferEncodingParser.h"





////////////////////////////////////////////////////////////////////////////////
// cChunkedTEParser:

class cChunkedTEParser:
	public cTransferEncodingParser
{
	typedef cTransferEncodingParser Super;

public:
	cChunkedTEParser(cCallbacks & a_Callbacks):
		Super(a_Callbacks),
		m_IsFinished(false)
	{
	}


protected:

	/** True if the datastream has finished (zero-length chunk received). */
	bool m_IsFinished;


	// cTransferEncodingParser overrides:
	virtual size_t Parse(const char * a_Data, size_t a_Size) override
	{
		// TODO
		m_Callbacks.OnError("cChunkedTEParser not implemented yet");
		return AString::npos;
	}

	virtual void Finish(void) override
	{
		if (!m_IsFinished)
		{
			m_Callbacks.OnError("ChunkedTransferEncoding: Finish signal received before the data stream ended");
		}
		m_IsFinished = true;
	}
};





////////////////////////////////////////////////////////////////////////////////
// cIdentityTEParser:

class cIdentityTEParser:
	public cTransferEncodingParser
{
	typedef cTransferEncodingParser Super;

public:
	cIdentityTEParser(cCallbacks & a_Callbacks, size_t a_ContentLength):
		Super(a_Callbacks),
		m_BytesLeft(a_ContentLength)
	{
	}


protected:
	/** How many bytes of content are left before the message ends. */
	size_t m_BytesLeft;

	// cTransferEncodingParser overrides:
	virtual size_t Parse(const char * a_Data, size_t a_Size) override
	{
		auto size = std::min(a_Size, m_BytesLeft);
		if (size > 0)
		{
			m_Callbacks.OnBodyData(a_Data, size);
		}
		m_BytesLeft -= size;
		if (m_BytesLeft == 0)
		{
			m_Callbacks.OnBodyFinished();
		}
		return a_Size - size;
	}

	virtual void Finish(void) override
	{
		if (m_BytesLeft > 0)
		{
			m_Callbacks.OnError("IdentityTransferEncoding: body was truncated");
		}
		else
		{
			// BodyFinished has already been called, just bail out
		}
	}
};





////////////////////////////////////////////////////////////////////////////////
// cTransferEncodingParser:

cTransferEncodingParserPtr cTransferEncodingParser::Create(
	cCallbacks & a_Callbacks,
	const AString & a_TransferEncoding,
	size_t a_ContentLength
)
{
	if (a_TransferEncoding == "chunked")
	{
		return std::make_shared<cChunkedTEParser>(a_Callbacks);
	}
	if (a_TransferEncoding.empty())
	{
		return std::make_shared<cIdentityTEParser>(a_Callbacks, a_ContentLength);
	}
	return nullptr;
}