content_encoding.c (25122B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 27 #include "urldata.h" 28 #include <curl/curl.h> 29 #include <stddef.h> 30 31 #ifdef HAVE_LIBZ 32 #include <zlib.h> 33 #endif 34 35 #ifdef HAVE_BROTLI 36 #if defined(__GNUC__) || defined(__clang__) 37 /* Ignore -Wvla warnings in brotli headers */ 38 #pragma GCC diagnostic push 39 #pragma GCC diagnostic ignored "-Wvla" 40 #endif 41 #include <brotli/decode.h> 42 #if defined(__GNUC__) || defined(__clang__) 43 #pragma GCC diagnostic pop 44 #endif 45 #endif 46 47 #ifdef HAVE_ZSTD 48 #include <zstd.h> 49 #endif 50 51 #include "sendf.h" 52 #include "http.h" 53 #include "content_encoding.h" 54 #include "strdup.h" 55 56 /* The last 3 #include files should be in this order */ 57 #include "curl_printf.h" 58 #include "curl_memory.h" 59 #include "memdebug.h" 60 61 #define CONTENT_ENCODING_DEFAULT "identity" 62 63 #ifndef CURL_DISABLE_HTTP 64 65 /* allow no more than 5 "chained" compression steps */ 66 #define MAX_ENCODE_STACK 5 67 68 #if defined(HAVE_LIBZ) || defined(HAVE_BROTLI) || defined(HAVE_ZSTD) 69 #define DECOMPRESS_BUFFER_SIZE 16384 /* buffer size for decompressed data */ 70 #endif 71 72 #ifdef HAVE_LIBZ 73 74 #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1252) 75 #error "requires zlib 1.2.5.2 or newer" 76 #endif 77 78 typedef enum { 79 ZLIB_UNINIT, /* uninitialized */ 80 ZLIB_INIT, /* initialized */ 81 ZLIB_INFLATING, /* inflating started. */ 82 ZLIB_EXTERNAL_TRAILER, /* reading external trailer */ 83 ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ 84 } zlibInitState; 85 86 /* Deflate and gzip writer. */ 87 struct zlib_writer { 88 struct Curl_cwriter super; 89 zlibInitState zlib_init; /* zlib init state */ 90 char buffer[DECOMPRESS_BUFFER_SIZE]; /* Put the decompressed data here. */ 91 uInt trailerlen; /* Remaining trailer byte count. */ 92 z_stream z; /* State structure for zlib. */ 93 }; 94 95 96 static voidpf 97 zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) 98 { 99 (void) opaque; 100 /* not a typo, keep it calloc() */ 101 return (voidpf) calloc(items, size); 102 } 103 104 static void 105 zfree_cb(voidpf opaque, voidpf ptr) 106 { 107 (void) opaque; 108 free(ptr); 109 } 110 111 static CURLcode 112 process_zlib_error(struct Curl_easy *data, z_stream *z) 113 { 114 if(z->msg) 115 failf(data, "Error while processing content unencoding: %s", 116 z->msg); 117 else 118 failf(data, "Error while processing content unencoding: " 119 "Unknown failure within decompression software."); 120 121 return CURLE_BAD_CONTENT_ENCODING; 122 } 123 124 static CURLcode 125 exit_zlib(struct Curl_easy *data, 126 z_stream *z, zlibInitState *zlib_init, CURLcode result) 127 { 128 if(*zlib_init != ZLIB_UNINIT) { 129 if(inflateEnd(z) != Z_OK && result == CURLE_OK) 130 result = process_zlib_error(data, z); 131 *zlib_init = ZLIB_UNINIT; 132 } 133 134 return result; 135 } 136 137 static CURLcode process_trailer(struct Curl_easy *data, 138 struct zlib_writer *zp) 139 { 140 z_stream *z = &zp->z; 141 CURLcode result = CURLE_OK; 142 uInt len = z->avail_in < zp->trailerlen ? z->avail_in : zp->trailerlen; 143 144 /* Consume expected trailer bytes. Terminate stream if exhausted. 145 Issue an error if unexpected bytes follow. */ 146 147 zp->trailerlen -= len; 148 z->avail_in -= len; 149 z->next_in += len; 150 if(z->avail_in) 151 result = CURLE_WRITE_ERROR; 152 if(result || !zp->trailerlen) 153 result = exit_zlib(data, z, &zp->zlib_init, result); 154 else { 155 /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */ 156 zp->zlib_init = ZLIB_EXTERNAL_TRAILER; 157 } 158 return result; 159 } 160 161 static CURLcode inflate_stream(struct Curl_easy *data, 162 struct Curl_cwriter *writer, int type, 163 zlibInitState started) 164 { 165 struct zlib_writer *zp = (struct zlib_writer *) writer; 166 z_stream *z = &zp->z; /* zlib state structure */ 167 uInt nread = z->avail_in; 168 z_const Bytef *orig_in = z->next_in; 169 bool done = FALSE; 170 CURLcode result = CURLE_OK; /* Curl_client_write status */ 171 172 /* Check state. */ 173 if(zp->zlib_init != ZLIB_INIT && 174 zp->zlib_init != ZLIB_INFLATING && 175 zp->zlib_init != ZLIB_INIT_GZIP) 176 return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR); 177 178 /* because the buffer size is fixed, iteratively decompress and transfer to 179 the client via next_write function. */ 180 while(!done) { 181 int status; /* zlib status */ 182 done = TRUE; 183 184 /* (re)set buffer for decompressed output for every iteration */ 185 z->next_out = (Bytef *) zp->buffer; 186 z->avail_out = DECOMPRESS_BUFFER_SIZE; 187 188 status = inflate(z, Z_BLOCK); 189 190 /* Flush output data if some. */ 191 if(z->avail_out != DECOMPRESS_BUFFER_SIZE) { 192 if(status == Z_OK || status == Z_STREAM_END) { 193 zp->zlib_init = started; /* Data started. */ 194 result = Curl_cwriter_write(data, writer->next, type, zp->buffer, 195 DECOMPRESS_BUFFER_SIZE - z->avail_out); 196 if(result) { 197 exit_zlib(data, z, &zp->zlib_init, result); 198 break; 199 } 200 } 201 } 202 203 /* Dispatch by inflate() status. */ 204 switch(status) { 205 case Z_OK: 206 /* Always loop: there may be unflushed latched data in zlib state. */ 207 done = FALSE; 208 break; 209 case Z_BUF_ERROR: 210 /* No more data to flush: just exit loop. */ 211 break; 212 case Z_STREAM_END: 213 result = process_trailer(data, zp); 214 break; 215 case Z_DATA_ERROR: 216 /* some servers seem to not generate zlib headers, so this is an attempt 217 to fix and continue anyway */ 218 if(zp->zlib_init == ZLIB_INIT) { 219 if(inflateReset2(z, -MAX_WBITS) == Z_OK) { 220 z->next_in = orig_in; 221 z->avail_in = nread; 222 zp->zlib_init = ZLIB_INFLATING; 223 zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */ 224 done = FALSE; 225 break; 226 } 227 zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */ 228 } 229 result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); 230 break; 231 default: 232 result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); 233 break; 234 } 235 } 236 237 /* We are about to leave this call so the `nread' data bytes will not be seen 238 again. If we are in a state that would wrongly allow restart in raw mode 239 at the next call, assume output has already started. */ 240 if(nread && zp->zlib_init == ZLIB_INIT) 241 zp->zlib_init = started; /* Cannot restart anymore. */ 242 243 return result; 244 } 245 246 247 /* Deflate handler. */ 248 static CURLcode deflate_do_init(struct Curl_easy *data, 249 struct Curl_cwriter *writer) 250 { 251 struct zlib_writer *zp = (struct zlib_writer *) writer; 252 z_stream *z = &zp->z; /* zlib state structure */ 253 254 /* Initialize zlib */ 255 z->zalloc = (alloc_func) zalloc_cb; 256 z->zfree = (free_func) zfree_cb; 257 258 if(inflateInit(z) != Z_OK) 259 return process_zlib_error(data, z); 260 zp->zlib_init = ZLIB_INIT; 261 return CURLE_OK; 262 } 263 264 static CURLcode deflate_do_write(struct Curl_easy *data, 265 struct Curl_cwriter *writer, int type, 266 const char *buf, size_t nbytes) 267 { 268 struct zlib_writer *zp = (struct zlib_writer *) writer; 269 z_stream *z = &zp->z; /* zlib state structure */ 270 271 if(!(type & CLIENTWRITE_BODY) || !nbytes) 272 return Curl_cwriter_write(data, writer->next, type, buf, nbytes); 273 274 /* Set the compressed input when this function is called */ 275 z->next_in = (z_const Bytef *)buf; 276 z->avail_in = (uInt)nbytes; 277 278 if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER) 279 return process_trailer(data, zp); 280 281 /* Now uncompress the data */ 282 return inflate_stream(data, writer, type, ZLIB_INFLATING); 283 } 284 285 static void deflate_do_close(struct Curl_easy *data, 286 struct Curl_cwriter *writer) 287 { 288 struct zlib_writer *zp = (struct zlib_writer *) writer; 289 z_stream *z = &zp->z; /* zlib state structure */ 290 291 exit_zlib(data, z, &zp->zlib_init, CURLE_OK); 292 } 293 294 static const struct Curl_cwtype deflate_encoding = { 295 "deflate", 296 NULL, 297 deflate_do_init, 298 deflate_do_write, 299 deflate_do_close, 300 sizeof(struct zlib_writer) 301 }; 302 303 304 /* Gzip handler. */ 305 static CURLcode gzip_do_init(struct Curl_easy *data, 306 struct Curl_cwriter *writer) 307 { 308 struct zlib_writer *zp = (struct zlib_writer *) writer; 309 z_stream *z = &zp->z; /* zlib state structure */ 310 311 /* Initialize zlib */ 312 z->zalloc = (alloc_func) zalloc_cb; 313 z->zfree = (free_func) zfree_cb; 314 315 if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) 316 return process_zlib_error(data, z); 317 318 zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ 319 return CURLE_OK; 320 } 321 322 static CURLcode gzip_do_write(struct Curl_easy *data, 323 struct Curl_cwriter *writer, int type, 324 const char *buf, size_t nbytes) 325 { 326 struct zlib_writer *zp = (struct zlib_writer *) writer; 327 z_stream *z = &zp->z; /* zlib state structure */ 328 329 if(!(type & CLIENTWRITE_BODY) || !nbytes) 330 return Curl_cwriter_write(data, writer->next, type, buf, nbytes); 331 332 if(zp->zlib_init == ZLIB_INIT_GZIP) { 333 /* Let zlib handle the gzip decompression entirely */ 334 z->next_in = (z_const Bytef *)buf; 335 z->avail_in = (uInt)nbytes; 336 /* Now uncompress the data */ 337 return inflate_stream(data, writer, type, ZLIB_INIT_GZIP); 338 } 339 340 /* We are running with an old version: return error. */ 341 return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR); 342 } 343 344 static void gzip_do_close(struct Curl_easy *data, 345 struct Curl_cwriter *writer) 346 { 347 struct zlib_writer *zp = (struct zlib_writer *) writer; 348 z_stream *z = &zp->z; /* zlib state structure */ 349 350 exit_zlib(data, z, &zp->zlib_init, CURLE_OK); 351 } 352 353 static const struct Curl_cwtype gzip_encoding = { 354 "gzip", 355 "x-gzip", 356 gzip_do_init, 357 gzip_do_write, 358 gzip_do_close, 359 sizeof(struct zlib_writer) 360 }; 361 362 #endif /* HAVE_LIBZ */ 363 364 #ifdef HAVE_BROTLI 365 /* Brotli writer. */ 366 struct brotli_writer { 367 struct Curl_cwriter super; 368 char buffer[DECOMPRESS_BUFFER_SIZE]; 369 BrotliDecoderState *br; /* State structure for brotli. */ 370 }; 371 372 static CURLcode brotli_map_error(BrotliDecoderErrorCode be) 373 { 374 switch(be) { 375 case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: 376 case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: 377 case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: 378 case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: 379 case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: 380 case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: 381 case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: 382 case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: 383 case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: 384 case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: 385 case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: 386 case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: 387 case BROTLI_DECODER_ERROR_FORMAT_PADDING_1: 388 case BROTLI_DECODER_ERROR_FORMAT_PADDING_2: 389 #ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY 390 case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY: 391 #endif 392 #ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET 393 case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: 394 #endif 395 case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: 396 return CURLE_BAD_CONTENT_ENCODING; 397 case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: 398 case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: 399 case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: 400 case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: 401 case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: 402 case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: 403 return CURLE_OUT_OF_MEMORY; 404 default: 405 break; 406 } 407 return CURLE_WRITE_ERROR; 408 } 409 410 static CURLcode brotli_do_init(struct Curl_easy *data, 411 struct Curl_cwriter *writer) 412 { 413 struct brotli_writer *bp = (struct brotli_writer *) writer; 414 (void) data; 415 416 bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL); 417 return bp->br ? CURLE_OK : CURLE_OUT_OF_MEMORY; 418 } 419 420 static CURLcode brotli_do_write(struct Curl_easy *data, 421 struct Curl_cwriter *writer, int type, 422 const char *buf, size_t nbytes) 423 { 424 struct brotli_writer *bp = (struct brotli_writer *) writer; 425 const uint8_t *src = (const uint8_t *) buf; 426 uint8_t *dst; 427 size_t dstleft; 428 CURLcode result = CURLE_OK; 429 BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; 430 431 if(!(type & CLIENTWRITE_BODY) || !nbytes) 432 return Curl_cwriter_write(data, writer->next, type, buf, nbytes); 433 434 if(!bp->br) 435 return CURLE_WRITE_ERROR; /* Stream already ended. */ 436 437 while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) && 438 result == CURLE_OK) { 439 dst = (uint8_t *) bp->buffer; 440 dstleft = DECOMPRESS_BUFFER_SIZE; 441 r = BrotliDecoderDecompressStream(bp->br, 442 &nbytes, &src, &dstleft, &dst, NULL); 443 result = Curl_cwriter_write(data, writer->next, type, 444 bp->buffer, DECOMPRESS_BUFFER_SIZE - dstleft); 445 if(result) 446 break; 447 switch(r) { 448 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 449 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 450 break; 451 case BROTLI_DECODER_RESULT_SUCCESS: 452 BrotliDecoderDestroyInstance(bp->br); 453 bp->br = NULL; 454 if(nbytes) 455 result = CURLE_WRITE_ERROR; 456 break; 457 default: 458 result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br)); 459 break; 460 } 461 } 462 return result; 463 } 464 465 static void brotli_do_close(struct Curl_easy *data, 466 struct Curl_cwriter *writer) 467 { 468 struct brotli_writer *bp = (struct brotli_writer *) writer; 469 (void) data; 470 471 if(bp->br) { 472 BrotliDecoderDestroyInstance(bp->br); 473 bp->br = NULL; 474 } 475 } 476 477 static const struct Curl_cwtype brotli_encoding = { 478 "br", 479 NULL, 480 brotli_do_init, 481 brotli_do_write, 482 brotli_do_close, 483 sizeof(struct brotli_writer) 484 }; 485 #endif 486 487 #ifdef HAVE_ZSTD 488 /* Zstd writer. */ 489 struct zstd_writer { 490 struct Curl_cwriter super; 491 ZSTD_DStream *zds; /* State structure for zstd. */ 492 char buffer[DECOMPRESS_BUFFER_SIZE]; 493 }; 494 495 #ifdef ZSTD_STATIC_LINKING_ONLY 496 static void *Curl_zstd_alloc(void *opaque, size_t size) 497 { 498 (void)opaque; 499 return Curl_cmalloc(size); 500 } 501 502 static void Curl_zstd_free(void *opaque, void *address) 503 { 504 (void)opaque; 505 Curl_cfree(address); 506 } 507 #endif 508 509 static CURLcode zstd_do_init(struct Curl_easy *data, 510 struct Curl_cwriter *writer) 511 { 512 struct zstd_writer *zp = (struct zstd_writer *) writer; 513 514 (void)data; 515 516 #ifdef ZSTD_STATIC_LINKING_ONLY 517 zp->zds = ZSTD_createDStream_advanced((ZSTD_customMem) { 518 .customAlloc = Curl_zstd_alloc, 519 .customFree = Curl_zstd_free, 520 .opaque = NULL 521 }); 522 #else 523 zp->zds = ZSTD_createDStream(); 524 #endif 525 526 return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY; 527 } 528 529 static CURLcode zstd_do_write(struct Curl_easy *data, 530 struct Curl_cwriter *writer, int type, 531 const char *buf, size_t nbytes) 532 { 533 CURLcode result = CURLE_OK; 534 struct zstd_writer *zp = (struct zstd_writer *) writer; 535 ZSTD_inBuffer in; 536 ZSTD_outBuffer out; 537 size_t errorCode; 538 539 if(!(type & CLIENTWRITE_BODY) || !nbytes) 540 return Curl_cwriter_write(data, writer->next, type, buf, nbytes); 541 542 in.pos = 0; 543 in.src = buf; 544 in.size = nbytes; 545 546 for(;;) { 547 out.pos = 0; 548 out.dst = zp->buffer; 549 out.size = DECOMPRESS_BUFFER_SIZE; 550 551 errorCode = ZSTD_decompressStream(zp->zds, &out, &in); 552 if(ZSTD_isError(errorCode)) { 553 return CURLE_BAD_CONTENT_ENCODING; 554 } 555 if(out.pos > 0) { 556 result = Curl_cwriter_write(data, writer->next, type, 557 zp->buffer, out.pos); 558 if(result) 559 break; 560 } 561 if((in.pos == nbytes) && (out.pos < out.size)) 562 break; 563 } 564 565 return result; 566 } 567 568 static void zstd_do_close(struct Curl_easy *data, 569 struct Curl_cwriter *writer) 570 { 571 struct zstd_writer *zp = (struct zstd_writer *) writer; 572 (void)data; 573 574 if(zp->zds) { 575 ZSTD_freeDStream(zp->zds); 576 zp->zds = NULL; 577 } 578 } 579 580 static const struct Curl_cwtype zstd_encoding = { 581 "zstd", 582 NULL, 583 zstd_do_init, 584 zstd_do_write, 585 zstd_do_close, 586 sizeof(struct zstd_writer) 587 }; 588 #endif 589 590 /* Identity handler. */ 591 static const struct Curl_cwtype identity_encoding = { 592 "identity", 593 "none", 594 Curl_cwriter_def_init, 595 Curl_cwriter_def_write, 596 Curl_cwriter_def_close, 597 sizeof(struct Curl_cwriter) 598 }; 599 600 /* supported general content decoders. */ 601 static const struct Curl_cwtype * const general_unencoders[] = { 602 &identity_encoding, 603 #ifdef HAVE_LIBZ 604 &deflate_encoding, 605 &gzip_encoding, 606 #endif 607 #ifdef HAVE_BROTLI 608 &brotli_encoding, 609 #endif 610 #ifdef HAVE_ZSTD 611 &zstd_encoding, 612 #endif 613 NULL 614 }; 615 616 /* supported content decoders only for transfer encodings */ 617 static const struct Curl_cwtype * const transfer_unencoders[] = { 618 #ifndef CURL_DISABLE_HTTP 619 &Curl_httpchunk_unencoder, 620 #endif 621 NULL 622 }; 623 624 /* Provide a list of comma-separated names of supported encodings. 625 */ 626 void Curl_all_content_encodings(char *buf, size_t blen) 627 { 628 size_t len = 0; 629 const struct Curl_cwtype * const *cep; 630 const struct Curl_cwtype *ce; 631 632 DEBUGASSERT(buf); 633 DEBUGASSERT(blen); 634 buf[0] = 0; 635 636 for(cep = general_unencoders; *cep; cep++) { 637 ce = *cep; 638 if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) 639 len += strlen(ce->name) + 2; 640 } 641 642 if(!len) { 643 if(blen >= sizeof(CONTENT_ENCODING_DEFAULT)) 644 strcpy(buf, CONTENT_ENCODING_DEFAULT); 645 } 646 else if(blen > len) { 647 char *p = buf; 648 for(cep = general_unencoders; *cep; cep++) { 649 ce = *cep; 650 if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) { 651 strcpy(p, ce->name); 652 p += strlen(p); 653 *p++ = ','; 654 *p++ = ' '; 655 } 656 } 657 p[-2] = '\0'; 658 } 659 } 660 661 /* Deferred error dummy writer. */ 662 static CURLcode error_do_init(struct Curl_easy *data, 663 struct Curl_cwriter *writer) 664 { 665 (void)data; 666 (void)writer; 667 return CURLE_OK; 668 } 669 670 static CURLcode error_do_write(struct Curl_easy *data, 671 struct Curl_cwriter *writer, int type, 672 const char *buf, size_t nbytes) 673 { 674 (void) writer; 675 (void) buf; 676 (void) nbytes; 677 678 if(!(type & CLIENTWRITE_BODY) || !nbytes) 679 return Curl_cwriter_write(data, writer->next, type, buf, nbytes); 680 else { 681 char all[256]; 682 (void)Curl_all_content_encodings(all, sizeof(all)); 683 failf(data, "Unrecognized content encoding type. " 684 "libcurl understands %s content encodings.", all); 685 } 686 return CURLE_BAD_CONTENT_ENCODING; 687 } 688 689 static void error_do_close(struct Curl_easy *data, 690 struct Curl_cwriter *writer) 691 { 692 (void) data; 693 (void) writer; 694 } 695 696 static const struct Curl_cwtype error_writer = { 697 "ce-error", 698 NULL, 699 error_do_init, 700 error_do_write, 701 error_do_close, 702 sizeof(struct Curl_cwriter) 703 }; 704 705 /* Find the content encoding by name. */ 706 static const struct Curl_cwtype *find_unencode_writer(const char *name, 707 size_t len, 708 Curl_cwriter_phase phase) 709 { 710 const struct Curl_cwtype * const *cep; 711 712 if(phase == CURL_CW_TRANSFER_DECODE) { 713 for(cep = transfer_unencoders; *cep; cep++) { 714 const struct Curl_cwtype *ce = *cep; 715 if((curl_strnequal(name, ce->name, len) && !ce->name[len]) || 716 (ce->alias && curl_strnequal(name, ce->alias, len) 717 && !ce->alias[len])) 718 return ce; 719 } 720 } 721 /* look among the general decoders */ 722 for(cep = general_unencoders; *cep; cep++) { 723 const struct Curl_cwtype *ce = *cep; 724 if((curl_strnequal(name, ce->name, len) && !ce->name[len]) || 725 (ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len])) 726 return ce; 727 } 728 return NULL; 729 } 730 731 /* Setup the unencoding stack from the Content-Encoding header value. 732 * See RFC 7231 section 3.1.2.2. */ 733 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, 734 const char *enclist, int is_transfer) 735 { 736 Curl_cwriter_phase phase = is_transfer ? 737 CURL_CW_TRANSFER_DECODE : CURL_CW_CONTENT_DECODE; 738 CURLcode result; 739 bool has_chunked = FALSE; 740 741 do { 742 const char *name; 743 size_t namelen; 744 bool is_chunked = FALSE; 745 746 /* Parse a single encoding name. */ 747 while(ISBLANK(*enclist) || *enclist == ',') 748 enclist++; 749 750 name = enclist; 751 752 for(namelen = 0; *enclist && *enclist != ','; enclist++) 753 if(*enclist > ' ') 754 namelen = enclist - name + 1; 755 756 if(namelen) { 757 const struct Curl_cwtype *cwt; 758 struct Curl_cwriter *writer; 759 760 CURL_TRC_WRITE(data, "looking for %s decoder: %.*s", 761 is_transfer ? "transfer" : "content", (int)namelen, name); 762 is_chunked = (is_transfer && (namelen == 7) && 763 curl_strnequal(name, "chunked", 7)); 764 /* if we skip the decoding in this phase, do not look further. 765 * Exception is "chunked" transfer-encoding which always must happen */ 766 if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) || 767 (!is_transfer && data->set.http_ce_skip)) { 768 bool is_identity = curl_strnequal(name, "identity", 8); 769 /* not requested, ignore */ 770 CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s", 771 (int)namelen, name); 772 if(is_transfer && !data->set.http_te_skip) { 773 if(has_chunked) 774 failf(data, "A Transfer-Encoding (%.*s) was listed after chunked", 775 (int)namelen, name); 776 else if(is_identity) 777 continue; 778 else 779 failf(data, "Unsolicited Transfer-Encoding (%.*s) found", 780 (int)namelen, name); 781 return CURLE_BAD_CONTENT_ENCODING; 782 } 783 return CURLE_OK; 784 } 785 786 if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) { 787 failf(data, "Reject response due to more than %u content encodings", 788 MAX_ENCODE_STACK); 789 return CURLE_BAD_CONTENT_ENCODING; 790 } 791 792 cwt = find_unencode_writer(name, namelen, phase); 793 if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) { 794 /* A 'chunked' transfer encoding has already been added. 795 * Ignore duplicates. See #13451. 796 * Also RFC 9112, ch. 6.1: 797 * "A sender MUST NOT apply the chunked transfer coding more than 798 * once to a message body." 799 */ 800 CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder"); 801 return CURLE_OK; 802 } 803 804 if(is_transfer && !is_chunked && 805 Curl_cwriter_get_by_name(data, "chunked")) { 806 /* RFC 9112, ch. 6.1: 807 * "If any transfer coding other than chunked is applied to a 808 * response's content, the sender MUST either apply chunked as the 809 * final transfer coding or terminate the message by closing the 810 * connection." 811 * "chunked" must be the last added to be the first in its phase, 812 * reject this. 813 */ 814 failf(data, "Reject response due to 'chunked' not being the last " 815 "Transfer-Encoding"); 816 return CURLE_BAD_CONTENT_ENCODING; 817 } 818 819 if(!cwt) 820 cwt = &error_writer; /* Defer error at use. */ 821 822 result = Curl_cwriter_create(&writer, data, cwt, phase); 823 CURL_TRC_WRITE(data, "added %s decoder %s -> %d", 824 is_transfer ? "transfer" : "content", cwt->name, result); 825 if(result) 826 return result; 827 828 result = Curl_cwriter_add(data, writer); 829 if(result) { 830 Curl_cwriter_free(data, writer); 831 return result; 832 } 833 if(is_chunked) 834 has_chunked = TRUE; 835 } 836 } while(*enclist); 837 838 return CURLE_OK; 839 } 840 841 #else 842 /* Stubs for builds without HTTP. */ 843 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, 844 const char *enclist, int is_transfer) 845 { 846 (void) data; 847 (void) enclist; 848 (void) is_transfer; 849 return CURLE_NOT_BUILT_IN; 850 } 851 852 void Curl_all_content_encodings(char *buf, size_t blen) 853 { 854 DEBUGASSERT(buf); 855 DEBUGASSERT(blen); 856 if(blen < sizeof(CONTENT_ENCODING_DEFAULT)) 857 buf[0] = 0; 858 else 859 strcpy(buf, CONTENT_ENCODING_DEFAULT); 860 } 861 862 #endif /* CURL_DISABLE_HTTP */