]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/CivetServer.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / CivetServer.cpp
1 /* Copyright (c) 2013-2020 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 <string.h>
12
13 #ifndef UNUSED_PARAMETER
14 #define UNUSED_PARAMETER(x) (void)(x)
15 #endif
16
17 #ifndef MAX_PARAM_BODY_LENGTH
18 // Set a default limit for parameters in a form body: 2 MB
19 #define MAX_PARAM_BODY_LENGTH (1024 * 1024 * 2)
20 #endif
21
22 bool
23 CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn)
24 {
25 UNUSED_PARAMETER(server);
26 UNUSED_PARAMETER(conn);
27 return false;
28 }
29
30 bool
31 CivetHandler::handleGet(CivetServer *server,
32 struct mg_connection *conn,
33 int *status_code)
34 {
35 UNUSED_PARAMETER(server);
36 UNUSED_PARAMETER(conn);
37 if (status_code) {
38 *status_code = -1;
39 }
40 return false;
41 }
42
43 bool
44 CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn)
45 {
46 UNUSED_PARAMETER(server);
47 UNUSED_PARAMETER(conn);
48 return false;
49 }
50
51 bool
52 CivetHandler::handlePost(CivetServer *server,
53 struct mg_connection *conn,
54 int *status_code)
55 {
56 UNUSED_PARAMETER(server);
57 UNUSED_PARAMETER(conn);
58 if (status_code) {
59 *status_code = -1;
60 }
61 return false;
62 }
63
64 bool
65 CivetHandler::handleHead(CivetServer *server, struct mg_connection *conn)
66 {
67 UNUSED_PARAMETER(server);
68 UNUSED_PARAMETER(conn);
69 return false;
70 }
71
72 bool
73 CivetHandler::handleHead(CivetServer *server,
74 struct mg_connection *conn,
75 int *status_code)
76 {
77 UNUSED_PARAMETER(server);
78 UNUSED_PARAMETER(conn);
79 if (status_code) {
80 *status_code = -1;
81 }
82 return false;
83 }
84
85 bool
86 CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn)
87 {
88 UNUSED_PARAMETER(server);
89 UNUSED_PARAMETER(conn);
90 return false;
91 }
92
93 bool
94 CivetHandler::handlePut(CivetServer *server,
95 struct mg_connection *conn,
96 int *status_code)
97 {
98 UNUSED_PARAMETER(server);
99 UNUSED_PARAMETER(conn);
100 if (status_code) {
101 *status_code = -1;
102 }
103 return false;
104 }
105
106 bool
107 CivetHandler::handlePatch(CivetServer *server, struct mg_connection *conn)
108 {
109 UNUSED_PARAMETER(server);
110 UNUSED_PARAMETER(conn);
111 return false;
112 }
113
114 bool
115 CivetHandler::handlePatch(CivetServer *server,
116 struct mg_connection *conn,
117 int *status_code)
118 {
119 UNUSED_PARAMETER(server);
120 UNUSED_PARAMETER(conn);
121 if (status_code) {
122 *status_code = -1;
123 }
124 return false;
125 }
126
127 bool
128 CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
129 {
130 UNUSED_PARAMETER(server);
131 UNUSED_PARAMETER(conn);
132 return false;
133 }
134
135 bool
136 CivetHandler::handleDelete(CivetServer *server,
137 struct mg_connection *conn,
138 int *status_code)
139 {
140 UNUSED_PARAMETER(server);
141 UNUSED_PARAMETER(conn);
142 if (status_code) {
143 *status_code = -1;
144 }
145 return false;
146 }
147
148 bool
149 CivetHandler::handleOptions(CivetServer *server, struct mg_connection *conn)
150 {
151 UNUSED_PARAMETER(server);
152 UNUSED_PARAMETER(conn);
153 return false;
154 }
155
156 bool
157 CivetHandler::handleOptions(CivetServer *server,
158 struct mg_connection *conn,
159 int *status_code)
160 {
161 UNUSED_PARAMETER(server);
162 UNUSED_PARAMETER(conn);
163 if (status_code) {
164 *status_code = -1;
165 }
166 return false;
167 }
168
169 bool
170 CivetWebSocketHandler::handleConnection(CivetServer *server,
171 const struct mg_connection *conn)
172 {
173 UNUSED_PARAMETER(server);
174 UNUSED_PARAMETER(conn);
175 return true;
176 }
177
178 void
179 CivetWebSocketHandler::handleReadyState(CivetServer *server,
180 struct mg_connection *conn)
181 {
182 UNUSED_PARAMETER(server);
183 UNUSED_PARAMETER(conn);
184 return;
185 }
186
187 bool
188 CivetWebSocketHandler::handleData(CivetServer *server,
189 struct mg_connection *conn,
190 int bits,
191 char *data,
192 size_t data_len)
193 {
194 UNUSED_PARAMETER(server);
195 UNUSED_PARAMETER(conn);
196 UNUSED_PARAMETER(bits);
197 UNUSED_PARAMETER(data);
198 UNUSED_PARAMETER(data_len);
199 return true;
200 }
201
202 void
203 CivetWebSocketHandler::handleClose(CivetServer *server,
204 const struct mg_connection *conn)
205 {
206 UNUSED_PARAMETER(server);
207 UNUSED_PARAMETER(conn);
208 return;
209 }
210
211 int
212 CivetServer::requestHandler(struct mg_connection *conn, void *cbdata)
213 {
214 const struct mg_request_info *request_info = mg_get_request_info(conn);
215 assert(request_info != NULL);
216 CivetServer *me = (CivetServer *)(request_info->user_data);
217 assert(me != NULL);
218 int http_status_code = -1;
219 bool status_ok = false;
220
221 // Happens when a request hits the server before the context is saved
222 if (me->context == NULL)
223 return 0;
224
225 mg_lock_context(me->context);
226 me->connections[conn] = CivetConnection();
227 mg_unlock_context(me->context);
228
229 CivetHandler *handler = (CivetHandler *)cbdata;
230
231 if (handler) {
232 if (strcmp(request_info->request_method, "GET") == 0) {
233 status_ok = handler->handleGet(me, conn, &http_status_code);
234 if (http_status_code < 0) {
235 status_ok = handler->handleGet(me, conn);
236 }
237 } else if (strcmp(request_info->request_method, "POST") == 0) {
238 status_ok = handler->handlePost(me, conn, &http_status_code);
239 if (http_status_code < 0) {
240 status_ok = handler->handlePost(me, conn);
241 }
242 } else if (strcmp(request_info->request_method, "HEAD") == 0) {
243 status_ok = handler->handleHead(me, conn, &http_status_code);
244 if (http_status_code < 0) {
245 status_ok = handler->handleHead(me, conn);
246 }
247 } else if (strcmp(request_info->request_method, "PUT") == 0) {
248 status_ok = handler->handlePut(me, conn, &http_status_code);
249 if (http_status_code < 0) {
250 status_ok = handler->handlePut(me, conn);
251 }
252 } else if (strcmp(request_info->request_method, "DELETE") == 0) {
253 status_ok = handler->handleDelete(me, conn, &http_status_code);
254 if (http_status_code < 0) {
255 status_ok = handler->handleDelete(me, conn);
256 }
257 } else if (strcmp(request_info->request_method, "OPTIONS") == 0) {
258 status_ok = handler->handleOptions(me, conn, &http_status_code);
259 if (http_status_code < 0) {
260 status_ok = handler->handleOptions(me, conn);
261 }
262 } else if (strcmp(request_info->request_method, "PATCH") == 0) {
263 status_ok = handler->handlePatch(me, conn, &http_status_code);
264 if (http_status_code < 0) {
265 status_ok = handler->handlePatch(me, conn);
266 }
267 }
268 }
269
270 if (http_status_code < 0) {
271 http_status_code = status_ok ? 1 : 0;
272 }
273
274 return http_status_code;
275 }
276
277 int
278 CivetServer::authHandler(struct mg_connection *conn, void *cbdata)
279 {
280 const struct mg_request_info *request_info = mg_get_request_info(conn);
281 assert(request_info != NULL);
282 CivetServer *me = (CivetServer *)(request_info->user_data);
283 assert(me != NULL);
284
285 // Happens when a request hits the server before the context is saved
286 if (me->context == NULL)
287 return 0;
288
289 mg_lock_context(me->context);
290 me->connections[conn] = CivetConnection();
291 mg_unlock_context(me->context);
292
293 CivetAuthHandler *handler = (CivetAuthHandler *)cbdata;
294
295 if (handler) {
296 return handler->authorize(me, conn) ? 1 : 0;
297 }
298
299 return 0; // No handler found
300 }
301
302 int
303 CivetServer::webSocketConnectionHandler(const struct mg_connection *conn,
304 void *cbdata)
305 {
306 const struct mg_request_info *request_info = mg_get_request_info(conn);
307 assert(request_info != NULL);
308 CivetServer *me = (CivetServer *)(request_info->user_data);
309 assert(me != NULL);
310
311 // Happens when a request hits the server before the context is saved
312 if (me->context == NULL)
313 return 0;
314
315 CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
316
317 if (handler) {
318 return handler->handleConnection(me, conn) ? 0 : 1;
319 }
320
321 return 1; // No handler found, close connection
322 }
323
324 void
325 CivetServer::webSocketReadyHandler(struct mg_connection *conn, void *cbdata)
326 {
327 const struct mg_request_info *request_info = mg_get_request_info(conn);
328 assert(request_info != NULL);
329 CivetServer *me = (CivetServer *)(request_info->user_data);
330 assert(me != NULL);
331
332 // Happens when a request hits the server before the context is saved
333 if (me->context == NULL)
334 return;
335
336 CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
337
338 if (handler) {
339 handler->handleReadyState(me, conn);
340 }
341 }
342
343 int
344 CivetServer::webSocketDataHandler(struct mg_connection *conn,
345 int bits,
346 char *data,
347 size_t data_len,
348 void *cbdata)
349 {
350 const struct mg_request_info *request_info = mg_get_request_info(conn);
351 assert(request_info != NULL);
352 CivetServer *me = (CivetServer *)(request_info->user_data);
353 assert(me != NULL);
354
355 // Happens when a request hits the server before the context is saved
356 if (me->context == NULL)
357 return 0;
358
359 CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
360
361 if (handler) {
362 return handler->handleData(me, conn, bits, data, data_len) ? 1 : 0;
363 }
364
365 return 1; // No handler found
366 }
367
368 void
369 CivetServer::webSocketCloseHandler(const struct mg_connection *conn,
370 void *cbdata)
371 {
372 const struct mg_request_info *request_info = mg_get_request_info(conn);
373 assert(request_info != NULL);
374 CivetServer *me = (CivetServer *)(request_info->user_data);
375 assert(me != NULL);
376
377 // Happens when a request hits the server before the context is saved
378 if (me->context == NULL)
379 return;
380
381 CivetWebSocketHandler *handler = (CivetWebSocketHandler *)cbdata;
382
383 if (handler) {
384 handler->handleClose(me, conn);
385 }
386 }
387
388 CivetCallbacks::CivetCallbacks()
389 {
390 memset(this, 0, sizeof(*this));
391 }
392
393 CivetServer::CivetServer(const char **options,
394 const struct CivetCallbacks *_callbacks,
395 const void *UserContextIn)
396 : context(0)
397 {
398 struct CivetCallbacks callbacks;
399 memset(&callbacks, 0, sizeof(callbacks));
400
401 UserContext = UserContextIn;
402
403 if (_callbacks) {
404 callbacks = *_callbacks;
405 userCloseHandler = _callbacks->connection_close;
406 } else {
407 userCloseHandler = NULL;
408 }
409 callbacks.connection_close = closeHandler;
410 context = mg_start(&callbacks, this, options);
411 if (context == NULL) {
412 throw CivetException("null context when constructing CivetServer. "
413 "Possible problem binding to port.");
414 }
415 }
416
417 CivetServer::CivetServer(const std::vector<std::string> &options,
418 const struct CivetCallbacks *_callbacks,
419 const void *UserContextIn)
420 : context(0)
421 {
422 struct CivetCallbacks callbacks;
423 memset(&callbacks, 0, sizeof(callbacks));
424
425 UserContext = UserContextIn;
426
427 if (_callbacks) {
428 callbacks = *_callbacks;
429 userCloseHandler = _callbacks->connection_close;
430 } else {
431 userCloseHandler = NULL;
432 }
433 callbacks.connection_close = closeHandler;
434
435 std::vector<const char *> pointers(options.size() + 1);
436 for (size_t i = 0; i < options.size(); i++) {
437 pointers[i] = (options[i].c_str());
438 }
439 pointers.back() = NULL;
440
441 context = mg_start(&callbacks, this, &pointers[0]);
442 if (context == NULL)
443 throw CivetException("null context when constructing CivetServer. "
444 "Possible problem binding to port.");
445 }
446
447 CivetServer::~CivetServer()
448 {
449 close();
450 }
451
452 void
453 CivetServer::closeHandler(const struct mg_connection *conn)
454 {
455 CivetServer *me = (CivetServer *)mg_get_user_data(mg_get_context(conn));
456 assert(me != NULL);
457
458 // Happens when a request hits the server before the context is saved
459 if (me->context == NULL)
460 return;
461
462 if (me->userCloseHandler) {
463 me->userCloseHandler(conn);
464 }
465 mg_lock_context(me->context);
466 me->connections.erase(conn);
467 mg_unlock_context(me->context);
468 }
469
470 void
471 CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
472 {
473 mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
474 }
475
476 void
477 CivetServer::addWebSocketHandler(const std::string &uri,
478 CivetWebSocketHandler *handler)
479 {
480 mg_set_websocket_handler(context,
481 uri.c_str(),
482 webSocketConnectionHandler,
483 webSocketReadyHandler,
484 webSocketDataHandler,
485 webSocketCloseHandler,
486 handler);
487 }
488
489 void
490 CivetServer::addAuthHandler(const std::string &uri, CivetAuthHandler *handler)
491 {
492 mg_set_auth_handler(context, uri.c_str(), authHandler, handler);
493 }
494
495 void
496 CivetServer::removeHandler(const std::string &uri)
497 {
498 mg_set_request_handler(context, uri.c_str(), NULL, NULL);
499 }
500
501 void
502 CivetServer::removeWebSocketHandler(const std::string &uri)
503 {
504 mg_set_websocket_handler(
505 context, uri.c_str(), NULL, NULL, NULL, NULL, NULL);
506 }
507
508 void
509 CivetServer::removeAuthHandler(const std::string &uri)
510 {
511 mg_set_auth_handler(context, uri.c_str(), NULL, NULL);
512 }
513
514 void
515 CivetServer::close()
516 {
517 if (context) {
518 mg_stop(context);
519 context = 0;
520 }
521 }
522
523 int
524 CivetServer::getCookie(struct mg_connection *conn,
525 const std::string &cookieName,
526 std::string &cookieValue)
527 {
528 // Maximum cookie length as per microsoft is 4096.
529 // http://msdn.microsoft.com/en-us/library/ms178194.aspx
530 char _cookieValue[4096];
531 const char *cookie = mg_get_header(conn, "Cookie");
532 int lRead = mg_get_cookie(cookie,
533 cookieName.c_str(),
534 _cookieValue,
535 sizeof(_cookieValue));
536 cookieValue.clear();
537 cookieValue.append(_cookieValue);
538 return lRead;
539 }
540
541 const char *
542 CivetServer::getHeader(struct mg_connection *conn,
543 const std::string &headerName)
544 {
545 return mg_get_header(conn, headerName.c_str());
546 }
547
548 const char *
549 CivetServer::getMethod(struct mg_connection *conn)
550 {
551 const struct mg_request_info *request_info = mg_get_request_info(conn);
552 assert(request_info != NULL);
553 return request_info->request_method;
554 }
555
556 void
557 CivetServer::urlDecode(const char *src,
558 std::string &dst,
559 bool is_form_url_encoded)
560 {
561 urlDecode(src, strlen(src), dst, is_form_url_encoded);
562 }
563
564 void
565 CivetServer::urlDecode(const char *src,
566 size_t src_len,
567 std::string &dst,
568 bool is_form_url_encoded)
569 {
570 // assign enough buffer
571 std::vector<char> buf(src_len + 1);
572 int r = mg_url_decode(src,
573 static_cast<int>(src_len),
574 &buf[0],
575 static_cast<int>(buf.size()),
576 is_form_url_encoded);
577 if (r < 0) {
578 // never reach here
579 throw std::out_of_range("");
580 }
581 // dst can contain NUL characters
582 dst.assign(buf.begin(), buf.begin() + r);
583 }
584
585 bool
586 CivetServer::getParam(struct mg_connection *conn,
587 const char *name,
588 std::string &dst,
589 size_t occurrence)
590 {
591 const char *formParams = NULL;
592 const char *queryString = NULL;
593 const struct mg_request_info *ri = mg_get_request_info(conn);
594 assert(ri != NULL);
595 CivetServer *me = (CivetServer *)(ri->user_data);
596 assert(me != NULL);
597 mg_lock_context(me->context);
598 CivetConnection &conobj = me->connections[conn];
599 mg_unlock_context(me->context);
600
601 mg_lock_connection(conn);
602 if (conobj.postData.empty()) {
603 // check if there is a request body
604 for (;;) {
605 char buf[2048];
606 int r = mg_read(conn, buf, sizeof(buf));
607 try {
608 if (r == 0) {
609 conobj.postData.push_back('\0');
610 break;
611 } else if ((r < 0)
612 || ((conobj.postData.size() + r)
613 > MAX_PARAM_BODY_LENGTH)) {
614 conobj.postData.assign(1, '\0');
615 break;
616 }
617 conobj.postData.insert(conobj.postData.end(), buf, buf + r);
618 } catch (...) {
619 conobj.postData.clear();
620 break;
621 }
622 }
623 }
624 if (!conobj.postData.empty()) {
625 // check if form parameter are already stored
626 formParams = &conobj.postData[0];
627 }
628
629 if (ri->query_string != NULL) {
630 // get requests do store html <form> field values in the http
631 // query_string
632 queryString = ri->query_string;
633 }
634
635 mg_unlock_connection(conn);
636
637 bool get_param_success = false;
638 if (formParams != NULL) {
639 get_param_success =
640 getParam(formParams, strlen(formParams), name, dst, occurrence);
641 }
642 if (!get_param_success && queryString != NULL) {
643 get_param_success =
644 getParam(queryString, strlen(queryString), name, dst, occurrence);
645 }
646
647 return get_param_success;
648 }
649
650 bool
651 CivetServer::getParam(const char *data,
652 size_t data_len,
653 const char *name,
654 std::string &dst,
655 size_t occurrence)
656 {
657 char buf[256];
658 int r = mg_get_var2(data, data_len, name, buf, sizeof(buf), occurrence);
659 if (r >= 0) {
660 // dst can contain NUL characters
661 dst.assign(buf, r);
662 return true;
663 } else if (r == -2) {
664 // more buffer
665 std::vector<char> vbuf(sizeof(buf) * 2);
666 for (;;) {
667 r = mg_get_var2(
668 data, data_len, name, &vbuf[0], vbuf.size(), occurrence);
669 if (r >= 0) {
670 dst.assign(vbuf.begin(), vbuf.begin() + r);
671 return true;
672 } else if (r != -2) {
673 break;
674 }
675 // more buffer
676 vbuf.resize(vbuf.size() * 2);
677 }
678 }
679 dst.clear();
680 return false;
681 }
682
683 std::string
684 CivetServer::getPostData(struct mg_connection *conn)
685 {
686 mg_lock_connection(conn);
687 std::string postdata;
688 char buf[2048];
689 int r = mg_read(conn, buf, sizeof(buf));
690 while (r > 0) {
691 postdata.append(buf, r);
692 r = mg_read(conn, buf, sizeof(buf));
693 }
694 mg_unlock_connection(conn);
695 return postdata;
696 }
697
698 void
699 CivetServer::urlEncode(const char *src, std::string &dst, bool append)
700 {
701 urlEncode(src, strlen(src), dst, append);
702 }
703
704 void
705 CivetServer::urlEncode(const char *src,
706 size_t src_len,
707 std::string &dst,
708 bool append)
709 {
710 if (!append)
711 dst.clear();
712
713 for (; src_len > 0; src++, src_len--) {
714 if (*src == '\0') {
715 // src and dst can contain NUL characters without encoding
716 dst.push_back(*src);
717 } else {
718 char buf[2] = {*src, '\0'};
719 char dst_buf[4];
720 if (mg_url_encode(buf, dst_buf, sizeof(dst_buf)) < 0) {
721 // never reach here
722 throw std::out_of_range("");
723 }
724 dst.append(dst_buf);
725 }
726 }
727 }
728
729 std::vector<int>
730 CivetServer::getListeningPorts()
731 {
732 std::vector<struct mg_server_port> server_ports = getListeningPortsFull();
733
734 std::vector<int> ports(server_ports.size());
735 for (size_t i = 0; i < server_ports.size(); i++) {
736 ports[i] = server_ports[i].port;
737 }
738
739 return ports;
740 }
741
742 std::vector<struct mg_server_port>
743 CivetServer::getListeningPortsFull()
744 {
745 std::vector<struct mg_server_port> server_ports(8);
746 for (;;) {
747 int size = mg_get_server_ports(context,
748 static_cast<int>(server_ports.size()),
749 &server_ports[0]);
750 if (size < static_cast<int>(server_ports.size())) {
751 server_ports.resize(size < 0 ? 0 : size);
752 break;
753 }
754 server_ports.resize(server_ports.size() * 2);
755 }
756 return server_ports;
757 }