1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: content_encoding.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
32 #include <curl/curl.h>
34 #include "content_encoding.h"
39 /* Comment this out if zlib is always going to be at least ver. 1.2.0.4
40 (doing so will reduce code size slightly). */
41 #define OLD_ZLIB_SUPPORT 1
43 #define DSIZ 0x10000 /* buffer size for decompressed data */
45 #define GZIP_MAGIC_0 0x1f
46 #define GZIP_MAGIC_1 0x8b
49 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
50 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
51 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
52 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
53 #define COMMENT 0x10 /* bit 4 set: file comment present */
54 #define RESERVED 0xE0 /* bits 5..7: reserved */
57 ZLIB_UNINIT
, /* uninitialized */
58 ZLIB_INIT
, /* initialized */
59 ZLIB_GZIP_HEADER
, /* reading gzip header */
60 ZLIB_GZIP_INFLATING
, /* inflating gzip stream */
61 ZLIB_INIT_GZIP
/* initialized in transparent gzip mode */
65 process_zlib_error(struct connectdata
*conn
, z_stream
*z
)
67 struct SessionHandle
*data
= conn
->data
;
69 failf (data
, "Error while processing content unencoding: %s",
72 failf (data
, "Error while processing content unencoding: "
73 "Unknown failure within decompression software.");
75 return CURLE_BAD_CONTENT_ENCODING
;
79 exit_zlib(z_stream
*z
, bool *zlib_init
, CURLcode result
)
82 *zlib_init
= ZLIB_UNINIT
;
87 inflate_stream(struct connectdata
*conn
,
88 struct Curl_transfer_keeper
*k
)
90 int allow_restart
= 1;
91 z_stream
*z
= &k
->z
; /* zlib state structure */
92 uInt nread
= z
->avail_in
;
93 Bytef
*orig_in
= z
->next_in
;
94 int status
; /* zlib status */
95 CURLcode result
= CURLE_OK
; /* Curl_client_write status */
96 char *decomp
; /* Put the decompressed data here. */
98 /* Dynamically allocate a buffer for decompression because it's uncommonly
99 large to hold on the stack */
100 decomp
= (char*)malloc(DSIZ
);
101 if (decomp
== NULL
) {
102 return exit_zlib(z
, &k
->zlib_init
, CURLE_OUT_OF_MEMORY
);
105 /* because the buffer size is fixed, iteratively decompress and transfer to
106 the client via client_write. */
108 /* (re)set buffer for decompressed output for every iteration */
109 z
->next_out
= (Bytef
*)decomp
;
112 status
= inflate(z
, Z_SYNC_FLUSH
);
113 if (status
== Z_OK
|| status
== Z_STREAM_END
) {
115 if(DSIZ
- z
->avail_out
) {
116 result
= Curl_client_write(conn
, CLIENTWRITE_BODY
, decomp
,
117 DSIZ
- z
->avail_out
);
118 /* if !CURLE_OK, clean up, return */
121 return exit_zlib(z
, &k
->zlib_init
, result
);
125 /* Done? clean up, return */
126 if (status
== Z_STREAM_END
) {
128 if (inflateEnd(z
) == Z_OK
)
129 return exit_zlib(z
, &k
->zlib_init
, result
);
131 return exit_zlib(z
, &k
->zlib_init
, process_zlib_error(conn
, z
));
134 /* Done with these bytes, exit */
135 if (status
== Z_OK
&& z
->avail_in
== 0) {
140 else if (allow_restart
&& status
== Z_DATA_ERROR
) {
141 /* some servers seem to not generate zlib headers, so this is an attempt
142 to fix and continue anyway */
145 if (inflateInit2(z
, -MAX_WBITS
) != Z_OK
) {
146 return process_zlib_error(conn
, z
);
148 z
->next_in
= orig_in
;
153 else { /* Error; exit loop, handle below */
155 return exit_zlib(z
, &k
->zlib_init
, process_zlib_error(conn
, z
));
158 /* Will never get here */
162 Curl_unencode_deflate_write(struct connectdata
*conn
,
163 struct Curl_transfer_keeper
*k
,
166 z_stream
*z
= &k
->z
; /* zlib state structure */
168 /* Initialize zlib? */
169 if (k
->zlib_init
== ZLIB_UNINIT
) {
170 z
->zalloc
= (alloc_func
)Z_NULL
;
171 z
->zfree
= (free_func
)Z_NULL
;
175 if (inflateInit(z
) != Z_OK
)
176 return process_zlib_error(conn
, z
);
177 k
->zlib_init
= ZLIB_INIT
;
180 /* Set the compressed input when this function is called */
181 z
->next_in
= (Bytef
*)k
->str
;
182 z
->avail_in
= (uInt
)nread
;
184 /* Now uncompress the data */
185 return inflate_stream(conn
, k
);
188 #ifdef OLD_ZLIB_SUPPORT
189 /* Skip over the gzip header */
194 } check_gzip_header(unsigned char const *data
, ssize_t len
, ssize_t
*headerlen
)
197 const ssize_t totallen
= len
;
199 /* The shortest header is 10 bytes */
201 return GZIP_UNDERFLOW
;
203 if ((data
[0] != GZIP_MAGIC_0
) || (data
[1] != GZIP_MAGIC_1
))
209 if (method
!= Z_DEFLATED
|| (flags
& RESERVED
) != 0) {
210 /* Can't handle this compression method or unknown flag */
214 /* Skip over time, xflags, OS code and all previous bytes */
218 if (flags
& EXTRA_FIELD
) {
222 return GZIP_UNDERFLOW
;
224 extra_len
= (data
[1] << 8) | data
[0];
226 if (len
< (extra_len
+2))
227 return GZIP_UNDERFLOW
;
229 len
-= (extra_len
+ 2);
230 data
+= (extra_len
+ 2);
233 if (flags
& ORIG_NAME
) {
234 /* Skip over NUL-terminated file name */
235 while (len
&& *data
) {
240 return GZIP_UNDERFLOW
;
242 /* Skip over the NUL */
247 if (flags
& COMMENT
) {
248 /* Skip over NUL-terminated comment */
249 while (len
&& *data
) {
254 return GZIP_UNDERFLOW
;
256 /* Skip over the NUL */
261 if (flags
& HEAD_CRC
) {
263 return GZIP_UNDERFLOW
;
269 *headerlen
= totallen
- len
;
275 Curl_unencode_gzip_write(struct connectdata
*conn
,
276 struct Curl_transfer_keeper
*k
,
279 z_stream
*z
= &k
->z
; /* zlib state structure */
281 /* Initialize zlib? */
282 if (k
->zlib_init
== ZLIB_UNINIT
) {
283 z
->zalloc
= (alloc_func
)Z_NULL
;
284 z
->zfree
= (free_func
)Z_NULL
;
289 if (strcmp(zlibVersion(), "1.2.0.4") >= 0) {
290 /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
291 if (inflateInit2(z
, MAX_WBITS
+32) != Z_OK
) {
292 return process_zlib_error(conn
, z
);
294 k
->zlib_init
= ZLIB_INIT_GZIP
; /* Transparent gzip decompress state */
297 /* we must parse the gzip header ourselves */
298 if (inflateInit2(z
, -MAX_WBITS
) != Z_OK
) {
299 return process_zlib_error(conn
, z
);
301 k
->zlib_init
= ZLIB_INIT
; /* Initial call state */
305 if (k
->zlib_init
== ZLIB_INIT_GZIP
) {
306 /* Let zlib handle the gzip decompression entirely */
307 z
->next_in
= (Bytef
*)k
->str
;
308 z
->avail_in
= (uInt
)nread
;
309 /* Now uncompress the data */
310 return inflate_stream(conn
, k
);
313 #ifndef OLD_ZLIB_SUPPORT
314 /* Support for old zlib versions is compiled away and we are running with
315 an old version, so return an error. */
316 return exit_zlib(z
, &k
->zlib_init
, CURLE_FUNCTION_NOT_FOUND
);
319 /* This next mess is to get around the potential case where there isn't
320 * enough data passed in to skip over the gzip header. If that happens, we
321 * malloc a block and copy what we have then wait for the next call. If
322 * there still isn't enough (this is definitely a worst-case scenario), we
323 * make the block bigger, copy the next part in and keep waiting.
325 * This is only required with zlib versions < 1.2.0.4 as newer versions
326 * can handle the gzip header themselves.
329 switch (k
->zlib_init
) {
330 /* Skip over gzip header? */
333 /* Initial call state */
336 switch (check_gzip_header((unsigned char *)k
->str
, nread
, &hlen
)) {
338 z
->next_in
= (Bytef
*)k
->str
+ hlen
;
339 z
->avail_in
= (uInt
)(nread
- hlen
);
340 k
->zlib_init
= ZLIB_GZIP_INFLATING
; /* Inflating stream state */
344 /* We need more data so we can find the end of the gzip header. It's
345 * possible that the memory block we malloc here will never be freed if
346 * the transfer abruptly aborts after this point. Since it's unlikely
347 * that circumstances will be right for this code path to be followed in
348 * the first place, and it's even more unlikely for a transfer to fail
349 * immediately afterwards, it should seldom be a problem.
351 z
->avail_in
= (uInt
)nread
;
352 z
->next_in
= malloc(z
->avail_in
);
353 if (z
->next_in
== NULL
) {
354 return exit_zlib(z
, &k
->zlib_init
, CURLE_OUT_OF_MEMORY
);
356 memcpy(z
->next_in
, k
->str
, z
->avail_in
);
357 k
->zlib_init
= ZLIB_GZIP_HEADER
; /* Need more gzip header data state */
358 /* We don't have any data to inflate yet */
363 return exit_zlib(z
, &k
->zlib_init
, process_zlib_error(conn
, z
));
369 case ZLIB_GZIP_HEADER
:
371 /* Need more gzip header data state */
373 unsigned char *oldblock
= z
->next_in
;
375 z
->avail_in
+= nread
;
376 z
->next_in
= realloc(z
->next_in
, z
->avail_in
);
377 if (z
->next_in
== NULL
) {
379 return exit_zlib(z
, &k
->zlib_init
, CURLE_OUT_OF_MEMORY
);
381 /* Append the new block of data to the previous one */
382 memcpy(z
->next_in
+ z
->avail_in
- nread
, k
->str
, nread
);
384 switch (check_gzip_header(z
->next_in
, z
->avail_in
, &hlen
)) {
386 /* This is the zlib stream data */
388 /* Don't point into the malloced block since we just freed it */
389 z
->next_in
= (Bytef
*)k
->str
+ hlen
+ nread
- z
->avail_in
;
390 z
->avail_in
= (uInt
)(z
->avail_in
- hlen
);
391 k
->zlib_init
= ZLIB_GZIP_INFLATING
; /* Inflating stream state */
395 /* We still don't have any data to inflate! */
401 return exit_zlib(z
, &k
->zlib_init
, process_zlib_error(conn
, z
));
407 case ZLIB_GZIP_INFLATING
:
409 /* Inflating stream state */
410 z
->next_in
= (Bytef
*)k
->str
;
411 z
->avail_in
= (uInt
)nread
;
415 if (z
->avail_in
== 0) {
416 /* We don't have any data to inflate; wait until next time */
420 /* We've parsed the header, now uncompress the data */
421 return inflate_stream(conn
, k
);
424 #endif /* HAVE_LIBZ */