From 1d7b86e72b5b7ceb9d6ae7c9b965ab61af5c7599 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 21 May 2024 11:38:47 +0200 Subject: [PATCH] content_encoding: reject transfer-encoding after chunked reject a response that applies a transfer-encoding after a 'chunked' encoding. RFC 9112 ch. 6.1 required chunked to be the final encoding. Closes #13733 --- lib/content_encoding.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 13b21dfa50..d34d3a1f5e 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -978,6 +978,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, do { const char *name; size_t namelen; + bool is_chunked = FALSE; /* Parse a single encoding name. */ while(ISBLANK(*enclist) || *enclist == ',') @@ -993,10 +994,11 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const struct Curl_cwtype *cwt; struct Curl_cwriter *writer; + is_chunked = (is_transfer && (namelen == 7) && + strncasecompare(name, "chunked", 7)); /* if we skip the decoding in this phase, do not look further. * Exception is "chunked" transfer-encoding which always must happen */ - if((is_transfer && !data->set.http_transfer_encoding && - (namelen != 7 || !strncasecompare(name, "chunked", 7))) || + if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) || (!is_transfer && data->set.http_ce_skip)) { /* not requested, ignore */ return CURLE_OK; @@ -1009,13 +1011,31 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, } cwt = find_unencode_writer(name, namelen, phase); - if(is_transfer && cwt && strncasecompare(name, "chunked", 7) && - Curl_cwriter_get_by_type(data, cwt)) { + if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) { /* A 'chunked' transfer encoding has already been added. - * Ignore duplicates. See #13451. */ + * Ignore duplicates. See #13451. + * Also RFC 9112, ch. 6.1: + * "A sender MUST NOT apply the chunked transfer coding more than + * once to a message body." + */ return CURLE_OK; } + if(is_transfer && !is_chunked && + Curl_cwriter_get_by_name(data, "chunked")) { + /* RFC 9112, ch. 6.1: + * "If any transfer coding other than chunked is applied to a + * response's content, the sender MUST either apply chunked as the + * final transfer coding or terminate the message by closing the + * connection." + * "chunked" must be the last added to be the first in its phase, + * reject this. + */ + failf(data, "Reject response due to 'chunked' not being the last " + "Transfer-Encoding"); + return CURLE_BAD_CONTENT_ENCODING; + } + if(!cwt) cwt = &error_writer; /* Defer error at use. */