summaryrefslogtreecommitdiffstats
path: root/source/WebServer.h
blob: 1a10e4461400a1f2c78948eb843df8a2e23cd61c (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

// WebServer.h

// Declares the cWebServer class representing a HTTP webserver that uses cListenThread and cSocketThreads for processing





#pragma once

#include "OSSupport/ListenThread.h"
#include "OSSupport/SocketThreads.h"
#include "../iniFile/iniFile.h"





// fwd:
class cWebServer;





class cWebRequest :
	public cSocketThreads::cCallback
{
public:
	enum
	{
		HTTP_OK = 200,
		HTTP_BAD_REQUEST = 400,
	} ;
	
	cWebRequest(cWebServer & a_WebServer);
	
	/// Sends HTTP status code together with a_Reason
	void SendStatusAndReason(int a_StatusCode, const AString & a_Reason);
	
protected:
	typedef std::map<AString, AString> cNameValueMap;
	
	cWebServer & m_WebServer;
	
	AString       m_Method;   ///< Method of the request (GET / PUT / POST / ...)
	AString       m_URL;      ///< Full URL of the request
	cNameValueMap m_Headers;  ///< All the headers the request has come with
	
	AString m_IncomingHeaderData;  ///< All the incoming data until the entire header is parsed
	
	/// Set to true when the header haven't been received yet. If false, receiving the optional body.
	bool m_IsReceivingHeaders;
	
	/// Data that is queued for sending, once the socket becomes writable
	AString m_OutgoingData;
	
	
	/// Parses the header in m_IncomingData until the specified end mark
	void ParseHeader(size_t a_IdxEnd);
	
	/** Parses the RequestLine out of m_IncomingHeaderData, up to index a_IdxEnd
	Returns the index to the next line, or npos if invalid request
	*/
	size_t ParseRequestLine(size_t a_IdxEnd);
	
	/** Parses one header field out of m_IncomingHeaderData, starting at the specified offset, up to offset a_IdxEnd.
	Returns the index to the next line, or npos if invalid request.
	a_Key is set to the key that was parsed (used for multi-line headers)
	*/
	size_t ParseHeaderField(size_t a_IdxStart, size_t a_IdxEnd, AString & a_Key);
	
	/** Parses one header field that is known to be a continuation of previous header.
	Returns the index to the next line, or npos if invalid request.
	*/
	size_t ParseHeaderFieldContinuation(size_t a_IdxStart, size_t a_IdxEnd, AString & a_Key);
	
	/// Adds a header into m_Headers; appends if key already exists
	void AddHeader(const AString & a_Key, const AString & a_Value);
	
	// cSocketThreads::cCallback overrides:
	virtual void DataReceived   (const char * a_Data, int a_Size) override;  // Data is received from the client
	virtual void GetOutgoingData(AString & a_Data) override;  // Data can be sent to client
	virtual void SocketClosed   (void) override;  // The socket has been closed for any reason
} ;

typedef std::vector<cWebRequest *> cWebRequests;




class cWebServer :
	public cListenThread::cCallback
{
public:
	cWebServer(void);
	
	bool Initialize(cIniFile & a_IniFile);
	
protected:
	friend class cWebRequest;
	
	cListenThread m_ListenThreadIPv4;
	cListenThread m_ListenThreadIPv6;
	
	cSocketThreads m_SocketThreads;

	cCriticalSection m_CSRequests;
	cWebRequests     m_Requests;    ///< All the requests that are currently being serviced

	// cListenThread::cCallback overrides:
	virtual void OnConnectionAccepted(cSocket & a_Socket) override;
	
	/// Called by cWebRequest when it finishes parsing its header
	void RequestReady(cWebRequest * a_Request);
} ;