2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
19 #define HTTP_WANT_ZLIB
22 #include "php_http_api.h"
23 #include "php_http_encoding_api.h"
24 #include "php_http_send_api.h"
25 #include "php_http_headers_api.h"
27 ZEND_EXTERN_MODULE_GLOBALS(http
);
30 PHP_MINIT_FUNCTION(http_encoding
)
32 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF
);
33 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN
);
34 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX
);
35 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB
);
36 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP
);
37 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW
);
38 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF
);
39 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT
);
40 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF
);
41 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE
);
42 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED
);
47 static inline int eol_match(char **line
, int *eol_len
)
51 while (0x20 == *ptr
) ++ptr
;
53 if (ptr
== http_locate_eol(*line
, eol_len
)) {
61 /* {{{ char *http_encoding_dechunk(char *, size_t, char **, size_t *) */
62 PHP_HTTP_API
const char *_http_encoding_dechunk(const char *encoded
, size_t encoded_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
66 const char *e_ptr
= encoded
;
69 *decoded
= ecalloc(1, encoded_len
);
71 while ((encoded
+ encoded_len
- e_ptr
) > 0) {
72 ulong chunk_len
= 0, rest
;
74 chunk_len
= strtoul(e_ptr
, &n_ptr
, 16);
76 /* we could not read in chunk size */
79 * if this is the first turn and there doesn't seem to be a chunk
80 * size at the begining of the body, do not fail on apparently
81 * not encoded data and return a copy
83 if (e_ptr
== encoded
) {
84 http_error(HE_NOTICE
, HTTP_E_ENCODING
, "Data does not seem to be chunked encoded");
85 memcpy(*decoded
, encoded
, encoded_len
);
86 *decoded_len
= encoded_len
;
87 return encoded
+ encoded_len
;
90 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Expected chunk size at pos %tu of %zu but got trash", n_ptr
- encoded
, encoded_len
);
97 /* move over '0' chunked encoding terminator */
98 while (*e_ptr
== '0') ++e_ptr
;
102 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
103 if (*n_ptr
&& !eol_match(&n_ptr
, &eol_len
)) {
105 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr
- encoded
, encoded_len
, *n_ptr
, *(n_ptr
+ 1));
107 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr
- encoded
, encoded_len
, *n_ptr
);
112 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
113 if (chunk_len
> (rest
= encoded
+ encoded_len
- n_ptr
)) {
114 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len
, rest
, n_ptr
- encoded
, encoded_len
);
119 memcpy(*decoded
+ *decoded_len
, n_ptr
, chunk_len
);
120 *decoded_len
+= chunk_len
;
122 if (chunk_len
== rest
) {
123 e_ptr
= n_ptr
+ chunk_len
;
126 /* advance to next chunk */
127 e_ptr
= n_ptr
+ chunk_len
+ eol_len
;
135 #ifdef HTTP_HAVE_ZLIB
137 #define HTTP_DEFLATE_LEVEL_SET(flags, level) \
138 switch (flags & 0xf) \
141 if ((flags & 0xf) < 10) { \
142 level = flags & 0xf; \
145 case HTTP_DEFLATE_LEVEL_DEF: \
146 level = Z_DEFAULT_COMPRESSION; \
150 #define HTTP_DEFLATE_WBITS_SET(flags, wbits) \
151 switch (flags & 0xf0) \
153 case HTTP_DEFLATE_TYPE_GZIP: \
154 wbits = HTTP_WINDOW_BITS_GZIP; \
156 case HTTP_DEFLATE_TYPE_RAW: \
157 wbits = HTTP_WINDOW_BITS_RAW; \
160 wbits = HTTP_WINDOW_BITS_ZLIB; \
164 #define HTTP_INFLATE_WBITS_SET(flags, wbits) \
165 if (flags & HTTP_INFLATE_TYPE_RAW) { \
166 wbits = HTTP_WINDOW_BITS_RAW; \
168 wbits = HTTP_WINDOW_BITS_ANY; \
171 #define HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
172 switch (flags & 0xf00) \
174 case HTTP_DEFLATE_STRATEGY_FILT: \
175 strategy = Z_FILTERED; \
177 case HTTP_DEFLATE_STRATEGY_HUFF: \
178 strategy = Z_HUFFMAN_ONLY; \
180 case HTTP_DEFLATE_STRATEGY_RLE: \
183 case HTTP_DEFLATE_STRATEGY_FIXED: \
184 strategy = Z_FIXED; \
187 strategy = Z_DEFAULT_STRATEGY; \
191 #define HTTP_WINDOW_BITS_ZLIB 0x0000000f
192 #define HTTP_WINDOW_BITS_GZIP 0x0000001f
193 #define HTTP_WINDOW_BITS_ANY 0x0000002f
194 #define HTTP_WINDOW_BITS_RAW -0x000000f
196 STATUS
_http_encoding_deflate(int flags
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
198 int status
, level
, wbits
, strategy
;
201 HTTP_DEFLATE_LEVEL_SET(flags
, level
);
202 HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
203 HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
205 memset(&Z
, 0, sizeof(z_stream
));
209 status
= deflateInit2(&Z
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
);
210 if (Z_OK
== status
) {
211 *encoded_len
= HTTP_ENCODING_BUFLEN(data_len
);
212 *encoded
= emalloc(*encoded_len
);
214 Z
.next_in
= (Bytef
*) data
;
215 Z
.next_out
= (Bytef
*) *encoded
;
216 Z
.avail_in
= data_len
;
217 Z
.avail_out
= *encoded_len
;
219 status
= deflate(&Z
, Z_FINISH
);
220 if (Z_STREAM_END
== status
) {
221 /* size buffer down to actual length */
222 *encoded
= erealloc(*encoded
, Z
.total_out
+ 1);
223 (*encoded
)[*encoded_len
= Z
.total_out
] = '\0';
227 STR_SET(*encoded
, NULL
);
232 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not deflate data: %s (%s)", zError(status
), Z
.msg
);
237 STATUS
_http_encoding_inflate(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
239 int status
, max
= 0, wbits
= HTTP_WINDOW_BITS_ANY
;
243 memset(&Z
, 0, sizeof(z_stream
));
247 phpstr_init_ex(&buffer
, data_len
<< 2, PHPSTR_INIT_PREALLOC
);
248 buffer
.size
= data_len
;
251 status
= inflateInit2(&Z
, wbits
);
252 if (Z_OK
== status
) {
253 Z
.next_in
= (Bytef
*) data
;
254 Z
.avail_in
= data_len
;
257 phpstr_resize(&buffer
, data_len
);
260 Z
.next_out
= buffer
.data
+ (buffer
.used
+= Z
.total_out
);
261 Z
.avail_out
= (buffer
.free
-= Z
.total_out
);
262 status
= inflate(&Z
, Z_NO_FLUSH
);
263 } while (Z_OK
== status
);
265 } while (Z_BUF_ERROR
== status
&& ++max
< HTTP_ENCODING_MAXTRY
);
267 if (Z_DATA_ERROR
== status
&& HTTP_WINDOW_BITS_ANY
== wbits
) {
268 /* raw deflated data? */
270 wbits
= HTTP_WINDOW_BITS_RAW
;
274 if (Z_STREAM_END
== status
) {
275 *decoded
= erealloc(buffer
.data
, (buffer
.used
+= Z
.total_out
) + 1);
276 (*decoded
)[*decoded_len
= buffer
.used
] = '\0';
280 phpstr_dtor(&buffer
);
284 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not inflate data: %s (%s)", zError(status
), Z
.msg
);
290 http_encoding_stream
*_http_encoding_deflate_stream_init(http_encoding_stream
*s
, int flags TSRMLS_DC
)
292 int status
, level
, wbits
, strategy
, free_stream
;
294 if ((free_stream
= !s
)) {
295 s
= pemalloc(sizeof(http_encoding_stream
), (flags
& HTTP_ENCODING_STREAM_PERSISTENT
));
297 memset(s
, 0, sizeof(http_encoding_stream
));
300 HTTP_DEFLATE_LEVEL_SET(flags
, level
);
301 HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
302 HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
304 if (Z_OK
== (status
= deflateInit2(&s
->stream
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
))) {
305 int p
= (flags
& HTTP_ENCODING_STREAM_PERSISTENT
) ? PHPSTR_INIT_PERSISTENT
:0;
307 if ((s
->stream
.opaque
= phpstr_init_ex(NULL
, 0x8000, p
))) {
310 deflateEnd(&s
->stream
);
311 status
= Z_MEM_ERROR
;
314 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to initialize deflate encoding stream: %s", zError(status
));
321 http_encoding_stream
*_http_encoding_inflate_stream_init(http_encoding_stream
*s
, int flags TSRMLS_DC
)
323 int status
, wbits
, free_stream
;
325 if ((free_stream
= !s
)) {
326 s
= emalloc(sizeof(http_encoding_stream
));
328 memset(s
, 0, sizeof(http_encoding_stream
));
331 HTTP_INFLATE_WBITS_SET(flags
, wbits
);
333 if (Z_OK
== (status
= inflateInit2(&s
->stream
, wbits
))) {
334 int p
= (flags
& HTTP_ENCODING_STREAM_PERSISTENT
) ? PHPSTR_INIT_PERSISTENT
:0;
336 if ((s
->stream
.opaque
= phpstr_init_ex(NULL
, 0x8000, p
))) {
339 inflateEnd(&s
->stream
);
340 status
= Z_MEM_ERROR
;
343 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to initialize inflate stream: %s", zError(status
));
350 STATUS
_http_encoding_deflate_stream_update(http_encoding_stream
*s
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
354 /* append input to our buffer */
355 phpstr_append(PHPSTR(s
->stream
.opaque
), data
, data_len
);
357 s
->stream
.next_in
= PHPSTR_VAL(s
->stream
.opaque
);
358 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
361 s
->stream
.avail_out
= *encoded_len
= HTTP_ENCODING_BUFLEN(data_len
);
362 s
->stream
.next_out
= *encoded
= emalloc(*encoded_len
);
364 switch (status
= deflate(&s
->stream
, Z_NO_FLUSH
))
368 /* cut processed chunk off the buffer */
369 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, data_len
- s
->stream
.avail_in
);
371 /* size buffer down to actual size */
372 *encoded_len
-= s
->stream
.avail_out
;
373 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
374 (*encoded
)[*encoded_len
] = '\0';
379 STR_SET(*encoded
, NULL
);
381 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to update deflate stream: %s", zError(status
));
385 STATUS
_http_encoding_inflate_stream_update(http_encoding_stream
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
389 /* append input to buffer */
390 phpstr_append(PHPSTR(s
->stream
.opaque
), data
, data_len
);
394 *decoded_len
= data_len
<< 1;
399 *decoded
= erealloc(*decoded
, *decoded_len
);
402 s
->stream
.next_in
= PHPSTR_VAL(s
->stream
.opaque
);
403 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
405 s
->stream
.next_out
= *decoded
;
406 s
->stream
.avail_out
= *decoded_len
;
408 switch (status
= inflate(&s
->stream
, Z_NO_FLUSH
))
413 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, data_len
- s
->stream
.avail_in
);
416 *decoded_len
-= s
->stream
.avail_out
;
417 *decoded
= erealloc(*decoded
, *decoded_len
+ 1);
418 (*decoded
)[*decoded_len
] = '\0';
423 /* raw deflated data ? */
424 if (!(s
->flags
& HTTP_INFLATE_TYPE_RAW
) && !s
->stream
.total_out
) {
425 inflateEnd(&s
->stream
);
426 s
->flags
|= HTTP_INFLATE_TYPE_RAW
;
427 inflateInit2(&s
->stream
, HTTP_WINDOW_BITS_RAW
);
428 goto retry_raw_inflate
;
432 if (Z_BUF_ERROR
== status
) DebugBreak();
433 } while (Z_BUF_ERROR
== status
&& ++max
< HTTP_ENCODING_MAXTRY
);
435 STR_SET(*decoded
, NULL
);
437 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not update inflate stream: %s", zError(status
));
441 STATUS
_http_encoding_deflate_stream_finish(http_encoding_stream
*s
, char **encoded
, size_t *encoded_len TSRMLS_DC
)
445 /* deflate remaining input */
446 s
->stream
.next_in
= PHPSTR_VAL(s
->stream
.opaque
);
447 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
449 s
->stream
.avail_out
= *encoded_len
= 0x800;
450 s
->stream
.next_out
= *encoded
= emalloc(*encoded_len
);
453 status
= deflate(&s
->stream
, Z_FINISH
);
454 } while (Z_OK
== status
);
456 if (Z_STREAM_END
== status
) {
457 /* cut processed intp off */
458 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
461 *encoded_len
-= s
->stream
.avail_out
;
462 *encoded
= erealloc(*encoded
, *encoded_len
+ 1);
463 (*encoded
)[*encoded_len
] = '\0';
467 STR_SET(*encoded
, NULL
);
469 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to finish deflate stream: %s", zError(status
));
473 STATUS
_http_encoding_inflate_stream_finish(http_encoding_stream
*s
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
477 /* inflate remaining input */
478 s
->stream
.next_in
= PHPSTR_VAL(s
->stream
.opaque
);
479 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
481 s
->stream
.avail_out
= *decoded_len
= s
->stream
.avail_in
<< 2;
482 s
->stream
.next_out
= *decoded
= emalloc(*decoded_len
);
484 if (Z_STREAM_END
== (status
= inflate(&s
->stream
, Z_FINISH
))) {
485 /* cut processed input off */
486 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
489 *decoded_len
-= s
->stream
.avail_out
;
490 *decoded
= erealloc(*decoded
, *decoded_len
+ 1);
491 (*decoded
)[*decoded_len
] = '\0';
495 STR_SET(*decoded
, NULL
);
497 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to finish inflate stream: %s", zError(status
));
501 void _http_encoding_deflate_stream_dtor(http_encoding_stream
*s TSRMLS_DC
)
504 if (s
->stream
.opaque
) {
505 phpstr_free((phpstr
**) &s
->stream
.opaque
);
507 deflateEnd(&s
->stream
);
511 void _http_encoding_inflate_stream_dtor(http_encoding_stream
*s TSRMLS_DC
)
514 if (s
->stream
.opaque
) {
515 phpstr_free((phpstr
**) &s
->stream
.opaque
);
517 inflateEnd(&s
->stream
);
521 void _http_encoding_deflate_stream_free(http_encoding_stream
**s TSRMLS_DC
)
524 http_encoding_deflate_stream_dtor(*s
);
526 pefree(*s
, (*s
)->flags
& HTTP_ENCODING_STREAM_PERSISTENT
);
532 void _http_encoding_inflate_stream_free(http_encoding_stream
**s TSRMLS_DC
)
535 http_encoding_inflate_stream_dtor(*s
);
537 pefree(*s
, (*s
)->flags
& HTTP_ENCODING_STREAM_PERSISTENT
);
543 static const char http_encoding_gzip_header
[] = {
544 (const char) 0x1f, // fixed value
545 (const char) 0x8b, // fixed value
546 (const char) Z_DEFLATED
, // compression algorithm
547 (const char) 0, // none of the possible flags defined by the GZIP "RFC"
548 (const char) 0, // MTIME
549 (const char) 0, // =*=
550 (const char) 0, // =*=
551 (const char) 0, // =*=
552 (const char) 0, // two possible flag values for 9 compression levels? o_O
554 (const char) 0x0b // OS_CODE
556 (const char) 0x03 // OS_CODE
560 PHP_HTTP_API STATUS
_http_encoding_gzencode_verify(const char *data
, size_t data_len
, const char **encoded
, size_t *encoded_len
, int error_level TSRMLS_DC
)
562 size_t offset
= sizeof(http_encoding_gzip_header
);
564 if (data_len
< offset
) {
565 goto really_bad_gzip_header
;
568 if (data
[0] != (const char) 0x1F || data
[1] != (const char) 0x8B) {
569 http_error_ex(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Unrecognized GZIP header start: 0x%02X 0x%02X", (int) data
[0], (int) (data
[1] & 0xFF));
573 if (data
[2] != (const char) Z_DEFLATED
) {
574 http_error_ex(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Unrecognized compression format (%d)", (int) (data
[2] & 0xFF));
575 /* still try to decode */
577 if ((data
[3] & 0x4) == 0x4) {
578 if (data_len
< offset
+ 2) {
579 goto really_bad_gzip_header
;
581 /* there are extra fields, the length follows the common header as 2 bytes LSB */
582 offset
+= (unsigned) ((data
[offset
] & 0xFF));
584 offset
+= (unsigned) ((data
[offset
] & 0xFF) << 8);
587 if ((data
[3] & 0x8) == 0x8) {
588 if (data_len
<= offset
) {
589 goto really_bad_gzip_header
;
591 /* there's a file name */
592 offset
+= strlen(&data
[offset
]) + 1 /*NUL*/;
594 if ((data
[3] & 0x10) == 0x10) {
595 if (data_len
<= offset
) {
596 goto really_bad_gzip_header
;
598 /* there's a comment */
599 offset
+= strlen(&data
[offset
]) + 1 /* NUL */;
601 if ((data
[3] & 0x2) == 0x2) {
602 /* there's a CRC16 of the header */
604 if (data_len
<= offset
) {
605 goto really_bad_gzip_header
;
609 cmp
= (unsigned) ((data
[offset
-2] & 0xFF));
610 cmp
+= (unsigned) ((data
[offset
-1] & 0xFF) << 8);
612 crc
= crc32(0L, Z_NULL
, 0);
613 crc
= crc32(crc
, (const Bytef
*) data
, sizeof(http_encoding_gzip_header
));
615 if (cmp
!= (crc
& 0xFFFF)) {
616 http_error_ex(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "GZIP headers CRC checksums so not match (%lu, %lu)", cmp
, crc
& 0xFFFF);
622 if (data_len
< offset
+ 8) {
623 http_error(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Missing or truncated GZIP footer");
628 *encoded
= data
+ offset
;
631 *encoded_len
= data_len
- offset
- 8 /* size of the assumed GZIP footer */;
636 really_bad_gzip_header
:
637 http_error(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Missing or truncated GZIP header");
641 PHP_HTTP_API STATUS
_http_encoding_gzdecode_verify(const char *data
, size_t data_len
, const char *decoded
, size_t decoded_len
, int error_level TSRMLS_DC
)
643 STATUS status
= SUCCESS
;
646 crc
= crc32(0L, Z_NULL
, 0);
647 crc
= crc32(crc
, (const Bytef
*) decoded
, decoded_len
);
649 cmp
= (unsigned) ((data
[data_len
-8] & 0xFF));
650 cmp
+= (unsigned) ((data
[data_len
-7] & 0xFF) << 8);
651 cmp
+= (unsigned) ((data
[data_len
-6] & 0xFF) << 16);
652 cmp
+= (unsigned) ((data
[data_len
-5] & 0xFF) << 24);
653 len
= (unsigned) ((data
[data_len
-4] & 0xFF));
654 len
+= (unsigned) ((data
[data_len
-3] & 0xFF) << 8);
655 len
+= (unsigned) ((data
[data_len
-2] & 0xFF) << 16);
656 len
+= (unsigned) ((data
[data_len
-1] & 0xFF) << 24);
659 http_error_ex(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Could not verify data integrity: CRC checksums do not match (%lu, %lu)", cmp
, crc
);
662 if (len
!= decoded_len
) {
663 http_error_ex(error_level TSRMLS_CC
, HTTP_E_ENCODING
, "Could not verify data integrity: data sizes do not match (%lu, %lu)", len
, decoded_len
);
669 #endif /* HTTP_HAVE_ZLIB */
671 PHP_HTTP_API zend_bool
_http_encoding_response_start(size_t content_length TSRMLS_DC
)
673 if ( php_ob_handler_used("ob_gzhandler" TSRMLS_CC
) ||
674 php_ob_handler_used("zlib output compression" TSRMLS_CC
)) {
675 HTTP_G(send
).gzip_encoding
= 0;
677 if (!HTTP_G(send
).gzip_encoding
) {
678 /* emit a content-length header */
679 if (content_length
) {
680 char cl_header_str
[128];
681 size_t cl_header_len
;
682 cl_header_len
= snprintf(cl_header_str
, lenof(cl_header_str
), "Content-Length: %zu", content_length
);
683 http_send_header_string_ex(cl_header_str
, cl_header_len
, 1);
686 #ifndef HTTP_HAVE_ZLIB
687 HTTP_G(send
).gzip_encoding
= 0;
688 php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC
);
693 INIT_PZVAL(&zsupported
);
694 array_init(&zsupported
);
695 add_next_index_stringl(&zsupported
, "gzip", lenof("gzip"), 1);
696 add_next_index_stringl(&zsupported
, "x-gzip", lenof("x-gzip"), 1);
697 add_next_index_stringl(&zsupported
, "deflate", lenof("deflate"), 1);
699 HTTP_G(send
).gzip_encoding
= 0;
701 if ((selected
= http_negotiate_encoding(&zsupported
))) {
703 char *encoding
= NULL
;
706 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key(selected
, &encoding
, &idx
, 0) && encoding
) {
707 if (!strcmp(encoding
, "gzip") || !strcmp(encoding
, "x-gzip")) {
708 if (SUCCESS
== (hs
= http_send_header_string("Content-Encoding: gzip"))) {
709 HTTP_G(send
).gzip_encoding
= HTTP_ENCODING_GZIP
;
711 } else if (!strcmp(encoding
, "deflate")) {
712 if (SUCCESS
== (hs
= http_send_header_string("Content-Encoding: deflate"))) {
713 HTTP_G(send
).gzip_encoding
= HTTP_ENCODING_DEFLATE
;
717 http_send_header_string("Vary: Accept-Encoding");
721 zend_hash_destroy(selected
);
722 FREE_HASHTABLE(selected
);
725 zval_dtor(&zsupported
);
726 return HTTP_G(send
).gzip_encoding
;
738 * vim600: noet sw=4 ts=4 fdm=marker
739 * vim<600: noet sw=4 ts=4