aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r--src/microhttpd/connection.c79
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)
1404static int 1404static int
1405build_header_response (struct MHD_Connection *connection) 1405build_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) &&