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