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