diff options
Diffstat (limited to 'lib/content_encoding.c')
-rw-r--r-- | lib/content_encoding.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/lib/content_encoding.c b/lib/content_encoding.c index c1abf24..d34d3a1 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data, struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ - if(!(type & CLIENTWRITE_BODY)) + if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); /* Set the compressed input when this function is called */ @@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data, struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ - if(!(type & CLIENTWRITE_BODY)) + if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); if(zp->zlib_init == ZLIB_INIT_GZIP) { @@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data, CURLcode result = CURLE_OK; BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; - if(!(type & CLIENTWRITE_BODY)) + if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); if(!bp->br) @@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data, ZSTD_outBuffer out; size_t errorCode; - if(!(type & CLIENTWRITE_BODY)) + if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); if(!zp->decomp) { @@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data, (void) buf; (void) nbytes; - if(!(type & CLIENTWRITE_BODY)) + if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); failf(data, "Unrecognized content encoding type. " @@ -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,6 +1011,31 @@ 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." + */ + 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. */ |