1 | /***************************************************************************
|
---|
2 | * _ _ ____ _
|
---|
3 | * Project ___| | | | _ \| |
|
---|
4 | * / __| | | | |_) | |
|
---|
5 | * | (__| |_| | _ <| |___
|
---|
6 | * \___|\___/|_| \_\_____|
|
---|
7 | *
|
---|
8 | * Copyright (C) 1998 - 2011, 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 | #ifdef HAVE_LIBZ
|
---|
26 |
|
---|
27 | #include "urldata.h"
|
---|
28 | #include <curl/curl.h>
|
---|
29 | #include "sendf.h"
|
---|
30 | #include "content_encoding.h"
|
---|
31 | #include "curl_memory.h"
|
---|
32 |
|
---|
33 | #include "memdebug.h"
|
---|
34 |
|
---|
35 | /* Comment this out if zlib is always going to be at least ver. 1.2.0.4
|
---|
36 | (doing so will reduce code size slightly). */
|
---|
37 | #define OLD_ZLIB_SUPPORT 1
|
---|
38 |
|
---|
39 | #define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
|
---|
40 |
|
---|
41 | #define GZIP_MAGIC_0 0x1f
|
---|
42 | #define GZIP_MAGIC_1 0x8b
|
---|
43 |
|
---|
44 | /* gzip flag byte */
|
---|
45 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
|
---|
46 | #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
|
---|
47 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
---|
48 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
---|
49 | #define COMMENT 0x10 /* bit 4 set: file comment present */
|
---|
50 | #define RESERVED 0xE0 /* bits 5..7: reserved */
|
---|
51 |
|
---|
52 | static voidpf
|
---|
53 | zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
|
---|
54 | {
|
---|
55 | (void) opaque;
|
---|
56 | /* not a typo, keep it calloc() */
|
---|
57 | return (voidpf) calloc(items, size);
|
---|
58 | }
|
---|
59 |
|
---|
60 | static void
|
---|
61 | zfree_cb(voidpf opaque, voidpf ptr)
|
---|
62 | {
|
---|
63 | (void) opaque;
|
---|
64 | free(ptr);
|
---|
65 | }
|
---|
66 |
|
---|
67 | static CURLcode
|
---|
68 | process_zlib_error(struct connectdata *conn, z_stream *z)
|
---|
69 | {
|
---|
70 | struct SessionHandle *data = conn->data;
|
---|
71 | if(z->msg)
|
---|
72 | failf (data, "Error while processing content unencoding: %s",
|
---|
73 | z->msg);
|
---|
74 | else
|
---|
75 | failf (data, "Error while processing content unencoding: "
|
---|
76 | "Unknown failure within decompression software.");
|
---|
77 |
|
---|
78 | return CURLE_BAD_CONTENT_ENCODING;
|
---|
79 | }
|
---|
80 |
|
---|
81 | static CURLcode
|
---|
82 | exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
|
---|
83 | {
|
---|
84 | inflateEnd(z);
|
---|
85 | *zlib_init = ZLIB_UNINIT;
|
---|
86 | return result;
|
---|
87 | }
|
---|
88 |
|
---|
89 | static CURLcode
|
---|
90 | inflate_stream(struct connectdata *conn,
|
---|
91 | struct SingleRequest *k)
|
---|
92 | {
|
---|
93 | int allow_restart = 1;
|
---|
94 | z_stream *z = &k->z; /* zlib state structure */
|
---|
95 | uInt nread = z->avail_in;
|
---|
96 | Bytef *orig_in = z->next_in;
|
---|
97 | int status; /* zlib status */
|
---|
98 | CURLcode result = CURLE_OK; /* Curl_client_write status */
|
---|
99 | char *decomp; /* Put the decompressed data here. */
|
---|
100 |
|
---|
101 | /* Dynamically allocate a buffer for decompression because it's uncommonly
|
---|
102 | large to hold on the stack */
|
---|
103 | decomp = malloc(DSIZ);
|
---|
104 | if(decomp == NULL) {
|
---|
105 | return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
|
---|
106 | }
|
---|
107 |
|
---|
108 | /* because the buffer size is fixed, iteratively decompress and transfer to
|
---|
109 | the client via client_write. */
|
---|
110 | for(;;) {
|
---|
111 | /* (re)set buffer for decompressed output for every iteration */
|
---|
112 | z->next_out = (Bytef *)decomp;
|
---|
113 | z->avail_out = DSIZ;
|
---|
114 |
|
---|
115 | status = inflate(z, Z_SYNC_FLUSH);
|
---|
116 | if(status == Z_OK || status == Z_STREAM_END) {
|
---|
117 | allow_restart = 0;
|
---|
118 | if((DSIZ - z->avail_out) && (!k->ignorebody)) {
|
---|
119 | result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
|
---|
120 | DSIZ - z->avail_out);
|
---|
121 | /* if !CURLE_OK, clean up, return */
|
---|
122 | if(result) {
|
---|
123 | free(decomp);
|
---|
124 | return exit_zlib(z, &k->zlib_init, result);
|
---|
125 | }
|
---|
126 | }
|
---|
127 |
|
---|
128 | /* Done? clean up, return */
|
---|
129 | if(status == Z_STREAM_END) {
|
---|
130 | free(decomp);
|
---|
131 | if(inflateEnd(z) == Z_OK)
|
---|
132 | return exit_zlib(z, &k->zlib_init, result);
|
---|
133 | else
|
---|
134 | return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
|
---|
135 | }
|
---|
136 |
|
---|
137 | /* Done with these bytes, exit */
|
---|
138 |
|
---|
139 | /* status is always Z_OK at this point! */
|
---|
140 | if(z->avail_in == 0) {
|
---|
141 | free(decomp);
|
---|
142 | return result;
|
---|
143 | }
|
---|
144 | }
|
---|
145 | else if(allow_restart && status == Z_DATA_ERROR) {
|
---|
146 | /* some servers seem to not generate zlib headers, so this is an attempt
|
---|
147 | to fix and continue anyway */
|
---|
148 |
|
---|
149 | (void) inflateEnd(z); /* don't care about the return code */
|
---|
150 | if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
---|
151 | free(decomp);
|
---|
152 | return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
|
---|
153 | }
|
---|
154 | z->next_in = orig_in;
|
---|
155 | z->avail_in = nread;
|
---|
156 | allow_restart = 0;
|
---|
157 | continue;
|
---|
158 | }
|
---|
159 | else { /* Error; exit loop, handle below */
|
---|
160 | free(decomp);
|
---|
161 | return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
|
---|
162 | }
|
---|
163 | }
|
---|
164 | /* Will never get here */
|
---|
165 | }
|
---|
166 |
|
---|
167 | CURLcode
|
---|
168 | Curl_unencode_deflate_write(struct connectdata *conn,
|
---|
169 | struct SingleRequest *k,
|
---|
170 | ssize_t nread)
|
---|
171 | {
|
---|
172 | z_stream *z = &k->z; /* zlib state structure */
|
---|
173 |
|
---|
174 | /* Initialize zlib? */
|
---|
175 | if(k->zlib_init == ZLIB_UNINIT) {
|
---|
176 | memset(z, 0, sizeof(z_stream));
|
---|
177 | z->zalloc = (alloc_func)zalloc_cb;
|
---|
178 | z->zfree = (free_func)zfree_cb;
|
---|
179 |
|
---|
180 | if(inflateInit(z) != Z_OK)
|
---|
181 | return process_zlib_error(conn, z);
|
---|
182 | k->zlib_init = ZLIB_INIT;
|
---|
183 | }
|
---|
184 |
|
---|
185 | /* Set the compressed input when this function is called */
|
---|
186 | z->next_in = (Bytef *)k->str;
|
---|
187 | z->avail_in = (uInt)nread;
|
---|
188 |
|
---|
189 | /* Now uncompress the data */
|
---|
190 | return inflate_stream(conn, k);
|
---|
191 | }
|
---|
192 |
|
---|
193 | #ifdef OLD_ZLIB_SUPPORT
|
---|
194 | /* Skip over the gzip header */
|
---|
195 | static enum {
|
---|
196 | GZIP_OK,
|
---|
197 | GZIP_BAD,
|
---|
198 | GZIP_UNDERFLOW
|
---|
199 | } check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
|
---|
200 | {
|
---|
201 | int method, flags;
|
---|
202 | const ssize_t totallen = len;
|
---|
203 |
|
---|
204 | /* The shortest header is 10 bytes */
|
---|
205 | if(len < 10)
|
---|
206 | return GZIP_UNDERFLOW;
|
---|
207 |
|
---|
208 | if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
|
---|
209 | return GZIP_BAD;
|
---|
210 |
|
---|
211 | method = data[2];
|
---|
212 | flags = data[3];
|
---|
213 |
|
---|
214 | if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
|
---|
215 | /* Can't handle this compression method or unknown flag */
|
---|
216 | return GZIP_BAD;
|
---|
217 | }
|
---|
218 |
|
---|
219 | /* Skip over time, xflags, OS code and all previous bytes */
|
---|
220 | len -= 10;
|
---|
221 | data += 10;
|
---|
222 |
|
---|
223 | if(flags & EXTRA_FIELD) {
|
---|
224 | ssize_t extra_len;
|
---|
225 |
|
---|
226 | if(len < 2)
|
---|
227 | return GZIP_UNDERFLOW;
|
---|
228 |
|
---|
229 | extra_len = (data[1] << 8) | data[0];
|
---|
230 |
|
---|
231 | if(len < (extra_len+2))
|
---|
232 | return GZIP_UNDERFLOW;
|
---|
233 |
|
---|
234 | len -= (extra_len + 2);
|
---|
235 | data += (extra_len + 2);
|
---|
236 | }
|
---|
237 |
|
---|
238 | if(flags & ORIG_NAME) {
|
---|
239 | /* Skip over NUL-terminated file name */
|
---|
240 | while(len && *data) {
|
---|
241 | --len;
|
---|
242 | ++data;
|
---|
243 | }
|
---|
244 | if(!len || *data)
|
---|
245 | return GZIP_UNDERFLOW;
|
---|
246 |
|
---|
247 | /* Skip over the NUL */
|
---|
248 | --len;
|
---|
249 | ++data;
|
---|
250 | }
|
---|
251 |
|
---|
252 | if(flags & COMMENT) {
|
---|
253 | /* Skip over NUL-terminated comment */
|
---|
254 | while(len && *data) {
|
---|
255 | --len;
|
---|
256 | ++data;
|
---|
257 | }
|
---|
258 | if(!len || *data)
|
---|
259 | return GZIP_UNDERFLOW;
|
---|
260 |
|
---|
261 | /* Skip over the NUL */
|
---|
262 | --len;
|
---|
263 | }
|
---|
264 |
|
---|
265 | if(flags & HEAD_CRC) {
|
---|
266 | if(len < 2)
|
---|
267 | return GZIP_UNDERFLOW;
|
---|
268 |
|
---|
269 | len -= 2;
|
---|
270 | }
|
---|
271 |
|
---|
272 | *headerlen = totallen - len;
|
---|
273 | return GZIP_OK;
|
---|
274 | }
|
---|
275 | #endif
|
---|
276 |
|
---|
277 | CURLcode
|
---|
278 | Curl_unencode_gzip_write(struct connectdata *conn,
|
---|
279 | struct SingleRequest *k,
|
---|
280 | ssize_t nread)
|
---|
281 | {
|
---|
282 | z_stream *z = &k->z; /* zlib state structure */
|
---|
283 |
|
---|
284 | /* Initialize zlib? */
|
---|
285 | if(k->zlib_init == ZLIB_UNINIT) {
|
---|
286 | memset(z, 0, sizeof(z_stream));
|
---|
287 | z->zalloc = (alloc_func)zalloc_cb;
|
---|
288 | z->zfree = (free_func)zfree_cb;
|
---|
289 |
|
---|
290 | if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
|
---|
291 | /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
|
---|
292 | if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
|
---|
293 | return process_zlib_error(conn, z);
|
---|
294 | }
|
---|
295 | k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
---|
296 | }
|
---|
297 | else {
|
---|
298 | /* we must parse the gzip header ourselves */
|
---|
299 | if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
---|
300 | return process_zlib_error(conn, z);
|
---|
301 | }
|
---|
302 | k->zlib_init = ZLIB_INIT; /* Initial call state */
|
---|
303 | }
|
---|
304 | }
|
---|
305 |
|
---|
306 | if(k->zlib_init == ZLIB_INIT_GZIP) {
|
---|
307 | /* Let zlib handle the gzip decompression entirely */
|
---|
308 | z->next_in = (Bytef *)k->str;
|
---|
309 | z->avail_in = (uInt)nread;
|
---|
310 | /* Now uncompress the data */
|
---|
311 | return inflate_stream(conn, k);
|
---|
312 | }
|
---|
313 |
|
---|
314 | #ifndef OLD_ZLIB_SUPPORT
|
---|
315 | /* Support for old zlib versions is compiled away and we are running with
|
---|
316 | an old version, so return an error. */
|
---|
317 | return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);
|
---|
318 |
|
---|
319 | #else
|
---|
320 | /* This next mess is to get around the potential case where there isn't
|
---|
321 | * enough data passed in to skip over the gzip header. If that happens, we
|
---|
322 | * malloc a block and copy what we have then wait for the next call. If
|
---|
323 | * there still isn't enough (this is definitely a worst-case scenario), we
|
---|
324 | * make the block bigger, copy the next part in and keep waiting.
|
---|
325 | *
|
---|
326 | * This is only required with zlib versions < 1.2.0.4 as newer versions
|
---|
327 | * can handle the gzip header themselves.
|
---|
328 | */
|
---|
329 |
|
---|
330 | switch (k->zlib_init) {
|
---|
331 | /* Skip over gzip header? */
|
---|
332 | case ZLIB_INIT:
|
---|
333 | {
|
---|
334 | /* Initial call state */
|
---|
335 | ssize_t hlen;
|
---|
336 |
|
---|
337 | switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
|
---|
338 | case GZIP_OK:
|
---|
339 | z->next_in = (Bytef *)k->str + hlen;
|
---|
340 | z->avail_in = (uInt)(nread - hlen);
|
---|
341 | k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
|
---|
342 | break;
|
---|
343 |
|
---|
344 | case GZIP_UNDERFLOW:
|
---|
345 | /* We need more data so we can find the end of the gzip header. It's
|
---|
346 | * possible that the memory block we malloc here will never be freed if
|
---|
347 | * the transfer abruptly aborts after this point. Since it's unlikely
|
---|
348 | * that circumstances will be right for this code path to be followed in
|
---|
349 | * the first place, and it's even more unlikely for a transfer to fail
|
---|
350 | * immediately afterwards, it should seldom be a problem.
|
---|
351 | */
|
---|
352 | z->avail_in = (uInt)nread;
|
---|
353 | z->next_in = malloc(z->avail_in);
|
---|
354 | if(z->next_in == NULL) {
|
---|
355 | return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
|
---|
356 | }
|
---|
357 | memcpy(z->next_in, k->str, z->avail_in);
|
---|
358 | k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
|
---|
359 | /* We don't have any data to inflate yet */
|
---|
360 | return CURLE_OK;
|
---|
361 |
|
---|
362 | case GZIP_BAD:
|
---|
363 | default:
|
---|
364 | return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
|
---|
365 | }
|
---|
366 |
|
---|
367 | }
|
---|
368 | break;
|
---|
369 |
|
---|
370 | case ZLIB_GZIP_HEADER:
|
---|
371 | {
|
---|
372 | /* Need more gzip header data state */
|
---|
373 | ssize_t hlen;
|
---|
374 | unsigned char *oldblock = z->next_in;
|
---|
375 |
|
---|
376 | z->avail_in += (uInt)nread;
|
---|
377 | z->next_in = realloc(z->next_in, z->avail_in);
|
---|
378 | if(z->next_in == NULL) {
|
---|
379 | free(oldblock);
|
---|
380 | return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
|
---|
381 | }
|
---|
382 | /* Append the new block of data to the previous one */
|
---|
383 | memcpy(z->next_in + z->avail_in - nread, k->str, nread);
|
---|
384 |
|
---|
385 | switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
|
---|
386 | case GZIP_OK:
|
---|
387 | /* This is the zlib stream data */
|
---|
388 | free(z->next_in);
|
---|
389 | /* Don't point into the malloced block since we just freed it */
|
---|
390 | z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
|
---|
391 | z->avail_in = (uInt)(z->avail_in - hlen);
|
---|
392 | k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
|
---|
393 | break;
|
---|
394 |
|
---|
395 | case GZIP_UNDERFLOW:
|
---|
396 | /* We still don't have any data to inflate! */
|
---|
397 | return CURLE_OK;
|
---|
398 |
|
---|
399 | case GZIP_BAD:
|
---|
400 | default:
|
---|
401 | free(z->next_in);
|
---|
402 | return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
|
---|
403 | }
|
---|
404 |
|
---|
405 | }
|
---|
406 | break;
|
---|
407 |
|
---|
408 | case ZLIB_GZIP_INFLATING:
|
---|
409 | default:
|
---|
410 | /* Inflating stream state */
|
---|
411 | z->next_in = (Bytef *)k->str;
|
---|
412 | z->avail_in = (uInt)nread;
|
---|
413 | break;
|
---|
414 | }
|
---|
415 |
|
---|
416 | if(z->avail_in == 0) {
|
---|
417 | /* We don't have any data to inflate; wait until next time */
|
---|
418 | return CURLE_OK;
|
---|
419 | }
|
---|
420 |
|
---|
421 | /* We've parsed the header, now uncompress the data */
|
---|
422 | return inflate_stream(conn, k);
|
---|
423 | #endif
|
---|
424 | }
|
---|
425 |
|
---|
426 | void Curl_unencode_cleanup(struct connectdata *conn)
|
---|
427 | {
|
---|
428 | struct SessionHandle *data = conn->data;
|
---|
429 | struct SingleRequest *k = &data->req;
|
---|
430 | z_stream *z = &k->z;
|
---|
431 | if(k->zlib_init != ZLIB_UNINIT)
|
---|
432 | (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
|
---|
433 | }
|
---|
434 |
|
---|
435 | #endif /* HAVE_LIBZ */
|
---|