diff options
Diffstat (limited to 'Utilities/cmcurl/lib/content_encoding.c')
-rw-r--r-- | Utilities/cmcurl/lib/content_encoding.c | 281 |
1 files changed, 134 insertions, 147 deletions
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c index ec4750e..082e0fa 100644 --- a/Utilities/cmcurl/lib/content_encoding.c +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -63,6 +63,9 @@ #ifndef CURL_DISABLE_HTTP +/* allow no more than 5 "chained" compression steps */ +#define MAX_ENCODE_STACK 5 + #define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */ @@ -95,7 +98,7 @@ typedef enum { /* Deflate and gzip writer. */ struct zlib_writer { - struct contenc_writer super; + struct Curl_cwriter super; zlibInitState zlib_init; /* zlib init state */ uInt trailerlen; /* Remaining trailer byte count. */ z_stream z; /* State structure for zlib. */ @@ -171,7 +174,7 @@ static CURLcode process_trailer(struct Curl_easy *data, } static CURLcode inflate_stream(struct Curl_easy *data, - struct contenc_writer *writer, + struct Curl_cwriter *writer, int type, zlibInitState started) { struct zlib_writer *zp = (struct zlib_writer *) writer; @@ -196,7 +199,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); /* because the buffer size is fixed, iteratively decompress and transfer to - the client via downstream_write function. */ + the client via next_write function. */ while(!done) { int status; /* zlib status */ done = TRUE; @@ -217,7 +220,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, if(z->avail_out != DSIZ) { if(status == Z_OK || status == Z_STREAM_END) { zp->zlib_init = started; /* Data started. */ - result = Curl_unencode_write(data, writer->downstream, decomp, + result = Curl_cwriter_write(data, writer->next, type, decomp, DSIZ - z->avail_out); if(result) { exit_zlib(data, z, &zp->zlib_init, result); @@ -274,8 +277,8 @@ static CURLcode inflate_stream(struct Curl_easy *data, /* Deflate handler. */ -static CURLcode deflate_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static CURLcode deflate_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ @@ -290,13 +293,16 @@ static CURLcode deflate_init_writer(struct Curl_easy *data, return CURLE_OK; } -static CURLcode deflate_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, +static CURLcode deflate_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + /* Set the compressed input when this function is called */ z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; @@ -305,11 +311,11 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data, return process_trailer(data, zp); /* Now uncompress the data */ - return inflate_stream(data, writer, ZLIB_INFLATING); + return inflate_stream(data, writer, type, ZLIB_INFLATING); } -static void deflate_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static void deflate_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ @@ -317,19 +323,19 @@ static void deflate_close_writer(struct Curl_easy *data, exit_zlib(data, z, &zp->zlib_init, CURLE_OK); } -static const struct content_encoding deflate_encoding = { +static const struct Curl_cwtype deflate_encoding = { "deflate", NULL, - deflate_init_writer, - deflate_unencode_write, - deflate_close_writer, + deflate_do_init, + deflate_do_write, + deflate_do_close, sizeof(struct zlib_writer) }; /* Gzip handler. */ -static CURLcode gzip_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static CURLcode gzip_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ @@ -441,19 +447,22 @@ static enum { } #endif -static CURLcode gzip_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, +static CURLcode gzip_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + if(zp->zlib_init == ZLIB_INIT_GZIP) { /* Let zlib handle the gzip decompression entirely */ z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; /* Now uncompress the data */ - return inflate_stream(data, writer, ZLIB_INIT_GZIP); + return inflate_stream(data, writer, type, ZLIB_INIT_GZIP); } #ifndef OLD_ZLIB_SUPPORT @@ -565,12 +574,12 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data, } /* We've parsed the header, now uncompress the data */ - return inflate_stream(data, writer, ZLIB_GZIP_INFLATING); + return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING); #endif } -static void gzip_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static void gzip_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ @@ -578,12 +587,12 @@ static void gzip_close_writer(struct Curl_easy *data, exit_zlib(data, z, &zp->zlib_init, CURLE_OK); } -static const struct content_encoding gzip_encoding = { +static const struct Curl_cwtype gzip_encoding = { "gzip", "x-gzip", - gzip_init_writer, - gzip_unencode_write, - gzip_close_writer, + gzip_do_init, + gzip_do_write, + gzip_do_close, sizeof(struct zlib_writer) }; @@ -593,7 +602,7 @@ static const struct content_encoding gzip_encoding = { #ifdef HAVE_BROTLI /* Brotli writer. */ struct brotli_writer { - struct contenc_writer super; + struct Curl_cwriter super; BrotliDecoderState *br; /* State structure for brotli. */ }; @@ -635,8 +644,8 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be) return CURLE_WRITE_ERROR; } -static CURLcode brotli_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static CURLcode brotli_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct brotli_writer *bp = (struct brotli_writer *) writer; (void) data; @@ -645,8 +654,8 @@ static CURLcode brotli_init_writer(struct Curl_easy *data, return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY; } -static CURLcode brotli_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, +static CURLcode brotli_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { struct brotli_writer *bp = (struct brotli_writer *) writer; @@ -657,6 +666,9 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, CURLcode result = CURLE_OK; BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + if(!bp->br) return CURLE_WRITE_ERROR; /* Stream already ended. */ @@ -670,7 +682,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, dstleft = DSIZ; r = BrotliDecoderDecompressStream(bp->br, &nbytes, &src, &dstleft, &dst, NULL); - result = Curl_unencode_write(data, writer->downstream, + result = Curl_cwriter_write(data, writer->next, type, decomp, DSIZ - dstleft); if(result) break; @@ -693,8 +705,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, return result; } -static void brotli_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static void brotli_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct brotli_writer *bp = (struct brotli_writer *) writer; @@ -706,12 +718,12 @@ static void brotli_close_writer(struct Curl_easy *data, } } -static const struct content_encoding brotli_encoding = { +static const struct Curl_cwtype brotli_encoding = { "br", NULL, - brotli_init_writer, - brotli_unencode_write, - brotli_close_writer, + brotli_do_init, + brotli_do_write, + brotli_do_close, sizeof(struct brotli_writer) }; #endif @@ -720,13 +732,13 @@ static const struct content_encoding brotli_encoding = { #ifdef HAVE_ZSTD /* Zstd writer. */ struct zstd_writer { - struct contenc_writer super; + struct Curl_cwriter super; ZSTD_DStream *zds; /* State structure for zstd. */ void *decomp; }; -static CURLcode zstd_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static CURLcode zstd_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zstd_writer *zp = (struct zstd_writer *) writer; @@ -737,8 +749,8 @@ static CURLcode zstd_init_writer(struct Curl_easy *data, return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY; } -static CURLcode zstd_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, +static CURLcode zstd_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { CURLcode result = CURLE_OK; @@ -747,6 +759,9 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, ZSTD_outBuffer out; size_t errorCode; + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + if(!zp->decomp) { zp->decomp = malloc(DSIZ); if(!zp->decomp) @@ -766,7 +781,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, return CURLE_BAD_CONTENT_ENCODING; } if(out.pos > 0) { - result = Curl_unencode_write(data, writer->downstream, + result = Curl_cwriter_write(data, writer->next, type, zp->decomp, out.pos); if(result) break; @@ -778,8 +793,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, return result; } -static void zstd_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static void zstd_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) { struct zstd_writer *zp = (struct zstd_writer *) writer; @@ -795,52 +810,30 @@ static void zstd_close_writer(struct Curl_easy *data, } } -static const struct content_encoding zstd_encoding = { +static const struct Curl_cwtype zstd_encoding = { "zstd", NULL, - zstd_init_writer, - zstd_unencode_write, - zstd_close_writer, + zstd_do_init, + zstd_do_write, + zstd_do_close, sizeof(struct zstd_writer) }; #endif /* Identity handler. */ -static CURLcode identity_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) -{ - (void)data; - (void)writer; - return CURLE_OK; -} - -static CURLcode identity_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, - const char *buf, size_t nbytes) -{ - return Curl_unencode_write(data, writer->downstream, buf, nbytes); -} - -static void identity_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) -{ - (void) data; - (void) writer; -} - -static const struct content_encoding identity_encoding = { +static const struct Curl_cwtype identity_encoding = { "identity", "none", - identity_init_writer, - identity_unencode_write, - identity_close_writer, - sizeof(struct contenc_writer) + Curl_cwriter_def_init, + Curl_cwriter_def_write, + Curl_cwriter_def_close, + sizeof(struct Curl_cwriter) }; /* supported content encodings table. */ -static const struct content_encoding * const encodings[] = { +static const struct Curl_cwtype * const encodings[] = { &identity_encoding, #ifdef HAVE_LIBZ &deflate_encoding, @@ -856,13 +849,17 @@ static const struct content_encoding * const encodings[] = { }; -/* Return a list of comma-separated names of supported encodings. */ -char *Curl_all_content_encodings(void) +/* Provide a list of comma-separated names of supported encodings. +*/ +void Curl_all_content_encodings(char *buf, size_t blen) { size_t len = 0; - const struct content_encoding * const *cep; - const struct content_encoding *ce; - char *ace; + const struct Curl_cwtype * const *cep; + const struct Curl_cwtype *ce; + + DEBUGASSERT(buf); + DEBUGASSERT(blen); + buf[0] = 0; for(cep = encodings; *cep; cep++) { ce = *cep; @@ -870,12 +867,12 @@ char *Curl_all_content_encodings(void) len += strlen(ce->name) + 2; } - if(!len) - return strdup(CONTENT_ENCODING_DEFAULT); - - ace = malloc(len); - if(ace) { - char *p = ace; + if(!len) { + if(blen >= sizeof(CONTENT_ENCODING_DEFAULT)) + strcpy(buf, CONTENT_ENCODING_DEFAULT); + } + else if(blen > len) { + char *p = buf; for(cep = encodings; *cep; cep++) { ce = *cep; if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) { @@ -887,75 +884,60 @@ char *Curl_all_content_encodings(void) } p[-2] = '\0'; } - - return ace; } - /* Deferred error dummy writer. */ -static CURLcode error_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static CURLcode error_do_init(struct Curl_easy *data, + struct Curl_cwriter *writer) { (void)data; (void)writer; return CURLE_OK; } -static CURLcode error_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, +static CURLcode error_do_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { - char *all = Curl_all_content_encodings(); + char all[256]; + (void)Curl_all_content_encodings(all, sizeof(all)); (void) writer; (void) buf; (void) nbytes; - if(!all) - return CURLE_OUT_OF_MEMORY; + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + failf(data, "Unrecognized content encoding type. " "libcurl understands %s content encodings.", all); - free(all); return CURLE_BAD_CONTENT_ENCODING; } -static void error_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) +static void error_do_close(struct Curl_easy *data, + struct Curl_cwriter *writer) { (void) data; (void) writer; } -static const struct content_encoding error_encoding = { - NULL, +static const struct Curl_cwtype error_writer = { + "ce-error", NULL, - error_init_writer, - error_unencode_write, - error_close_writer, - sizeof(struct contenc_writer) + error_do_init, + error_do_write, + error_do_close, + sizeof(struct Curl_cwriter) }; -/* Write data using an unencoding writer stack. "nbytes" is not - allowed to be 0. */ -CURLcode Curl_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, - const char *buf, size_t nbytes) -{ - if(!nbytes) - return CURLE_OK; - if(!writer) - return CURLE_WRITE_ERROR; - return writer->handler->unencode_write(data, writer, buf, nbytes); -} - /* Find the content encoding by name. */ -static const struct content_encoding *find_encoding(const char *name, +static const struct Curl_cwtype *find_encoding(const char *name, size_t len) { - const struct content_encoding * const *cep; + const struct Curl_cwtype * const *cep; for(cep = encodings; *cep; cep++) { - const struct content_encoding *ce = *cep; + const struct Curl_cwtype *ce = *cep; if((strncasecompare(name, ce->name, len) && !ce->name[len]) || (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) return ce; @@ -969,7 +951,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const char *enclist, int is_transfer) { struct SingleRequest *k = &data->req; - unsigned int order = is_transfer? 2: 1; + Curl_cwriter_phase phase = is_transfer? + CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE; CURLcode result; do { @@ -992,23 +975,32 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, Curl_httpchunk_init(data); /* init our chunky engine. */ } else if(namelen) { - const struct content_encoding *encoding; - struct contenc_writer *writer; - if(is_transfer && !data->set.http_transfer_encoding) + const struct Curl_cwtype *cwt; + struct Curl_cwriter *writer; + + if((is_transfer && !data->set.http_transfer_encoding) || + (!is_transfer && data->set.http_ce_skip)) { /* not requested, ignore */ return CURLE_OK; + } - encoding = find_encoding(name, namelen); - if(!encoding) - encoding = &error_encoding; /* Defer error at stack use. */ + if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) { + failf(data, "Reject response due to more than %u content encodings", + MAX_ENCODE_STACK); + return CURLE_BAD_CONTENT_ENCODING; + } + + cwt = find_encoding(name, namelen); + if(!cwt) + cwt = &error_writer; /* Defer error at use. */ - result = Curl_client_create_writer(&writer, data, encoding, order); + result = Curl_cwriter_create(&writer, data, cwt, phase); if(result) return result; - result = Curl_client_add_writer(data, writer); + result = Curl_cwriter_add(data, writer); if(result) { - Curl_client_free_writer(data, writer); + Curl_cwriter_free(data, writer); return result; } } @@ -1028,20 +1020,15 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, - const char *buf, size_t nbytes) +void Curl_all_content_encodings(char *buf, size_t blen) { - (void) data; - (void) writer; - (void) buf; - (void) nbytes; - return CURLE_NOT_BUILT_IN; + DEBUGASSERT(buf); + DEBUGASSERT(blen); + if(blen < sizeof(CONTENT_ENCODING_DEFAULT)) + buf[0] = 0; + else + strcpy(buf, CONTENT_ENCODING_DEFAULT); } -char *Curl_all_content_encodings(void) -{ - return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */ -} #endif /* CURL_DISABLE_HTTP */ |