aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-15 11:13:50 +0000
committerChristian Grothoff <christian@grothoff.org>2016-08-15 11:13:50 +0000
commite1257548dad58058dd3854acc79a906ed8ce501c (patch)
tree7d18d87efd4c051175baab4851a4c0396624d5ee
parentbd629c51f6ccdacdde67549b457be59b34b05b08 (diff)
downloadlibmicrohttpd-e1257548dad58058dd3854acc79a906ed8ce501c.tar.gz
libmicrohttpd-e1257548dad58058dd3854acc79a906ed8ce501c.zip
fixing crash bug, connection-limit bug and documenting connection-limit behavior better
-rw-r--r--ChangeLog11
-rw-r--r--doc/libmicrohttpd.texi9
-rw-r--r--src/include/microhttpd.h2
-rw-r--r--src/microhttpd/connection.c32
-rw-r--r--src/microhttpd/daemon.c76
5 files changed, 93 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 90b1ecf0..f79b8137 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
1Mon Aug 15 13:06:52 CEST 2016
2 Fixed possible crash due to write to read-only region of
3 memory given ill-formed HTTP request (write was otherwise
4 harmless, writing 0 to where there was already a 0).
5 Fixed issue with closed connection slots not immediately
6 being available again for new connections if we reached
7 our connection limit.
8 Avoid even accept()ing connections in certain thread modes
9 if we are at the connection limit and
10 MHD_USE_PIPE_FOR_SHUTDOWN is available.
11
1Wed Aug 10 16:42:57 MSK 2016 12Wed Aug 10 16:42:57 MSK 2016
2 Moved threads, locks and mutex abstraction to separate files, 13 Moved threads, locks and mutex abstraction to separate files,
3 some minor errors fixed, added support for thread name functions 14 some minor errors fixed, added support for thread name functions
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
index ed2e58c9..49a74b4c 100644
--- a/doc/libmicrohttpd.texi
+++ b/doc/libmicrohttpd.texi
@@ -626,6 +626,15 @@ maximum number of file descriptors supported by @code{select} minus
626four for @code{stdin}, @code{stdout}, @code{stderr} and the server 626four for @code{stdin}, @code{stdout}, @code{stderr} and the server
627socket). In other words, the default is as large as possible. 627socket). In other words, the default is as large as possible.
628 628
629If the connection limit is reached, MHD's behavior depends a bit on
630other options. If @code{MHD_USE_PIPE_FOR_SHUTDOWN} was given, MHD
631will stop accepting connections on the listen socket. This will cause
632the operating system to queue connections (up to the @code{listen()}
633limit) above the connection limit. Those connections will be held
634until MHD is done processing at least one of the active connections.
635If @code{MHD_USE_PIPE_FOR_SHUTDOWN} is not set, then MHD will continue
636to @code{accept()} and immediately @code{close()} these connections.
637
629Note that if you set a low connection limit, you can easily get into 638Note that if you set a low connection limit, you can easily get into
630trouble with browsers doing request pipelining. For example, if your 639trouble with browsers doing request pipelining. For example, if your
631connection limit is ``1'', a browser may open a first connection to 640connection limit is ``1'', a browser may open a first connection to
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 4e30a40d..d5e08d82 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -131,7 +131,7 @@ typedef intptr_t ssize_t;
131 * Current version of the library. 131 * Current version of the library.
132 * 0x01093001 = 1.9.30-1. 132 * 0x01093001 = 1.9.30-1.
133 */ 133 */
134#define MHD_VERSION 0x00095004 134#define MHD_VERSION 0x00095005
135 135
136/** 136/**
137 * MHD-internal return code for "YES". 137 * MHD-internal return code for "YES".
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index b3c43b63..6223b994 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -483,6 +483,19 @@ MHD_connection_close_ (struct MHD_Connection *connection,
483 &connection->client_context, 483 &connection->client_context,
484 termination_code); 484 termination_code);
485 connection->client_aware = MHD_NO; 485 connection->client_aware = MHD_NO;
486
487 /* if we were at the connection limit before and are in
488 thread-per-connection mode, signal the main thread
489 to resume accepting connections */
490 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
491 (MHD_INVALID_PIPE_ != daemon->wpipe[1]) &&
492 (1 != MHD_pipe_write_ (daemon->wpipe[1], "c", 1)) )
493 {
494#ifdef HAVE_MESSAGES
495 MHD_DLOG (daemon,
496 "failed to signal end of connection via pipe");
497#endif
498 }
486} 499}
487 500
488 501
@@ -1527,6 +1540,7 @@ parse_initial_message_line (struct MHD_Connection *connection,
1527 size_t line_len) 1540 size_t line_len)
1528{ 1541{
1529 struct MHD_Daemon *daemon = connection->daemon; 1542 struct MHD_Daemon *daemon = connection->daemon;
1543 const char *curi;
1530 char *uri; 1544 char *uri;
1531 char *http_version; 1545 char *http_version;
1532 char *args; 1546 char *args;
@@ -1539,16 +1553,19 @@ parse_initial_message_line (struct MHD_Connection *connection,
1539 uri++; 1553 uri++;
1540 /* Skip any spaces. Not required by standard but allow 1554 /* Skip any spaces. Not required by standard but allow
1541 to be more tolerant. */ 1555 to be more tolerant. */
1542 while (' ' == uri[0] && (size_t)(uri - line) < line_len) 1556 while ( (' ' == uri[0]) &&
1557 ( (size_t)(uri - line) < line_len) )
1543 uri++; 1558 uri++;
1544 if (uri - line == line_len) 1559 if (uri - line == line_len)
1545 { 1560 {
1546 uri = ""; 1561 curi = "";
1562 uri = NULL;
1547 connection->version = ""; 1563 connection->version = "";
1548 args = NULL; 1564 args = NULL;
1549 } 1565 }
1550 else 1566 else
1551 { 1567 {
1568 curi = uri;
1552 /* Search from back to accept misformed URI with space */ 1569 /* Search from back to accept misformed URI with space */
1553 http_version = line + line_len - 1; 1570 http_version = line + line_len - 1;
1554 /* Skip any trailing spaces */ 1571 /* Skip any trailing spaces */
@@ -1572,7 +1589,7 @@ parse_initial_message_line (struct MHD_Connection *connection,
1572 if (NULL != daemon->uri_log_callback) 1589 if (NULL != daemon->uri_log_callback)
1573 connection->client_context 1590 connection->client_context
1574 = daemon->uri_log_callback (daemon->uri_log_callback_cls, 1591 = daemon->uri_log_callback (daemon->uri_log_callback_cls,
1575 uri, 1592 curi,
1576 connection); 1593 connection);
1577 if (NULL != args) 1594 if (NULL != args)
1578 { 1595 {
@@ -1585,10 +1602,11 @@ parse_initial_message_line (struct MHD_Connection *connection,
1585 &connection_add_header, 1602 &connection_add_header,
1586 &unused_num_headers); 1603 &unused_num_headers);
1587 } 1604 }
1588 daemon->unescape_callback (daemon->unescape_callback_cls, 1605 if (NULL != uri)
1589 connection, 1606 daemon->unescape_callback (daemon->unescape_callback_cls,
1590 uri); 1607 connection,
1591 connection->url = uri; 1608 uri);
1609 connection->url = curi;
1592 return MHD_YES; 1610 return MHD_YES;
1593} 1611}
1594 1612
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 7e13e311..77f43537 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1281,6 +1281,17 @@ send_param_adapter (struct MHD_Connection *connection,
1281 1281
1282 1282
1283/** 1283/**
1284 * Free resources associated with all closed connections.
1285 * (destroy responses, free buffers, etc.). All closed
1286 * connections are kept in the "cleanup" doubly-linked list.
1287 *
1288 * @param daemon daemon to clean up
1289 */
1290static void
1291MHD_cleanup_connections (struct MHD_Daemon *daemon);
1292
1293
1294/**
1284 * Add another client connection to the set of connections 1295 * Add another client connection to the set of connections
1285 * managed by MHD. This API is usually not needed (since 1296 * managed by MHD. This API is usually not needed (since
1286 * MHD will accept inbound connections on the server socket). 1297 * MHD will accept inbound connections on the server socket).
@@ -1371,6 +1382,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
1371 client_socket); 1382 client_socket);
1372#endif 1383#endif
1373#endif 1384#endif
1385 //if (daemon->connections == daemon->connection_limit)
1386 // MHD_cleanup_connections (daemon); /* try to aggressively clean up to make room */
1374 if ( (daemon->connections == daemon->connection_limit) || 1387 if ( (daemon->connections == daemon->connection_limit) ||
1375 (MHD_NO == MHD_ip_limit_add (daemon, addr, addrlen)) ) 1388 (MHD_NO == MHD_ip_limit_add (daemon, addr, addrlen)) )
1376 { 1389 {
@@ -1537,7 +1550,7 @@ internal_add_connection (struct MHD_Daemon *daemon,
1537 1550
1538 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 1551 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1539 { 1552 {
1540 if (!MHD_mutex_lock_ (&daemon->cleanup_connection_mutex)) 1553 if (! MHD_mutex_lock_ (&daemon->cleanup_connection_mutex))
1541 MHD_PANIC ("Failed to acquire cleanup mutex\n"); 1554 MHD_PANIC ("Failed to acquire cleanup mutex\n");
1542 } 1555 }
1543 else 1556 else
@@ -2070,7 +2083,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
2070 struct MHD_Connection *pos; 2083 struct MHD_Connection *pos;
2071 2084
2072 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 2085 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
2073 (!MHD_mutex_lock_ (&daemon->cleanup_connection_mutex)) ) 2086 (! MHD_mutex_lock_ (&daemon->cleanup_connection_mutex)) )
2074 MHD_PANIC ("Failed to acquire cleanup mutex\n"); 2087 MHD_PANIC ("Failed to acquire cleanup mutex\n");
2075 while (NULL != (pos = daemon->cleanup_head)) 2088 while (NULL != (pos = daemon->cleanup_head))
2076 { 2089 {
@@ -2080,7 +2093,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
2080 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 2093 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
2081 (MHD_NO == pos->thread_joined) ) 2094 (MHD_NO == pos->thread_joined) )
2082 { 2095 {
2083 if (!MHD_join_thread_ (pos->pid)) 2096 if (! MHD_join_thread_ (pos->pid))
2084 { 2097 {
2085 MHD_PANIC ("Failed to join a thread\n"); 2098 MHD_PANIC ("Failed to join a thread\n");
2086 } 2099 }
@@ -2092,6 +2105,8 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
2092#endif 2105#endif
2093 daemon->connections--; 2106 daemon->connections--;
2094 daemon->at_limit = MHD_NO; 2107 daemon->at_limit = MHD_NO;
2108
2109 /* clean up the connection */
2095 if (NULL != daemon->notify_connection) 2110 if (NULL != daemon->notify_connection)
2096 daemon->notify_connection (daemon->notify_connection_cls, 2111 daemon->notify_connection (daemon->notify_connection_cls,
2097 pos, 2112 pos,
@@ -2141,7 +2156,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
2141 free (pos); 2156 free (pos);
2142 } 2157 }
2143 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 2158 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
2144 (!MHD_mutex_unlock_ (&daemon->cleanup_connection_mutex)) ) 2159 (! MHD_mutex_unlock_ (&daemon->cleanup_connection_mutex)) )
2145 MHD_PANIC ("Failed to release cleanup mutex\n"); 2160 MHD_PANIC ("Failed to release cleanup mutex\n");
2146} 2161}
2147 2162
@@ -2364,17 +2379,6 @@ MHD_select (struct MHD_Daemon *daemon,
2364#endif 2379#endif
2365 err_state = MHD_YES; 2380 err_state = MHD_YES;
2366 } 2381 }
2367
2368 /* If we're at the connection limit, no need to
2369 accept new connections; however, make sure
2370 we do not miss the shutdown, so only do this
2371 optimization if we have a shutdown signaling
2372 pipe. */
2373 if ( (MHD_INVALID_SOCKET != daemon->socket_fd) &&
2374 ( ( (daemon->connections == daemon->connection_limit) &&
2375 (0 != (daemon->options & MHD_USE_PIPE_FOR_SHUTDOWN)) ) ||
2376 (MHD_YES == daemon->at_limit) ) )
2377 FD_CLR (daemon->socket_fd, &rs);
2378 } 2382 }
2379 else 2383 else
2380 { 2384 {
@@ -2420,7 +2424,21 @@ MHD_select (struct MHD_Daemon *daemon,
2420 } 2424 }
2421#endif /* MHD_WINSOCK_SOCKETS */ 2425#endif /* MHD_WINSOCK_SOCKETS */
2422 } 2426 }
2423 2427 /* Stop listening if we are at the configured connection limit */
2428 /* If we're at the connection limit, no point in really
2429 accepting new connections; however, make sure we do not miss
2430 the shutdown OR the termination of an existing connection; so
2431 only do this optimization if we have a signaling pipe in
2432 place. */
2433 if ( (MHD_INVALID_SOCKET != daemon->socket_fd) &&
2434 (MHD_INVALID_PIPE_ != daemon->wpipe[0]) &&
2435 (0 != (daemon->options & MHD_USE_PIPE_FOR_SHUTDOWN)) &&
2436 ( (daemon->connections == daemon->connection_limit) ||
2437 (MHD_YES == daemon->at_limit) ) )
2438 {
2439 FD_CLR (daemon->socket_fd,
2440 &rs);
2441 }
2424 tv = NULL; 2442 tv = NULL;
2425 if (MHD_YES == err_state) 2443 if (MHD_YES == err_state)
2426 may_block = MHD_NO; 2444 may_block = MHD_NO;
@@ -4185,7 +4203,7 @@ MHD_start_daemon_va (unsigned int flags,
4185 } 4203 }
4186#endif 4204#endif
4187 4205
4188 if (!MHD_mutex_init_ (&daemon->per_ip_connection_mutex)) 4206 if (! MHD_mutex_init_ (&daemon->per_ip_connection_mutex))
4189 { 4207 {
4190#ifdef HAVE_MESSAGES 4208#ifdef HAVE_MESSAGES
4191 MHD_DLOG (daemon, 4209 MHD_DLOG (daemon,
@@ -4196,7 +4214,7 @@ MHD_start_daemon_va (unsigned int flags,
4196 MHD_PANIC ("close failed\n"); 4214 MHD_PANIC ("close failed\n");
4197 goto free_and_fail; 4215 goto free_and_fail;
4198 } 4216 }
4199 if (!MHD_mutex_init_ (&daemon->cleanup_connection_mutex)) 4217 if (! MHD_mutex_init_ (&daemon->cleanup_connection_mutex))
4200 { 4218 {
4201#ifdef HAVE_MESSAGES 4219#ifdef HAVE_MESSAGES
4202 MHD_DLOG (daemon, 4220 MHD_DLOG (daemon,
@@ -4229,12 +4247,12 @@ MHD_start_daemon_va (unsigned int flags,
4229 ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) && 4247 ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) &&
4230 (0 == daemon->worker_pool_size)) ) && 4248 (0 == daemon->worker_pool_size)) ) &&
4231 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) && 4249 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) &&
4232 (!MHD_create_named_thread_ (&daemon->pid, 4250 (! MHD_create_named_thread_ (&daemon->pid,
4233 (flags & MHD_USE_THREAD_PER_CONNECTION) ? 4251 (flags & MHD_USE_THREAD_PER_CONNECTION) ?
4234 "MHD-listen" : "MHD-single", 4252 "MHD-listen" : "MHD-single",
4235 daemon->thread_stack_size, 4253 daemon->thread_stack_size,
4236 &MHD_select_thread, 4254 &MHD_select_thread,
4237 daemon) ) ) 4255 daemon) ) )
4238 { 4256 {
4239#ifdef HAVE_MESSAGES 4257#ifdef HAVE_MESSAGES
4240 MHD_DLOG (daemon, 4258 MHD_DLOG (daemon,
@@ -4342,11 +4360,11 @@ MHD_start_daemon_va (unsigned int flags,
4342 } 4360 }
4343 4361
4344 /* Spawn the worker thread */ 4362 /* Spawn the worker thread */
4345 if (!MHD_create_named_thread_(&d->pid, 4363 if (! MHD_create_named_thread_(&d->pid,
4346 "MHD-worker", 4364 "MHD-worker",
4347 daemon->thread_stack_size, 4365 daemon->thread_stack_size,
4348 &MHD_select_thread, 4366 &MHD_select_thread,
4349 d)) 4367 d))
4350 { 4368 {
4351#ifdef HAVE_MESSAGES 4369#ifdef HAVE_MESSAGES
4352 MHD_DLOG (daemon, 4370 MHD_DLOG (daemon,