summaryrefslogtreecommitdiffstats
path: root/lib/content_encoding.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/content_encoding.c')
-rw-r--r--lib/content_encoding.c41
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. */