-
Notifications
You must be signed in to change notification settings - Fork 7.6k
/
Copy pathWebServer.h
323 lines (270 loc) · 12.1 KB
/
WebServer.h
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
WebServer.h - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include <functional>
#include <memory>
#include "FS.h"
#include "Network.h"
#include "HTTP_Method.h"
#include "Uri.h"
enum HTTPUploadStatus {
UPLOAD_FILE_START,
UPLOAD_FILE_WRITE,
UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED
};
enum HTTPRawStatus {
RAW_START,
RAW_WRITE,
RAW_END,
RAW_ABORTED
};
enum HTTPClientStatus {
HC_NONE,
HC_WAIT_READ,
HC_WAIT_CLOSE
};
enum HTTPAuthMethod {
BASIC_AUTH,
DIGEST_AUTH,
OTHER_AUTH
};
#define HTTP_DOWNLOAD_UNIT_SIZE 1436
#ifndef HTTP_UPLOAD_BUFLEN
#define HTTP_UPLOAD_BUFLEN 1436
#endif
#ifndef HTTP_RAW_BUFLEN
#define HTTP_RAW_BUFLEN 1436
#endif
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
#define HTTP_MAX_CLOSE_WAIT 5000 //ms to wait for the client to close the connection
#define HTTP_MAX_BASIC_AUTH_LEN 256 // maximum length of a basic Auth base64 encoded username:password string
#define CONTENT_LENGTH_UNKNOWN ((size_t) - 1)
#define CONTENT_LENGTH_NOT_SET ((size_t) - 2)
class WebServer;
typedef struct {
HTTPUploadStatus status;
String filename;
String name;
String type;
size_t totalSize; // file size
size_t currentSize; // size of data currently in buf
uint8_t buf[HTTP_UPLOAD_BUFLEN];
} HTTPUpload;
typedef struct {
HTTPRawStatus status;
size_t totalSize; // content size
size_t currentSize; // size of data currently in buf
uint8_t buf[HTTP_RAW_BUFLEN];
void *data; // additional data
} HTTPRaw;
#include "middleware/Middleware.h"
#include "detail/RequestHandler.h"
namespace fs {
class FS;
}
class WebServer {
public:
WebServer(IPAddress addr, int port = 80);
WebServer(int port = 80);
virtual ~WebServer();
virtual void begin();
virtual void begin(uint16_t port);
virtual void handleClient();
virtual void close();
void stop();
const String AuthTypeDigest = F("Digest");
const String AuthTypeBasic = F("Basic");
/* Callbackhandler for authentication. The extra parameters depend on the
* HTTPAuthMethod mode:
*
* BASIC_AUTH enteredUsernameOrReq contains the username entered by the user
* param[0] password entered (in the clear)
* param[1] authentication realm.
*
* To return - the password the user entered password is compared to. Or Null on fail.
*
* DIGEST_AUTH enteredUsernameOrReq contains the username entered by the user
* param[0] autenticaiton realm
* param[1] authentication URI
*
* To return - the password of which the digest will be based on for comparison. Or NULL
* to fail.
*
* OTHER_AUTH enteredUsernameOrReq rest of the auth line.
* params empty array
*
* To return - NULL to fail; or any string.
*/
typedef std::function<String *(HTTPAuthMethod mode, String enteredUsernameOrReq, String extraParams[])> THandlerFunctionAuthCheck;
bool authenticate(THandlerFunctionAuthCheck fn);
bool authenticate(const char *username, const char *password);
bool authenticateBasicSHA1(const char *_username, const char *_sha1AsBase64orHex);
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char *realm = NULL, const String &authFailMsg = String(""));
typedef std::function<void(void)> THandlerFunction;
typedef std::function<bool(WebServer &server)> FilterFunction;
RequestHandler &on(const Uri &uri, THandlerFunction fn);
RequestHandler &on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
RequestHandler &on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
bool removeRoute(const char *uri);
bool removeRoute(const char *uri, HTTPMethod method);
bool removeRoute(const String &uri);
bool removeRoute(const String &uri, HTTPMethod method);
void addHandler(RequestHandler *handler);
bool removeHandler(RequestHandler *handler);
void serveStatic(const char *uri, fs::FS &fs, const char *path, const char *cache_header = NULL);
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction ufn); //handle file uploads
WebServer &addMiddleware(Middleware *middleware);
WebServer &addMiddleware(Middleware::Function fn);
WebServer &removeMiddleware(Middleware *middleware);
String uri() const {
return _currentUri;
}
HTTPMethod method() const {
return _currentMethod;
}
virtual NetworkClient &client() {
return _currentClient;
}
HTTPUpload &upload() {
return *_currentUpload;
}
HTTPRaw &raw() {
return *_currentRaw;
}
String pathArg(unsigned int i) const; // get request path argument by number
String arg(const String &name) const; // get request argument value by name
String arg(int i) const; // get request argument value by number
String argName(int i) const; // get request argument name by number
int args() const; // get arguments count
bool hasArg(const String &name) const; // check if argument exists
void collectHeaders(const char *headerKeys[], const size_t headerKeysCount); // set the request headers to collect
void collectAllHeaders(); // collect all request headers
String header(const String &name) const; // get request header value by name
String header(int i) const; // get request header value by number
String headerName(int i) const; // get request header name by number
int headers() const; // get header count
bool hasHeader(const String &name) const; // check if header exists
int clientContentLength() const; // return "content-length" of incoming HTTP header from "_currentClient"
const String version() const; // get the HTTP version string
String hostHeader() const; // get request host header if available or empty String if not
int responseCode() const; // get the HTTP response code set
int responseHeaders() const; // get the HTTP response headers count
const String &responseHeader(String name) const; // get the HTTP response header value by name
const String &responseHeader(int i) const; // get the HTTP response header value by number
const String &responseHeaderName(int i) const; // get the HTTP response header name by number
bool hasResponseHeader(const String &name) const; // check if response header exists
// send response to the client
// code - HTTP response code, can be 200 or 404
// content_type - HTTP content type, like "text/plain" or "image/png"
// content - actual content body
void send(int code, const char *content_type = NULL, const String &content = String(""));
void send(int code, char *content_type, const String &content);
void send(int code, const String &content_type, const String &content);
void send(int code, const char *content_type, const char *content);
void send_P(int code, PGM_P content_type, PGM_P content);
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
void enableDelay(boolean value);
void enableCORS(boolean value = true);
void enableCrossOrigin(boolean value = true);
typedef std::function<String(FS &fs, const String &fName)> ETagFunction;
void enableETag(bool enable, ETagFunction fn = nullptr);
void setContentLength(const size_t contentLength);
void sendHeader(const String &name, const String &value, bool first = false);
void sendContent(const String &content);
void sendContent(const char *content, size_t contentLength);
void sendContent_P(PGM_P content);
void sendContent_P(PGM_P content, size_t size);
static String urlDecode(const String &text);
template<typename T> size_t streamFile(T &file, const String &contentType, const int code = 200) {
_streamFileCore(file.size(), file.name(), contentType, code);
return _currentClient.write(file);
}
bool _eTagEnabled = false;
ETagFunction _eTagFunction = nullptr;
static String responseCodeToString(int code);
protected:
virtual size_t _currentClientWrite(const char *b, size_t l) {
return _currentClient.write(b, l);
}
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) {
return _currentClient.write_P(b, l);
}
void _addRequestHandler(RequestHandler *handler);
bool _removeRequestHandler(RequestHandler *handler);
bool _handleRequest();
void _finalizeResponse();
bool _parseRequest(NetworkClient &client);
void _parseArguments(const String &data);
bool _parseForm(NetworkClient &client, const String &boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
int _uploadReadByte(NetworkClient &client);
void _prepareHeader(String &response, int code, const char *content_type, size_t contentLength);
bool _collectHeader(const char *headerName, const char *headerValue);
void _streamFileCore(const size_t fileSize, const String &fileName, const String &contentType, const int code = 200);
String _getRandomHexString();
// for extracting Auth parameters
String _extractParam(String &authReq, const String ¶m, const char delimit = '"');
void _clearResponseHeaders();
void _clearRequestHeaders();
struct RequestArgument {
String key;
String value;
RequestArgument *next;
};
boolean _corsEnabled = false;
NetworkServer _server;
NetworkClient _currentClient;
HTTPMethod _currentMethod = HTTP_ANY;
String _currentUri;
uint8_t _currentVersion = 0;
HTTPClientStatus _currentStatus = HC_NONE;
unsigned long _statusChange = 0;
boolean _nullDelay = true;
RequestHandler *_currentHandler = nullptr;
RequestHandler *_firstHandler = nullptr;
RequestHandler *_lastHandler = nullptr;
THandlerFunction _notFoundHandler = nullptr;
THandlerFunction _fileUploadHandler = nullptr;
int _currentArgCount = 0;
RequestArgument *_currentArgs = nullptr;
int _postArgsLen = 0;
RequestArgument *_postArgs = nullptr;
std::unique_ptr<HTTPUpload> _currentUpload;
std::unique_ptr<HTTPRaw> _currentRaw;
int _headerKeysCount = 0;
RequestArgument *_currentHeaders = nullptr;
size_t _contentLength = 0;
int _clientContentLength = 0; // "Content-Length" from header of incoming POST or GET request
RequestArgument *_responseHeaders = nullptr;
String _hostHeader;
bool _chunked = false;
String _snonce; // Store noance and opaque for future comparison
String _sopaque;
String _srealm; // Store the Auth realm between Calls
int _responseHeaderCount = 0;
int _responseCode = 0;
bool _collectAllHeaders = false;
MiddlewareChain *_chain = nullptr;
};
#endif //ESP8266WEBSERVER_H