Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/cpp/civetweb/CivetServer.cpp
2868 views
1
/* Copyright (c) 2013-2017 the Civetweb developers
2
* Copyright (c) 2013 No Face Press, LLC
3
*
4
* License http://opensource.org/licenses/mit-license.php MIT License
5
*/
6
7
#include "CivetServer.h"
8
9
#include <assert.h>
10
#include <stdexcept>
11
#include <stdlib.h>
12
#include <string.h>
13
14
#ifndef UNUSED_PARAMETER
15
#define UNUSED_PARAMETER(x) (void)(x)
16
#endif
17
18
#ifndef MAX_PARAM_BODY_LENGTH
19
// Set a default limit for parameters in a form body: 2 MB
20
#define MAX_PARAM_BODY_LENGTH (1024 * 1024 * 2)
21
#endif
22
23
bool
24
CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn)
25
{
26
UNUSED_PARAMETER(server);
27
UNUSED_PARAMETER(conn);
28
return false;
29
}
30
31
bool
32
CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn)
33
{
34
UNUSED_PARAMETER(server);
35
UNUSED_PARAMETER(conn);
36
return false;
37
}
38
39
bool
40
CivetHandler::handleHead(CivetServer *server, struct mg_connection *conn)
41
{
42
UNUSED_PARAMETER(server);
43
UNUSED_PARAMETER(conn);
44
return false;
45
}
46
47
bool
48
CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn)
49
{
50
UNUSED_PARAMETER(server);
51
UNUSED_PARAMETER(conn);
52
return false;
53
}
54
55
bool
56
CivetHandler::handlePatch(CivetServer *server, struct mg_connection *conn)
57
{
58
UNUSED_PARAMETER(server);
59
UNUSED_PARAMETER(conn);
60
return false;
61
}
62
63
bool
64
CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
65
{
66
UNUSED_PARAMETER(server);
67
UNUSED_PARAMETER(conn);
68
return false;
69
}
70
71
bool
72
CivetHandler::handleOptions(CivetServer *server, struct mg_connection *conn)
73
{
74
UNUSED_PARAMETER(server);
75
UNUSED_PARAMETER(conn);
76
return false;
77
}
78
79
bool
80
CivetWebSocketHandler::handleConnection(CivetServer *server,
81
const struct mg_connection *conn)
82
{
83
UNUSED_PARAMETER(server);
84
UNUSED_PARAMETER(conn);
85
return true;
86
}
87
88
void
89
CivetWebSocketHandler::handleReadyState(CivetServer *server,
90
struct mg_connection *conn)
91
{
92
UNUSED_PARAMETER(server);
93
UNUSED_PARAMETER(conn);
94
return;
95
}
96
97
bool
98
CivetWebSocketHandler::handleData(CivetServer *server,
99
struct mg_connection *conn,
100
int bits,
101
char *data,
102
size_t data_len)
103
{
104
UNUSED_PARAMETER(server);
105
UNUSED_PARAMETER(conn);
106
UNUSED_PARAMETER(bits);
107
UNUSED_PARAMETER(data);
108
UNUSED_PARAMETER(data_len);
109
return true;
110
}
111
112
void
113
CivetWebSocketHandler::handleClose(CivetServer *server,
114
const struct mg_connection *conn)
115
{
116
UNUSED_PARAMETER(server);
117
UNUSED_PARAMETER(conn);
118
return;
119
}
120
121
int
122
CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
123
{
124
const struct mg_request_info *request_info = mg_get_request_info(conn);
125
assert(request_info != NULL);
126
CivetServer *me = (CivetServer *)(request_info->user_data);
127
assert(me != NULL);
128
129
// Happens when a request hits the server before the context is saved
130
if (me->context == NULL)
131
return 0;
132
133
mg_lock_context(me->context);
134
me->connections[conn] = CivetConnection();
135
mg_unlock_context(me->context);
136
137
CivetHandler *handler = (CivetHandler *)cbdata;
138
139
if (handler) {
140
if (strcmp(request_info->request_method, "GET") == 0) {
141
return handler->handleGet(me, conn) ? 1 : 0;
142
} else if (strcmp(request_info->request_method, "POST") == 0) {
143
return handler->handlePost(me, conn) ? 1 : 0;
144
} else if (strcmp(request_info->request_method, "HEAD") == 0) {
145
return handler->handleHead(me, conn) ? 1 : 0;
146
} else if (strcmp(request_info->request_method, "PUT") == 0) {
147
return handler->handlePut(me, conn) ? 1 : 0;
148
} else if (strcmp(request_info->request_method, "DELETE") == 0) {
149
return handler->handleDelete(me, conn) ? 1 : 0;
150
} else if (strcmp(request_info->request_method, "OPTIONS") == 0) {
151
return handler->handleOptions(me, conn) ? 1 : 0;
152
} else if (strcmp(request_info->request_method, "PATCH") == 0) {
153
return handler->handlePatch(me, conn) ? 1 : 0;
154
}
155
}
156
157
return 0; // No handler found
158
}
159
160
int
161
CivetServer::authHandler(struct mg_connection *conn, void *cbdata)
162
{
163
const struct mg_request_info *request_info = mg_get_request_info(conn);
164
assert(request_info != NULL);
165
CivetServer *me = (CivetServer *)(request_info->user_data);
166
assert(me != NULL);
167
168
// Happens when a request hits the server before the context is saved
169
if (me->context == NULL)
170
return 0;
171
172
mg_lock_context(me->context);
173
me->connections[conn] = CivetConnection();
174
mg_unlock_context(me->context);
175
176
CivetAuthHandler *handler = (CivetAuthHandler *)cbdata;
177
178
if (handler) {
179
return handler->authorize(me, conn) ? 1 : 0;
180
}
181
182
return 0; // No handler found
183
}
184
185
int
186
CivetServer::webSocketConnectionHandler(const struct mg_connection *conn,
187
void *cbdata)
188
{
189
const struct mg_request_info *request_info = mg_get_request_info(conn);
190
assert(request_info != NULL);
191
CivetServer *me = (CivetServer *)(request_info->user_data);
192
assert(me != NULL);
193
194
// Happens when a request hits the server before the context is saved
195
if (me->context == NULL)
196
return 0;
197
198
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
199
200
if (handler) {
201
return handler->handleConnection(me, conn) ? 0 : 1;
202
}
203
204
return 1; // No handler found, close connection
205
}
206
207
void
208
CivetServer::webSocketReadyHandler(struct mg_connection *conn, void *cbdata)
209
{
210
const struct mg_request_info *request_info = mg_get_request_info(conn);
211
assert(request_info != NULL);
212
CivetServer *me = (CivetServer *)(request_info->user_data);
213
assert(me != NULL);
214
215
// Happens when a request hits the server before the context is saved
216
if (me->context == NULL)
217
return;
218
219
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
220
221
if (handler) {
222
handler->handleReadyState(me, conn);
223
}
224
}
225
226
int
227
CivetServer::webSocketDataHandler(struct mg_connection *conn,
228
int bits,
229
char *data,
230
size_t data_len,
231
void *cbdata)
232
{
233
const struct mg_request_info *request_info = mg_get_request_info(conn);
234
assert(request_info != NULL);
235
CivetServer *me = (CivetServer *)(request_info->user_data);
236
assert(me != NULL);
237
238
// Happens when a request hits the server before the context is saved
239
if (me->context == NULL)
240
return 0;
241
242
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
243
244
if (handler) {
245
return handler->handleData(me, conn, bits, data, data_len) ? 1 : 0;
246
}
247
248
return 1; // No handler found
249
}
250
251
void
252
CivetServer::webSocketCloseHandler(const struct mg_connection *conn,
253
void *cbdata)
254
{
255
const struct mg_request_info *request_info = mg_get_request_info(conn);
256
assert(request_info != NULL);
257
CivetServer *me = (CivetServer *)(request_info->user_data);
258
assert(me != NULL);
259
260
// Happens when a request hits the server before the context is saved
261
if (me->context == NULL)
262
return;
263
264
CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
265
266
if (handler) {
267
handler->handleClose(me, conn);
268
}
269
}
270
271
CivetCallbacks::CivetCallbacks()
272
{
273
memset(this, 0, sizeof(*this));
274
}
275
276
CivetServer::CivetServer(const char **options,
277
const struct CivetCallbacks *_callbacks,
278
const void *UserContextIn)
279
: context(0)
280
{
281
struct CivetCallbacks callbacks;
282
283
UserContext = UserContextIn;
284
285
if (_callbacks) {
286
callbacks = *_callbacks;
287
userCloseHandler = _callbacks->connection_close;
288
} else {
289
userCloseHandler = NULL;
290
}
291
callbacks.connection_close = closeHandler;
292
context = mg_start(&callbacks, this, options);
293
if (context == NULL)
294
throw CivetException("null context when constructing CivetServer. "
295
"Possible problem binding to port.");
296
}
297
298
CivetServer::CivetServer(std::vector<std::string> options,
299
const struct CivetCallbacks *_callbacks,
300
const void *UserContextIn)
301
: context(0)
302
{
303
struct CivetCallbacks callbacks;
304
305
UserContext = UserContextIn;
306
307
if (_callbacks) {
308
callbacks = *_callbacks;
309
userCloseHandler = _callbacks->connection_close;
310
} else {
311
userCloseHandler = NULL;
312
}
313
callbacks.connection_close = closeHandler;
314
315
std::vector<const char *> pointers(options.size());
316
for (size_t i = 0; i < options.size(); i++) {
317
pointers[i] = (options[i].c_str());
318
}
319
pointers.push_back(0);
320
321
context = mg_start(&callbacks, this, &pointers[0]);
322
if (context == NULL)
323
throw CivetException("null context when constructing CivetServer. "
324
"Possible problem binding to port.");
325
}
326
327
CivetServer::~CivetServer()
328
{
329
close();
330
}
331
332
void
333
CivetServer::closeHandler(const struct mg_connection *conn)
334
{
335
CivetServer *me = (CivetServer *)mg_get_user_data(mg_get_context(conn));
336
assert(me != NULL);
337
338
// Happens when a request hits the server before the context is saved
339
if (me->context == NULL)
340
return;
341
342
if (me->userCloseHandler) {
343
me->userCloseHandler(conn);
344
}
345
mg_lock_context(me->context);
346
me->connections.erase(const_cast<struct mg_connection *>(conn));
347
mg_unlock_context(me->context);
348
}
349
350
void
351
CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
352
{
353
mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
354
}
355
356
void
357
CivetServer::addWebSocketHandler(const std::string &uri,
358
CivetWebSocketHandler *handler)
359
{
360
mg_set_websocket_handler(context,
361
uri.c_str(),
362
webSocketConnectionHandler,
363
webSocketReadyHandler,
364
webSocketDataHandler,
365
webSocketCloseHandler,
366
handler);
367
}
368
369
void
370
CivetServer::addAuthHandler(const std::string &uri, CivetAuthHandler *handler)
371
{
372
mg_set_auth_handler(context, uri.c_str(), authHandler, handler);
373
}
374
375
void
376
CivetServer::removeHandler(const std::string &uri)
377
{
378
mg_set_request_handler(context, uri.c_str(), NULL, NULL);
379
}
380
381
void
382
CivetServer::removeWebSocketHandler(const std::string &uri)
383
{
384
mg_set_websocket_handler(
385
context, uri.c_str(), NULL, NULL, NULL, NULL, NULL);
386
}
387
388
void
389
CivetServer::removeAuthHandler(const std::string &uri)
390
{
391
mg_set_auth_handler(context, uri.c_str(), NULL, NULL);
392
}
393
394
void
395
CivetServer::close()
396
{
397
if (context) {
398
mg_stop(context);
399
context = 0;
400
}
401
}
402
403
int
404
CivetServer::getCookie(struct mg_connection *conn,
405
const std::string &cookieName,
406
std::string &cookieValue)
407
{
408
// Maximum cookie length as per microsoft is 4096.
409
// http://msdn.microsoft.com/en-us/library/ms178194.aspx
410
char _cookieValue[4096];
411
const char *cookie = mg_get_header(conn, "Cookie");
412
int lRead = mg_get_cookie(cookie,
413
cookieName.c_str(),
414
_cookieValue,
415
sizeof(_cookieValue));
416
cookieValue.clear();
417
cookieValue.append(_cookieValue);
418
return lRead;
419
}
420
421
const char *
422
CivetServer::getHeader(struct mg_connection *conn,
423
const std::string &headerName)
424
{
425
return mg_get_header(conn, headerName.c_str());
426
}
427
428
void
429
CivetServer::urlDecode(const char *src,
430
std::string &dst,
431
bool is_form_url_encoded)
432
{
433
urlDecode(src, strlen(src), dst, is_form_url_encoded);
434
}
435
436
void
437
CivetServer::urlDecode(const char *src,
438
size_t src_len,
439
std::string &dst,
440
bool is_form_url_encoded)
441
{
442
int i, j, a, b;
443
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
444
445
dst.clear();
446
for (i = j = 0; i < (int)src_len; i++, j++) {
447
if (i < (int)src_len - 2 && src[i] == '%'
448
&& isxdigit(*(const unsigned char *)(src + i + 1))
449
&& isxdigit(*(const unsigned char *)(src + i + 2))) {
450
a = tolower(*(const unsigned char *)(src + i + 1));
451
b = tolower(*(const unsigned char *)(src + i + 2));
452
dst.push_back((char)((HEXTOI(a) << 4) | HEXTOI(b)));
453
i += 2;
454
} else if (is_form_url_encoded && src[i] == '+') {
455
dst.push_back(' ');
456
} else {
457
dst.push_back(src[i]);
458
}
459
}
460
}
461
462
bool
463
CivetServer::getParam(struct mg_connection *conn,
464
const char *name,
465
std::string &dst,
466
size_t occurrence)
467
{
468
const char *formParams = NULL;
469
const char *queryString = NULL;
470
const struct mg_request_info *ri = mg_get_request_info(conn);
471
assert(ri != NULL);
472
CivetServer *me = (CivetServer *)(ri->user_data);
473
assert(me != NULL);
474
mg_lock_context(me->context);
475
CivetConnection &conobj = me->connections[conn];
476
mg_lock_connection(conn);
477
mg_unlock_context(me->context);
478
479
if (conobj.postData != NULL) {
480
// check if form parameter are already stored
481
formParams = conobj.postData;
482
} else {
483
// otherwise, check if there is a request body
484
const char *con_len_str = mg_get_header(conn, "Content-Length");
485
if (con_len_str) {
486
char *end = 0;
487
unsigned long con_len = strtoul(con_len_str, &end, 10);
488
if ((end == NULL) || (*end != 0)) {
489
// malformed header
490
return false;
491
}
492
if ((con_len > 0) && (con_len <= MAX_PARAM_BODY_LENGTH)) {
493
// Body is within a reasonable range
494
495
// Allocate memory:
496
// Add one extra character: in case the post-data is a text, it
497
// is required as 0-termination.
498
// Do not increment con_len, since the 0 terminating is not part
499
// of the content (text or binary).
500
conobj.postData = (char *)malloc(con_len + 1);
501
if (conobj.postData != NULL) {
502
// malloc may fail for huge requests
503
mg_read(conn, conobj.postData, con_len);
504
conobj.postData[con_len] = 0;
505
formParams = conobj.postData;
506
conobj.postDataLen = con_len;
507
}
508
}
509
if (conobj.postData == NULL) {
510
// we cannot store the body
511
return false;
512
}
513
}
514
}
515
516
if (ri->query_string != NULL) {
517
// get requests do store html <form> field values in the http
518
// query_string
519
queryString = ri->query_string;
520
}
521
522
mg_unlock_connection(conn);
523
524
bool get_param_success = false;
525
if (!get_param_success && formParams != NULL) {
526
get_param_success =
527
getParam(formParams, strlen(formParams), name, dst, occurrence);
528
}
529
if (!get_param_success && queryString != NULL) {
530
get_param_success =
531
getParam(queryString, strlen(queryString), name, dst, occurrence);
532
}
533
534
return get_param_success;
535
}
536
537
bool
538
CivetServer::getParam(const char *data,
539
size_t data_len,
540
const char *name,
541
std::string &dst,
542
size_t occurrence)
543
{
544
const char *p, *e, *s;
545
size_t name_len;
546
547
dst.clear();
548
if (data == NULL || name == NULL || data_len == 0) {
549
return false;
550
}
551
name_len = strlen(name);
552
e = data + data_len;
553
554
// data is "var1=val1&var2=val2...". Find variable first
555
for (p = data; p + name_len < e; p++) {
556
if ((p == data || p[-1] == '&') && p[name_len] == '='
557
&& !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
558
559
// Point p to variable value
560
p += name_len + 1;
561
562
// Point s to the end of the value
563
s = (const char *)memchr(p, '&', (size_t)(e - p));
564
if (s == NULL) {
565
s = e;
566
}
567
assert(s >= p);
568
569
// Decode variable into destination buffer
570
urlDecode(p, (int)(s - p), dst, true);
571
return true;
572
}
573
}
574
return false;
575
}
576
577
std::string
578
CivetServer::getPostData(struct mg_connection *conn)
579
{
580
mg_lock_connection(conn);
581
std::string postdata;
582
char buf[2048];
583
int r = mg_read(conn, buf, sizeof(buf));
584
while (r > 0) {
585
std::string p = std::string(buf);
586
p.resize(r);
587
postdata += p;
588
r = mg_read(conn, buf, sizeof(buf));
589
}
590
mg_unlock_connection(conn);
591
return postdata;
592
}
593
594
void
595
CivetServer::urlEncode(const char *src, std::string &dst, bool append)
596
{
597
urlEncode(src, strlen(src), dst, append);
598
}
599
600
void
601
CivetServer::urlEncode(const char *src,
602
size_t src_len,
603
std::string &dst,
604
bool append)
605
{
606
static const char *dont_escape = "._-$,;~()";
607
static const char *hex = "0123456789abcdef";
608
609
if (!append)
610
dst.clear();
611
612
for (; src_len > 0; src++, src_len--) {
613
if (isalnum(*(const unsigned char *)src)
614
|| strchr(dont_escape, *(const unsigned char *)src) != NULL) {
615
dst.push_back(*src);
616
} else {
617
dst.push_back('%');
618
dst.push_back(hex[(*(const unsigned char *)src) >> 4]);
619
dst.push_back(hex[(*(const unsigned char *)src) & 0xf]);
620
}
621
}
622
}
623
624
std::vector<int>
625
CivetServer::getListeningPorts()
626
{
627
std::vector<int> ports(50);
628
std::vector<struct mg_server_ports> server_ports(50);
629
int size = mg_get_server_ports(context,
630
(int)server_ports.size(),
631
&server_ports[0]);
632
if (size <= 0) {
633
ports.resize(0);
634
return ports;
635
}
636
ports.resize(size);
637
server_ports.resize(size);
638
for (int i = 0; i < size; i++) {
639
ports[i] = server_ports[i].port;
640
}
641
642
return ports;
643
}
644
645
CivetServer::CivetConnection::CivetConnection()
646
{
647
postData = NULL;
648
postDataLen = 0;
649
}
650
651
CivetServer::CivetConnection::~CivetConnection()
652
{
653
free(postData);
654
}
655
656