]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/CivetServer.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / civetweb / src / CivetServer.cpp
CommitLineData
7c673cae
FG
1/* Copyright (c) 2013-2014 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
18bool
19CivetHandler::handleGet(CivetServer *server, struct mg_connection *conn)
20{
21 UNUSED_PARAMETER(server);
22 UNUSED_PARAMETER(conn);
23 return false;
24}
25
26bool
27CivetHandler::handlePost(CivetServer *server, struct mg_connection *conn)
28{
29 UNUSED_PARAMETER(server);
30 UNUSED_PARAMETER(conn);
31 return false;
32}
33
34bool
35CivetHandler::handleHead(CivetServer *server, struct mg_connection *conn)
36{
37 UNUSED_PARAMETER(server);
38 UNUSED_PARAMETER(conn);
39 return false;
40}
41
42bool
43CivetHandler::handlePut(CivetServer *server, struct mg_connection *conn)
44{
45 UNUSED_PARAMETER(server);
46 UNUSED_PARAMETER(conn);
47 return false;
48}
49
50bool
51CivetHandler::handlePatch(CivetServer *server, struct mg_connection *conn)
52{
53 UNUSED_PARAMETER(server);
54 UNUSED_PARAMETER(conn);
55 return false;
56}
57
58bool
59CivetHandler::handleDelete(CivetServer *server, struct mg_connection *conn)
60{
61 UNUSED_PARAMETER(server);
62 UNUSED_PARAMETER(conn);
63 return false;
64}
65
66bool
67CivetHandler::handleOptions(CivetServer *server, struct mg_connection *conn)
68{
69 UNUSED_PARAMETER(server);
70 UNUSED_PARAMETER(conn);
71 return false;
72}
73
74bool
75CivetWebSocketHandler::handleConnection(CivetServer *server,
76 const struct mg_connection *conn)
77{
78 UNUSED_PARAMETER(server);
79 UNUSED_PARAMETER(conn);
80 return true;
81}
82
83void
84CivetWebSocketHandler::handleReadyState(CivetServer *server,
85 struct mg_connection *conn)
86{
87 UNUSED_PARAMETER(server);
88 UNUSED_PARAMETER(conn);
89 return;
90}
91
92bool
93CivetWebSocketHandler::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
107void
108CivetWebSocketHandler::handleClose(CivetServer *server,
109 const struct mg_connection *conn)
110{
111 UNUSED_PARAMETER(server);
112 UNUSED_PARAMETER(conn);
113 return;
114}
115
116int
117CivetServer::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
155int
156CivetServer::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
180int
181CivetServer::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
202void
203CivetServer::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
221int
222CivetServer::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
246void
247CivetServer::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
266CivetCallbacks::CivetCallbacks()
267{
268 memset(this, 0, sizeof(*this));
269}
270
271CivetServer::CivetServer(const char **options,
272 const struct CivetCallbacks *_callbacks)
273 : context(0)
274{
275 struct CivetCallbacks callbacks;
276
277 if (_callbacks) {
278 callbacks = *_callbacks;
279 userCloseHandler = _callbacks->connection_close;
280 } else {
281 userCloseHandler = NULL;
282 }
283 callbacks.connection_close = closeHandler;
284 context = mg_start(&callbacks, this, options);
285 if (context == NULL)
286 throw CivetException("null context when constructing CivetServer. "
287 "Possible problem binding to port.");
288}
289
290CivetServer::CivetServer(std::vector<std::string> options,
291 const struct CivetCallbacks *_callbacks)
292 : context(0)
293{
294 struct CivetCallbacks callbacks;
295
296 if (_callbacks) {
297 callbacks = *_callbacks;
298 userCloseHandler = _callbacks->connection_close;
299 } else {
300 userCloseHandler = NULL;
301 }
302 callbacks.connection_close = closeHandler;
303
304 std::vector<const char *> pointers(options.size());
305 for (size_t i = 0; i < options.size(); i++) {
306 pointers[i] = (options[i].c_str());
307 }
308 pointers.push_back(0);
309
310 context = mg_start(&callbacks, this, &pointers[0]);
311 if (context == NULL)
312 throw CivetException("null context when constructing CivetServer. "
313 "Possible problem binding to port.");
314}
315
316CivetServer::~CivetServer()
317{
318 close();
319}
320
321void
322CivetServer::closeHandler(const struct mg_connection *conn)
323{
324 const struct mg_request_info *request_info = mg_get_request_info(conn);
325 assert(request_info != NULL);
326 CivetServer *me = (CivetServer *)(request_info->user_data);
327 assert(me != NULL);
328
329 // Happens when a request hits the server before the context is saved
330 if (me->context == NULL)
331 return;
332
333 if (me->userCloseHandler)
334 me->userCloseHandler(conn);
335 mg_lock_context(me->context);
336 me->connections.erase(const_cast<struct mg_connection *>(conn));
337 mg_unlock_context(me->context);
338}
339
340void
341CivetServer::addHandler(const std::string &uri, CivetHandler *handler)
342{
343 mg_set_request_handler(context, uri.c_str(), requestHandler, handler);
344}
345
346void
347CivetServer::addWebSocketHandler(const std::string &uri,
348 CivetWebSocketHandler *handler)
349{
350 mg_set_websocket_handler(context,
351 uri.c_str(),
352 webSocketConnectionHandler,
353 webSocketReadyHandler,
354 webSocketDataHandler,
355 webSocketCloseHandler,
356 handler);
357}
358
359void
360CivetServer::addAuthHandler(const std::string &uri, CivetAuthHandler *handler)
361{
362 mg_set_auth_handler(context, uri.c_str(), authHandler, handler);
363}
364
365void
366CivetServer::removeHandler(const std::string &uri)
367{
368 mg_set_request_handler(context, uri.c_str(), NULL, NULL);
369}
370
371void
372CivetServer::removeWebSocketHandler(const std::string &uri)
373{
374 mg_set_websocket_handler(
375 context, uri.c_str(), NULL, NULL, NULL, NULL, NULL);
376}
377
378void
379CivetServer::removeAuthHandler(const std::string &uri)
380{
381 mg_set_auth_handler(context, uri.c_str(), NULL, NULL);
382}
383
384void
385CivetServer::close()
386{
387 if (context) {
388 mg_stop(context);
389 context = 0;
390 }
391}
392
393int
394CivetServer::getCookie(struct mg_connection *conn,
395 const std::string &cookieName,
396 std::string &cookieValue)
397{
398 // Maximum cookie length as per microsoft is 4096.
399 // http://msdn.microsoft.com/en-us/library/ms178194.aspx
400 char _cookieValue[4096];
401 const char *cookie = mg_get_header(conn, "Cookie");
402 int lRead = mg_get_cookie(cookie,
403 cookieName.c_str(),
404 _cookieValue,
405 sizeof(_cookieValue));
406 cookieValue.clear();
407 cookieValue.append(_cookieValue);
408 return lRead;
409}
410
411const char *
412CivetServer::getHeader(struct mg_connection *conn,
413 const std::string &headerName)
414{
415 return mg_get_header(conn, headerName.c_str());
416}
417
418void
419CivetServer::urlDecode(const char *src,
420 std::string &dst,
421 bool is_form_url_encoded)
422{
423 urlDecode(src, strlen(src), dst, is_form_url_encoded);
424}
425
426void
427CivetServer::urlDecode(const char *src,
428 size_t src_len,
429 std::string &dst,
430 bool is_form_url_encoded)
431{
432 int i, j, a, b;
433#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
434
435 dst.clear();
436 for (i = j = 0; i < (int)src_len; i++, j++) {
437 if (i < (int)src_len - 2 && src[i] == '%'
438 && isxdigit(*(const unsigned char *)(src + i + 1))
439 && isxdigit(*(const unsigned char *)(src + i + 2))) {
440 a = tolower(*(const unsigned char *)(src + i + 1));
441 b = tolower(*(const unsigned char *)(src + i + 2));
442 dst.push_back((char)((HEXTOI(a) << 4) | HEXTOI(b)));
443 i += 2;
444 } else if (is_form_url_encoded && src[i] == '+') {
445 dst.push_back(' ');
446 } else {
447 dst.push_back(src[i]);
448 }
449 }
450}
451
452bool
453CivetServer::getParam(struct mg_connection *conn,
454 const char *name,
455 std::string &dst,
456 size_t occurrence)
457{
458 const char *formParams = NULL;
459 const struct mg_request_info *ri = mg_get_request_info(conn);
460 assert(ri != NULL);
461 CivetServer *me = (CivetServer *)(ri->user_data);
462 assert(me != NULL);
463 mg_lock_context(me->context);
464 CivetConnection &conobj = me->connections[conn];
465 mg_lock_connection(conn);
466 mg_unlock_context(me->context);
467
468 if (conobj.postData != NULL) {
469 formParams = conobj.postData;
470 } else {
471 const char *con_len_str = mg_get_header(conn, "Content-Length");
472 if (con_len_str) {
473 unsigned long con_len = atoi(con_len_str);
474 if (con_len > 0) {
475 // Add one extra character: in case the post-data is a text, it
476 // is required as 0-termination.
477 // Do not increment con_len, since the 0 terminating is not part
478 // of the content (text or binary).
479 conobj.postData = (char *)malloc(con_len + 1);
480 if (conobj.postData != NULL) {
481 // malloc may fail for huge requests
482 mg_read(conn, conobj.postData, con_len);
483 conobj.postData[con_len] = 0;
484 formParams = conobj.postData;
485 conobj.postDataLen = con_len;
486 }
487 }
488 }
489 }
490 if (formParams == NULL) {
491 // get requests do store html <form> field values in the http
492 // query_string
493 formParams = ri->query_string;
494 }
495 mg_unlock_connection(conn);
496
497 if (formParams != NULL) {
498 return getParam(formParams, strlen(formParams), name, dst, occurrence);
499 }
500
501 return false;
502}
503
504bool
505CivetServer::getParam(const char *data,
506 size_t data_len,
507 const char *name,
508 std::string &dst,
509 size_t occurrence)
510{
511 const char *p, *e, *s;
512 size_t name_len;
513
514 dst.clear();
515 if (data == NULL || name == NULL || data_len == 0) {
516 return false;
517 }
518 name_len = strlen(name);
519 e = data + data_len;
520
521 // data is "var1=val1&var2=val2...". Find variable first
522 for (p = data; p + name_len < e; p++) {
523 if ((p == data || p[-1] == '&') && p[name_len] == '='
524 && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
525
526 // Point p to variable value
527 p += name_len + 1;
528
529 // Point s to the end of the value
530 s = (const char *)memchr(p, '&', (size_t)(e - p));
531 if (s == NULL) {
532 s = e;
533 }
534 assert(s >= p);
535
536 // Decode variable into destination buffer
537 urlDecode(p, (int)(s - p), dst, true);
538 return true;
539 }
540 }
541 return false;
542}
543
544void
545CivetServer::urlEncode(const char *src, std::string &dst, bool append)
546{
547 urlEncode(src, strlen(src), dst, append);
548}
549
550void
551CivetServer::urlEncode(const char *src,
552 size_t src_len,
553 std::string &dst,
554 bool append)
555{
556 static const char *dont_escape = "._-$,;~()";
557 static const char *hex = "0123456789abcdef";
558
559 if (!append)
560 dst.clear();
561
562 for (; src_len > 0; src++, src_len--) {
563 if (isalnum(*(const unsigned char *)src)
564 || strchr(dont_escape, *(const unsigned char *)src) != NULL) {
565 dst.push_back(*src);
566 } else {
567 dst.push_back('%');
568 dst.push_back(hex[(*(const unsigned char *)src) >> 4]);
569 dst.push_back(hex[(*(const unsigned char *)src) & 0xf]);
570 }
571 }
572}
573
574std::vector<int>
575CivetServer::getListeningPorts()
576{
577 std::vector<int> ports(10);
578 std::vector<int> ssl(10);
579 size_t size = mg_get_ports(context, ports.size(), &ports[0], &ssl[0]);
580 ports.resize(size);
581 ssl.resize(size);
582 return ports;
583}
584
585CivetServer::CivetConnection::CivetConnection()
586{
587 postData = NULL;
588 postDataLen = 0;
589}
590
591CivetServer::CivetConnection::~CivetConnection()
592{
593 free(postData);
594}