diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-01-01 20:43:44 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-01-01 20:43:44 +0000 |
commit | e4e05d001ce05928d72aa07f34a3a7581107d842 (patch) | |
tree | 1364a8b1c645fe662ef25f2c00f53f35c4c1898c /src | |
parent | cb11cac74d2a5dca1039dd2ab70d42e8fe1d501b (diff) | |
download | libmicrohttpd-e4e05d001ce05928d72aa07f34a3a7581107d842.tar.gz libmicrohttpd-e4e05d001ce05928d72aa07f34a3a7581107d842.zip |
enable use of keep-alive with http 1.0 if explicitly requested by the client
Diffstat (limited to 'src')
-rw-r--r-- | src/examples/demo.c | 6 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 256 |
2 files changed, 174 insertions, 88 deletions
diff --git a/src/examples/demo.c b/src/examples/demo.c index d22f005b..4a16b656 100644 --- a/src/examples/demo.c +++ b/src/examples/demo.c | |||
@@ -43,7 +43,7 @@ | |||
43 | * Number of threads to run in the thread pool. Should (roughly) match | 43 | * Number of threads to run in the thread pool. Should (roughly) match |
44 | * the number of cores on your system. | 44 | * the number of cores on your system. |
45 | */ | 45 | */ |
46 | #define NUMBER_OF_THREADS 4 | 46 | #define NUMBER_OF_THREADS 8 |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * How many bytes of a file do we give to libmagic to determine the mime type? | 49 | * How many bytes of a file do we give to libmagic to determine the mime type? |
@@ -362,9 +362,11 @@ update_directory () | |||
362 | rdc.buf, | 362 | rdc.buf, |
363 | MHD_RESPMEM_MUST_FREE); | 363 | MHD_RESPMEM_MUST_FREE); |
364 | mark_as_html (response); | 364 | mark_as_html (response); |
365 | #if FORCE_CLOSE | ||
365 | (void) MHD_add_response_header (response, | 366 | (void) MHD_add_response_header (response, |
366 | MHD_HTTP_HEADER_CONNECTION, | 367 | MHD_HTTP_HEADER_CONNECTION, |
367 | "close"); | 368 | "close"); |
369 | #endif | ||
368 | update_cached_response (response); | 370 | update_cached_response (response); |
369 | } | 371 | } |
370 | 372 | ||
@@ -775,7 +777,9 @@ generate_page (void *cls, | |||
775 | } | 777 | } |
776 | } | 778 | } |
777 | if (0 == strcmp (method, MHD_HTTP_METHOD_GET)) | 779 | if (0 == strcmp (method, MHD_HTTP_METHOD_GET)) |
780 | { | ||
778 | return return_directory_response (connection); | 781 | return return_directory_response (connection); |
782 | } | ||
779 | 783 | ||
780 | /* unexpected request, refuse */ | 784 | /* unexpected request, refuse */ |
781 | return MHD_queue_response (connection, | 785 | return MHD_queue_response (connection, |
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index aec86880..7709a92d 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -484,8 +484,56 @@ try_ready_chunked_body (struct MHD_Connection *connection) | |||
484 | 484 | ||
485 | 485 | ||
486 | /** | 486 | /** |
487 | * Are we allowed to keep the given connection alive? We can use the | ||
488 | * TCP stream for a second request if the connection is HTTP 1.1 and | ||
489 | * the "Connection" header either does not exist or is not set to | ||
490 | * "close", or if the connection is HTTP 1.0 and the "Connection" | ||
491 | * header is explicitly set to "keep-alive". If no HTTP version is | ||
492 | * specified (or if it is not 1.0 or 1.1), we definitively close the | ||
493 | * connection. If the "Connection" header is not exactly "close" or | ||
494 | * "keep-alive", we proceed to use the default for the respective HTTP | ||
495 | * version (which is conservative for HTTP 1.0, but might be a bit | ||
496 | * optimistic for HTTP 1.1). | ||
497 | * | ||
498 | * @param connection the connection to check for keepalive | ||
499 | * @return #MHD_YES if (based on the request), a keepalive is | ||
500 | * legal | ||
501 | */ | ||
502 | static int | ||
503 | keepalive_possible (struct MHD_Connection *connection) | ||
504 | { | ||
505 | const char *end; | ||
506 | |||
507 | if (NULL == connection->version) | ||
508 | return MHD_NO; | ||
509 | end = MHD_lookup_connection_value (connection, | ||
510 | MHD_HEADER_KIND, | ||
511 | MHD_HTTP_HEADER_CONNECTION); | ||
512 | if (0 == strcasecmp (connection->version, | ||
513 | MHD_HTTP_VERSION_1_1)) | ||
514 | { | ||
515 | if (NULL == end) | ||
516 | return MHD_YES; | ||
517 | if (0 == strcasecmp (end, "close")) | ||
518 | return MHD_NO; | ||
519 | return MHD_YES; | ||
520 | } | ||
521 | if (0 == strcasecmp (connection->version, | ||
522 | MHD_HTTP_VERSION_1_0)) | ||
523 | { | ||
524 | if (NULL == end) | ||
525 | return MHD_NO; | ||
526 | if (0 == strcasecmp (end, "Keep-Alive")) | ||
527 | return MHD_YES; | ||
528 | return MHD_NO; | ||
529 | } | ||
530 | return MHD_NO; | ||
531 | } | ||
532 | |||
533 | |||
534 | /** | ||
487 | * Check if we need to set some additional headers | 535 | * Check if we need to set some additional headers |
488 | * for http-compiliance. | 536 | * for HTTP-compiliance. |
489 | * | 537 | * |
490 | * @param connection connection to check (and possibly modify) | 538 | * @param connection connection to check (and possibly modify) |
491 | */ | 539 | */ |
@@ -493,6 +541,7 @@ static void | |||
493 | add_extra_headers (struct MHD_Connection *connection) | 541 | add_extra_headers (struct MHD_Connection *connection) |
494 | { | 542 | { |
495 | const char *have_close; | 543 | const char *have_close; |
544 | const char *have_keepalive; | ||
496 | const char *client_close; | 545 | const char *client_close; |
497 | const char *have_encoding; | 546 | const char *have_encoding; |
498 | char buf[128]; | 547 | char buf[128]; |
@@ -502,12 +551,18 @@ add_extra_headers (struct MHD_Connection *connection) | |||
502 | MHD_HEADER_KIND, | 551 | MHD_HEADER_KIND, |
503 | MHD_HTTP_HEADER_CONNECTION); | 552 | MHD_HTTP_HEADER_CONNECTION); |
504 | /* we only care about 'close', everything else is ignored */ | 553 | /* we only care about 'close', everything else is ignored */ |
505 | if ( (NULL != client_close) && (0 != strcasecmp (client_close, "close")) ) | 554 | if ( (NULL != client_close) && |
555 | (0 != strcasecmp (client_close, "close")) ) | ||
506 | client_close = NULL; | 556 | client_close = NULL; |
507 | have_close = MHD_get_response_header (connection->response, | 557 | have_close = MHD_get_response_header (connection->response, |
508 | MHD_HTTP_HEADER_CONNECTION); | 558 | MHD_HTTP_HEADER_CONNECTION); |
509 | if ( (NULL != have_close) && (0 != strcasecmp (have_close, "close")) ) | 559 | have_keepalive = have_close; |
560 | if ( (NULL != have_close) && | ||
561 | (0 != strcasecmp (have_close, "close")) ) | ||
510 | have_close = NULL; | 562 | have_close = NULL; |
563 | if ( (NULL != have_keepalive) && | ||
564 | (0 != strcasecmp (have_keepalive, "keep-alive")) ) | ||
565 | have_keepalive = NULL; | ||
511 | connection->have_chunked_upload = MHD_NO; | 566 | connection->have_chunked_upload = MHD_NO; |
512 | add_close = MHD_NO; | 567 | add_close = MHD_NO; |
513 | if (MHD_SIZE_UNKNOWN == connection->response->total_size) | 568 | if (MHD_SIZE_UNKNOWN == connection->response->total_size) |
@@ -518,9 +573,10 @@ add_extra_headers (struct MHD_Connection *connection) | |||
518 | { | 573 | { |
519 | /* 'close' header doesn't exist yet, see if we need to add one; | 574 | /* 'close' header doesn't exist yet, see if we need to add one; |
520 | if the client asked for a close, no need to start chunk'ing */ | 575 | if the client asked for a close, no need to start chunk'ing */ |
521 | if ((NULL == client_close) && | 576 | if ( (NULL == client_close) && |
522 | (NULL != connection->version) && | 577 | (MHD_YES == keepalive_possible (connection)) && |
523 | (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) | 578 | (0 == strcasecmp (connection->version, |
579 | MHD_HTTP_VERSION_1_1)) ) | ||
524 | { | 580 | { |
525 | connection->have_chunked_upload = MHD_YES; | 581 | connection->have_chunked_upload = MHD_YES; |
526 | have_encoding = MHD_get_response_header (connection->response, | 582 | have_encoding = MHD_get_response_header (connection->response, |
@@ -578,7 +634,15 @@ add_extra_headers (struct MHD_Connection *connection) | |||
578 | } | 634 | } |
579 | if (MHD_YES == add_close) | 635 | if (MHD_YES == add_close) |
580 | MHD_add_response_header (connection->response, | 636 | MHD_add_response_header (connection->response, |
581 | MHD_HTTP_HEADER_CONNECTION, "close"); | 637 | MHD_HTTP_HEADER_CONNECTION, |
638 | "close"); | ||
639 | if ( (NULL == have_keepalive) && | ||
640 | (NULL == have_close) && | ||
641 | (MHD_NO == add_close) && | ||
642 | (MHD_YES == keepalive_possible (connection)) ) | ||
643 | MHD_add_response_header (connection->response, | ||
644 | MHD_HTTP_HEADER_CONNECTION, | ||
645 | "Keep-Alive"); | ||
582 | } | 646 | } |
583 | 647 | ||
584 | 648 | ||
@@ -669,6 +733,7 @@ build_header_response (struct MHD_Connection *connection) | |||
669 | const char *reason_phrase; | 733 | const char *reason_phrase; |
670 | uint32_t rc; | 734 | uint32_t rc; |
671 | int must_add_close; | 735 | int must_add_close; |
736 | const char *end; | ||
672 | 737 | ||
673 | EXTRA_CHECK (NULL != connection->version); | 738 | EXTRA_CHECK (NULL != connection->version); |
674 | if (0 == strlen (connection->version)) | 739 | if (0 == strlen (connection->version)) |
@@ -709,16 +774,17 @@ build_header_response (struct MHD_Connection *connection) | |||
709 | } | 774 | } |
710 | else | 775 | else |
711 | { | 776 | { |
777 | /* 2 bytes for final CRLF of a Chunked-Body */ | ||
712 | size = 2; | 778 | size = 2; |
713 | kind = MHD_FOOTER_KIND; | 779 | kind = MHD_FOOTER_KIND; |
714 | off = 0; | 780 | off = 0; |
715 | } | 781 | } |
782 | end = MHD_get_response_header (connection->response, | ||
783 | MHD_HTTP_HEADER_CONNECTION); | ||
716 | must_add_close = ( (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) && | 784 | must_add_close = ( (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) && |
717 | (MHD_YES == connection->read_closed) && | 785 | (MHD_YES == connection->read_closed) && |
718 | (0 == strcasecmp (connection->version, | 786 | (MHD_YES == keepalive_possible (connection)) && |
719 | MHD_HTTP_VERSION_1_1)) && | 787 | (NULL == end) ); |
720 | (NULL == MHD_get_response_header (connection->response, | ||
721 | MHD_HTTP_HEADER_CONNECTION)) ); | ||
722 | if (must_add_close) | 788 | if (must_add_close) |
723 | size += strlen ("Connection: close\r\n"); | 789 | size += strlen ("Connection: close\r\n"); |
724 | for (pos = connection->response->first_header; NULL != pos; pos = pos->next) | 790 | for (pos = connection->response->first_header; NULL != pos; pos = pos->next) |
@@ -729,7 +795,8 @@ build_header_response (struct MHD_Connection *connection) | |||
729 | if (NULL == data) | 795 | if (NULL == data) |
730 | { | 796 | { |
731 | #if HAVE_MESSAGES | 797 | #if HAVE_MESSAGES |
732 | MHD_DLOG (connection->daemon, "Not enough memory for write!\n"); | 798 | MHD_DLOG (connection->daemon, |
799 | "Not enough memory for write!\n"); | ||
733 | #endif | 800 | #endif |
734 | return MHD_NO; | 801 | return MHD_NO; |
735 | } | 802 | } |
@@ -834,8 +901,10 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) | |||
834 | while (1) | 901 | while (1) |
835 | { | 902 | { |
836 | #if DEBUG_STATES | 903 | #if DEBUG_STATES |
837 | MHD_DLOG (connection->daemon, "%s: state: %s\n", | 904 | MHD_DLOG (connection->daemon, |
838 | __FUNCTION__, MHD_state_to_string (connection->state)); | 905 | "%s: state: %s\n", |
906 | __FUNCTION__, | ||
907 | MHD_state_to_string (connection->state)); | ||
839 | #endif | 908 | #endif |
840 | switch (connection->state) | 909 | switch (connection->state) |
841 | { | 910 | { |
@@ -1194,15 +1263,16 @@ parse_cookie_header (struct MHD_Connection *connection) | |||
1194 | equals = sce + 1; | 1263 | equals = sce + 1; |
1195 | quotes = 0; | 1264 | quotes = 0; |
1196 | semicolon = equals; | 1265 | semicolon = equals; |
1197 | while ((semicolon[0] != '\0') && | 1266 | while ( ('\0' != semicolon[0]) && |
1198 | ((quotes != 0) || | 1267 | ( (0 != quotes) || |
1199 | ((semicolon[0] != ';') && (semicolon[0] != ',')))) | 1268 | ( (';' != semicolon[0]) && |
1269 | (',' != semicolon[0]) ) ) ) | ||
1200 | { | 1270 | { |
1201 | if (semicolon[0] == '"') | 1271 | if ('"' == semicolon[0]) |
1202 | quotes = (quotes + 1) & 1; | 1272 | quotes = (quotes + 1) & 1; |
1203 | semicolon++; | 1273 | semicolon++; |
1204 | } | 1274 | } |
1205 | if (semicolon[0] == '\0') | 1275 | if ('\0' == semicolon[0]) |
1206 | semicolon = NULL; | 1276 | semicolon = NULL; |
1207 | if (NULL != semicolon) | 1277 | if (NULL != semicolon) |
1208 | { | 1278 | { |
@@ -1210,7 +1280,8 @@ parse_cookie_header (struct MHD_Connection *connection) | |||
1210 | semicolon++; | 1280 | semicolon++; |
1211 | } | 1281 | } |
1212 | /* remove quotes */ | 1282 | /* remove quotes */ |
1213 | if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"')) | 1283 | if ( ('"' == equals[0]) && |
1284 | ('"' == equals[strlen (equals) - 1]) ) | ||
1214 | { | 1285 | { |
1215 | equals[strlen (equals) - 1] = '\0'; | 1286 | equals[strlen (equals) - 1] = '\0'; |
1216 | equals++; | 1287 | equals++; |
@@ -1232,7 +1303,8 @@ parse_cookie_header (struct MHD_Connection *connection) | |||
1232 | * @return #MHD_YES if the line is ok, #MHD_NO if it is malformed | 1303 | * @return #MHD_YES if the line is ok, #MHD_NO if it is malformed |
1233 | */ | 1304 | */ |
1234 | static int | 1305 | static int |
1235 | parse_initial_message_line (struct MHD_Connection *connection, char *line) | 1306 | parse_initial_message_line (struct MHD_Connection *connection, |
1307 | char *line) | ||
1236 | { | 1308 | { |
1237 | char *uri; | 1309 | char *uri; |
1238 | char *http_version; | 1310 | char *http_version; |
@@ -1243,7 +1315,7 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line) | |||
1243 | uri[0] = '\0'; | 1315 | uri[0] = '\0'; |
1244 | connection->method = line; | 1316 | connection->method = line; |
1245 | uri++; | 1317 | uri++; |
1246 | while (uri[0] == ' ') | 1318 | while (' ' == uri[0]) |
1247 | uri++; | 1319 | uri++; |
1248 | http_version = strchr (uri, ' '); | 1320 | http_version = strchr (uri, ' '); |
1249 | if (NULL != http_version) | 1321 | if (NULL != http_version) |
@@ -1292,9 +1364,9 @@ call_connection_handler (struct MHD_Connection *connection) | |||
1292 | processed = 0; | 1364 | processed = 0; |
1293 | connection->client_aware = MHD_YES; | 1365 | connection->client_aware = MHD_YES; |
1294 | if (MHD_NO == | 1366 | if (MHD_NO == |
1295 | connection->daemon->default_handler (connection->daemon-> | 1367 | connection->daemon->default_handler (connection->daemon-> default_handler_cls, |
1296 | default_handler_cls, | 1368 | connection, |
1297 | connection, connection->url, | 1369 | connection->url, |
1298 | connection->method, | 1370 | connection->method, |
1299 | connection->version, | 1371 | connection->version, |
1300 | NULL, &processed, | 1372 | NULL, &processed, |
@@ -1336,12 +1408,12 @@ process_request_body (struct MHD_Connection *connection) | |||
1336 | do | 1408 | do |
1337 | { | 1409 | { |
1338 | instant_retry = MHD_NO; | 1410 | instant_retry = MHD_NO; |
1339 | if ((connection->have_chunked_upload == MHD_YES) && | 1411 | if ( (MHD_YES == connection->have_chunked_upload) && |
1340 | (connection->remaining_upload_size == MHD_SIZE_UNKNOWN)) | 1412 | (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) ) |
1341 | { | 1413 | { |
1342 | if ((connection->current_chunk_offset == | 1414 | if ( (connection->current_chunk_offset == connection->current_chunk_size) && |
1343 | connection->current_chunk_size) | 1415 | (0 != connection->current_chunk_offset) && |
1344 | && (connection->current_chunk_offset != 0) && (available >= 2)) | 1416 | (available >= 2) ) |
1345 | { | 1417 | { |
1346 | /* skip new line at the *end* of a chunk */ | 1418 | /* skip new line at the *end* of a chunk */ |
1347 | i = 0; | 1419 | i = 0; |
@@ -1448,12 +1520,13 @@ process_request_body (struct MHD_Connection *connection) | |||
1448 | used = processed; | 1520 | used = processed; |
1449 | connection->client_aware = MHD_YES; | 1521 | connection->client_aware = MHD_YES; |
1450 | if (MHD_NO == | 1522 | if (MHD_NO == |
1451 | connection->daemon->default_handler (connection->daemon-> | 1523 | connection->daemon->default_handler (connection->daemon->default_handler_cls, |
1452 | default_handler_cls, | 1524 | connection, |
1453 | connection, connection->url, | 1525 | connection->url, |
1454 | connection->method, | 1526 | connection->method, |
1455 | connection->version, | 1527 | connection->version, |
1456 | buffer_head, &processed, | 1528 | buffer_head, |
1529 | &processed, | ||
1457 | &connection->client_context)) | 1530 | &connection->client_context)) |
1458 | { | 1531 | { |
1459 | /* serious internal error, close connection */ | 1532 | /* serious internal error, close connection */ |
@@ -1510,7 +1583,7 @@ do_read (struct MHD_Connection *connection) | |||
1510 | connection->read_buffer_offset); | 1583 | connection->read_buffer_offset); |
1511 | if (bytes_read < 0) | 1584 | if (bytes_read < 0) |
1512 | { | 1585 | { |
1513 | if ((EINTR == errno) || (EAGAIN == errno)) | 1586 | if ((EINTR == errno) || (EAGAIN == errno) || (ECONNRESET == errno)) |
1514 | return MHD_NO; | 1587 | return MHD_NO; |
1515 | #if HAVE_MESSAGES | 1588 | #if HAVE_MESSAGES |
1516 | #if HTTPS_SUPPORT | 1589 | #if HTTPS_SUPPORT |
@@ -1521,7 +1594,8 @@ do_read (struct MHD_Connection *connection) | |||
1521 | else | 1594 | else |
1522 | #endif | 1595 | #endif |
1523 | MHD_DLOG (connection->daemon, | 1596 | MHD_DLOG (connection->daemon, |
1524 | "Failed to receive data: %s\n", STRERROR (errno)); | 1597 | "Failed to receive data: %s\n", |
1598 | STRERROR (errno)); | ||
1525 | #endif | 1599 | #endif |
1526 | CONNECTION_CLOSE_ERROR (connection, NULL); | 1600 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1527 | return MHD_YES; | 1601 | return MHD_YES; |
@@ -1539,6 +1613,7 @@ do_read (struct MHD_Connection *connection) | |||
1539 | return MHD_YES; | 1613 | return MHD_YES; |
1540 | } | 1614 | } |
1541 | 1615 | ||
1616 | |||
1542 | /** | 1617 | /** |
1543 | * Try writing data to the socket from the | 1618 | * Try writing data to the socket from the |
1544 | * write buffer of the connection. | 1619 | * write buffer of the connection. |
@@ -1750,12 +1825,13 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1750 | char *end; | 1825 | char *end; |
1751 | 1826 | ||
1752 | parse_cookie_header (connection); | 1827 | parse_cookie_header (connection); |
1753 | if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) | 1828 | if ( (0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) && |
1754 | && (NULL != connection->version) | 1829 | (NULL != connection->version) && |
1755 | && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) | 1830 | (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) && |
1756 | && (NULL == | 1831 | (NULL == |
1757 | MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | 1832 | MHD_lookup_connection_value (connection, |
1758 | MHD_HTTP_HEADER_HOST))) | 1833 | MHD_HEADER_KIND, |
1834 | MHD_HTTP_HEADER_HOST)) ) | ||
1759 | { | 1835 | { |
1760 | /* die, http 1.1 request without host and we are pedantic */ | 1836 | /* die, http 1.1 request without host and we are pedantic */ |
1761 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 1837 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
@@ -1765,7 +1841,7 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1765 | "Received `%s' request without `%s' header.\n", | 1841 | "Received `%s' request without `%s' header.\n", |
1766 | MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); | 1842 | MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); |
1767 | #endif | 1843 | #endif |
1768 | EXTRA_CHECK (connection->response == NULL); | 1844 | EXTRA_CHECK (NULL == connection->response); |
1769 | response = | 1845 | response = |
1770 | MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST), | 1846 | MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST), |
1771 | REQUEST_LACKS_HOST, | 1847 | REQUEST_LACKS_HOST, |
@@ -1798,8 +1874,9 @@ parse_connection_headers (struct MHD_Connection *connection) | |||
1798 | { | 1874 | { |
1799 | #if HAVE_MESSAGES | 1875 | #if HAVE_MESSAGES |
1800 | MHD_DLOG (connection->daemon, | 1876 | MHD_DLOG (connection->daemon, |
1801 | "Failed to parse `%s' header `%s', closing connection.\n", | 1877 | "Failed to parse `%s' header `%s', closing connection.\n", |
1802 | MHD_HTTP_HEADER_CONTENT_LENGTH, clen); | 1878 | MHD_HTTP_HEADER_CONTENT_LENGTH, |
1879 | clen); | ||
1803 | #endif | 1880 | #endif |
1804 | CONNECTION_CLOSE_ERROR (connection, NULL); | 1881 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1805 | return; | 1882 | return; |
@@ -1868,7 +1945,8 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
1868 | { | 1945 | { |
1869 | #if DEBUG_STATES | 1946 | #if DEBUG_STATES |
1870 | MHD_DLOG (connection->daemon, "%s: state: %s\n", | 1947 | MHD_DLOG (connection->daemon, "%s: state: %s\n", |
1871 | __FUNCTION__, MHD_state_to_string (connection->state)); | 1948 | __FUNCTION__, |
1949 | MHD_state_to_string (connection->state)); | ||
1872 | #endif | 1950 | #endif |
1873 | switch (connection->state) | 1951 | switch (connection->state) |
1874 | { | 1952 | { |
@@ -1925,7 +2003,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1925 | { | 2003 | { |
1926 | #if DEBUG_STATES | 2004 | #if DEBUG_STATES |
1927 | MHD_DLOG (connection->daemon, "%s: state: %s\n", | 2005 | MHD_DLOG (connection->daemon, "%s: state: %s\n", |
1928 | __FUNCTION__, MHD_state_to_string (connection->state)); | 2006 | __FUNCTION__, |
2007 | MHD_state_to_string (connection->state)); | ||
1929 | #endif | 2008 | #endif |
1930 | switch (connection->state) | 2009 | switch (connection->state) |
1931 | { | 2010 | { |
@@ -1949,7 +2028,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1949 | break; | 2028 | break; |
1950 | #if HAVE_MESSAGES | 2029 | #if HAVE_MESSAGES |
1951 | MHD_DLOG (connection->daemon, | 2030 | MHD_DLOG (connection->daemon, |
1952 | "Failed to send data: %s\n", STRERROR (errno)); | 2031 | "Failed to send data: %s\n", |
2032 | STRERROR (errno)); | ||
1953 | #endif | 2033 | #endif |
1954 | CONNECTION_CLOSE_ERROR (connection, NULL); | 2034 | CONNECTION_CLOSE_ERROR (connection, NULL); |
1955 | return MHD_YES; | 2035 | return MHD_YES; |
@@ -1958,8 +2038,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1958 | FPRINTF (stderr, | 2038 | FPRINTF (stderr, |
1959 | "Sent 100 continue response: `%.*s'\n", | 2039 | "Sent 100 continue response: `%.*s'\n", |
1960 | ret, | 2040 | ret, |
1961 | &HTTP_100_CONTINUE | 2041 | &HTTP_100_CONTINUE[connection->continue_message_write_offset]); |
1962 | [connection->continue_message_write_offset]); | ||
1963 | #endif | 2042 | #endif |
1964 | connection->continue_message_write_offset += ret; | 2043 | connection->continue_message_write_offset += ret; |
1965 | break; | 2044 | break; |
@@ -2007,7 +2086,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2007 | return MHD_YES; | 2086 | return MHD_YES; |
2008 | #if HAVE_MESSAGES | 2087 | #if HAVE_MESSAGES |
2009 | MHD_DLOG (connection->daemon, | 2088 | MHD_DLOG (connection->daemon, |
2010 | "Failed to send data: %s\n", STRERROR (errno)); | 2089 | "Failed to send data: %s\n", |
2090 | STRERROR (errno)); | ||
2011 | #endif | 2091 | #endif |
2012 | CONNECTION_CLOSE_ERROR (connection, NULL); | 2092 | CONNECTION_CLOSE_ERROR (connection, NULL); |
2013 | return MHD_YES; | 2093 | return MHD_YES; |
@@ -2015,7 +2095,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2015 | connection->response_write_position += ret; | 2095 | connection->response_write_position += ret; |
2016 | if (connection->response_write_position == | 2096 | if (connection->response_write_position == |
2017 | connection->response->total_size) | 2097 | connection->response->total_size) |
2018 | connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */ | 2098 | connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */ |
2019 | break; | 2099 | break; |
2020 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: | 2100 | case MHD_CONNECTION_NORMAL_BODY_UNREADY: |
2021 | EXTRA_CHECK (0); | 2101 | EXTRA_CHECK (0); |
@@ -2050,7 +2130,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
2050 | break; | 2130 | break; |
2051 | default: | 2131 | default: |
2052 | EXTRA_CHECK (0); | 2132 | EXTRA_CHECK (0); |
2053 | CONNECTION_CLOSE_ERROR (connection, "Internal error\n"); | 2133 | CONNECTION_CLOSE_ERROR (connection, |
2134 | "Internal error\n"); | ||
2054 | return MHD_YES; | 2135 | return MHD_YES; |
2055 | } | 2136 | } |
2056 | break; | 2137 | break; |
@@ -2121,15 +2202,16 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2121 | struct MHD_Daemon *daemon = connection->daemon; | 2202 | struct MHD_Daemon *daemon = connection->daemon; |
2122 | unsigned int timeout; | 2203 | unsigned int timeout; |
2123 | const char *end; | 2204 | const char *end; |
2124 | int rend; | ||
2125 | char *line; | 2205 | char *line; |
2126 | 2206 | ||
2127 | connection->in_idle = MHD_YES; | 2207 | connection->in_idle = MHD_YES; |
2128 | while (1) | 2208 | while (1) |
2129 | { | 2209 | { |
2130 | #if DEBUG_STATES | 2210 | #if DEBUG_STATES |
2131 | MHD_DLOG (daemon, "%s: state: %s\n", | 2211 | MHD_DLOG (daemon, |
2132 | __FUNCTION__, MHD_state_to_string (connection->state)); | 2212 | "%s: state: %s\n", |
2213 | __FUNCTION__, | ||
2214 | MHD_state_to_string (connection->state)); | ||
2133 | #endif | 2215 | #endif |
2134 | switch (connection->state) | 2216 | switch (connection->state) |
2135 | { | 2217 | { |
@@ -2241,15 +2323,15 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2241 | } | 2323 | } |
2242 | break; | 2324 | break; |
2243 | case MHD_CONNECTION_CONTINUE_SENT: | 2325 | case MHD_CONNECTION_CONTINUE_SENT: |
2244 | if (connection->read_buffer_offset != 0) | 2326 | if (0 != connection->read_buffer_offset) |
2245 | { | 2327 | { |
2246 | process_request_body (connection); /* loop call */ | 2328 | process_request_body (connection); /* loop call */ |
2247 | if (MHD_CONNECTION_CLOSED == connection->state) | 2329 | if (MHD_CONNECTION_CLOSED == connection->state) |
2248 | continue; | 2330 | continue; |
2249 | } | 2331 | } |
2250 | if ((connection->remaining_upload_size == 0) || | 2332 | if ((0 == connection->remaining_upload_size) || |
2251 | ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) && | 2333 | ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) && |
2252 | (connection->read_buffer_offset == 0) && | 2334 | (0 == connection->read_buffer_offset) && |
2253 | (MHD_YES == connection->read_closed))) | 2335 | (MHD_YES == connection->read_closed))) |
2254 | { | 2336 | { |
2255 | if ((MHD_YES == connection->have_chunked_upload) && | 2337 | if ((MHD_YES == connection->have_chunked_upload) && |
@@ -2262,7 +2344,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2262 | break; | 2344 | break; |
2263 | case MHD_CONNECTION_BODY_RECEIVED: | 2345 | case MHD_CONNECTION_BODY_RECEIVED: |
2264 | line = get_next_header_line (connection); | 2346 | line = get_next_header_line (connection); |
2265 | if (line == NULL) | 2347 | if (NULL == line) |
2266 | { | 2348 | { |
2267 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) | 2349 | if (connection->state != MHD_CONNECTION_BODY_RECEIVED) |
2268 | continue; | 2350 | continue; |
@@ -2274,7 +2356,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2274 | } | 2356 | } |
2275 | break; | 2357 | break; |
2276 | } | 2358 | } |
2277 | if (strlen (line) == 0) | 2359 | if (0 == strlen (line)) |
2278 | { | 2360 | { |
2279 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 2361 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
2280 | continue; | 2362 | continue; |
@@ -2290,7 +2372,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2290 | continue; | 2372 | continue; |
2291 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: | 2373 | case MHD_CONNECTION_FOOTER_PART_RECEIVED: |
2292 | line = get_next_header_line (connection); | 2374 | line = get_next_header_line (connection); |
2293 | if (line == NULL) | 2375 | if (NULL == line) |
2294 | { | 2376 | { |
2295 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) | 2377 | if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) |
2296 | continue; | 2378 | continue; |
@@ -2305,7 +2387,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2305 | if (MHD_NO == | 2387 | if (MHD_NO == |
2306 | process_broken_line (connection, line, MHD_FOOTER_KIND)) | 2388 | process_broken_line (connection, line, MHD_FOOTER_KIND)) |
2307 | continue; | 2389 | continue; |
2308 | if (strlen (line) == 0) | 2390 | if (0 == strlen (line)) |
2309 | { | 2391 | { |
2310 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 2392 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
2311 | continue; | 2393 | continue; |
@@ -2315,7 +2397,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2315 | call_connection_handler (connection); /* "final" call */ | 2397 | call_connection_handler (connection); /* "final" call */ |
2316 | if (connection->state == MHD_CONNECTION_CLOSED) | 2398 | if (connection->state == MHD_CONNECTION_CLOSED) |
2317 | continue; | 2399 | continue; |
2318 | if (connection->response == NULL) | 2400 | if (NULL == connection->response) |
2319 | break; /* try again next time */ | 2401 | break; /* try again next time */ |
2320 | if (MHD_NO == build_header_response (connection)) | 2402 | if (MHD_NO == build_header_response (connection)) |
2321 | { | 2403 | { |
@@ -2412,44 +2494,29 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2412 | end = | 2494 | end = |
2413 | MHD_get_response_header (connection->response, | 2495 | MHD_get_response_header (connection->response, |
2414 | MHD_HTTP_HEADER_CONNECTION); | 2496 | MHD_HTTP_HEADER_CONNECTION); |
2415 | rend = ( (MHD_YES == connection->read_closed) || | ||
2416 | ( (end != NULL) && (0 == strcasecmp (end, "close")) ) ); | ||
2417 | MHD_destroy_response (connection->response); | 2497 | MHD_destroy_response (connection->response); |
2418 | connection->response = NULL; | 2498 | connection->response = NULL; |
2419 | if (daemon->notify_completed != NULL) | 2499 | if (NULL != daemon->notify_completed) |
2420 | daemon->notify_completed (daemon->notify_completed_cls, | 2500 | daemon->notify_completed (daemon->notify_completed_cls, |
2421 | connection, | 2501 | connection, |
2422 | &connection->client_context, | 2502 | &connection->client_context, |
2423 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 2503 | MHD_REQUEST_TERMINATED_COMPLETED_OK); |
2424 | connection->client_aware = MHD_NO; | ||
2425 | end = | 2504 | end = |
2426 | MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | 2505 | MHD_lookup_connection_value (connection, MHD_HEADER_KIND, |
2427 | MHD_HTTP_HEADER_CONNECTION); | 2506 | MHD_HTTP_HEADER_CONNECTION); |
2428 | connection->client_context = NULL; | 2507 | if ( (MHD_YES == connection->read_closed) || |
2429 | connection->continue_message_write_offset = 0; | 2508 | ((NULL != end) && (0 == strcasecmp (end, "close"))) ) |
2430 | connection->responseCode = 0; | ||
2431 | connection->headers_received = NULL; | ||
2432 | connection->headers_received_tail = NULL; | ||
2433 | connection->response_write_position = 0; | ||
2434 | connection->have_chunked_upload = MHD_NO; | ||
2435 | connection->method = NULL; | ||
2436 | connection->url = NULL; | ||
2437 | connection->write_buffer = NULL; | ||
2438 | connection->write_buffer_size = 0; | ||
2439 | connection->write_buffer_send_offset = 0; | ||
2440 | connection->write_buffer_append_offset = 0; | ||
2441 | if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) ) | ||
2442 | { | 2509 | { |
2443 | connection->read_closed = MHD_YES; | 2510 | connection->read_closed = MHD_YES; |
2444 | connection->read_buffer_offset = 0; | 2511 | connection->read_buffer_offset = 0; |
2445 | } | 2512 | } |
2446 | if (((MHD_YES == connection->read_closed) && | 2513 | if (((MHD_YES == connection->read_closed) && |
2447 | (0 == connection->read_buffer_offset)) || | 2514 | (0 == connection->read_buffer_offset)) || |
2448 | (connection->version == NULL) || | 2515 | (MHD_NO == keepalive_possible (connection))) |
2449 | (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) | ||
2450 | { | 2516 | { |
2451 | /* http 1.0, version-less requests cannot be pipelined */ | 2517 | /* have to close for some reason */ |
2452 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK); | 2518 | MHD_connection_close (connection, |
2519 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
2453 | MHD_pool_destroy (connection->pool); | 2520 | MHD_pool_destroy (connection->pool); |
2454 | connection->pool = NULL; | 2521 | connection->pool = NULL; |
2455 | connection->read_buffer = NULL; | 2522 | connection->read_buffer = NULL; |
@@ -2458,6 +2525,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2458 | } | 2525 | } |
2459 | else | 2526 | else |
2460 | { | 2527 | { |
2528 | /* can try to keep-alive */ | ||
2461 | connection->version = NULL; | 2529 | connection->version = NULL; |
2462 | connection->state = MHD_CONNECTION_INIT; | 2530 | connection->state = MHD_CONNECTION_INIT; |
2463 | connection->read_buffer | 2531 | connection->read_buffer |
@@ -2465,6 +2533,20 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2465 | connection->read_buffer, | 2533 | connection->read_buffer, |
2466 | connection->read_buffer_size); | 2534 | connection->read_buffer_size); |
2467 | } | 2535 | } |
2536 | connection->client_aware = MHD_NO; | ||
2537 | connection->client_context = NULL; | ||
2538 | connection->continue_message_write_offset = 0; | ||
2539 | connection->responseCode = 0; | ||
2540 | connection->headers_received = NULL; | ||
2541 | connection->headers_received_tail = NULL; | ||
2542 | connection->response_write_position = 0; | ||
2543 | connection->have_chunked_upload = MHD_NO; | ||
2544 | connection->method = NULL; | ||
2545 | connection->url = NULL; | ||
2546 | connection->write_buffer = NULL; | ||
2547 | connection->write_buffer_size = 0; | ||
2548 | connection->write_buffer_send_offset = 0; | ||
2549 | connection->write_buffer_append_offset = 0; | ||
2468 | continue; | 2550 | continue; |
2469 | case MHD_CONNECTION_CLOSED: | 2551 | case MHD_CONNECTION_CLOSED: |
2470 | cleanup_connection (connection); | 2552 | cleanup_connection (connection); |
@@ -2476,7 +2558,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2476 | break; | 2558 | break; |
2477 | } | 2559 | } |
2478 | timeout = connection->connection_timeout; | 2560 | timeout = connection->connection_timeout; |
2479 | if ( (timeout != 0) && | 2561 | if ( (0 != timeout) && |
2480 | (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) | 2562 | (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) |
2481 | { | 2563 | { |
2482 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | 2564 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |