X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_encoding_api.c;h=1d9b9163a31af614fda99c992818fe4ef40ed7a3;hp=534b7628a1e3c65bc525c1b892d31d99fd72352e;hb=refs%2Fheads%2Fv1.7.x;hpb=32e91737086db53bb1fd9ed9f79d693c43ec459f diff --git a/http_encoding_api.c b/http_encoding_api.c index 534b762..1d9b916 100644 --- a/http_encoding_api.c +++ b/http_encoding_api.c @@ -6,16 +6,12 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2006, Michael Wallner | + | Copyright (c) 2004-2010, Michael Wallner | +--------------------------------------------------------------------+ */ /* $Id$ */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #define HTTP_WANT_ZLIB #include "php_http.h" @@ -39,31 +35,40 @@ PHP_MINIT_FUNCTION(http_encoding) HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF); HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE); HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED); + + HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_NONE", HTTP_ENCODING_STREAM_FLUSH_NONE); + HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_SYNC", HTTP_ENCODING_STREAM_FLUSH_SYNC); + HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_FULL", HTTP_ENCODING_STREAM_FLUSH_FULL); + return SUCCESS; } PHP_RINIT_FUNCTION(http_encoding) { - getGlobals(G); - - if (G->send.inflate.start_auto) { + if (HTTP_G->send.inflate.start_auto) { +#ifdef PHP_OUTPUT_NEWAPI + php_output_start_internal(ZEND_STRL("http inflate"), _http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, 0 TSRMLS_CC); +#else php_ob_set_internal_handler(_http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, "http inflate", 0 TSRMLS_CC); +#endif } - if (G->send.deflate.start_auto) { + if (HTTP_G->send.deflate.start_auto) { +#ifdef PHP_OUTPUT_NEWAPI + php_output_start_internal(ZEND_STRL("http deflate"), _http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, 0 TSRMLS_CC); +#else php_ob_set_internal_handler(_http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, "http deflate", 0 TSRMLS_CC); +#endif } return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(http_encoding) { - getGlobals(G); - - if (G->send.deflate.stream) { - http_encoding_deflate_stream_free((http_encoding_stream **) &G->send.deflate.stream); + if (HTTP_G->send.deflate.stream) { + http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream); } - if (G->send.inflate.stream) { - http_encoding_inflate_stream_free((http_encoding_stream **) &G->send.inflate.stream); + if (HTTP_G->send.inflate.stream) { + http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream); } return SUCCESS; } @@ -161,130 +166,126 @@ PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t enco /* }}} */ /* {{{ int http_encoding_response_start(size_t) */ -PHP_HTTP_API int _http_encoding_response_start(size_t content_length TSRMLS_DC) +PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC) { - if ( php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || - php_ob_handler_used("zlib output compression" TSRMLS_CC)) { - HTTP_G(send).deflate.encoding = 0; - } else { - if (!HTTP_G(send).deflate.encoding) { - /* emit a content-length header */ - if (content_length) { - char cl_header_str[128]; - size_t cl_header_len; - cl_header_len = snprintf(cl_header_str, lenof(cl_header_str), "Content-Length: %zu", content_length); - http_send_header_string_ex(cl_header_str, cl_header_len, 1); - } - } else { -#ifndef HTTP_HAVE_ZLIB - HTTP_G(send).deflate.encoding = 0; - php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC); + int response = HTTP_G->send.deflate.response; +#ifdef PHP_OUTPUT_NEWAPI + int ohandler = php_output_handler_started(ZEND_STRL("ob_gzhandler") TSRMLS_CC) || php_output_handler_started(ZEND_STRL("zlib output compression") TSRMLS_CC); #else - HashTable *selected; - zval zsupported; - - INIT_PZVAL(&zsupported); - array_init(&zsupported); - add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1); - add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1); - add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1); - - HTTP_G(send).deflate.encoding = 0; + int ohandler = php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || php_ob_handler_used("zlib output compression" TSRMLS_CC); +#endif + + if (!ohandler && !ignore_http_ohandler) { +#ifdef PHP_OUTPUT_NEWAPI + ohandler = php_output_handler_started(ZEND_STRL("ob_defaltehandler") TSRMLS_CC) || php_output_handler_started(ZEND_STRL("http deflate") TSRMLS_CC); +#else + ohandler = php_ob_handler_used("ob_deflatehandler" TSRMLS_CC) || php_ob_handler_used("http deflate" TSRMLS_CC); +#endif + } + + if (response && !ohandler) { +#ifdef HTTP_HAVE_ZLIB + HashTable *selected; + zval zsupported; + + HTTP_G->send.deflate.encoding = 0; + + INIT_PZVAL(&zsupported); + array_init(&zsupported); + add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1); + add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1); + add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1); + + if ((selected = http_negotiate_encoding(&zsupported))) { + STATUS hs = FAILURE; + char *encoding = NULL; + ulong idx; - if ((selected = http_negotiate_encoding(&zsupported))) { - STATUS hs = FAILURE; - char *encoding = NULL; - ulong idx; - - if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) { - if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) { - if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) { - HTTP_G(send).deflate.encoding = HTTP_ENCODING_GZIP; - } - } else if (!strcmp(encoding, "deflate")) { - if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) { - HTTP_G(send).deflate.encoding = HTTP_ENCODING_DEFLATE; - } + if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) { + if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) { + if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) { + HTTP_G->send.deflate.encoding = HTTP_ENCODING_GZIP; } - if (SUCCESS == hs) { - http_send_header_string("Vary: Accept-Encoding"); + } else if (!strcmp(encoding, "deflate")) { + if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) { + HTTP_G->send.deflate.encoding = HTTP_ENCODING_DEFLATE; } } - - zend_hash_destroy(selected); - FREE_HASHTABLE(selected); + if (SUCCESS == hs) { + http_send_header_string("Vary: Accept-Encoding"); + } } - zval_dtor(&zsupported); - return HTTP_G(send).deflate.encoding; -#endif + zend_hash_destroy(selected); + FREE_HASHTABLE(selected); } + + zval_dtor(&zsupported); +#else + HTTP_G->send.deflate.encoding = 0; + php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC); +#endif /* HTTP_HAVE_ZLIB */ + } else if (content_length && !ohandler) { + /* emit a content-length header */ + phpstr header; + + phpstr_init(&header); + phpstr_appendf(&header, "Content-Length: %zu", content_length); + phpstr_fix(&header); + http_send_header_string_ex(PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1); + phpstr_dtor(&header); + } else { + HTTP_G->send.deflate.encoding = 0; } - return 0; + + return HTTP_G->send.deflate.encoding; } /* }}} */ #ifdef HTTP_HAVE_ZLIB -/* {{{ */ -#define HTTP_DEFLATE_LEVEL_SET(flags, level) \ - switch (flags & 0xf) \ - { \ - default: \ - if ((flags & 0xf) < 10) { \ - level = flags & 0xf; \ - break; \ - } \ - case HTTP_DEFLATE_LEVEL_DEF: \ - level = Z_DEFAULT_COMPRESSION; \ - break; \ - } +/* {{{ inline int http_inflate_rounds */ +static inline int http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len) +{ + int status = 0, round = 0; + phpstr buffer; -#define HTTP_DEFLATE_WBITS_SET(flags, wbits) \ - switch (flags & 0xf0) \ - { \ - case HTTP_DEFLATE_TYPE_GZIP: \ - wbits = HTTP_WINDOW_BITS_GZIP; \ - break; \ - case HTTP_DEFLATE_TYPE_RAW: \ - wbits = HTTP_WINDOW_BITS_RAW; \ - break; \ - default: \ - wbits = HTTP_WINDOW_BITS_ZLIB; \ - break; \ - } - -#define HTTP_INFLATE_WBITS_SET(flags, wbits) \ - if (flags & HTTP_INFLATE_TYPE_RAW) { \ - wbits = HTTP_WINDOW_BITS_RAW; \ - } else { \ - wbits = HTTP_WINDOW_BITS_ANY; \ - } - -#define HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \ - switch (flags & 0xf00) \ - { \ - case HTTP_DEFLATE_STRATEGY_FILT: \ - strategy = Z_FILTERED; \ - break; \ - case HTTP_DEFLATE_STRATEGY_HUFF: \ - strategy = Z_HUFFMAN_ONLY; \ - break; \ - case HTTP_DEFLATE_STRATEGY_RLE: \ - strategy = Z_RLE; \ - break; \ - case HTTP_DEFLATE_STRATEGY_FIXED: \ - strategy = Z_FIXED; \ - break; \ - default: \ - strategy = Z_DEFAULT_STRATEGY; \ - break; \ + *buf = NULL; + *len = 0; + + phpstr_init_ex(&buffer, Z->avail_in, PHPSTR_INIT_PREALLOC); + + do { + if (PHPSTR_NOMEM == phpstr_resize_ex(&buffer, buffer.size, 0, 1)) { + status = Z_MEM_ERROR; + } else { + Z->avail_out = buffer.free; + Z->next_out = (Bytef *) buffer.data + buffer.used; +#if 0 + fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); +#endif + status = inflate(Z, flush); + + buffer.used += buffer.free - Z->avail_out; + buffer.free = Z->avail_out; +#if 0 + fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); +#endif + HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size); + } + } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < HTTP_INFLATE_ROUNDS); + + if (status == Z_OK || status == Z_STREAM_END) { + phpstr_shrink(&buffer); + phpstr_fix(&buffer); + *buf = buffer.data; + *len = buffer.used; + } else { + phpstr_dtor(&buffer); } - -#define HTTP_WINDOW_BITS_ZLIB 0x0000000f -#define HTTP_WINDOW_BITS_GZIP 0x0000001f -#define HTTP_WINDOW_BITS_ANY 0x0000002f -#define HTTP_WINDOW_BITS_RAW -0x000000f + + return status; +} /* }}} */ /* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */ @@ -333,50 +334,35 @@ PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t d /* {{{ STATUS http_encoding_inflate(char *, size_t, char **, size_t) */ 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) { - int status, round = 0, wbits = HTTP_WINDOW_BITS_ANY; z_stream Z; - phpstr buffer; + int status, wbits = HTTP_WINDOW_BITS_ANY; memset(&Z, 0, sizeof(z_stream)); - *decoded = NULL; - *decoded_len = 0; - - phpstr_init_ex(&buffer, data_len << 2, PHPSTR_INIT_PREALLOC); - buffer.size = data_len; -retry_inflate: +retry_raw_inflate: status = inflateInit2(&Z, wbits); if (Z_OK == status) { Z.next_in = (Bytef *) data; Z.avail_in = data_len; - do { - phpstr_resize(&buffer, data_len << 2); - - do { - Z.avail_out = (buffer.free -= Z.total_out - buffer.used); - Z.next_out = (Bytef *) buffer.data + (buffer.used = Z.total_out); - status = inflate(&Z, Z_NO_FLUSH); - } while (Z_OK == status); - } while (Z_BUF_ERROR == status && ++round < HTTP_INFLATE_ROUNDS); - - if (Z_DATA_ERROR == status && HTTP_WINDOW_BITS_ANY == wbits) { - /* raw deflated data? */ - inflateEnd(&Z); - wbits = HTTP_WINDOW_BITS_RAW; - goto retry_inflate; + switch (status = http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) { + case Z_STREAM_END: + inflateEnd(&Z); + return SUCCESS; + + case Z_OK: + status = Z_DATA_ERROR; + break; + + case Z_DATA_ERROR: + /* raw deflated data? */ + if (HTTP_WINDOW_BITS_ANY == wbits) { + inflateEnd(&Z); + wbits = HTTP_WINDOW_BITS_RAW; + goto retry_raw_inflate; + } } - inflateEnd(&Z); - - if (Z_STREAM_END == status) { - *decoded_len = Z.total_out; - *decoded = erealloc_rel(buffer.data, *decoded_len + 1); - (*decoded)[*decoded_len] = '\0'; - return SUCCESS; - } else { - phpstr_dtor(&buffer); - } } http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s", zError(status)); @@ -465,19 +451,21 @@ PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s s->stream.avail_out = *encoded_len; s->stream.next_out = (Bytef *) *encoded; - switch (status = deflate(&s->stream, Z_NO_FLUSH)) - { + switch (status = deflate(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) { case Z_OK: case Z_STREAM_END: /* cut processed chunk off the buffer */ - phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); + if (s->stream.avail_in) { + phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); + } else { + phpstr_reset(PHPSTR(s->stream.opaque)); + } /* size buffer down to actual size */ *encoded_len -= s->stream.avail_out; *encoded = erealloc_rel(*encoded, *encoded_len + 1); (*encoded)[*encoded_len] = '\0'; return SUCCESS; - break; } STR_SET(*encoded, NULL); @@ -490,55 +478,36 @@ PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s /* {{{ STATUS http_encoding_inflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */ 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) { - int status, round = 0; + int status; /* append input to buffer */ phpstr_append(PHPSTR(s->stream.opaque), data, data_len); - /* for realloc() */ - *decoded = NULL; - *decoded_len = data_len << 1; - - /* inflate */ - do { - *decoded_len <<= 1; - *decoded = erealloc_rel(*decoded, *decoded_len); - retry_raw_inflate: - s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); - s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); + s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); + s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); - s->stream.next_out = (Bytef *) *decoded; - s->stream.avail_out = *decoded_len; - - switch (status = inflate(&s->stream, Z_NO_FLUSH)) - { - case Z_OK: - case Z_STREAM_END: - /* cut off */ + switch (status = http_inflate_rounds(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) { + case Z_OK: + case Z_STREAM_END: + /* cut off */ + if (s->stream.avail_in) { phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); - - /* size down */ - *decoded_len -= s->stream.avail_out; - *decoded = erealloc_rel(*decoded, *decoded_len + 1); - (*decoded)[*decoded_len] = '\0'; - return SUCCESS; - break; - - case Z_DATA_ERROR: - /* raw deflated data ? */ - if (!(s->flags & HTTP_INFLATE_TYPE_RAW) && !s->stream.total_out) { - inflateEnd(&s->stream); - s->flags |= HTTP_INFLATE_TYPE_RAW; - inflateInit2(&s->stream, HTTP_WINDOW_BITS_RAW); - goto retry_raw_inflate; - } - break; - } - } while (Z_BUF_ERROR == status && ++round < HTTP_INFLATE_ROUNDS); + } else { + phpstr_reset(PHPSTR(s->stream.opaque)); + } + return SUCCESS; + + case Z_DATA_ERROR: + /* raw deflated data ? */ + if (!(s->flags & HTTP_INFLATE_TYPE_RAW) && !s->stream.total_out) { + inflateEnd(&s->stream); + s->flags |= HTTP_INFLATE_TYPE_RAW; + inflateInit2(&s->stream, HTTP_WINDOW_BITS_RAW); + goto retry_raw_inflate; + } + } - STR_SET(*decoded, NULL); - *decoded_len = 0; http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update inflate stream: %s", zError(status)); return FAILURE; } @@ -557,15 +526,13 @@ PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, s->stream.avail_out = *encoded_len; s->stream.next_out = (Bytef *) *encoded; - switch (status = deflate(&s->stream, Z_SYNC_FLUSH)) - { + switch (status = deflate(&s->stream, Z_FULL_FLUSH)) { case Z_OK: case Z_STREAM_END: *encoded_len = HTTP_DEFLATE_BUFFER_SIZE - s->stream.avail_out; *encoded = erealloc_rel(*encoded, *encoded_len + 1); (*encoded)[*encoded_len] = '\0'; return SUCCESS; - break; } STR_SET(*encoded, NULL); @@ -626,6 +593,12 @@ PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s { int status; + if (!PHPSTR_LEN(s->stream.opaque)) { + *decoded = NULL; + *decoded_len = 0; + return SUCCESS; + } + *decoded_len = (PHPSTR_LEN(s->stream.opaque) + 1) * HTTP_INFLATE_ROUNDS; *decoded = emalloc_rel(*decoded_len); @@ -707,7 +680,7 @@ PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TS /* {{{ void http_ob_deflatehandler(char *, uint, char **, uint *, int) */ void _http_ob_deflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) { - getGlobals(G); + int encoding; *handled_output = NULL; *handled_output_len = 0; @@ -715,41 +688,46 @@ void _http_ob_deflatehandler(char *output, uint output_len, char **handled_outpu if (mode & PHP_OUTPUT_HANDLER_START) { int flags; - if (G->send.deflate.stream) { + if (HTTP_G->send.deflate.stream) { zend_error(E_ERROR, "ob_deflatehandler() can only be used once"); return; } - G->send.deflate.encoding = !0; + HTTP_G->send.deflate.response = 1; + encoding = http_encoding_response_start(0, 1); + HTTP_G->send.deflate.response = 0; - switch (http_encoding_response_start(0)) - { + switch (encoding) { case HTTP_ENCODING_GZIP: flags = HTTP_DEFLATE_TYPE_GZIP; - break; + break; case HTTP_ENCODING_DEFLATE: flags = HTTP_DEFLATE_TYPE_ZLIB; - break; + break; default: goto deflate_passthru_plain; - break; } - flags |= (G->send.deflate.start_flags &~ 0xf0); - G->send.deflate.stream = http_encoding_deflate_stream_init(NULL, flags); + flags |= (HTTP_G->send.deflate.start_flags &~ 0xf0); + HTTP_G->send.deflate.stream = http_encoding_deflate_stream_init(NULL, flags); } - if (G->send.deflate.stream) { - http_encoding_deflate_stream_update((http_encoding_stream *) G->send.deflate.stream, output, output_len, handled_output, handled_output_len); + if (HTTP_G->send.deflate.stream) { + if (output_len) { + size_t tmp_len; + + http_encoding_deflate_stream_update((http_encoding_stream *) HTTP_G->send.deflate.stream, output, output_len, handled_output, &tmp_len); + *handled_output_len = tmp_len; + } if (mode & PHP_OUTPUT_HANDLER_END) { char *remaining = NULL; size_t remaining_len = 0; - http_encoding_deflate_stream_finish((http_encoding_stream *) G->send.deflate.stream, &remaining, &remaining_len); - http_encoding_deflate_stream_free((http_encoding_stream **) &G->send.deflate.stream); + http_encoding_deflate_stream_finish((http_encoding_stream *) HTTP_G->send.deflate.stream, &remaining, &remaining_len); + http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream); if (remaining) { *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1); memcpy(*handled_output + *handled_output_len, remaining, remaining_len); @@ -767,28 +745,31 @@ deflate_passthru_plain: /* {{{ void http_ob_inflatehandler(char *, uint, char **, uint *, int) */ void _http_ob_inflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) { - getGlobals(G); - *handled_output = NULL; *handled_output_len = 0; if (mode & PHP_OUTPUT_HANDLER_START) { - if (G->send.inflate.stream) { + if (HTTP_G->send.inflate.stream) { zend_error(E_ERROR, "ob_inflatehandler() can only be used once"); return; } - G->send.inflate.stream = http_encoding_inflate_stream_init(NULL, (HTTP_G(send).inflate.start_flags &~ 0xf0)); + HTTP_G->send.inflate.stream = http_encoding_inflate_stream_init(NULL, (HTTP_G->send.inflate.start_flags &~ 0xf0)); } - if (G->send.inflate.stream) { - http_encoding_inflate_stream_update((http_encoding_stream *) G->send.inflate.stream, output, output_len, handled_output, handled_output_len); + if (HTTP_G->send.inflate.stream) { + if (output_len) { + size_t tmp_len; + + http_encoding_inflate_stream_update((http_encoding_stream *) HTTP_G->send.inflate.stream, output, output_len, handled_output, &tmp_len); + *handled_output_len = tmp_len; + } if (mode & PHP_OUTPUT_HANDLER_END) { char *remaining = NULL; size_t remaining_len = 0; - http_encoding_inflate_stream_finish((http_encoding_stream *) G->send.inflate.stream, &remaining, &remaining_len); - http_encoding_inflate_stream_free((http_encoding_stream **) &G->send.inflate.stream); + http_encoding_inflate_stream_finish((http_encoding_stream *) HTTP_G->send.inflate.stream, &remaining, &remaining_len); + http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream); if (remaining) { *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1); memcpy(*handled_output + *handled_output_len, remaining, remaining_len);