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
handleGet(CivetServer * server,struct mg_connection * conn)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
handlePost(CivetServer * server,struct mg_connection * conn)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
handleHead(CivetServer * server,struct mg_connection * conn)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
handlePut(CivetServer * server,struct mg_connection * conn)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
handlePatch(CivetServer * server,struct mg_connection * conn)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
handleDelete(CivetServer * server,struct mg_connection * conn)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
handleOptions(CivetServer * server,struct mg_connection * conn)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
handleConnection(CivetServer * server,const struct mg_connection * conn)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
handleReadyState(CivetServer * server,struct mg_connection * conn)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
handleData(CivetServer * server,struct mg_connection * conn,int bits,char * data,size_t data_len)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
handleClose(CivetServer * server,const struct mg_connection * conn)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
requestHandler(struct mg_connection * conn,void * cbdata)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
authHandler(struct mg_connection * conn,void * cbdata)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
webSocketConnectionHandler(const struct mg_connection * conn,void * cbdata)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
webSocketReadyHandler(struct mg_connection * conn,void * cbdata)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
webSocketDataHandler(struct mg_connection * conn,int bits,char * data,size_t data_len,void * cbdata)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
webSocketCloseHandler(const struct mg_connection * conn,void * cbdata)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 
CivetCallbacks()271 CivetCallbacks::CivetCallbacks()
272 {
273 	memset(this, 0, sizeof(*this));
274 }
275 
CivetServer(const char ** options,const struct CivetCallbacks * _callbacks,const void * UserContextIn)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 
CivetServer(std::vector<std::string> options,const struct CivetCallbacks * _callbacks,const void * UserContextIn)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 
~CivetServer()327 CivetServer::~CivetServer()
328 {
329 	close();
330 }
331 
332 void
closeHandler(const struct mg_connection * conn)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
addHandler(const std::string & uri,CivetHandler * handler)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
addWebSocketHandler(const std::string & uri,CivetWebSocketHandler * handler)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
addAuthHandler(const std::string & uri,CivetAuthHandler * handler)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
removeHandler(const std::string & uri)376 CivetServer::removeHandler(const std::string &uri)
377 {
378 	mg_set_request_handler(context, uri.c_str(), NULL, NULL);
379 }
380 
381 void
removeWebSocketHandler(const std::string & uri)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
removeAuthHandler(const std::string & uri)389 CivetServer::removeAuthHandler(const std::string &uri)
390 {
391 	mg_set_auth_handler(context, uri.c_str(), NULL, NULL);
392 }
393 
394 void
close()395 CivetServer::close()
396 {
397 	if (context) {
398 		mg_stop(context);
399 		context = 0;
400 	}
401 }
402 
403 int
getCookie(struct mg_connection * conn,const std::string & cookieName,std::string & cookieValue)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 *
getHeader(struct mg_connection * conn,const std::string & headerName)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
urlDecode(const char * src,std::string & dst,bool is_form_url_encoded)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
urlDecode(const char * src,size_t src_len,std::string & dst,bool is_form_url_encoded)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((unsigned char)src[i + 1])
449 		    && isxdigit((unsigned char)src[i + 2])) {
450 			a = tolower((unsigned char)src[i + 1]);
451 			b = tolower((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
getParam(struct mg_connection * conn,const char * name,std::string & dst,size_t occurrence)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 				mg_unlock_connection(conn);
491 				return false;
492 			}
493 			if ((con_len > 0) && (con_len <= MAX_PARAM_BODY_LENGTH)) {
494 				// Body is within a reasonable range
495 
496 				// Allocate memory:
497 				// Add one extra character: in case the post-data is a text, it
498 				// is required as 0-termination.
499 				// Do not increment con_len, since the 0 terminating is not part
500 				// of the content (text or binary).
501 				conobj.postData = (char *)malloc(con_len + 1);
502 				if (conobj.postData != NULL) {
503 					// malloc may fail for huge requests
504 					mg_read(conn, conobj.postData, con_len);
505 					conobj.postData[con_len] = 0;
506 					formParams = conobj.postData;
507 					conobj.postDataLen = con_len;
508 				}
509 			}
510 			if (conobj.postData == NULL) {
511 				// we cannot store the body
512 				mg_unlock_connection(conn);
513 				return false;
514 			}
515 		}
516 	}
517 
518 	if (ri->query_string != NULL) {
519 		// get requests do store html <form> field values in the http
520 		// query_string
521 		queryString = ri->query_string;
522 	}
523 
524 	mg_unlock_connection(conn);
525 
526 	bool get_param_success = false;
527 	if (formParams != NULL) {
528 		get_param_success =
529 		    getParam(formParams, strlen(formParams), name, dst, occurrence);
530 	}
531 	if (!get_param_success && queryString != NULL) {
532 		get_param_success =
533 		    getParam(queryString, strlen(queryString), name, dst, occurrence);
534 	}
535 
536 	return get_param_success;
537 }
538 
539 bool
getParam(const char * data,size_t data_len,const char * name,std::string & dst,size_t occurrence)540 CivetServer::getParam(const char *data,
541                       size_t data_len,
542                       const char *name,
543                       std::string &dst,
544                       size_t occurrence)
545 {
546 	const char *p, *e, *s;
547 	size_t name_len;
548 
549 	dst.clear();
550 	if (data == NULL || name == NULL || data_len == 0) {
551 		return false;
552 	}
553 	name_len = strlen(name);
554 	e = data + data_len;
555 
556 	// data is "var1=val1&var2=val2...". Find variable first
557 	for (p = data; p + name_len < e; p++) {
558 		if ((p == data || p[-1] == '&') && p[name_len] == '='
559 		    && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
560 
561 			// Point p to variable value
562 			p += name_len + 1;
563 
564 			// Point s to the end of the value
565 			s = (const char *)memchr(p, '&', (size_t)(e - p));
566 			if (s == NULL) {
567 				s = e;
568 			}
569 			assert(s >= p);
570 
571 			// Decode variable into destination buffer
572 			urlDecode(p, (s - p), dst, true);
573 			return true;
574 		}
575 	}
576 	return false;
577 }
578 
579 std::string
getPostData(struct mg_connection * conn)580 CivetServer::getPostData(struct mg_connection *conn)
581 {
582 	mg_lock_connection(conn);
583 	std::string postdata;
584 	char buf[2048];
585 	int r = mg_read(conn, buf, sizeof(buf));
586 	while (r > 0) {
587 		postdata += std::string(buf, r);
588 		r = mg_read(conn, buf, sizeof(buf));
589 	}
590 	mg_unlock_connection(conn);
591 	return postdata;
592 }
593 
594 void
urlEncode(const char * src,std::string & dst,bool append)595 CivetServer::urlEncode(const char *src, std::string &dst, bool append)
596 {
597 	urlEncode(src, strlen(src), dst, append);
598 }
599 
600 void
urlEncode(const char * src,size_t src_len,std::string & dst,bool append)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((unsigned char)*src) || strchr(dont_escape, *src) != NULL) {
614 			dst.push_back(*src);
615 		} else {
616 			dst.push_back('%');
617 			dst.push_back(hex[(unsigned char)*src >> 4]);
618 			dst.push_back(hex[(unsigned char)*src & 0xf]);
619 		}
620 	}
621 }
622 
623 std::vector<int>
getListeningPorts()624 CivetServer::getListeningPorts()
625 {
626 	std::vector<struct mg_server_port> server_ports = getListeningPortsFull();
627 
628 	std::vector<int> ports(server_ports.size());
629 	for (size_t i = 0; i < server_ports.size(); i++) {
630 		ports[i] = server_ports[i].port;
631 	}
632 
633 	return ports;
634 }
635 
636 std::vector<struct mg_server_port>
getListeningPortsFull()637 CivetServer::getListeningPortsFull()
638 {
639 	std::vector<struct mg_server_port> server_ports(50);
640 	int size = mg_get_server_ports(context,
641 	                               (int)server_ports.size(),
642 	                               &server_ports[0]);
643 	if (size <= 0) {
644 		server_ports.resize(0);
645 		return server_ports;
646 	}
647 	server_ports.resize(size);
648 	return server_ports;
649 }
650 
CivetConnection()651 CivetServer::CivetConnection::CivetConnection()
652 {
653 	postData = NULL;
654 	postDataLen = 0;
655 }
656 
~CivetConnection()657 CivetServer::CivetConnection::~CivetConnection()
658 {
659 	free(postData);
660 }
661