VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/content_encoding.c@ 99005

Last change on this file since 99005 was 98326, checked in by vboxsync, 2 years ago

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • Property svn:eol-style set to native
File size: 30.7 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, 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#include <brotli/decode.h>
37#endif
38
39#ifdef HAVE_ZSTD
40#include <zstd.h>
41#endif
42
43#include "sendf.h"
44#include "http.h"
45#include "content_encoding.h"
46#include "strdup.h"
47#include "strcase.h"
48#include "curl_memory.h"
49#include "memdebug.h"
50
51#define CONTENT_ENCODING_DEFAULT "identity"
52
53#ifndef CURL_DISABLE_HTTP
54
55#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
56
57
58#ifdef HAVE_LIBZ
59
60/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
61 (doing so will reduce code size slightly). */
62#define OLD_ZLIB_SUPPORT 1
63
64#define GZIP_MAGIC_0 0x1f
65#define GZIP_MAGIC_1 0x8b
66
67/* gzip flag byte */
68#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
69#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
70#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
71#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
72#define COMMENT 0x10 /* bit 4 set: file comment present */
73#define RESERVED 0xE0 /* bits 5..7: reserved */
74
75typedef enum {
76 ZLIB_UNINIT, /* uninitialized */
77 ZLIB_INIT, /* initialized */
78 ZLIB_INFLATING, /* inflating started. */
79 ZLIB_EXTERNAL_TRAILER, /* reading external trailer */
80 ZLIB_GZIP_HEADER, /* reading gzip header */
81 ZLIB_GZIP_INFLATING, /* inflating gzip stream */
82 ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
83} zlibInitState;
84
85/* Deflate and gzip writer. */
86struct zlib_writer {
87 struct contenc_writer super;
88 zlibInitState zlib_init; /* zlib init state */
89 uInt trailerlen; /* Remaining trailer byte count. */
90 z_stream z; /* State structure for zlib. */
91};
92
93
94static voidpf
95zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
96{
97 (void) opaque;
98 /* not a typo, keep it calloc() */
99 return (voidpf) calloc(items, size);
100}
101
102static void
103zfree_cb(voidpf opaque, voidpf ptr)
104{
105 (void) opaque;
106 free(ptr);
107}
108
109static CURLcode
110process_zlib_error(struct Curl_easy *data, z_stream *z)
111{
112 if(z->msg)
113 failf(data, "Error while processing content unencoding: %s",
114 z->msg);
115 else
116 failf(data, "Error while processing content unencoding: "
117 "Unknown failure within decompression software.");
118
119 return CURLE_BAD_CONTENT_ENCODING;
120}
121
122static CURLcode
123exit_zlib(struct Curl_easy *data,
124 z_stream *z, zlibInitState *zlib_init, CURLcode result)
125{
126 if(*zlib_init == ZLIB_GZIP_HEADER)
127 Curl_safefree(z->next_in);
128
129 if(*zlib_init != ZLIB_UNINIT) {
130 if(inflateEnd(z) != Z_OK && result == CURLE_OK)
131 result = process_zlib_error(data, z);
132 *zlib_init = ZLIB_UNINIT;
133 }
134
135 return result;
136}
137
138static CURLcode process_trailer(struct Curl_easy *data,
139 struct zlib_writer *zp)
140{
141 z_stream *z = &zp->z;
142 CURLcode result = CURLE_OK;
143 uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen;
144
145 /* Consume expected trailer bytes. Terminate stream if exhausted.
146 Issue an error if unexpected bytes follow. */
147
148 zp->trailerlen -= len;
149 z->avail_in -= len;
150 z->next_in += len;
151 if(z->avail_in)
152 result = CURLE_WRITE_ERROR;
153 if(result || !zp->trailerlen)
154 result = exit_zlib(data, z, &zp->zlib_init, result);
155 else {
156 /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
157 zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
158 }
159 return result;
160}
161
162static CURLcode inflate_stream(struct Curl_easy *data,
163 struct contenc_writer *writer,
164 zlibInitState started)
165{
166 struct zlib_writer *zp = (struct zlib_writer *) writer;
167 z_stream *z = &zp->z; /* zlib state structure */
168 uInt nread = z->avail_in;
169 Bytef *orig_in = z->next_in;
170 bool done = FALSE;
171 CURLcode result = CURLE_OK; /* Curl_client_write status */
172 char *decomp; /* Put the decompressed data here. */
173
174 /* Check state. */
175 if(zp->zlib_init != ZLIB_INIT &&
176 zp->zlib_init != ZLIB_INFLATING &&
177 zp->zlib_init != ZLIB_INIT_GZIP &&
178 zp->zlib_init != ZLIB_GZIP_INFLATING)
179 return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
180
181 /* Dynamically allocate a buffer for decompression because it's uncommonly
182 large to hold on the stack */
183 decomp = malloc(DSIZ);
184 if(!decomp)
185 return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
186
187 /* because the buffer size is fixed, iteratively decompress and transfer to
188 the client via downstream_write function. */
189 while(!done) {
190 int status; /* zlib status */
191 done = TRUE;
192
193 /* (re)set buffer for decompressed output for every iteration */
194 z->next_out = (Bytef *) decomp;
195 z->avail_out = DSIZ;
196
197#ifdef Z_BLOCK
198 /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
199 status = inflate(z, Z_BLOCK);
200#else
201 /* fallback for zlib ver. < 1.2.0.5 */
202 status = inflate(z, Z_SYNC_FLUSH);
203#endif
204
205 /* Flush output data if some. */
206 if(z->avail_out != DSIZ) {
207 if(status == Z_OK || status == Z_STREAM_END) {
208 zp->zlib_init = started; /* Data started. */
209 result = Curl_unencode_write(data, writer->downstream, decomp,
210 DSIZ - z->avail_out);
211 if(result) {
212 exit_zlib(data, z, &zp->zlib_init, result);
213 break;
214 }
215 }
216 }
217
218 /* Dispatch by inflate() status. */
219 switch(status) {
220 case Z_OK:
221 /* Always loop: there may be unflushed latched data in zlib state. */
222 done = FALSE;
223 break;
224 case Z_BUF_ERROR:
225 /* No more data to flush: just exit loop. */
226 break;
227 case Z_STREAM_END:
228 result = process_trailer(data, zp);
229 break;
230 case Z_DATA_ERROR:
231 /* some servers seem to not generate zlib headers, so this is an attempt
232 to fix and continue anyway */
233 if(zp->zlib_init == ZLIB_INIT) {
234 /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
235 (void) inflateEnd(z); /* don't care about the return code */
236 if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
237 z->next_in = orig_in;
238 z->avail_in = nread;
239 zp->zlib_init = ZLIB_INFLATING;
240 zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
241 done = FALSE;
242 break;
243 }
244 zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
245 }
246 result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
247 break;
248 default:
249 result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
250 break;
251 }
252 }
253 free(decomp);
254
255 /* We're about to leave this call so the `nread' data bytes won't be seen
256 again. If we are in a state that would wrongly allow restart in raw mode
257 at the next call, assume output has already started. */
258 if(nread && zp->zlib_init == ZLIB_INIT)
259 zp->zlib_init = started; /* Cannot restart anymore. */
260
261 return result;
262}
263
264
265/* Deflate handler. */
266static CURLcode deflate_init_writer(struct Curl_easy *data,
267 struct contenc_writer *writer)
268{
269 struct zlib_writer *zp = (struct zlib_writer *) writer;
270 z_stream *z = &zp->z; /* zlib state structure */
271
272 if(!writer->downstream)
273 return CURLE_WRITE_ERROR;
274
275 /* Initialize zlib */
276 z->zalloc = (alloc_func) zalloc_cb;
277 z->zfree = (free_func) zfree_cb;
278
279 if(inflateInit(z) != Z_OK)
280 return process_zlib_error(data, z);
281 zp->zlib_init = ZLIB_INIT;
282 return CURLE_OK;
283}
284
285static CURLcode deflate_unencode_write(struct Curl_easy *data,
286 struct contenc_writer *writer,
287 const char *buf, size_t nbytes)
288{
289 struct zlib_writer *zp = (struct zlib_writer *) writer;
290 z_stream *z = &zp->z; /* zlib state structure */
291
292 /* Set the compressed input when this function is called */
293 z->next_in = (Bytef *) buf;
294 z->avail_in = (uInt) nbytes;
295
296 if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
297 return process_trailer(data, zp);
298
299 /* Now uncompress the data */
300 return inflate_stream(data, writer, ZLIB_INFLATING);
301}
302
303static void deflate_close_writer(struct Curl_easy *data,
304 struct contenc_writer *writer)
305{
306 struct zlib_writer *zp = (struct zlib_writer *) writer;
307 z_stream *z = &zp->z; /* zlib state structure */
308
309 exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
310}
311
312static const struct content_encoding deflate_encoding = {
313 "deflate",
314 NULL,
315 deflate_init_writer,
316 deflate_unencode_write,
317 deflate_close_writer,
318 sizeof(struct zlib_writer)
319};
320
321
322/* Gzip handler. */
323static CURLcode gzip_init_writer(struct Curl_easy *data,
324 struct contenc_writer *writer)
325{
326 struct zlib_writer *zp = (struct zlib_writer *) writer;
327 z_stream *z = &zp->z; /* zlib state structure */
328
329 if(!writer->downstream)
330 return CURLE_WRITE_ERROR;
331
332 /* Initialize zlib */
333 z->zalloc = (alloc_func) zalloc_cb;
334 z->zfree = (free_func) zfree_cb;
335
336 if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
337 /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
338 if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
339 return process_zlib_error(data, z);
340 }
341 zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
342 }
343 else {
344 /* we must parse the gzip header and trailer ourselves */
345 if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
346 return process_zlib_error(data, z);
347 }
348 zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
349 zp->zlib_init = ZLIB_INIT; /* Initial call state */
350 }
351
352 return CURLE_OK;
353}
354
355#ifdef OLD_ZLIB_SUPPORT
356/* Skip over the gzip header */
357static enum {
358 GZIP_OK,
359 GZIP_BAD,
360 GZIP_UNDERFLOW
361} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
362{
363 int method, flags;
364 const ssize_t totallen = len;
365
366 /* The shortest header is 10 bytes */
367 if(len < 10)
368 return GZIP_UNDERFLOW;
369
370 if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
371 return GZIP_BAD;
372
373 method = data[2];
374 flags = data[3];
375
376 if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
377 /* Can't handle this compression method or unknown flag */
378 return GZIP_BAD;
379 }
380
381 /* Skip over time, xflags, OS code and all previous bytes */
382 len -= 10;
383 data += 10;
384
385 if(flags & EXTRA_FIELD) {
386 ssize_t extra_len;
387
388 if(len < 2)
389 return GZIP_UNDERFLOW;
390
391 extra_len = (data[1] << 8) | data[0];
392
393 if(len < (extra_len + 2))
394 return GZIP_UNDERFLOW;
395
396 len -= (extra_len + 2);
397 data += (extra_len + 2);
398 }
399
400 if(flags & ORIG_NAME) {
401 /* Skip over NUL-terminated file name */
402 while(len && *data) {
403 --len;
404 ++data;
405 }
406 if(!len || *data)
407 return GZIP_UNDERFLOW;
408
409 /* Skip over the NUL */
410 --len;
411 ++data;
412 }
413
414 if(flags & COMMENT) {
415 /* Skip over NUL-terminated comment */
416 while(len && *data) {
417 --len;
418 ++data;
419 }
420 if(!len || *data)
421 return GZIP_UNDERFLOW;
422
423 /* Skip over the NUL */
424 --len;
425 }
426
427 if(flags & HEAD_CRC) {
428 if(len < 2)
429 return GZIP_UNDERFLOW;
430
431 len -= 2;
432 }
433
434 *headerlen = totallen - len;
435 return GZIP_OK;
436}
437#endif
438
439static CURLcode gzip_unencode_write(struct Curl_easy *data,
440 struct contenc_writer *writer,
441 const char *buf, size_t nbytes)
442{
443 struct zlib_writer *zp = (struct zlib_writer *) writer;
444 z_stream *z = &zp->z; /* zlib state structure */
445
446 if(zp->zlib_init == ZLIB_INIT_GZIP) {
447 /* Let zlib handle the gzip decompression entirely */
448 z->next_in = (Bytef *) buf;
449 z->avail_in = (uInt) nbytes;
450 /* Now uncompress the data */
451 return inflate_stream(data, writer, ZLIB_INIT_GZIP);
452 }
453
454#ifndef OLD_ZLIB_SUPPORT
455 /* Support for old zlib versions is compiled away and we are running with
456 an old version, so return an error. */
457 return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
458
459#else
460 /* This next mess is to get around the potential case where there isn't
461 * enough data passed in to skip over the gzip header. If that happens, we
462 * malloc a block and copy what we have then wait for the next call. If
463 * there still isn't enough (this is definitely a worst-case scenario), we
464 * make the block bigger, copy the next part in and keep waiting.
465 *
466 * This is only required with zlib versions < 1.2.0.4 as newer versions
467 * can handle the gzip header themselves.
468 */
469
470 switch(zp->zlib_init) {
471 /* Skip over gzip header? */
472 case ZLIB_INIT:
473 {
474 /* Initial call state */
475 ssize_t hlen;
476
477 switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
478 case GZIP_OK:
479 z->next_in = (Bytef *) buf + hlen;
480 z->avail_in = (uInt) (nbytes - hlen);
481 zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
482 break;
483
484 case GZIP_UNDERFLOW:
485 /* We need more data so we can find the end of the gzip header. It's
486 * possible that the memory block we malloc here will never be freed if
487 * the transfer abruptly aborts after this point. Since it's unlikely
488 * that circumstances will be right for this code path to be followed in
489 * the first place, and it's even more unlikely for a transfer to fail
490 * immediately afterwards, it should seldom be a problem.
491 */
492 z->avail_in = (uInt) nbytes;
493 z->next_in = malloc(z->avail_in);
494 if(!z->next_in) {
495 return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
496 }
497 memcpy(z->next_in, buf, z->avail_in);
498 zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
499 /* We don't have any data to inflate yet */
500 return CURLE_OK;
501
502 case GZIP_BAD:
503 default:
504 return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
505 }
506
507 }
508 break;
509
510 case ZLIB_GZIP_HEADER:
511 {
512 /* Need more gzip header data state */
513 ssize_t hlen;
514 z->avail_in += (uInt) nbytes;
515 z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
516 if(!z->next_in) {
517 return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
518 }
519 /* Append the new block of data to the previous one */
520 memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
521
522 switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
523 case GZIP_OK:
524 /* This is the zlib stream data */
525 free(z->next_in);
526 /* Don't point into the malloced block since we just freed it */
527 z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
528 z->avail_in = (uInt) (z->avail_in - hlen);
529 zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
530 break;
531
532 case GZIP_UNDERFLOW:
533 /* We still don't have any data to inflate! */
534 return CURLE_OK;
535
536 case GZIP_BAD:
537 default:
538 return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
539 }
540
541 }
542 break;
543
544 case ZLIB_EXTERNAL_TRAILER:
545 z->next_in = (Bytef *) buf;
546 z->avail_in = (uInt) nbytes;
547 return process_trailer(data, zp);
548
549 case ZLIB_GZIP_INFLATING:
550 default:
551 /* Inflating stream state */
552 z->next_in = (Bytef *) buf;
553 z->avail_in = (uInt) nbytes;
554 break;
555 }
556
557 if(z->avail_in == 0) {
558 /* We don't have any data to inflate; wait until next time */
559 return CURLE_OK;
560 }
561
562 /* We've parsed the header, now uncompress the data */
563 return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
564#endif
565}
566
567static void gzip_close_writer(struct Curl_easy *data,
568 struct contenc_writer *writer)
569{
570 struct zlib_writer *zp = (struct zlib_writer *) writer;
571 z_stream *z = &zp->z; /* zlib state structure */
572
573 exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
574}
575
576static const struct content_encoding gzip_encoding = {
577 "gzip",
578 "x-gzip",
579 gzip_init_writer,
580 gzip_unencode_write,
581 gzip_close_writer,
582 sizeof(struct zlib_writer)
583};
584
585#endif /* HAVE_LIBZ */
586
587
588#ifdef HAVE_BROTLI
589/* Brotli writer. */
590struct brotli_writer {
591 struct contenc_writer super;
592 BrotliDecoderState *br; /* State structure for brotli. */
593};
594
595static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
596{
597 switch(be) {
598 case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
599 case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
600 case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
601 case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
602 case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
603 case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
604 case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
605 case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
606 case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
607 case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
608 case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
609 case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
610 case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
611 case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
612#ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY
613 case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
614#endif
615#ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET
616 case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
617#endif
618 case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
619 return CURLE_BAD_CONTENT_ENCODING;
620 case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
621 case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
622 case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
623 case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
624 case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
625 case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
626 return CURLE_OUT_OF_MEMORY;
627 default:
628 break;
629 }
630 return CURLE_WRITE_ERROR;
631}
632
633static CURLcode brotli_init_writer(struct Curl_easy *data,
634 struct contenc_writer *writer)
635{
636 struct brotli_writer *bp = (struct brotli_writer *) writer;
637 (void) data;
638
639 if(!writer->downstream)
640 return CURLE_WRITE_ERROR;
641
642 bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
643 return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
644}
645
646static CURLcode brotli_unencode_write(struct Curl_easy *data,
647 struct contenc_writer *writer,
648 const char *buf, size_t nbytes)
649{
650 struct brotli_writer *bp = (struct brotli_writer *) writer;
651 const uint8_t *src = (const uint8_t *) buf;
652 char *decomp;
653 uint8_t *dst;
654 size_t dstleft;
655 CURLcode result = CURLE_OK;
656 BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
657
658 if(!bp->br)
659 return CURLE_WRITE_ERROR; /* Stream already ended. */
660
661 decomp = malloc(DSIZ);
662 if(!decomp)
663 return CURLE_OUT_OF_MEMORY;
664
665 while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
666 result == CURLE_OK) {
667 dst = (uint8_t *) decomp;
668 dstleft = DSIZ;
669 r = BrotliDecoderDecompressStream(bp->br,
670 &nbytes, &src, &dstleft, &dst, NULL);
671 result = Curl_unencode_write(data, writer->downstream,
672 decomp, DSIZ - dstleft);
673 if(result)
674 break;
675 switch(r) {
676 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
677 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
678 break;
679 case BROTLI_DECODER_RESULT_SUCCESS:
680 BrotliDecoderDestroyInstance(bp->br);
681 bp->br = NULL;
682 if(nbytes)
683 result = CURLE_WRITE_ERROR;
684 break;
685 default:
686 result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
687 break;
688 }
689 }
690 free(decomp);
691 return result;
692}
693
694static void brotli_close_writer(struct Curl_easy *data,
695 struct contenc_writer *writer)
696{
697 struct brotli_writer *bp = (struct brotli_writer *) writer;
698
699 (void) data;
700
701 if(bp->br) {
702 BrotliDecoderDestroyInstance(bp->br);
703 bp->br = NULL;
704 }
705}
706
707static const struct content_encoding brotli_encoding = {
708 "br",
709 NULL,
710 brotli_init_writer,
711 brotli_unencode_write,
712 brotli_close_writer,
713 sizeof(struct brotli_writer)
714};
715#endif
716
717
718#ifdef HAVE_ZSTD
719/* Zstd writer. */
720struct zstd_writer {
721 struct contenc_writer super;
722 ZSTD_DStream *zds; /* State structure for zstd. */
723 void *decomp;
724};
725
726static CURLcode zstd_init_writer(struct Curl_easy *data,
727 struct contenc_writer *writer)
728{
729 struct zstd_writer *zp = (struct zstd_writer *) writer;
730
731 (void)data;
732
733 if(!writer->downstream)
734 return CURLE_WRITE_ERROR;
735
736 zp->zds = ZSTD_createDStream();
737 zp->decomp = NULL;
738 return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
739}
740
741static CURLcode zstd_unencode_write(struct Curl_easy *data,
742 struct contenc_writer *writer,
743 const char *buf, size_t nbytes)
744{
745 CURLcode result = CURLE_OK;
746 struct zstd_writer *zp = (struct zstd_writer *) writer;
747 ZSTD_inBuffer in;
748 ZSTD_outBuffer out;
749 size_t errorCode;
750
751 if(!zp->decomp) {
752 zp->decomp = malloc(DSIZ);
753 if(!zp->decomp)
754 return CURLE_OUT_OF_MEMORY;
755 }
756 in.pos = 0;
757 in.src = buf;
758 in.size = nbytes;
759
760 for(;;) {
761 out.pos = 0;
762 out.dst = zp->decomp;
763 out.size = DSIZ;
764
765 errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
766 if(ZSTD_isError(errorCode)) {
767 return CURLE_BAD_CONTENT_ENCODING;
768 }
769 if(out.pos > 0) {
770 result = Curl_unencode_write(data, writer->downstream,
771 zp->decomp, out.pos);
772 if(result)
773 break;
774 }
775 if((in.pos == nbytes) && (out.pos < out.size))
776 break;
777 }
778
779 return result;
780}
781
782static void zstd_close_writer(struct Curl_easy *data,
783 struct contenc_writer *writer)
784{
785 struct zstd_writer *zp = (struct zstd_writer *) writer;
786
787 (void)data;
788
789 if(zp->decomp) {
790 free(zp->decomp);
791 zp->decomp = NULL;
792 }
793 if(zp->zds) {
794 ZSTD_freeDStream(zp->zds);
795 zp->zds = NULL;
796 }
797}
798
799static const struct content_encoding zstd_encoding = {
800 "zstd",
801 NULL,
802 zstd_init_writer,
803 zstd_unencode_write,
804 zstd_close_writer,
805 sizeof(struct zstd_writer)
806};
807#endif
808
809
810/* Identity handler. */
811static CURLcode identity_init_writer(struct Curl_easy *data,
812 struct contenc_writer *writer)
813{
814 (void) data;
815 return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
816}
817
818static CURLcode identity_unencode_write(struct Curl_easy *data,
819 struct contenc_writer *writer,
820 const char *buf, size_t nbytes)
821{
822 return Curl_unencode_write(data, writer->downstream, buf, nbytes);
823}
824
825static void identity_close_writer(struct Curl_easy *data,
826 struct contenc_writer *writer)
827{
828 (void) data;
829 (void) writer;
830}
831
832static const struct content_encoding identity_encoding = {
833 "identity",
834 "none",
835 identity_init_writer,
836 identity_unencode_write,
837 identity_close_writer,
838 sizeof(struct contenc_writer)
839};
840
841
842/* supported content encodings table. */
843static const struct content_encoding * const encodings[] = {
844 &identity_encoding,
845#ifdef HAVE_LIBZ
846 &deflate_encoding,
847 &gzip_encoding,
848#endif
849#ifdef HAVE_BROTLI
850 &brotli_encoding,
851#endif
852#ifdef HAVE_ZSTD
853 &zstd_encoding,
854#endif
855 NULL
856};
857
858
859/* Return a list of comma-separated names of supported encodings. */
860char *Curl_all_content_encodings(void)
861{
862 size_t len = 0;
863 const struct content_encoding * const *cep;
864 const struct content_encoding *ce;
865 char *ace;
866
867 for(cep = encodings; *cep; cep++) {
868 ce = *cep;
869 if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
870 len += strlen(ce->name) + 2;
871 }
872
873 if(!len)
874 return strdup(CONTENT_ENCODING_DEFAULT);
875
876 ace = malloc(len);
877 if(ace) {
878 char *p = ace;
879 for(cep = encodings; *cep; cep++) {
880 ce = *cep;
881 if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
882 strcpy(p, ce->name);
883 p += strlen(p);
884 *p++ = ',';
885 *p++ = ' ';
886 }
887 }
888 p[-2] = '\0';
889 }
890
891 return ace;
892}
893
894
895/* Real client writer: no downstream. */
896static CURLcode client_init_writer(struct Curl_easy *data,
897 struct contenc_writer *writer)
898{
899 (void) data;
900 return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
901}
902
903static CURLcode client_unencode_write(struct Curl_easy *data,
904 struct contenc_writer *writer,
905 const char *buf, size_t nbytes)
906{
907 struct SingleRequest *k = &data->req;
908
909 (void) writer;
910
911 if(!nbytes || k->ignorebody)
912 return CURLE_OK;
913
914 return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes);
915}
916
917static void client_close_writer(struct Curl_easy *data,
918 struct contenc_writer *writer)
919{
920 (void) data;
921 (void) writer;
922}
923
924static const struct content_encoding client_encoding = {
925 NULL,
926 NULL,
927 client_init_writer,
928 client_unencode_write,
929 client_close_writer,
930 sizeof(struct contenc_writer)
931};
932
933
934/* Deferred error dummy writer. */
935static CURLcode error_init_writer(struct Curl_easy *data,
936 struct contenc_writer *writer)
937{
938 (void) data;
939 return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
940}
941
942static CURLcode error_unencode_write(struct Curl_easy *data,
943 struct contenc_writer *writer,
944 const char *buf, size_t nbytes)
945{
946 char *all = Curl_all_content_encodings();
947
948 (void) writer;
949 (void) buf;
950 (void) nbytes;
951
952 if(!all)
953 return CURLE_OUT_OF_MEMORY;
954 failf(data, "Unrecognized content encoding type. "
955 "libcurl understands %s content encodings.", all);
956 free(all);
957 return CURLE_BAD_CONTENT_ENCODING;
958}
959
960static void error_close_writer(struct Curl_easy *data,
961 struct contenc_writer *writer)
962{
963 (void) data;
964 (void) writer;
965}
966
967static const struct content_encoding error_encoding = {
968 NULL,
969 NULL,
970 error_init_writer,
971 error_unencode_write,
972 error_close_writer,
973 sizeof(struct contenc_writer)
974};
975
976/* Create an unencoding writer stage using the given handler. */
977static struct contenc_writer *
978new_unencoding_writer(struct Curl_easy *data,
979 const struct content_encoding *handler,
980 struct contenc_writer *downstream)
981{
982 struct contenc_writer *writer;
983
984 DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer));
985 writer = (struct contenc_writer *) calloc(1, handler->writersize);
986
987 if(writer) {
988 writer->handler = handler;
989 writer->downstream = downstream;
990 if(handler->init_writer(data, writer)) {
991 free(writer);
992 writer = NULL;
993 }
994 }
995
996 return writer;
997}
998
999/* Write data using an unencoding writer stack. "nbytes" is not
1000 allowed to be 0. */
1001CURLcode Curl_unencode_write(struct Curl_easy *data,
1002 struct contenc_writer *writer,
1003 const char *buf, size_t nbytes)
1004{
1005 if(!nbytes)
1006 return CURLE_OK;
1007 return writer->handler->unencode_write(data, writer, buf, nbytes);
1008}
1009
1010/* Close and clean-up the connection's writer stack. */
1011void Curl_unencode_cleanup(struct Curl_easy *data)
1012{
1013 struct SingleRequest *k = &data->req;
1014 struct contenc_writer *writer = k->writer_stack;
1015
1016 while(writer) {
1017 k->writer_stack = writer->downstream;
1018 writer->handler->close_writer(data, writer);
1019 free(writer);
1020 writer = k->writer_stack;
1021 }
1022}
1023
1024/* Find the content encoding by name. */
1025static const struct content_encoding *find_encoding(const char *name,
1026 size_t len)
1027{
1028 const struct content_encoding * const *cep;
1029
1030 for(cep = encodings; *cep; cep++) {
1031 const struct content_encoding *ce = *cep;
1032 if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
1033 (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
1034 return ce;
1035 }
1036 return NULL;
1037}
1038
1039/* allow no more than 5 "chained" compression steps */
1040#define MAX_ENCODE_STACK 5
1041
1042/* Set-up the unencoding stack from the Content-Encoding header value.
1043 * See RFC 7231 section 3.1.2.2. */
1044CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
1045 const char *enclist, int maybechunked)
1046{
1047 struct SingleRequest *k = &data->req;
1048 int counter = 0;
1049
1050 do {
1051 const char *name;
1052 size_t namelen;
1053
1054 /* Parse a single encoding name. */
1055 while(ISBLANK(*enclist) || *enclist == ',')
1056 enclist++;
1057
1058 name = enclist;
1059
1060 for(namelen = 0; *enclist && *enclist != ','; enclist++)
1061 if(!ISSPACE(*enclist))
1062 namelen = enclist - name + 1;
1063
1064 /* Special case: chunked encoding is handled at the reader level. */
1065 if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
1066 k->chunk = TRUE; /* chunks coming our way. */
1067 Curl_httpchunk_init(data); /* init our chunky engine. */
1068 }
1069 else if(namelen) {
1070 const struct content_encoding *encoding = find_encoding(name, namelen);
1071 struct contenc_writer *writer;
1072
1073 if(!k->writer_stack) {
1074 k->writer_stack = new_unencoding_writer(data, &client_encoding, NULL);
1075
1076 if(!k->writer_stack)
1077 return CURLE_OUT_OF_MEMORY;
1078 }
1079
1080 if(!encoding)
1081 encoding = &error_encoding; /* Defer error at stack use. */
1082
1083 if(++counter >= MAX_ENCODE_STACK) {
1084 failf(data, "Reject response due to %u content encodings",
1085 counter);
1086 return CURLE_BAD_CONTENT_ENCODING;
1087 }
1088 /* Stack the unencoding stage. */
1089 writer = new_unencoding_writer(data, encoding, k->writer_stack);
1090 if(!writer)
1091 return CURLE_OUT_OF_MEMORY;
1092 k->writer_stack = writer;
1093 }
1094 } while(*enclist);
1095
1096 return CURLE_OK;
1097}
1098
1099#else
1100/* Stubs for builds without HTTP. */
1101CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
1102 const char *enclist, int maybechunked)
1103{
1104 (void) data;
1105 (void) enclist;
1106 (void) maybechunked;
1107 return CURLE_NOT_BUILT_IN;
1108}
1109
1110CURLcode Curl_unencode_write(struct Curl_easy *data,
1111 struct contenc_writer *writer,
1112 const char *buf, size_t nbytes)
1113{
1114 (void) data;
1115 (void) writer;
1116 (void) buf;
1117 (void) nbytes;
1118 return CURLE_NOT_BUILT_IN;
1119}
1120
1121void Curl_unencode_cleanup(struct Curl_easy *data)
1122{
1123 (void) data;
1124}
1125
1126char *Curl_all_content_encodings(void)
1127{
1128 return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */
1129}
1130
1131#endif /* CURL_DISABLE_HTTP */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette