From: Michael Wallner Date: Thu, 13 Oct 2005 14:36:21 +0000 (+0000) Subject: - independency from ext/zlib X-Git-Tag: RELEASE_0_16_0~17 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=a8eb47f443e1ead6b1b2d79000f0b89374a92629 - independency from ext/zlib - added http_encode()/http_decode() wrappers - added http_negotiate_encoding() - removed bug_34191.phpt; does not affect us any longer # Ineed to look up the RFC before the ranges support gz encoding; # I even think the current/past behaviour of sending multiple # ranges with og_gzhandler/zlib.output_compression was bogus --- diff --git a/http_encoding_api.c b/http_encoding_api.c index 4d08e71..28ea423 100644 --- a/http_encoding_api.c +++ b/http_encoding_api.c @@ -308,6 +308,71 @@ inline STATUS http_verify_gzdecode_buffer(const char *data, size_t data_len, con return status; } +PHP_HTTP_API STATUS _http_encode(http_encoding_type type, int level, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) +{ + STATUS status = SUCCESS; + + switch (type) + { + case HTTP_ENCODING_ANY: + case HTTP_ENCODING_GZIP: + status = http_encoding_gzencode(level, data, data_len, encoded, encoded_len); + break; + + case HTTP_ENCODING_DEFLATE: + status = http_encoding_deflate(level, data, data_len, encoded, encoded_len); + break; + + case HTTP_ENCODING_COMPRESS: + status = http_encoding_compress(level, data, data_len, encoded, encoded_len); + break; + + case HTTP_ENCODING_NONE: + default: + *encoded = estrndup(data, data_len); + *encoded_len = data_len; + break; + } + + return status; +} + +PHP_HTTP_API STATUS _http_decode(http_encoding_type type, const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + STATUS status = SUCCESS; + + switch (type) + { + case HTTP_ENCODING_ANY: + if ( SUCCESS != http_encoding_gzdecode(data, data_len, decoded, decoded_len) && + SUCCESS != http_encoding_inflate(data, data_len, decoded, decoded_len) && + SUCCESS != http_encoding_uncompress(data, data_len, decoded, decoded_len)) { + status = FAILURE; + } + break; + + case HTTP_ENCODING_GZIP: + status = http_encoding_gzdecode(data, data_len, decoded, decoded_len); + break; + + case HTTP_ENCODING_DEFLATE: + status = http_encoding_inflate(data, data_len, decoded, decoded_len); + break; + + case HTTP_ENCODING_COMPRESS: + status = http_encoding_uncompress(data, data_len, decoded, decoded_len); + break; + + case HTTP_ENCODING_NONE: + default: + *decoded = estrndup(data, data_len); + *decoded_len = data_len; + break; + } + + return status; +} + PHP_HTTP_API STATUS _http_encoding_gzencode(int level, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) { z_stream Z; diff --git a/http_headers_api.c b/http_headers_api.c index e934180..52f2bb8 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -103,8 +103,8 @@ char *_http_negotiate_language_func(const char *test, double *quality, HashTable } /* }}} */ -/* {{{ char *http_negotiate_charset_func */ -char *_http_negotiate_charset_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) +/* {{{ char *http_negotiate_default_func */ +char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) { zval **value; diff --git a/http_response_object.c b/http_response_object.c index 9193590..a617c9f 100644 --- a/http_response_object.c +++ b/http_response_object.c @@ -1106,17 +1106,14 @@ PHP_METHOD(HttpResponse, send) } /* throttling */ - { - HTTP_G(send).buffer_size = Z_LVAL_P(convert_to_type_ex(IS_LONG, GET_STATIC_PROP(bufferSize))); - HTTP_G(send).throttle_delay = Z_DVAL_P(convert_to_type_ex(IS_DOUBLE, GET_STATIC_PROP(throttleDelay))); - } + HTTP_G(send).buffer_size = Z_LVAL_P(convert_to_type_ex(IS_LONG, GET_STATIC_PROP(bufferSize))); + HTTP_G(send).throttle_delay = Z_DVAL_P(convert_to_type_ex(IS_DOUBLE, GET_STATIC_PROP(throttleDelay))); /* gzip */ - if (zval_is_true(GET_STATIC_PROP(gzip))) { - php_start_ob_buffer_named("ob_gzhandler", HTTP_G(send).buffer_size, 0 TSRMLS_CC); - } else { - php_start_ob_buffer(NULL, HTTP_G(send).buffer_size, 0 TSRMLS_CC); - } + HTTP_G(send).gzip_encoding = zval_is_true(GET_STATIC_PROP(gzip)); + + /* start ob */ + php_start_ob_buffer(NULL, HTTP_G(send).buffer_size, 0 TSRMLS_CC); /* send */ switch (Z_LVAL_P(GET_STATIC_PROP(mode))) diff --git a/http_send_api.c b/http_send_api.c index 0c4306f..f6b3d73 100644 --- a/http_send_api.c +++ b/http_send_api.c @@ -32,6 +32,7 @@ #include "php_http_headers_api.h" #include "php_http_date_api.h" #include "php_http_cache_api.h" +#include "php_http_encoding_api.h" ZEND_EXTERN_MODULE_GLOBALS(http); @@ -73,11 +74,30 @@ static inline void _http_sleep(TSRMLS_D) } } /* }}} */ +#ifdef HTTP_HAVE_ZLIB +# define HTTP_CHUNK_ENCODE(data, size, dogzip) \ + if (dogzip) { \ + char *encoded = NULL; \ + size_t encoded_len = 0; \ + \ + if (SUCCESS != http_encode(dogzip, 1, data, size, &encoded, &encoded_len)) { \ + return FAILURE; \ + } \ + \ + data = encoded; \ + size = encoded_len; \ + } +#else +# define HTTP_CHUNK_ENCODE(data, size, dogzip) +#endif -#define HTTP_CHUNK_AVAIL(len) ((len -= HTTP_G(send).buffer_size) >= 0) -#define HTTP_CHUNK_WRITE(data, l, dofree, dosleep) \ +#define HTTP_CHUNK_AVAIL(len, cs) ((len -= cs) >= 0) +#define HTTP_CHUNK_WRITE(d, l, dofree, dosleep, dogzip) \ { \ long size = (long) l; \ + char *data = (char *) d; \ + \ + HTTP_CHUNK_ENCODE(data, size, dogzip); \ \ if ((1 > size) || (size - PHPWRITE(data, size))) { \ if (dofree) { \ @@ -97,6 +117,8 @@ static inline void _http_sleep(TSRMLS_D) static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_send_mode mode TSRMLS_DC) { long len = end - begin; + size_t chunk_size = HTTP_G(send).buffer_size; + http_encoding_type gzip = HTTP_G(send).gzip_encoding; switch (mode) { @@ -111,13 +133,13 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_ buf = emalloc(HTTP_G(send).buffer_size); - while (HTTP_CHUNK_AVAIL(len)) { - HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, HTTP_G(send).buffer_size), 1, 1); + while (HTTP_CHUNK_AVAIL(len, chunk_size)) { + HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, chunk_size), 1, 1, gzip); } /* read & write left over */ if (len) { - HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, HTTP_G(send).buffer_size + len), 1, 0); + HTTP_CHUNK_WRITE(buf, php_stream_read(s, buf, chunk_size + len), 1, 0, gzip); } efree(buf); @@ -128,14 +150,14 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_ { char *s = (char *) data + begin; - while (HTTP_CHUNK_AVAIL(len)) { - HTTP_CHUNK_WRITE(s, HTTP_G(send).buffer_size, 0, 1); - s += HTTP_G(send).buffer_size; + while (HTTP_CHUNK_AVAIL(len, chunk_size)) { + HTTP_CHUNK_WRITE(s, chunk_size, 0, 1, gzip); + s += chunk_size; } /* write left over */ if (len) { - HTTP_CHUNK_WRITE(s, HTTP_G(send).buffer_size + len, 0, 0); + HTTP_CHUNK_WRITE(s, chunk_size + len, 0, 0, gzip); } return SUCCESS; @@ -340,7 +362,7 @@ PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_s { HashTable ranges; http_range_status range_status; - int cache_etag = 0; + int cache_etag = 0, external_gzip_handlers = 0; if (!data_ptr) { return FAILURE; @@ -352,6 +374,10 @@ PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_s /* stop on-the-fly etag generation */ cache_etag = http_interrupt_ob_etaghandler(); + if ( php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || + php_ob_handler_used("zlib output compression" TSRMLS_CC)) { + external_gzip_handlers = 1; + } /* enable partial dl and resume */ http_send_header_string("Accept-Ranges: bytes"); @@ -400,13 +426,62 @@ PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_s return http_exit_ex(304, sent_header, NULL, 0); } - /* emit a content-length header */ - if (!php_ob_handler_used("ob_gzhandler" TSRMLS_CC)) { + if (external_gzip_handlers) { +#ifdef HTTP_HAVE_ZLIB + if (HTTP_G(send).gzip_encoding) { + HTTP_G(send).gzip_encoding = 0; + } + } else if (HTTP_G(send).gzip_encoding) { + HashTable *selected; + zval zsupported; + + INIT_PZVAL(&zsupported); + array_init(&zsupported); + add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1); + add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1); + add_next_index_stringl(&zsupported, "compress", lenof("compress"), 1); + + if (selected = http_negotiate_encoding(&zsupported)) { + char *encoding = NULL; + ulong idx; + + if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) { + STATUS hs = FAILURE; + + if (!strcmp(encoding, "gzip")) { + if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) { + HTTP_G(send).gzip_encoding = HTTP_ENCODING_GZIP; + } + } else if (!strcmp(encoding, "deflate")) { + if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) { + HTTP_G(send).gzip_encoding = HTTP_ENCODING_DEFLATE; + } + } else if (!strcmp(encoding, "compress")) { + if (SUCCESS == (hs = http_send_header_string("Content-Encoding: compress"))) { + HTTP_G(send).gzip_encoding = HTTP_ENCODING_COMPRESS; + } + } + if (SUCCESS == hs) { + http_send_header_string("Vary: Accept-Encoding"); + } else { + HTTP_G(send).gzip_encoding = 0; + } + } + + zend_hash_destroy(selected); + FREE_HASHTABLE(selected); + } + + zval_dtor(&zsupported); +#endif + } else { + /* emit a content-length header */ char *cl; spprintf(&cl, 0, "Content-Length: %lu", (unsigned long) data_size); http_send_header_string(cl); efree(cl); } + /* send full entity */ return http_send_chunk(data_ptr, 0, data_size, data_mode); } diff --git a/php_http.h b/php_http.h index a11d484..224a3aa 100644 --- a/php_http.h +++ b/php_http.h @@ -18,7 +18,7 @@ #ifndef PHP_EXT_HTTP_H #define PHP_EXT_HTTP_H -#define HTTP_PEXT_VERSION "0.15.1dev" +#define HTTP_PEXT_VERSION "0.16.0dev" /* make compile on Win32 */ #ifdef HTTP_HAVE_CURL @@ -59,6 +59,7 @@ ZEND_BEGIN_MODULE_GLOBALS(http) char *content_type; char *unquoted_etag; time_t last_modified; + zend_bool gzip_encoding; } send; struct _http_globals_request { diff --git a/php_http_encoding_api.h b/php_http_encoding_api.h index 7e235c7..60dbc11 100644 --- a/php_http_encoding_api.h +++ b/php_http_encoding_api.h @@ -25,6 +25,19 @@ PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t enco #ifdef HTTP_HAVE_ZLIB +typedef enum { + HTTP_ENCODING_NONE = 0, + HTTP_ENCODING_ANY = 1, + HTTP_ENCODING_GZIP, + HTTP_ENCODING_DEFLATE, + HTTP_ENCODING_COMPRESS +} http_encoding_type; + +#define http_encode(t, l, d, dl, r, rl) _http_encode((t), (l), (d), (dl), (r), (rl) TSRMLS_CC) +PHP_HTTP_API STATUS _http_encode(http_encoding_type type, int level, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); +#define http_decode(t, d, dl, r, rl) _http_decode((t), (l), (d), (dl), (r), (rl) TSRMLS_CC) +PHP_HTTP_API STATUS _http_decode(http_encoding_type type, const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC); + #define http_encoding_gzencode(l, d, dl, r, rl) _http_encoding_gzencode((l), (d), (dl), (r), (rl) TSRMLS_CC) PHP_HTTP_API STATUS _http_encoding_gzencode(int level, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); #define http_encoding_gzdecode(d, dl, r, rl) _http_encoding_gzdecode((d), (dl), (r), (rl) TSRMLS_CC) diff --git a/php_http_headers_api.h b/php_http_headers_api.h index 8b3b95f..be39e17 100644 --- a/php_http_headers_api.h +++ b/php_http_headers_api.h @@ -47,13 +47,17 @@ typedef char *(*negotiate_func_t)(const char *test, double *quality, HashTable * #define http_negotiate_language_func _http_negotiate_language_func extern char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); -#define http_negotiate_charset_func _http_negotiate_charset_func -extern char *_http_negotiate_charset_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); +#define http_negotiate_encoding_func _http_negotiate_default_func +#define http_negotiate_charset_func _http_negotiate_default_func +#define http_negotiate_default_func _http_negotiate_default_func +extern char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); #define http_negotiate_language(zsupported) http_negotiate_language_ex(Z_ARRVAL_P(zsupported)) #define http_negotiate_language_ex(supported) http_negotiate_q("HTTP_ACCEPT_LANGUAGE", (supported), http_negotiate_language_func) #define http_negotiate_charset(zsupported) http_negotiate_charset_ex(Z_ARRVAL_P(zsupported)) #define http_negotiate_charset_ex(supported) http_negotiate_q("HTTP_ACCEPT_CHARSET", (supported), http_negotiate_charset_func) +#define http_negotiate_encoding(zsupported) http_negotiate_encoding_ex(Z_ARRVAL_P(zsupported)) +#define http_negotiate_encoding_ex(supported) http_negotiate_q("HTTP_ACCEPT_ENCODING", (supported), http_negotiate_encoding_func) #define http_negotiate_q(e, s, n) _http_negotiate_q((e), (s), (n) TSRMLS_CC) PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC); diff --git a/tests/bug_34191.phpt b/tests/bug_34191.phpt deleted file mode 100644 index 65c2b89..0000000 Binary files a/tests/bug_34191.phpt and /dev/null differ