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