From 2b336e6b73c3da9a0cf645aada31853c80985963 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Jun 2026 10:59:05 +0200 Subject: [PATCH] content_encoding: fix non-last chunked rejection Even when two 'chunked' are listed and neither is the last encoding the transfer is rejected. Verified by test 1722 and 1723 Reported-by: violet12331 on hackerone Closes #21966 --- lib/content_encoding.c | 47 ++++++++++++++++---------------- tests/data/Makefile.am | 2 +- tests/data/test1722 | 61 ++++++++++++++++++++++++++++++++++++++++++ tests/data/test1723 | 61 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 tests/data/test1722 create mode 100644 tests/data/test1723 diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 73eb5201eb..fd08077259 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -789,17 +789,6 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, } cwt = find_unencode_writer(name, namelen, phase); - if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) { - /* A 'chunked' transfer encoding has already been added. - * 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." - */ - CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder"); - return CURLE_OK; - } - if(is_transfer && !is_chunked && Curl_cwriter_get_by_name(data, "chunked")) { /* RFC 9112, ch. 6.1: @@ -814,21 +803,31 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, "Transfer-Encoding"); return CURLE_BAD_CONTENT_ENCODING; } + if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) { + /* A 'chunked' transfer encoding has already been added. + * 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." + */ + CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder"); + } + else { + if(!cwt) + cwt = &error_writer; /* Defer error at use. */ - if(!cwt) - cwt = &error_writer; /* Defer error at use. */ + result = Curl_cwriter_create(&writer, data, cwt, phase); + CURL_TRC_WRITE(data, "added %s decoder %s -> %d", + is_transfer ? "transfer" : "content", cwt->name, + (int)result); + if(result) + return result; - result = Curl_cwriter_create(&writer, data, cwt, phase); - CURL_TRC_WRITE(data, "added %s decoder %s -> %d", - is_transfer ? "transfer" : "content", cwt->name, - (int)result); - if(result) - return result; - - result = Curl_cwriter_add(data, writer); - if(result) { - Curl_cwriter_free(data, writer); - return result; + result = Curl_cwriter_add(data, writer); + if(result) { + Curl_cwriter_free(data, writer); + return result; + } } if(is_chunked) has_chunked = TRUE; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 50a5e5629e..5e5395b126 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -225,7 +225,7 @@ test1685 test1686 \ \ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ test1708 test1709 test1710 test1711 test1712 test1713 test1714 test1715 \ -test1720 test1721 \ +test1720 test1721 test1722 test1723 \ \ test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1851 \ \ diff --git a/tests/data/test1722 b/tests/data/test1722 new file mode 100644 index 0000000000..e51f26f4b4 --- /dev/null +++ b/tests/data/test1722 @@ -0,0 +1,61 @@ + + + + +HTTP +HTTP GET +chunked Transfer-Encoding + + +# Server-side + + +HTTP/1.1 200 funky chunky! +Server: fakeit/0.9 fakeitbad/1.0 +Transfer-Encoding: chunked, another +Connection: mooo + +40%CR +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%CR +30%CR +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb%CR +21;heresatest=moooo%CR +cccccccccccccccccccccccccccccccc +%CR +0%CR +%CR + + +HTTP/1.1 200 funky chunky! +Server: fakeit/0.9 fakeitbad/1.0 + + + +# Client-side + + +http + + +HTTP with chunked Transfer-Encoding not listed last + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +61 + + + + diff --git a/tests/data/test1723 b/tests/data/test1723 new file mode 100644 index 0000000000..ad93c30168 --- /dev/null +++ b/tests/data/test1723 @@ -0,0 +1,61 @@ + + + + +HTTP +HTTP GET +chunked Transfer-Encoding + + +# Server-side + + +HTTP/1.1 200 funky chunky! +Server: fakeit/0.9 fakeitbad/1.0 +Transfer-Encoding: chunked, chunked, another +Connection: mooo + +40%CR +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%CR +30%CR +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb%CR +21;heresatest=moooo%CR +cccccccccccccccccccccccccccccccc +%CR +0%CR +%CR + + +HTTP/1.1 200 funky chunky! +Server: fakeit/0.9 fakeitbad/1.0 + + + +# Client-side + + +http + + +HTTP with two chunked Transfer-Encoding not listed last + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +61 + + + +