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
|
/*
* HttpResponder.h
*
* Created on: 14 Apr 2017
* Author: David
*/
#ifndef SRC_NETWORKING_HTTPRESPONDER_H_
#define SRC_NETWORKING_HTTPRESPONDER_H_
#include "NetworkResponder.h"
class HttpResponder : public NetworkResponder
{
public:
HttpResponder(NetworkResponder *n);
bool Spin() override; // do some work, returning true if we did anything significant
bool Accept(Socket *s, NetworkProtocol protocol) override; // ask the responder to accept this connection, returns true if it did
void Terminate(NetworkProtocol protocol) override; // terminate the responder if it is serving the specified protocol
void Diagnostics(MessageType mtype) const override;
static void InitStatic();
static void HandleGCodeReply(const char *reply);
static void HandleGCodeReply(OutputBuffer *reply);
static uint32_t GetReplySeq() { return seq; }
static void CheckSessions();
static void CommonDiagnostics(MessageType mtype);
protected:
void CancelUpload() override;
void SendData() override;
private:
static const size_t MaxHttpSessions = 8; // maximum number of simultaneous HTTP sessions
static const uint16_t WebMessageLength = 1460; // maximum length of the web message we accept after decoding
static const size_t MaxCommandWords = 4; // max number of space-separated words in the command
static const size_t MaxQualKeys = 5; // max number of key/value pairs in the qualifier
static const size_t MaxHeaders = 30; // max number of key/value pairs in the headers
static const uint32_t HttpSessionTimeout = 8000; // HTTP session timeout in milliseconds
static const uint32_t MaxFileInfoGetTime = 1800; // maximum length of time we spend getting file info, to avoid the client timing out (actual time will be a little longer than this)
enum class HttpParseState
{
doingCommandWord, // receiving a word in the first line of the HTTP request
doingFilename, // receiving the filename (second word in the command line)
doingFilenameEsc1, // received '%' in the filename (e.g. we are being asked for a filename with spaces in it)
doingFilenameEsc2, // received '%' and one hex digit in the filename
doingQualifierKey, // receiving a key name in the HTTP request
doingQualifierValue, // receiving a key value in the HTTP request
doingQualifierValueEsc1, // received '%' in the qualifier
doingQualifierValueEsc2, // received '%' and one hex digit in the qualifier
doingHeaderKey, // receiving a header key
expectingHeaderValue, // expecting a header value
doingHeaderValue, // receiving a header value
doingHeaderContinuation // received a newline after a header value
};
struct KeyValueIndices
{
const char* key;
const char* value;
};
// HTTP sessions
struct HttpSession
{
uint32_t ip;
uint32_t lastQueryTime;
bool isPostUploading;
uint16_t postPort;
};
bool Authenticate();
bool CheckAuthenticated();
bool RemoveAuthentication();
bool CharFromClient(char c);
void SendFile(const char* nameOfFileToSend, bool isWebFile);
void SendGCodeReply();
void SendJsonResponse(const char* command);
bool GetJsonResponse(const char* request, OutputBuffer *&response, bool& keepOpen);
void ProcessMessage();
void ProcessRequest();
void RejectMessage(const char* s, unsigned int code = 500);
bool SendFileInfo(bool quitEarly);
void DoUpload();
const char* GetKeyValue(const char *key) const; // return the value of the specified key, or nullptr if not present
HttpParseState parseState;
// Buffers for processing HTTP input
char clientMessage[WebMessageLength + 3]; // holds the command, qualifier, and headers
size_t clientPointer; // current index into clientMessage
char decodeChar; // the character we are decoding in a URL-encoded argument
// Parser state
const char* commandWords[MaxCommandWords];
KeyValueIndices qualifiers[MaxQualKeys + 1]; // offsets into clientQualifier of the key/value pairs, the +1 is needed so that values can contain nulls
KeyValueIndices headers[MaxHeaders]; // offsets into clientHeader of the key/value pairs
size_t numCommandWords;
size_t numQualKeys; // number of qualifier keys we have found, <= maxQualKeys
size_t numHeaderKeys; // number of keys we have found, <= maxHeaders
// rr_fileinfo requests
uint32_t startedProcessingRequestAt; // when we started processing the current HTTP request
char filenameBeingProcessed[MaxFilenameLength]; // The filename being processed (for rr_fileinfo)
// Keeping track of HTTP sessions
static HttpSession sessions[MaxHttpSessions];
static unsigned int numSessions;
static unsigned int clientsServed;
// Responses from GCodes class
static volatile uint32_t seq; // Sequence number for G-Code replies
static volatile OutputStack gcodeReply;
static Mutex gcodeReplyMutex;
};
#endif /* SRC_NETWORKING_HTTPRESPONDER_H_ */
|