mirror of
https://github.com/php/php-src.git
synced 2024-11-28 20:34:29 +08:00
fix bug #60326 - restore ob_gzhandler
This commit is contained in:
parent
3805e0a2c4
commit
bb6855124d
@ -13,7 +13,7 @@
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
|
||||
| Stefan Röhrich <sr@linux.de> |
|
||||
| Stefan R<EFBFBD>hrich <sr@linux.de> |
|
||||
| Michael Wallner <mike@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
@ -34,14 +34,6 @@
|
||||
#define PHP_ZLIB_OUTPUT_HANDLER_NAME "zlib output compression"
|
||||
#define PHP_ZLIB_BUFFER_SIZE_GUESS(in_len) (((size_t) ((double) in_len * (double) 1.015)) + 10 + 8 + 4 + 1)
|
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(zlib)
|
||||
/* variables for transparent gzip encoding */
|
||||
int compression_coding;
|
||||
long output_compression;
|
||||
long output_compression_level;
|
||||
char *output_handler;
|
||||
ZEND_END_MODULE_GLOBALS(zlib);
|
||||
|
||||
typedef struct _php_zlib_buffer {
|
||||
char *data;
|
||||
char *aptr;
|
||||
@ -55,6 +47,15 @@ typedef struct _php_zlib_context {
|
||||
php_zlib_buffer buffer;
|
||||
} php_zlib_context;
|
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(zlib)
|
||||
/* variables for transparent gzip encoding */
|
||||
int compression_coding;
|
||||
long output_compression;
|
||||
long output_compression_level;
|
||||
char *output_handler;
|
||||
php_zlib_context *ob_gzhandler;
|
||||
ZEND_END_MODULE_GLOBALS(zlib);
|
||||
|
||||
php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
|
||||
extern php_stream_ops php_stream_gzio_ops;
|
||||
extern php_stream_wrapper php_stream_gzip_wrapper;
|
||||
|
211
ext/zlib/zlib.c
211
ext/zlib/zlib.c
@ -13,7 +13,7 @@
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
|
||||
| Stefan Röhrich <sr@linux.de> |
|
||||
| Stefan R<EFBFBD>hrich <sr@linux.de> |
|
||||
| Zeev Suraski <zeev@zend.com> |
|
||||
| Jade Nicoletti <nicoletti@nns.ch> |
|
||||
| Michael Wallner <mike@php.net> |
|
||||
@ -84,30 +84,12 @@ static int php_zlib_output_encoding(TSRMLS_D)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_zlib_output_handler() */
|
||||
static int php_zlib_output_handler(void **handler_context, php_output_context *output_context)
|
||||
/* {{{ php_zlib_output_handler_ex() */
|
||||
static int php_zlib_output_handler_ex(php_zlib_context *ctx, php_output_context *output_context)
|
||||
{
|
||||
php_zlib_context *ctx = *(php_zlib_context **) handler_context;
|
||||
int flags = Z_SYNC_FLUSH;
|
||||
PHP_OUTPUT_TSRMLS(output_context);
|
||||
|
||||
if (!php_zlib_output_encoding(TSRMLS_C)) {
|
||||
/* "Vary: Accept-Encoding" header sent along uncompressed content breaks caching in MSIE,
|
||||
so let's just send it with successfully compressed content or unless the complete
|
||||
buffer gets discarded, see http://bugs.php.net/40325;
|
||||
|
||||
Test as follows:
|
||||
+Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
|
||||
+Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
|
||||
-Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
|
||||
-Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
|
||||
*/
|
||||
if (output_context->op != (PHP_OUTPUT_HANDLER_START|PHP_OUTPUT_HANDLER_CLEAN|PHP_OUTPUT_HANDLER_FINAL)) {
|
||||
sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (output_context->op & PHP_OUTPUT_HANDLER_START) {
|
||||
/* start up */
|
||||
if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
|
||||
@ -179,37 +161,85 @@ static int php_zlib_output_handler(void **handler_context, php_output_context *o
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, &flags TSRMLS_CC);
|
||||
if (!(flags & PHP_OUTPUT_HANDLER_STARTED)) {
|
||||
if (SG(headers_sent) || !ZLIBG(output_compression)) {
|
||||
deflateEnd(&ctx->Z);
|
||||
return FAILURE;
|
||||
}
|
||||
switch (ZLIBG(compression_coding)) {
|
||||
case PHP_ZLIB_ENCODING_GZIP:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
case PHP_ZLIB_ENCODING_DEFLATE:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
default:
|
||||
deflateEnd(&ctx->Z);
|
||||
return FAILURE;
|
||||
}
|
||||
sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
|
||||
deflateEnd(&ctx->Z);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_zlib_output_handler_dtor() */
|
||||
static void php_zlib_output_handler_dtor(void *opaq TSRMLS_DC)
|
||||
/* {{{ php_zlib_output_handler() */
|
||||
static int php_zlib_output_handler(void **handler_context, php_output_context *output_context)
|
||||
{
|
||||
php_zlib_context *ctx = *(php_zlib_context **) handler_context;
|
||||
PHP_OUTPUT_TSRMLS(output_context);
|
||||
|
||||
if (!php_zlib_output_encoding(TSRMLS_C)) {
|
||||
/* "Vary: Accept-Encoding" header sent along uncompressed content breaks caching in MSIE,
|
||||
so let's just send it with successfully compressed content or unless the complete
|
||||
buffer gets discarded, see http://bugs.php.net/40325;
|
||||
|
||||
Test as follows:
|
||||
+Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
|
||||
+Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
|
||||
-Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
|
||||
-Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
|
||||
*/
|
||||
if (output_context->op != (PHP_OUTPUT_HANDLER_START|PHP_OUTPUT_HANDLER_CLEAN|PHP_OUTPUT_HANDLER_FINAL)) {
|
||||
sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (SUCCESS != php_zlib_output_handler_ex(ctx, output_context)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
|
||||
int flags;
|
||||
|
||||
if (SUCCESS == php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, &flags TSRMLS_CC)) {
|
||||
/* only run this once */
|
||||
if (!(flags & PHP_OUTPUT_HANDLER_STARTED)) {
|
||||
if (SG(headers_sent) || !ZLIBG(output_compression)) {
|
||||
deflateEnd(&ctx->Z);
|
||||
return FAILURE;
|
||||
}
|
||||
switch (ZLIBG(compression_coding)) {
|
||||
case PHP_ZLIB_ENCODING_GZIP:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
case PHP_ZLIB_ENCODING_DEFLATE:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
default:
|
||||
deflateEnd(&ctx->Z);
|
||||
return FAILURE;
|
||||
}
|
||||
sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_zlib_output_handler_context_init() */
|
||||
static php_zlib_context *php_zlib_output_handler_context_init(TSRMLS_D)
|
||||
{
|
||||
php_zlib_context *ctx = (php_zlib_context *) ecalloc(1, sizeof(php_zlib_context));
|
||||
ctx->Z.zalloc = php_zlib_alloc;
|
||||
ctx->Z.zfree = php_zlib_free;
|
||||
return ctx;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_zlib_output_handler_context_dtor() */
|
||||
static void php_zlib_output_handler_context_dtor(void *opaq TSRMLS_DC)
|
||||
{
|
||||
php_zlib_context *ctx = (php_zlib_context *) opaq;
|
||||
|
||||
@ -226,17 +256,13 @@ static void php_zlib_output_handler_dtor(void *opaq TSRMLS_DC)
|
||||
static php_output_handler *php_zlib_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC)
|
||||
{
|
||||
php_output_handler *h = NULL;
|
||||
php_zlib_context *ctx;
|
||||
|
||||
if (!ZLIBG(output_compression)) {
|
||||
ZLIBG(output_compression) = chunk_size ? chunk_size : PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
if ((h = php_output_handler_create_internal(handler_name, handler_name_len, php_zlib_output_handler, chunk_size, flags TSRMLS_CC))) {
|
||||
ctx = (php_zlib_context *) ecalloc(1, sizeof(php_zlib_context));
|
||||
ctx->Z.zalloc = php_zlib_alloc;
|
||||
ctx->Z.zfree = php_zlib_free;
|
||||
php_output_handler_set_context(h, ctx, php_zlib_output_handler_dtor TSRMLS_CC);
|
||||
php_output_handler_set_context(h, php_zlib_output_handler_context_init(TSRMLS_C), php_zlib_output_handler_context_dtor TSRMLS_CC);
|
||||
}
|
||||
|
||||
return h;
|
||||
@ -401,6 +427,85 @@ retry_raw_inflate:
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_zlib_cleanup_ob_gzhandler_mess() */
|
||||
static void php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_D)
|
||||
{
|
||||
if (ZLIBG(ob_gzhandler)) {
|
||||
deflateEnd(&(ZLIBG(ob_gzhandler)->Z));
|
||||
php_zlib_output_handler_context_dtor(ZLIBG(ob_gzhandler));
|
||||
ZLIBG(ob_gzhandler) = NULL;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string ob_gzhandler(string data, int flags)
|
||||
Legacy hack */
|
||||
static PHP_FUNCTION(ob_gzhandler)
|
||||
{
|
||||
char *in_str;
|
||||
int in_len;
|
||||
long flags = 0;
|
||||
php_output_context ctx = {0};
|
||||
int encoding, rv;
|
||||
|
||||
/*
|
||||
* NOTE that the real ob_gzhandler is an alias to "zlib output compression".
|
||||
* This is a really bad hack, because
|
||||
* - we have to initialize a php_zlib_context on demand
|
||||
* - we have to clean it up in RSHUTDOWN
|
||||
* - OG(running) is not set or set to any other output handler
|
||||
* - we have to mess around with php_output_context */
|
||||
|
||||
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &in_str, &in_len, &flags)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!(encoding = php_zlib_output_encoding(TSRMLS_C))) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (flags & PHP_OUTPUT_HANDLER_START) {
|
||||
switch (encoding) {
|
||||
case PHP_ZLIB_ENCODING_GZIP:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
case PHP_ZLIB_ENCODING_DEFLATE:
|
||||
sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (!ZLIBG(ob_gzhandler)) {
|
||||
ZLIBG(ob_gzhandler) = php_zlib_output_handler_context_init(TSRMLS_C);
|
||||
}
|
||||
|
||||
TSRMLS_SET_CTX(ctx.tsrm_ls);
|
||||
ctx.op = flags;
|
||||
ctx.in.data = in_str;
|
||||
ctx.in.used = in_len;
|
||||
|
||||
rv = php_zlib_output_handler_ex(ZLIBG(ob_gzhandler), &ctx);
|
||||
|
||||
if (SUCCESS != rv) {
|
||||
if (ctx.out.data && ctx.out.free) {
|
||||
efree(ctx.out.data);
|
||||
}
|
||||
php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_C);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (ctx.out.data) {
|
||||
RETVAL_STRINGL(ctx.out.data, ctx.out.used, 1);
|
||||
if (ctx.out.free) {
|
||||
efree(ctx.out.data);
|
||||
}
|
||||
} else {
|
||||
RETVAL_EMPTY_STRING();
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string zlib_get_coding_type(void)
|
||||
Returns the coding type used for output compression */
|
||||
static PHP_FUNCTION(zlib_get_coding_type)
|
||||
@ -615,6 +720,11 @@ ZEND_GET_MODULE(php_zlib)
|
||||
#endif
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_ob_gzhandler, 0, 0, 2)
|
||||
ZEND_ARG_INFO(0, data)
|
||||
ZEND_ARG_INFO(0, flags)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_zlib_get_coding_type, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@ -737,6 +847,7 @@ static const zend_function_entry php_zlib_functions[] = {
|
||||
PHP_FE(zlib_encode, arginfo_zlib_encode)
|
||||
PHP_FE(zlib_decode, arginfo_zlib_decode)
|
||||
PHP_FE(zlib_get_coding_type, arginfo_zlib_get_coding_type)
|
||||
PHP_FE(ob_gzhandler, arginfo_ob_gzhandler)
|
||||
PHP_FE_END
|
||||
};
|
||||
/* }}} */
|
||||
@ -859,6 +970,8 @@ static PHP_RSHUTDOWN_FUNCTION(zlib)
|
||||
{
|
||||
ZLIBG(output_compression) = 0;
|
||||
|
||||
php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_C);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user