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