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