libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 39eb60df61232bfc7da8e2f7afc48efcad0f1019
parent db2ab3a5aee00d9716523eb9b478b29dcb332f9a
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Sun,  1 Aug 2021 15:31:30 +0300

response header: more pre-processing, better docs

* Disallow "Transfer-encoding: identity", not allowed by RFC
* Allow only single "Date" header

Diffstat:
Msrc/include/microhttpd.h | 11+++++++++++
Msrc/microhttpd/internal.h | 9+++++----
Msrc/microhttpd/response.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/microhttpd/test_response_entries.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 170 insertions(+), 26 deletions(-)

diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -3648,6 +3648,7 @@ MHD_destroy_response (struct MHD_Response *response); * The list of automatic headers: * + "Date" header is added automatically unless already set by * this function + * @see #MHD_USE_SUPPRESS_DATE_NO_CLOCK * + "Content-Length" is added automatically when required, attempt to set * it manually by this function is ignored. * @see #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH @@ -3662,6 +3663,16 @@ MHD_destroy_response (struct MHD_Response *response); * to enforce closure of the connection after sending this response. * "Keep-Alive" cannot be enforced and will be removed automatically. * + * Some headers are pre-processed by this function: + * * "Connection" headers are combined into single header entry, value is + * normilised, "Keep-Alive" tokens are removed. + * * "Transfer-Encoding" header: the only one header is allowed, the only + * allowed value is "chunked". + * * "Date" header: the only one header is allowed, the second added header + * replaces the first one. + * * "Content-Length" manual header is now allowed. + * @see #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH + * * Headers are used in order as they were added. * * @param response the response to add a header to diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -356,10 +356,11 @@ struct MHD_HTTP_Header */ enum MHD_ResponseAutoFlags { - MHD_RAF_NO_FLAGS = 0, /**< No auto flags */ - MHD_RAF_HAS_CONNECTION_HDR = 1 << 0, /**< Has "Connection" header */ - MHD_RAF_HAS_CONNECTION_CLOSE = 1 << 1, /**< Has "Connection: close" */ - MHD_RAF_HAS_TRANS_ENC_CHUNKED = 2 << 2 /**< Has "Transfer-Encoding: chunked */ + MHD_RAF_NO_FLAGS = 0, /**< No auto flags */ + MHD_RAF_HAS_CONNECTION_HDR = 1 << 0, /**< Has "Connection" header */ + MHD_RAF_HAS_CONNECTION_CLOSE = 1 << 1, /**< Has "Connection: close" */ + MHD_RAF_HAS_TRANS_ENC_CHUNKED = 1 << 2, /**< Has "Transfer-Encoding: chunked */ + MHD_RAF_HAS_DATE_HDR = 1 << 3 /**< Has "Date" header */ } _MHD_FIXED_FLAGS_ENUM; diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c @@ -438,6 +438,7 @@ del_response_header_connection (struct MHD_Response *response, * The list of automatic headers: * + "Date" header is added automatically unless already set by * this function + * @see #MHD_USE_SUPPRESS_DATE_NO_CLOCK * + "Content-Length" is added automatically when required, attempt to set * it manually by this function is ignored. * @see #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH @@ -452,6 +453,16 @@ del_response_header_connection (struct MHD_Response *response, * to enforce closure of the connection after sending this response. * "Keep-Alive" cannot be enforced and will be removed automatically. * + * Some headers are pre-processed by this function: + * * "Connection" headers are combined into single header entry, value is + * normilised, "Keep-Alive" tokens are removed. + * * "Transfer-Encoding" header: the only one header is allowed, the only + * allowed value is "chunked". + * * "Date" header: the only one header is allowed, the second added header + * replaces the first one. + * * "Content-Length" manual header is now allowed. + * @see #MHD_RF_INSANITY_HEADER_CONTENT_LENGTH + * * Headers are used in order as they were added. * * @param response the response to add a header to @@ -473,30 +484,40 @@ MHD_add_response_header (struct MHD_Response *response, if (MHD_str_equal_caseless_ (header, MHD_HTTP_HEADER_TRANSFER_ENCODING)) { - /* TODO: remove support for "identity" */ - /* Only one "Transfer-Encoding" header is allowed */ - if (NULL != - MHD_get_response_header (response, MHD_HTTP_HEADER_TRANSFER_ENCODING) ) + if (! MHD_str_equal_caseless_ (content, "chunked")) return MHD_NO; - /* Setting transfer encodings other than "identity" or - "chunked" is not allowed. Note that MHD will set the - correct transfer encoding if required automatically. */ - /* NOTE: for compressed bodies, use the "Content-encoding" header */ - if (MHD_str_equal_caseless_ (content, "identity")) - return add_response_entry (response, - MHD_HEADER_KIND, - header, - content); - else if (MHD_str_equal_caseless_ (content, "chunked")) + if (0 != (response->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED)) + return MHD_YES; + if (MHD_NO != add_response_entry (response, + MHD_HEADER_KIND, + header, + content)) { - if (MHD_NO != add_response_entry (response, - MHD_HEADER_KIND, - header, - content)) - { - response->flags_auto |= MHD_RAF_HAS_TRANS_ENC_CHUNKED; - return MHD_YES; - } + response->flags_auto |= MHD_RAF_HAS_TRANS_ENC_CHUNKED; + return MHD_YES; + } + return MHD_NO; + } + if (MHD_str_equal_caseless_ (header, + MHD_HTTP_HEADER_DATE)) + { + if (0 != (response->flags_auto & MHD_RAF_HAS_DATE_HDR)) + { + struct MHD_HTTP_Header *hdr; + hdr = MHD_get_response_element_n_ (response, MHD_HEADER_KIND, + MHD_HTTP_HEADER_DATE, + MHD_STATICSTR_LEN_ ( \ + MHD_HTTP_HEADER_DATE)); + mhd_assert (NULL != hdr); + _MHD_remove_header (response, hdr); + } + if (MHD_NO != add_response_entry (response, + MHD_HEADER_KIND, + header, + content)) + { + response->flags_auto |= MHD_RAF_HAS_DATE_HDR; + return MHD_YES; } return MHD_NO; } @@ -590,6 +611,12 @@ MHD_del_response_header (struct MHD_Response *response, MHD_HTTP_HEADER_TRANSFER_ENCODING, header_len) ) response->flags_auto &= ~(MHD_RAF_HAS_TRANS_ENC_CHUNKED); + else if ( (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_DATE) == + header_len) && + MHD_str_equal_caseless_bin_n_ (header, + MHD_HTTP_HEADER_DATE, + header_len) ) + response->flags_auto &= ~(MHD_RAF_HAS_DATE_HDR); return MHD_YES; } pos = pos->next; diff --git a/src/microhttpd/test_response_entries.c b/src/microhttpd/test_response_entries.c @@ -775,6 +775,111 @@ main (int argc, return 4; } + if (MHD_YES != MHD_add_response_header (r, "Date", + "Wed, 01 Apr 2015 00:00:00 GMT")) + { + fprintf (stderr, + "Cannot add \"Date\" header with \"Wed, 01 Apr 2015 00:00:00 GMT\".\n"); + MHD_destroy_response (r); + return 5; + } + if (! expect_str (MHD_get_response_header (r, "Date"), + "Wed, 01 Apr 2015 00:00:00 GMT")) + { + MHD_destroy_response (r); + return 5; + } + if (MHD_YES != MHD_add_response_header (r, "Date", + "Thu, 01 Apr 2021 00:00:00 GMT")) + { + fprintf (stderr, + "Cannot add \"Date\" header with \"Thu, 01 Apr 2021 00:00:00 GMT\".\n"); + MHD_destroy_response (r); + return 5; + } + if (! expect_str (MHD_get_response_header (r, "Date"), + "Thu, 01 Apr 2021 00:00:00 GMT")) + { + MHD_destroy_response (r); + return 5; + } + if (MHD_YES != MHD_del_response_header (r, "Date", + "Thu, 01 Apr 2021 00:00:00 GMT")) + { + fprintf (stderr, "Cannot remove \"Date\" header.\n"); + MHD_destroy_response (r); + return 5; + } + if (! expect_str (MHD_get_response_header (r, "Date"), NULL)) + { + MHD_destroy_response (r); + return 5; + } + + if (MHD_YES != MHD_add_response_header (r, MHD_HTTP_HEADER_TRANSFER_ENCODING, + "chunked")) + { + fprintf (stderr, + "Cannot add \"" MHD_HTTP_HEADER_TRANSFER_ENCODING \ + "\" header with \"chunked\".\n"); + MHD_destroy_response (r); + return 6; + } + if (! expect_str (MHD_get_response_header (r, + MHD_HTTP_HEADER_TRANSFER_ENCODING), + "chunked")) + { + MHD_destroy_response (r); + return 6; + } + if (MHD_YES != MHD_add_response_header (r, MHD_HTTP_HEADER_TRANSFER_ENCODING, + "chunked")) + { + fprintf (stderr, + "Cannot add \"" MHD_HTTP_HEADER_TRANSFER_ENCODING \ + "\" second header with \"chunked\".\n"); + MHD_destroy_response (r); + return 6; + } + if (! expect_str (MHD_get_response_header (r, + MHD_HTTP_HEADER_TRANSFER_ENCODING), + "chunked")) + { + MHD_destroy_response (r); + return 6; + } + if (MHD_NO != MHD_add_response_header (r, MHD_HTTP_HEADER_TRANSFER_ENCODING, + "identity")) + { + fprintf (stderr, + "Successfully added \"" MHD_HTTP_HEADER_TRANSFER_ENCODING \ + "\" header with \"identity\".\n"); + MHD_destroy_response (r); + return 6; + } + if (! expect_str (MHD_get_response_header (r, + MHD_HTTP_HEADER_TRANSFER_ENCODING), + "chunked")) + { + MHD_destroy_response (r); + return 6; + } + if (MHD_YES != MHD_del_response_header (r, MHD_HTTP_HEADER_TRANSFER_ENCODING, + "chunked")) + { + fprintf (stderr, "Cannot remove \"" MHD_HTTP_HEADER_TRANSFER_ENCODING \ + "\" header.\n"); + MHD_destroy_response (r); + return 6; + } + if (! expect_str (MHD_get_response_header (r, + MHD_HTTP_HEADER_TRANSFER_ENCODING), + NULL)) + { + MHD_destroy_response (r); + return 6; + } + MHD_destroy_response (r); printf ("All tests has been successfully passed.\n"); return 0;