diff options
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r-- | src/microhttpd/connection.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 1778c59b..60dc5eb4 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -1404,6 +1404,7 @@ try_grow_read_buffer (struct MHD_Connection *connection) | |||
1404 | static int | 1404 | static int |
1405 | build_header_response (struct MHD_Connection *connection) | 1405 | build_header_response (struct MHD_Connection *connection) |
1406 | { | 1406 | { |
1407 | struct MHD_Response *response = connection->response; | ||
1407 | size_t size; | 1408 | size_t size; |
1408 | size_t off; | 1409 | size_t off; |
1409 | struct MHD_HTTP_Header *pos; | 1410 | struct MHD_HTTP_Header *pos; |
@@ -1420,11 +1421,11 @@ build_header_response (struct MHD_Connection *connection) | |||
1420 | bool response_has_close; | 1421 | bool response_has_close; |
1421 | bool response_has_keepalive; | 1422 | bool response_has_keepalive; |
1422 | const char *have_encoding; | 1423 | const char *have_encoding; |
1423 | const char *have_content_length; | ||
1424 | int must_add_close; | 1424 | int must_add_close; |
1425 | int must_add_chunked_encoding; | 1425 | int must_add_chunked_encoding; |
1426 | int must_add_keep_alive; | 1426 | int must_add_keep_alive; |
1427 | int must_add_content_length; | 1427 | int must_add_content_length; |
1428 | int may_add_content_length; | ||
1428 | 1429 | ||
1429 | mhd_assert (NULL != connection->version); | 1430 | mhd_assert (NULL != connection->version); |
1430 | if (0 == connection->version[0]) | 1431 | if (0 == connection->version[0]) |
@@ -1458,7 +1459,7 @@ build_header_response (struct MHD_Connection *connection) | |||
1458 | size = off + 2; /* +2 for extra "\r\n" at the end */ | 1459 | size = off + 2; /* +2 for extra "\r\n" at the end */ |
1459 | kind = MHD_HEADER_KIND; | 1460 | kind = MHD_HEADER_KIND; |
1460 | if ( (0 == (connection->daemon->options & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && | 1461 | if ( (0 == (connection->daemon->options & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && |
1461 | (NULL == MHD_get_response_header (connection->response, | 1462 | (NULL == MHD_get_response_header (response, |
1462 | MHD_HTTP_HEADER_DATE)) ) | 1463 | MHD_HTTP_HEADER_DATE)) ) |
1463 | get_date_string (date, | 1464 | get_date_string (date, |
1464 | sizeof (date)); | 1465 | sizeof (date)); |
@@ -1486,30 +1487,35 @@ build_header_response (struct MHD_Connection *connection) | |||
1486 | switch (connection->state) | 1487 | switch (connection->state) |
1487 | { | 1488 | { |
1488 | case MHD_CONNECTION_FOOTERS_RECEIVED: | 1489 | case MHD_CONNECTION_FOOTERS_RECEIVED: |
1489 | response_has_close = MHD_check_response_header_s_token_ci (connection->response, | 1490 | response_has_close = MHD_check_response_header_s_token_ci (response, |
1490 | MHD_HTTP_HEADER_CONNECTION, | 1491 | MHD_HTTP_HEADER_CONNECTION, |
1491 | "close"); | 1492 | "close"); |
1492 | response_has_keepalive = MHD_check_response_header_s_token_ci (connection->response, | 1493 | response_has_keepalive = MHD_check_response_header_s_token_ci (response, |
1493 | MHD_HTTP_HEADER_CONNECTION, | 1494 | MHD_HTTP_HEADER_CONNECTION, |
1494 | "Keep-Alive"); | 1495 | "Keep-Alive"); |
1495 | client_requested_close = MHD_lookup_header_s_token_ci (connection, | 1496 | client_requested_close = MHD_lookup_header_s_token_ci (connection, |
1496 | MHD_HTTP_HEADER_CONNECTION, | 1497 | MHD_HTTP_HEADER_CONNECTION, |
1497 | "close"); | 1498 | "close"); |
1498 | 1499 | ||
1499 | if (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) | 1500 | if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) |
1500 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1501 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1501 | #ifdef UPGRADE_SUPPORT | 1502 | #ifdef UPGRADE_SUPPORT |
1502 | else if (NULL != connection->response->upgrade_handler) | 1503 | else if (NULL != response->upgrade_handler) |
1503 | /* If this connection will not be "upgraded", it must be closed. */ | 1504 | /* If this connection will not be "upgraded", it must be closed. */ |
1504 | connection->keepalive = MHD_CONN_MUST_CLOSE; | 1505 | connection->keepalive = MHD_CONN_MUST_CLOSE; |
1505 | #endif /* UPGRADE_SUPPORT */ | 1506 | #endif /* UPGRADE_SUPPORT */ |
1506 | 1507 | ||
1507 | /* now analyze chunked encoding situation */ | 1508 | /* now analyze chunked encoding situation */ |
1508 | connection->have_chunked_upload = false; | 1509 | connection->have_chunked_upload = false; |
1509 | 1510 | have_encoding = MHD_get_response_header (response, | |
1510 | if ( (MHD_SIZE_UNKNOWN == connection->response->total_size) && | 1511 | MHD_HTTP_HEADER_TRANSFER_ENCODING); |
1512 | if (NULL == have_encoding) | ||
1513 | may_add_content_length = MHD_YES; | ||
1514 | else | ||
1515 | may_add_content_length = MHD_NO; /* RFC 7230, Section 3.3.2 forbids header */ | ||
1516 | if ( (MHD_SIZE_UNKNOWN == response->total_size) && | ||
1511 | #ifdef UPGRADE_SUPPORT | 1517 | #ifdef UPGRADE_SUPPORT |
1512 | (NULL == connection->response->upgrade_handler) && | 1518 | (NULL == response->upgrade_handler) && |
1513 | #endif /* UPGRADE_SUPPORT */ | 1519 | #endif /* UPGRADE_SUPPORT */ |
1514 | (! response_has_close) && | 1520 | (! response_has_close) && |
1515 | (! client_requested_close) ) | 1521 | (! client_requested_close) ) |
@@ -1523,22 +1529,23 @@ build_header_response (struct MHD_Connection *connection) | |||
1523 | (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, | 1529 | (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, |
1524 | connection->version) ) ) | 1530 | connection->version) ) ) |
1525 | { | 1531 | { |
1526 | have_encoding = MHD_get_response_header (connection->response, | ||
1527 | MHD_HTTP_HEADER_TRANSFER_ENCODING); | ||
1528 | if (NULL == have_encoding) | 1532 | if (NULL == have_encoding) |
1529 | { | 1533 | { |
1530 | must_add_chunked_encoding = MHD_YES; | 1534 | must_add_chunked_encoding = MHD_YES; |
1531 | connection->have_chunked_upload = true; | 1535 | connection->have_chunked_upload = true; |
1532 | } | 1536 | } |
1533 | else if (MHD_str_equal_caseless_ (have_encoding, | ||
1534 | "identity")) | ||
1535 | { | ||
1536 | /* application forced identity encoding, can't do 'chunked' */ | ||
1537 | must_add_close = MHD_YES; | ||
1538 | } | ||
1539 | else | 1537 | else |
1540 | { | 1538 | { |
1541 | connection->have_chunked_upload = true; | 1539 | if (MHD_str_equal_caseless_ (have_encoding, |
1540 | "identity")) | ||
1541 | { | ||
1542 | /* application forced identity encoding, can't do 'chunked' */ | ||
1543 | must_add_close = MHD_YES; | ||
1544 | } | ||
1545 | else | ||
1546 | { | ||
1547 | connection->have_chunked_upload = true; | ||
1548 | } | ||
1542 | } | 1549 | } |
1543 | } | 1550 | } |
1544 | else | 1551 | else |
@@ -1556,23 +1563,29 @@ build_header_response (struct MHD_Connection *connection) | |||
1556 | (MHD_CONN_MUST_CLOSE == connection->keepalive)) && | 1563 | (MHD_CONN_MUST_CLOSE == connection->keepalive)) && |
1557 | (! response_has_close) && | 1564 | (! response_has_close) && |
1558 | #ifdef UPGRADE_SUPPORT | 1565 | #ifdef UPGRADE_SUPPORT |
1559 | (NULL == connection->response->upgrade_handler) && | 1566 | (NULL == response->upgrade_handler) && |
1560 | #endif /* UPGRADE_SUPPORT */ | 1567 | #endif /* UPGRADE_SUPPORT */ |
1561 | (0 == (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) | 1568 | (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) |
1562 | must_add_close = MHD_YES; | 1569 | must_add_close = MHD_YES; |
1563 | 1570 | ||
1564 | /* check if we should add a 'content length' header */ | 1571 | /* check if we must add 'close' header because we cannot add content-length |
1565 | have_content_length = MHD_get_response_header (connection->response, | 1572 | because it is forbidden AND we don't have a 'chunked' encoding */ |
1566 | MHD_HTTP_HEADER_CONTENT_LENGTH); | 1573 | if ( (! may_add_content_length) && |
1567 | 1574 | (! connection->have_chunked_upload) && | |
1568 | /* MHD_HTTP_NO_CONTENT, MHD_HTTP_NOT_MODIFIED and 1xx-status | 1575 | (! response_has_close) ) |
1576 | must_add_close = MHD_YES; | ||
1577 | /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status | ||
1569 | codes SHOULD NOT have a Content-Length according to spec; | 1578 | codes SHOULD NOT have a Content-Length according to spec; |
1570 | also chunked encoding / unknown length or CONNECT... */ | 1579 | also chunked encoding / unknown length or CONNECT... */ |
1571 | if ( (MHD_SIZE_UNKNOWN != connection->response->total_size) && | 1580 | if ( (MHD_SIZE_UNKNOWN != response->total_size) && |
1572 | (MHD_HTTP_NO_CONTENT != rc) && | 1581 | (MHD_HTTP_NO_CONTENT != rc) && |
1573 | (MHD_HTTP_NOT_MODIFIED != rc) && | 1582 | (MHD_HTTP_NOT_MODIFIED != rc) && |
1574 | (MHD_HTTP_OK <= rc) && | 1583 | (MHD_HTTP_OK <= rc) && |
1575 | (NULL == have_content_length) && | 1584 | (NULL == /* this should always succeed due to check in |
1585 | MHD_add_response_header() */ | ||
1586 | MHD_get_response_header (response, | ||
1587 | MHD_HTTP_HEADER_CONTENT_LENGTH)) && | ||
1588 | (may_add_content_length) && | ||
1576 | ( (NULL == connection->method) || | 1589 | ( (NULL == connection->method) || |
1577 | (! MHD_str_equal_caseless_ (connection->method, | 1590 | (! MHD_str_equal_caseless_ (connection->method, |
1578 | MHD_HTTP_METHOD_CONNECT)) ) ) | 1591 | MHD_HTTP_METHOD_CONNECT)) ) ) |
@@ -1596,7 +1609,7 @@ build_header_response (struct MHD_Connection *connection) | |||
1596 | = MHD_snprintf_ (content_length_buf, | 1609 | = MHD_snprintf_ (content_length_buf, |
1597 | sizeof (content_length_buf), | 1610 | sizeof (content_length_buf), |
1598 | MHD_HTTP_HEADER_CONTENT_LENGTH ": " MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", | 1611 | MHD_HTTP_HEADER_CONTENT_LENGTH ": " MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", |
1599 | (MHD_UNSIGNED_LONG_LONG) connection->response->total_size); | 1612 | (MHD_UNSIGNED_LONG_LONG) response->total_size); |
1600 | must_add_content_length = MHD_YES; | 1613 | must_add_content_length = MHD_YES; |
1601 | } | 1614 | } |
1602 | 1615 | ||
@@ -1606,7 +1619,7 @@ build_header_response (struct MHD_Connection *connection) | |||
1606 | (MHD_NO == must_add_close) && | 1619 | (MHD_NO == must_add_close) && |
1607 | (MHD_CONN_MUST_CLOSE != connection->keepalive) && | 1620 | (MHD_CONN_MUST_CLOSE != connection->keepalive) && |
1608 | #ifdef UPGRADE_SUPPORT | 1621 | #ifdef UPGRADE_SUPPORT |
1609 | (NULL == connection->response->upgrade_handler) && | 1622 | (NULL == response->upgrade_handler) && |
1610 | #endif /* UPGRADE_SUPPORT */ | 1623 | #endif /* UPGRADE_SUPPORT */ |
1611 | (MHD_YES == keepalive_possible (connection)) ) | 1624 | (MHD_YES == keepalive_possible (connection)) ) |
1612 | must_add_keep_alive = MHD_YES; | 1625 | must_add_keep_alive = MHD_YES; |
@@ -1638,7 +1651,7 @@ build_header_response (struct MHD_Connection *connection) | |||
1638 | mhd_assert (! (must_add_close && must_add_keep_alive) ); | 1651 | mhd_assert (! (must_add_close && must_add_keep_alive) ); |
1639 | mhd_assert (! (must_add_chunked_encoding && must_add_content_length) ); | 1652 | mhd_assert (! (must_add_chunked_encoding && must_add_content_length) ); |
1640 | 1653 | ||
1641 | for (pos = connection->response->first_header; NULL != pos; pos = pos->next) | 1654 | for (pos = response->first_header; NULL != pos; pos = pos->next) |
1642 | { | 1655 | { |
1643 | /* TODO: add proper support for excluding "Keep-Alive" token. */ | 1656 | /* TODO: add proper support for excluding "Keep-Alive" token. */ |
1644 | if ( (pos->kind == kind) && | 1657 | if ( (pos->kind == kind) && |
@@ -1700,7 +1713,7 @@ build_header_response (struct MHD_Connection *connection) | |||
1700 | content_length_len); | 1713 | content_length_len); |
1701 | off += content_length_len; | 1714 | off += content_length_len; |
1702 | } | 1715 | } |
1703 | for (pos = connection->response->first_header; NULL != pos; pos = pos->next) | 1716 | for (pos = response->first_header; NULL != pos; pos = pos->next) |
1704 | { | 1717 | { |
1705 | /* TODO: add proper support for excluding "Keep-Alive" token. */ | 1718 | /* TODO: add proper support for excluding "Keep-Alive" token. */ |
1706 | if ( (pos->kind == kind) && | 1719 | if ( (pos->kind == kind) && |