aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-10-05 19:23:26 +0200
committerChristian Grothoff <christian@grothoff.org>2018-10-05 19:23:26 +0200
commit0db81a9248b12abc74f153ebd642441d0f9c3e58 (patch)
tree01406d248d24a802445824ffda019200ce203ab2
parentbc8e12c8379d7bf1d99bf67260bcefadd77852a8 (diff)
downloadlibmicrohttpd-0db81a9248b12abc74f153ebd642441d0f9c3e58.tar.gz
libmicrohttpd-0db81a9248b12abc74f153ebd642441d0f9c3e58.zip
fix #5411
-rw-r--r--ChangeLog10
-rw-r--r--doc/libmicrohttpd.texi15
-rw-r--r--src/microhttpd/connection.c79
-rw-r--r--src/microhttpd/response.c21
4 files changed, 90 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index 068780e3..eb273daf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
1Fri Oct 5 18:44:45 CEST 2018
2 MHD_add_response_header() now prevents applications from
3 setting a "Transfer-Encoding" header to values other than
4 "identity" or "chunked" as other transfer encodings are
5 not supported by MHD. (Note that usually MHD will pick the
6 transfer encoding correctly automatically, but applications
7 can use the header to force a particular behavior.)
8 Fixing #5411 (never set Content-length if Transfer-Encoding
9 is given). -CG
10
1Sat Jul 14 11:42:15 CEST 2018 11Sat Jul 14 11:42:15 CEST 2018
2 Add MHD_OPTION_GNUTLS_PSK_CRED_HANDLER to allow use of PSK with 12 Add MHD_OPTION_GNUTLS_PSK_CRED_HANDLER to allow use of PSK with
3 TLS connections. -CG/TM 13 TLS connections. -CG/TM
diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi
index d2886a25..b61c94ff 100644
--- a/doc/libmicrohttpd.texi
+++ b/doc/libmicrohttpd.texi
@@ -874,9 +874,9 @@ or higher.
874@cindex TLS 874@cindex TLS
875@cindex PSK 875@cindex PSK
876Use pre-shared key for TLS credentials. 876Use pre-shared key for TLS credentials.
877Pass a pointer to callback of type 877Pass a pointer to callback of type
878@code{MHD_PskServerCredentialsCallback} and a closure. 878@code{MHD_PskServerCredentialsCallback} and a closure.
879The function will be called to 879The function will be called to
880retrieve the shared key for a given username. 880retrieve the shared key for a given username.
881 881
882@item MHD_OPTION_DIGEST_AUTH_RANDOM 882@item MHD_OPTION_DIGEST_AUTH_RANDOM
@@ -2050,6 +2050,17 @@ duplicated into memory blocks embedded in @var{response}.
2050Notice that the strings must not hold newlines, carriage returns or tab 2050Notice that the strings must not hold newlines, carriage returns or tab
2051chars. 2051chars.
2052 2052
2053MHD_add_response_header() prevents applications from setting a
2054``Transfer-Encoding'' header to values other than ``identity'' or
2055``chunked'' as other transfer encodings are not supported by MHD. Note
2056that usually MHD will pick the transfer encoding correctly
2057automatically, but applications can use the header to force a
2058particular behavior.
2059
2060MHD_add_response_header() also prevents applications from setting a
2061``Content-Length'' header. MHD will automatically set a correct
2062``Content-Length'' header if it is possible and allowed.
2063
2053Return @code{MHD_NO} on error (i.e. invalid header or content format or 2064Return @code{MHD_NO} on error (i.e. invalid header or content format or
2054memory allocation error). 2065memory allocation error).
2055@end deftypefun 2066@end deftypefun
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) &&
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index 9de4843d..d7835c20 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -119,6 +119,27 @@ MHD_add_response_header (struct MHD_Response *response,
119 const char *header, 119 const char *header,
120 const char *content) 120 const char *content)
121{ 121{
122 if ( (MHD_str_equal_caseless_ (header,
123 MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
124 (! MHD_str_equal_caseless_ (content,
125 "identity")) &&
126 (! MHD_str_equal_caseless_ (content,
127 "chunked")) )
128 {
129 /* Setting transfer encodings other than "identity" or
130 "chunked" is not allowed. Note that MHD will set the
131 correct transfer encoding if required automatically. */
132 /* NOTE: for compressed bodies, use the "Content-encoding" header */
133 return MHD_NO;
134 }
135 if (MHD_str_equal_caseless_ (header,
136 MHD_HTTP_HEADER_CONTENT_LENGTH))
137 {
138 /* MHD will set Content-length if allowed and possible,
139 reject attempt by application */
140 return MHD_NO;
141 }
142
122 return add_response_entry (response, 143 return add_response_entry (response,
123 MHD_HEADER_KIND, 144 MHD_HEADER_KIND,
124 header, 145 header,