1 /* Copyright (c) 2013-2017 the Civetweb developers
2 * Copyright (c) 2013 No Face Press, LLC
4 * License http://opensource.org/licenses/mit-license.php MIT License
7 #include "CivetServer.h"
14 #ifndef UNUSED_PARAMETER
15 #define UNUSED_PARAMETER(x) (void)(x)
19 CivetHandler::handleGet(CivetServer
*server
, struct mg_connection
*conn
)
21 UNUSED_PARAMETER(server
);
22 UNUSED_PARAMETER(conn
);
27 CivetHandler::handlePost(CivetServer
*server
, struct mg_connection
*conn
)
29 UNUSED_PARAMETER(server
);
30 UNUSED_PARAMETER(conn
);
35 CivetHandler::handleHead(CivetServer
*server
, struct mg_connection
*conn
)
37 UNUSED_PARAMETER(server
);
38 UNUSED_PARAMETER(conn
);
43 CivetHandler::handlePut(CivetServer
*server
, struct mg_connection
*conn
)
45 UNUSED_PARAMETER(server
);
46 UNUSED_PARAMETER(conn
);
51 CivetHandler::handlePatch(CivetServer
*server
, struct mg_connection
*conn
)
53 UNUSED_PARAMETER(server
);
54 UNUSED_PARAMETER(conn
);
59 CivetHandler::handleDelete(CivetServer
*server
, struct mg_connection
*conn
)
61 UNUSED_PARAMETER(server
);
62 UNUSED_PARAMETER(conn
);
67 CivetHandler::handleOptions(CivetServer
*server
, struct mg_connection
*conn
)
69 UNUSED_PARAMETER(server
);
70 UNUSED_PARAMETER(conn
);
75 CivetWebSocketHandler::handleConnection(CivetServer
*server
,
76 const struct mg_connection
*conn
)
78 UNUSED_PARAMETER(server
);
79 UNUSED_PARAMETER(conn
);
84 CivetWebSocketHandler::handleReadyState(CivetServer
*server
,
85 struct mg_connection
*conn
)
87 UNUSED_PARAMETER(server
);
88 UNUSED_PARAMETER(conn
);
93 CivetWebSocketHandler::handleData(CivetServer
*server
,
94 struct mg_connection
*conn
,
99 UNUSED_PARAMETER(server
);
100 UNUSED_PARAMETER(conn
);
101 UNUSED_PARAMETER(bits
);
102 UNUSED_PARAMETER(data
);
103 UNUSED_PARAMETER(data_len
);
108 CivetWebSocketHandler::handleClose(CivetServer
*server
,
109 const struct mg_connection
*conn
)
111 UNUSED_PARAMETER(server
);
112 UNUSED_PARAMETER(conn
);
117 CivetServer::requestHandler(struct mg_connection
*conn
, void *cbdata
)
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
);
124 // Happens when a request hits the server before the context is saved
125 if (me
->context
== NULL
)
128 mg_lock_context(me
->context
);
129 me
->connections
[conn
] = CivetConnection();
130 mg_unlock_context(me
->context
);
132 CivetHandler
*handler
= (CivetHandler
*)cbdata
;
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;
152 return 0; // No handler found
156 CivetServer::authHandler(struct mg_connection
*conn
, void *cbdata
)
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
);
163 // Happens when a request hits the server before the context is saved
164 if (me
->context
== NULL
)
167 mg_lock_context(me
->context
);
168 me
->connections
[conn
] = CivetConnection();
169 mg_unlock_context(me
->context
);
171 CivetAuthHandler
*handler
= (CivetAuthHandler
*)cbdata
;
174 return handler
->authorize(me
, conn
) ? 1 : 0;
177 return 0; // No handler found
181 CivetServer::webSocketConnectionHandler(const struct mg_connection
*conn
,
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
);
189 // Happens when a request hits the server before the context is saved
190 if (me
->context
== NULL
)
193 CivetWebSocketHandler
*handler
= (CivetWebSocketHandler
*)cbdata
;
196 return handler
->handleConnection(me
, conn
) ? 0 : 1;
199 return 1; // No handler found, close connection
203 CivetServer::webSocketReadyHandler(struct mg_connection
*conn
, void *cbdata
)
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
);
210 // Happens when a request hits the server before the context is saved
211 if (me
->context
== NULL
)
214 CivetWebSocketHandler
*handler
= (CivetWebSocketHandler
*)cbdata
;
217 handler
->handleReadyState(me
, conn
);
222 CivetServer::webSocketDataHandler(struct mg_connection
*conn
,
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
);
233 // Happens when a request hits the server before the context is saved
234 if (me
->context
== NULL
)
237 CivetWebSocketHandler
*handler
= (CivetWebSocketHandler
*)cbdata
;
240 return handler
->handleData(me
, conn
, bits
, data
, data_len
) ? 1 : 0;
243 return 1; // No handler found
247 CivetServer::webSocketCloseHandler(const struct mg_connection
*conn
,
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
);
255 // Happens when a request hits the server before the context is saved
256 if (me
->context
== NULL
)
259 CivetWebSocketHandler
*handler
= (CivetWebSocketHandler
*)cbdata
;
262 handler
->handleClose(me
, conn
);
266 CivetCallbacks::CivetCallbacks()
268 memset(this, 0, sizeof(*this));
271 CivetServer::CivetServer(const char **options
,
272 const struct CivetCallbacks
*_callbacks
,
273 const void *UserContextIn
)
276 struct CivetCallbacks callbacks
;
278 UserContext
= UserContextIn
;
281 callbacks
= *_callbacks
;
282 userCloseHandler
= _callbacks
->connection_close
;
284 userCloseHandler
= NULL
;
286 callbacks
.connection_close
= closeHandler
;
287 context
= mg_start(&callbacks
, this, options
);
289 throw CivetException("null context when constructing CivetServer. "
290 "Possible problem binding to port.");
293 CivetServer::CivetServer(std::vector
<std::string
> options
,
294 const struct CivetCallbacks
*_callbacks
,
295 const void *UserContextIn
)
298 struct CivetCallbacks callbacks
;
300 UserContext
= UserContextIn
;
303 callbacks
= *_callbacks
;
304 userCloseHandler
= _callbacks
->connection_close
;
306 userCloseHandler
= NULL
;
308 callbacks
.connection_close
= closeHandler
;
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());
314 pointers
.push_back(0);
316 context
= mg_start(&callbacks
, this, &pointers
[0]);
318 throw CivetException("null context when constructing CivetServer. "
319 "Possible problem binding to port.");
322 CivetServer::~CivetServer()
328 CivetServer::closeHandler(const struct mg_connection
*conn
)
330 CivetServer
*me
= (CivetServer
*)mg_get_user_data(mg_get_context(conn
));
333 // Happens when a request hits the server before the context is saved
334 if (me
->context
== NULL
)
337 if (me
->userCloseHandler
) {
338 me
->userCloseHandler(conn
);
340 mg_lock_context(me
->context
);
341 me
->connections
.erase(const_cast<struct mg_connection
*>(conn
));
342 mg_unlock_context(me
->context
);
346 CivetServer::addHandler(const std::string
&uri
, CivetHandler
*handler
)
348 mg_set_request_handler(context
, uri
.c_str(), requestHandler
, handler
);
352 CivetServer::addWebSocketHandler(const std::string
&uri
,
353 CivetWebSocketHandler
*handler
)
355 mg_set_websocket_handler(context
,
357 webSocketConnectionHandler
,
358 webSocketReadyHandler
,
359 webSocketDataHandler
,
360 webSocketCloseHandler
,
365 CivetServer::addAuthHandler(const std::string
&uri
, CivetAuthHandler
*handler
)
367 mg_set_auth_handler(context
, uri
.c_str(), authHandler
, handler
);
371 CivetServer::removeHandler(const std::string
&uri
)
373 mg_set_request_handler(context
, uri
.c_str(), NULL
, NULL
);
377 CivetServer::removeWebSocketHandler(const std::string
&uri
)
379 mg_set_websocket_handler(
380 context
, uri
.c_str(), NULL
, NULL
, NULL
, NULL
, NULL
);
384 CivetServer::removeAuthHandler(const std::string
&uri
)
386 mg_set_auth_handler(context
, uri
.c_str(), NULL
, NULL
);
399 CivetServer::getCookie(struct mg_connection
*conn
,
400 const std::string
&cookieName
,
401 std::string
&cookieValue
)
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
,
410 sizeof(_cookieValue
));
412 cookieValue
.append(_cookieValue
);
417 CivetServer::getHeader(struct mg_connection
*conn
,
418 const std::string
&headerName
)
420 return mg_get_header(conn
, headerName
.c_str());
424 CivetServer::urlDecode(const char *src
,
426 bool is_form_url_encoded
)
428 urlDecode(src
, strlen(src
), dst
, is_form_url_encoded
);
432 CivetServer::urlDecode(const char *src
,
435 bool is_form_url_encoded
)
438 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
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
)));
449 } else if (is_form_url_encoded
&& src
[i
] == '+') {
452 dst
.push_back(src
[i
]);
458 CivetServer::getParam(struct mg_connection
*conn
,
463 const char *formParams
= NULL
;
464 const struct mg_request_info
*ri
= mg_get_request_info(conn
);
466 CivetServer
*me
= (CivetServer
*)(ri
->user_data
);
468 mg_lock_context(me
->context
);
469 CivetConnection
&conobj
= me
->connections
[conn
];
470 mg_lock_connection(conn
);
471 mg_unlock_context(me
->context
);
473 if (conobj
.postData
!= NULL
) {
474 formParams
= conobj
.postData
;
476 const char *con_len_str
= mg_get_header(conn
, "Content-Length");
478 unsigned long con_len
= atoi(con_len_str
);
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
;
495 if (formParams
== NULL
) {
496 // get requests do store html <form> field values in the http
498 formParams
= ri
->query_string
;
500 mg_unlock_connection(conn
);
502 if (formParams
!= NULL
) {
503 return getParam(formParams
, strlen(formParams
), name
, dst
, occurrence
);
510 CivetServer::getParam(const char *data
,
516 const char *p
, *e
, *s
;
520 if (data
== NULL
|| name
== NULL
|| data_len
== 0) {
523 name_len
= strlen(name
);
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
--) {
531 // Point p to variable value
534 // Point s to the end of the value
535 s
= (const char *)memchr(p
, '&', (size_t)(e
- p
));
541 // Decode variable into destination buffer
542 urlDecode(p
, (int)(s
- p
), dst
, true);
550 CivetServer::urlEncode(const char *src
, std::string
&dst
, bool append
)
552 urlEncode(src
, strlen(src
), dst
, append
);
556 CivetServer::urlEncode(const char *src
,
561 static const char *dont_escape
= "._-$,;~()";
562 static const char *hex
= "0123456789abcdef";
567 for (; src_len
> 0; src
++, src_len
--) {
568 if (isalnum(*(const unsigned char *)src
)
569 || strchr(dont_escape
, *(const unsigned char *)src
) != NULL
) {
573 dst
.push_back(hex
[(*(const unsigned char *)src
) >> 4]);
574 dst
.push_back(hex
[(*(const unsigned char *)src
) & 0xf]);
580 CivetServer::getListeningPorts()
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(),
592 server_ports
.resize(size
);
593 for (int i
= 0; i
< size
; i
++) {
594 ports
[i
] = server_ports
[i
].port
;
600 CivetServer::CivetConnection::CivetConnection()
606 CivetServer::CivetConnection::~CivetConnection()