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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_ZLIB
18 #include "php_http_api.h"
19 #include "php_http_encoding_api.h"
20 #include "php_http_send_api.h"
21 #include "php_http_headers_api.h"
25 PHP_MINIT_FUNCTION(http_encoding
)
27 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF
);
28 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN
);
29 HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX
);
30 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB
);
31 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP
);
32 HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW
);
33 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF
);
34 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT
);
35 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF
);
36 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE
);
37 HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED
);
41 PHP_RINIT_FUNCTION(http_encoding
)
45 if (G
->send
.inflate
.start_auto
) {
46 php_ob_set_internal_handler(_http_ob_inflatehandler
, HTTP_INFLATE_BUFFER_SIZE
, "http inflate", 0 TSRMLS_CC
);
48 if (G
->send
.deflate
.start_auto
) {
49 php_ob_set_internal_handler(_http_ob_deflatehandler
, HTTP_DEFLATE_BUFFER_SIZE
, "http deflate", 0 TSRMLS_CC
);
54 PHP_RSHUTDOWN_FUNCTION(http_encoding
)
58 if (G
->send
.deflate
.stream
) {
59 http_encoding_deflate_stream_free((http_encoding_stream
**) &G
->send
.deflate
.stream
);
61 if (G
->send
.inflate
.stream
) {
62 http_encoding_inflate_stream_free((http_encoding_stream
**) &G
->send
.inflate
.stream
);
69 /* {{{ eol_match(char **, int *) */
70 static inline int eol_match(char **line
, int *eol_len
)
74 while (' ' == *ptr
) ++ptr
;
76 if (ptr
== http_locate_eol(*line
, eol_len
)) {
85 /* {{{ char *http_encoding_dechunk(char *, size_t, char **, size_t *) */
86 PHP_HTTP_API
const char *_http_encoding_dechunk(const char *encoded
, size_t encoded_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
90 const char *e_ptr
= encoded
;
93 *decoded
= ecalloc(1, encoded_len
);
95 while ((encoded
+ encoded_len
- e_ptr
) > 0) {
96 ulong chunk_len
= 0, rest
;
98 chunk_len
= strtoul(e_ptr
, &n_ptr
, 16);
100 /* we could not read in chunk size */
101 if (n_ptr
== e_ptr
) {
103 * if this is the first turn and there doesn't seem to be a chunk
104 * size at the begining of the body, do not fail on apparently
105 * not encoded data and return a copy
107 if (e_ptr
== encoded
) {
108 http_error(HE_NOTICE
, HTTP_E_ENCODING
, "Data does not seem to be chunked encoded");
109 memcpy(*decoded
, encoded
, encoded_len
);
110 *decoded_len
= encoded_len
;
111 return encoded
+ encoded_len
;
114 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Expected chunk size at pos %tu of %zu but got trash", n_ptr
- encoded
, encoded_len
);
119 /* reached the end */
121 /* move over '0' chunked encoding terminator */
122 while (*e_ptr
== '0') ++e_ptr
;
126 /* there should be CRLF after the chunk size, but we'll ignore SP+ too */
127 if (*n_ptr
&& !eol_match(&n_ptr
, &eol_len
)) {
129 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));
131 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
);
136 /* chunk size pretends more data than we actually got, so it's probably a truncated message */
137 if (chunk_len
> (rest
= encoded
+ encoded_len
- n_ptr
)) {
138 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
);
143 memcpy(*decoded
+ *decoded_len
, n_ptr
, chunk_len
);
144 *decoded_len
+= chunk_len
;
146 if (chunk_len
== rest
) {
147 e_ptr
= n_ptr
+ chunk_len
;
150 /* advance to next chunk */
151 e_ptr
= n_ptr
+ chunk_len
+ eol_len
;
159 /* {{{ int http_encoding_response_start(size_t) */
160 PHP_HTTP_API
int _http_encoding_response_start(size_t content_length TSRMLS_DC
)
162 if ( php_ob_handler_used("ob_gzhandler" TSRMLS_CC
) ||
163 php_ob_handler_used("zlib output compression" TSRMLS_CC
)) {
164 HTTP_G(send
).deflate
.encoding
= 0;
166 if (!HTTP_G(send
).deflate
.encoding
) {
167 /* emit a content-length header */
168 if (content_length
) {
169 char cl_header_str
[128];
170 size_t cl_header_len
;
171 cl_header_len
= snprintf(cl_header_str
, lenof(cl_header_str
), "Content-Length: %zu", content_length
);
172 http_send_header_string_ex(cl_header_str
, cl_header_len
, 1);
175 #ifndef HTTP_HAVE_ZLIB
176 HTTP_G(send
).deflate
.encoding
= 0;
177 php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC
);
182 INIT_PZVAL(&zsupported
);
183 array_init(&zsupported
);
184 add_next_index_stringl(&zsupported
, "gzip", lenof("gzip"), 1);
185 add_next_index_stringl(&zsupported
, "x-gzip", lenof("x-gzip"), 1);
186 add_next_index_stringl(&zsupported
, "deflate", lenof("deflate"), 1);
188 HTTP_G(send
).deflate
.encoding
= 0;
190 if ((selected
= http_negotiate_encoding(&zsupported
))) {
192 char *encoding
= NULL
;
195 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key(selected
, &encoding
, &idx
, 0) && encoding
) {
196 if (!strcmp(encoding
, "gzip") || !strcmp(encoding
, "x-gzip")) {
197 if (SUCCESS
== (hs
= http_send_header_string("Content-Encoding: gzip"))) {
198 HTTP_G(send
).deflate
.encoding
= HTTP_ENCODING_GZIP
;
200 } else if (!strcmp(encoding
, "deflate")) {
201 if (SUCCESS
== (hs
= http_send_header_string("Content-Encoding: deflate"))) {
202 HTTP_G(send
).deflate
.encoding
= HTTP_ENCODING_DEFLATE
;
206 http_send_header_string("Vary: Accept-Encoding");
210 zend_hash_destroy(selected
);
211 FREE_HASHTABLE(selected
);
214 zval_dtor(&zsupported
);
215 return HTTP_G(send
).deflate
.encoding
;
223 #ifdef HTTP_HAVE_ZLIB
226 #define HTTP_DEFLATE_LEVEL_SET(flags, level) \
227 switch (flags & 0xf) \
230 if ((flags & 0xf) < 10) { \
231 level = flags & 0xf; \
234 case HTTP_DEFLATE_LEVEL_DEF: \
235 level = Z_DEFAULT_COMPRESSION; \
239 #define HTTP_DEFLATE_WBITS_SET(flags, wbits) \
240 switch (flags & 0xf0) \
242 case HTTP_DEFLATE_TYPE_GZIP: \
243 wbits = HTTP_WINDOW_BITS_GZIP; \
245 case HTTP_DEFLATE_TYPE_RAW: \
246 wbits = HTTP_WINDOW_BITS_RAW; \
249 wbits = HTTP_WINDOW_BITS_ZLIB; \
253 #define HTTP_INFLATE_WBITS_SET(flags, wbits) \
254 if (flags & HTTP_INFLATE_TYPE_RAW) { \
255 wbits = HTTP_WINDOW_BITS_RAW; \
257 wbits = HTTP_WINDOW_BITS_ANY; \
260 #define HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
261 switch (flags & 0xf00) \
263 case HTTP_DEFLATE_STRATEGY_FILT: \
264 strategy = Z_FILTERED; \
266 case HTTP_DEFLATE_STRATEGY_HUFF: \
267 strategy = Z_HUFFMAN_ONLY; \
269 case HTTP_DEFLATE_STRATEGY_RLE: \
272 case HTTP_DEFLATE_STRATEGY_FIXED: \
273 strategy = Z_FIXED; \
276 strategy = Z_DEFAULT_STRATEGY; \
280 #define HTTP_WINDOW_BITS_ZLIB 0x0000000f
281 #define HTTP_WINDOW_BITS_GZIP 0x0000001f
282 #define HTTP_WINDOW_BITS_ANY 0x0000002f
283 #define HTTP_WINDOW_BITS_RAW -0x000000f
286 /* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */
287 PHP_HTTP_API STATUS
_http_encoding_deflate(int flags
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
289 int status
, level
, wbits
, strategy
;
292 HTTP_DEFLATE_LEVEL_SET(flags
, level
);
293 HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
294 HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
296 memset(&Z
, 0, sizeof(z_stream
));
300 status
= deflateInit2(&Z
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
);
301 if (Z_OK
== status
) {
302 *encoded_len
= HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
303 *encoded
= emalloc_rel(*encoded_len
);
305 Z
.next_in
= (Bytef
*) data
;
306 Z
.next_out
= (Bytef
*) *encoded
;
307 Z
.avail_in
= data_len
;
308 Z
.avail_out
= *encoded_len
;
310 status
= deflate(&Z
, Z_FINISH
);
313 if (Z_STREAM_END
== status
) {
314 /* size buffer down to actual length */
315 *encoded
= erealloc_rel(*encoded
, Z
.total_out
+ 1);
316 (*encoded
)[*encoded_len
= Z
.total_out
] = '\0';
319 STR_SET(*encoded
, NULL
);
324 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not deflate data: %s", zError(status
));
329 /* {{{ STATUS http_encoding_inflate(char *, size_t, char **, size_t) */
330 PHP_HTTP_API STATUS
_http_encoding_inflate(const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
332 int status
, round
= 0, wbits
= HTTP_WINDOW_BITS_ANY
;
336 memset(&Z
, 0, sizeof(z_stream
));
340 phpstr_init_ex(&buffer
, data_len
<< 2, PHPSTR_INIT_PREALLOC
);
341 buffer
.size
= data_len
;
344 status
= inflateInit2(&Z
, wbits
);
345 if (Z_OK
== status
) {
346 Z
.next_in
= (Bytef
*) data
;
347 Z
.avail_in
= data_len
;
350 phpstr_resize(&buffer
, data_len
<< 2);
353 Z
.avail_out
= (buffer
.free
-= Z
.total_out
- buffer
.used
);
354 Z
.next_out
= (Bytef
*) buffer
.data
+ (buffer
.used
= Z
.total_out
);
355 status
= inflate(&Z
, Z_NO_FLUSH
);
356 } while (Z_OK
== status
);
357 } while (Z_BUF_ERROR
== status
&& ++round
< HTTP_INFLATE_ROUNDS
);
359 if (Z_DATA_ERROR
== status
&& HTTP_WINDOW_BITS_ANY
== wbits
) {
360 /* raw deflated data? */
362 wbits
= HTTP_WINDOW_BITS_RAW
;
368 if (Z_STREAM_END
== status
) {
369 *decoded_len
= Z
.total_out
;
370 *decoded
= erealloc_rel(buffer
.data
, *decoded_len
+ 1);
371 (*decoded
)[*decoded_len
] = '\0';
374 phpstr_dtor(&buffer
);
378 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not inflate data: %s", zError(status
));
383 /* {{{ http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *, int) */
384 PHP_HTTP_API http_encoding_stream
*_http_encoding_deflate_stream_init(http_encoding_stream
*s
, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
386 int status
, level
, wbits
, strategy
, free_stream
;
388 if ((free_stream
= !s
)) {
389 s
= pemalloc_rel(sizeof(http_encoding_stream
), (flags
& HTTP_ENCODING_STREAM_PERSISTENT
));
391 memset(s
, 0, sizeof(http_encoding_stream
));
394 HTTP_DEFLATE_LEVEL_SET(flags
, level
);
395 HTTP_DEFLATE_WBITS_SET(flags
, wbits
);
396 HTTP_DEFLATE_STRATEGY_SET(flags
, strategy
);
398 if (Z_OK
== (status
= deflateInit2(&s
->stream
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, strategy
))) {
399 int p
= (flags
& HTTP_ENCODING_STREAM_PERSISTENT
) ? PHPSTR_INIT_PERSISTENT
:0;
401 if ((s
->stream
.opaque
= phpstr_init_ex(NULL
, HTTP_DEFLATE_BUFFER_SIZE
, p
))) {
404 deflateEnd(&s
->stream
);
405 status
= Z_MEM_ERROR
;
408 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to initialize deflate encoding stream: %s", zError(status
));
416 /* {{{ http_encoding_stream *http_encoding_inflate_stream_init(http_encoding_stream *, int) */
417 PHP_HTTP_API http_encoding_stream
*_http_encoding_inflate_stream_init(http_encoding_stream
*s
, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
419 int status
, wbits
, free_stream
;
421 if ((free_stream
= !s
)) {
422 s
= pemalloc_rel(sizeof(http_encoding_stream
), (flags
& HTTP_ENCODING_STREAM_PERSISTENT
));
424 memset(s
, 0, sizeof(http_encoding_stream
));
427 HTTP_INFLATE_WBITS_SET(flags
, wbits
);
429 if (Z_OK
== (status
= inflateInit2(&s
->stream
, wbits
))) {
430 int p
= (flags
& HTTP_ENCODING_STREAM_PERSISTENT
) ? PHPSTR_INIT_PERSISTENT
:0;
432 if ((s
->stream
.opaque
= phpstr_init_ex(NULL
, HTTP_DEFLATE_BUFFER_SIZE
, p
))) {
435 inflateEnd(&s
->stream
);
436 status
= Z_MEM_ERROR
;
439 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to initialize inflate stream: %s", zError(status
));
447 /* {{{ STATUS http_encoding_deflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
448 PHP_HTTP_API STATUS
_http_encoding_deflate_stream_update(http_encoding_stream
*s
, const char *data
, size_t data_len
, char **encoded
, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
452 /* append input to our buffer */
453 phpstr_append(PHPSTR(s
->stream
.opaque
), data
, data_len
);
455 s
->stream
.next_in
= (Bytef
*) PHPSTR_VAL(s
->stream
.opaque
);
456 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
459 *encoded_len
= HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len
);
460 *encoded
= emalloc_rel(*encoded_len
);
461 s
->stream
.avail_out
= *encoded_len
;
462 s
->stream
.next_out
= (Bytef
*) *encoded
;
464 switch (status
= deflate(&s
->stream
, Z_NO_FLUSH
))
468 /* cut processed chunk off the buffer */
469 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
471 /* size buffer down to actual size */
472 *encoded_len
-= s
->stream
.avail_out
;
473 *encoded
= erealloc_rel(*encoded
, *encoded_len
+ 1);
474 (*encoded
)[*encoded_len
] = '\0';
479 STR_SET(*encoded
, NULL
);
481 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to update deflate stream: %s", zError(status
));
486 /* {{{ STATUS http_encoding_inflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */
487 PHP_HTTP_API STATUS
_http_encoding_inflate_stream_update(http_encoding_stream
*s
, const char *data
, size_t data_len
, char **decoded
, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
489 int status
, round
= 0;
491 /* append input to buffer */
492 phpstr_append(PHPSTR(s
->stream
.opaque
), data
, data_len
);
496 *decoded_len
= data_len
<< 1;
501 *decoded
= erealloc_rel(*decoded
, *decoded_len
);
504 s
->stream
.next_in
= (Bytef
*) PHPSTR_VAL(s
->stream
.opaque
);
505 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
507 s
->stream
.next_out
= (Bytef
*) *decoded
;
508 s
->stream
.avail_out
= *decoded_len
;
510 switch (status
= inflate(&s
->stream
, Z_NO_FLUSH
))
515 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
518 *decoded_len
-= s
->stream
.avail_out
;
519 *decoded
= erealloc_rel(*decoded
, *decoded_len
+ 1);
520 (*decoded
)[*decoded_len
] = '\0';
525 /* raw deflated data ? */
526 if (!(s
->flags
& HTTP_INFLATE_TYPE_RAW
) && !s
->stream
.total_out
) {
527 inflateEnd(&s
->stream
);
528 s
->flags
|= HTTP_INFLATE_TYPE_RAW
;
529 inflateInit2(&s
->stream
, HTTP_WINDOW_BITS_RAW
);
530 goto retry_raw_inflate
;
534 } while (Z_BUF_ERROR
== status
&& ++round
< HTTP_INFLATE_ROUNDS
);
536 STR_SET(*decoded
, NULL
);
538 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to update inflate stream: %s", zError(status
));
543 /* {{{ STATUS http_encoding_deflate_stream_flush(http_encoding_stream *, char **, size_t *) */
544 PHP_HTTP_API STATUS
_http_encoding_deflate_stream_flush(http_encoding_stream
*s
, char **encoded
, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
548 *encoded_len
= HTTP_DEFLATE_BUFFER_SIZE
;
549 *encoded
= emalloc_rel(*encoded_len
);
551 s
->stream
.avail_in
= 0;
552 s
->stream
.next_in
= NULL
;
553 s
->stream
.avail_out
= *encoded_len
;
554 s
->stream
.next_out
= (Bytef
*) *encoded
;
556 switch (status
= deflate(&s
->stream
, Z_SYNC_FLUSH
))
560 *encoded_len
= HTTP_DEFLATE_BUFFER_SIZE
- s
->stream
.avail_out
;
561 *encoded
= erealloc_rel(*encoded
, *encoded_len
+ 1);
562 (*encoded
)[*encoded_len
] = '\0';
567 STR_SET(*encoded
, NULL
);
569 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to flush deflate stream: %s", zError(status
));
574 /* {{{ STATUS http_encoding_inflate_straem_flush(http_encoding_stream *, char **, size_t *) */
575 PHP_HTTP_API STATUS
_http_encoding_inflate_stream_flush(http_encoding_stream
*s
, char **decoded
, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
578 *decoded
= estrndup("", *decoded_len
= 0);
583 /* {{{ STATUS http_encoding_deflate_stream_finish(http_encoding_stream *, char **, size_t *) */
584 PHP_HTTP_API STATUS
_http_encoding_deflate_stream_finish(http_encoding_stream
*s
, char **encoded
, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
588 *encoded_len
= HTTP_DEFLATE_BUFFER_SIZE
;
589 *encoded
= emalloc_rel(*encoded_len
);
591 /* deflate remaining input */
592 s
->stream
.next_in
= (Bytef
*) PHPSTR_VAL(s
->stream
.opaque
);
593 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
595 s
->stream
.avail_out
= *encoded_len
;
596 s
->stream
.next_out
= (Bytef
*) *encoded
;
599 status
= deflate(&s
->stream
, Z_FINISH
);
600 } while (Z_OK
== status
);
602 if (Z_STREAM_END
== status
) {
603 /* cut processed intp off */
604 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
607 *encoded_len
-= s
->stream
.avail_out
;
608 *encoded
= erealloc_rel(*encoded
, *encoded_len
+ 1);
609 (*encoded
)[*encoded_len
] = '\0';
613 STR_SET(*encoded
, NULL
);
615 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to finish deflate stream: %s", zError(status
));
620 /* {{{ STATUS http_encoding_inflate_stream_finish(http_encoding_stream *, char **, size_t *) */
621 PHP_HTTP_API STATUS
_http_encoding_inflate_stream_finish(http_encoding_stream
*s
, char **decoded
, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC
)
625 *decoded_len
= (PHPSTR_LEN(s
->stream
.opaque
) + 1) * HTTP_INFLATE_ROUNDS
;
626 *decoded
= emalloc_rel(*decoded_len
);
628 /* inflate remaining input */
629 s
->stream
.next_in
= (Bytef
*) PHPSTR_VAL(s
->stream
.opaque
);
630 s
->stream
.avail_in
= PHPSTR_LEN(s
->stream
.opaque
);
632 s
->stream
.avail_out
= *decoded_len
;
633 s
->stream
.next_out
= (Bytef
*) *decoded
;
635 if (Z_STREAM_END
== (status
= inflate(&s
->stream
, Z_FINISH
))) {
636 /* cut processed input off */
637 phpstr_cut(PHPSTR(s
->stream
.opaque
), 0, PHPSTR_LEN(s
->stream
.opaque
) - s
->stream
.avail_in
);
640 *decoded_len
-= s
->stream
.avail_out
;
641 *decoded
= erealloc_rel(*decoded
, *decoded_len
+ 1);
642 (*decoded
)[*decoded_len
] = '\0';
646 STR_SET(*decoded
, NULL
);
648 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Failed to finish inflate stream: %s", zError(status
));
653 /* {{{ void http_encoding_deflate_stream_dtor(http_encoding_stream *) */
654 PHP_HTTP_API
void _http_encoding_deflate_stream_dtor(http_encoding_stream
*s TSRMLS_DC
)
657 if (s
->stream
.opaque
) {
658 phpstr_free((phpstr
**) &s
->stream
.opaque
);
660 deflateEnd(&s
->stream
);
665 /* {{{ void http_encoding_inflate_stream_dtor(http_encoding_stream *) */
666 PHP_HTTP_API
void _http_encoding_inflate_stream_dtor(http_encoding_stream
*s TSRMLS_DC
)
669 if (s
->stream
.opaque
) {
670 phpstr_free((phpstr
**) &s
->stream
.opaque
);
672 inflateEnd(&s
->stream
);
677 /* {{{ void http_encoding_deflate_stream_free(http_encoding_stream **) */
678 PHP_HTTP_API
void _http_encoding_deflate_stream_free(http_encoding_stream
**s TSRMLS_DC
)
681 http_encoding_deflate_stream_dtor(*s
);
683 pefree(*s
, (*s
)->flags
& HTTP_ENCODING_STREAM_PERSISTENT
);
690 /* {{{ void http_encoding_inflate_stream_free(http_encoding_stream **) */
691 PHP_HTTP_API
void _http_encoding_inflate_stream_free(http_encoding_stream
**s TSRMLS_DC
)
694 http_encoding_inflate_stream_dtor(*s
);
696 pefree(*s
, (*s
)->flags
& HTTP_ENCODING_STREAM_PERSISTENT
);
703 /* {{{ void http_ob_deflatehandler(char *, uint, char **, uint *, int) */
704 void _http_ob_deflatehandler(char *output
, uint output_len
, char **handled_output
, uint
*handled_output_len
, int mode TSRMLS_DC
)
708 *handled_output
= NULL
;
709 *handled_output_len
= 0;
711 if (mode
& PHP_OUTPUT_HANDLER_START
) {
714 if (G
->send
.deflate
.stream
) {
715 zend_error(E_ERROR
, "ob_deflatehandler() can only be used once");
719 G
->send
.deflate
.encoding
= !0;
721 switch (http_encoding_response_start(0))
723 case HTTP_ENCODING_GZIP
:
724 flags
= HTTP_DEFLATE_TYPE_GZIP
;
727 case HTTP_ENCODING_DEFLATE
:
728 flags
= HTTP_DEFLATE_TYPE_ZLIB
;
732 goto deflate_passthru_plain
;
736 flags
|= (G
->send
.deflate
.start_flags
&~ 0xf0);
737 G
->send
.deflate
.stream
= http_encoding_deflate_stream_init(NULL
, flags
);
740 if (G
->send
.deflate
.stream
) {
741 http_encoding_deflate_stream_update((http_encoding_stream
*) G
->send
.deflate
.stream
, output
, output_len
, handled_output
, handled_output_len
);
743 if (mode
& PHP_OUTPUT_HANDLER_END
) {
744 char *remaining
= NULL
;
745 size_t remaining_len
= 0;
747 http_encoding_deflate_stream_finish((http_encoding_stream
*) G
->send
.deflate
.stream
, &remaining
, &remaining_len
);
748 http_encoding_deflate_stream_free((http_encoding_stream
**) &G
->send
.deflate
.stream
);
750 *handled_output
= erealloc(*handled_output
, *handled_output_len
+ remaining_len
+ 1);
751 memcpy(*handled_output
+ *handled_output_len
, remaining
, remaining_len
);
752 (*handled_output
)[*handled_output_len
+= remaining_len
] = '\0';
757 deflate_passthru_plain
:
758 *handled_output
= estrndup(output
, *handled_output_len
= output_len
);
763 /* {{{ void http_ob_inflatehandler(char *, uint, char **, uint *, int) */
764 void _http_ob_inflatehandler(char *output
, uint output_len
, char **handled_output
, uint
*handled_output_len
, int mode TSRMLS_DC
)
768 *handled_output
= NULL
;
769 *handled_output_len
= 0;
771 if (mode
& PHP_OUTPUT_HANDLER_START
) {
772 if (G
->send
.inflate
.stream
) {
773 zend_error(E_ERROR
, "ob_inflatehandler() can only be used once");
776 G
->send
.inflate
.stream
= http_encoding_inflate_stream_init(NULL
, (HTTP_G(send
).inflate
.start_flags
&~ 0xf0));
779 if (G
->send
.inflate
.stream
) {
780 http_encoding_inflate_stream_update((http_encoding_stream
*) G
->send
.inflate
.stream
, output
, output_len
, handled_output
, handled_output_len
);
782 if (mode
& PHP_OUTPUT_HANDLER_END
) {
783 char *remaining
= NULL
;
784 size_t remaining_len
= 0;
786 http_encoding_inflate_stream_finish((http_encoding_stream
*) G
->send
.inflate
.stream
, &remaining
, &remaining_len
);
787 http_encoding_inflate_stream_free((http_encoding_stream
**) &G
->send
.inflate
.stream
);
789 *handled_output
= erealloc(*handled_output
, *handled_output_len
+ remaining_len
+ 1);
790 memcpy(*handled_output
+ *handled_output_len
, remaining
, remaining_len
);
791 (*handled_output
)[*handled_output_len
+= remaining_len
] = '\0';
796 *handled_output
= estrndup(output
, *handled_output_len
= output_len
);
801 #endif /* HTTP_HAVE_ZLIB */
808 * vim600: noet sw=4 ts=4 fdm=marker
809 * vim<600: noet sw=4 ts=4