- independency from ext/zlib
authorMichael Wallner <mike@php.net>
Thu, 13 Oct 2005 14:36:21 +0000 (14:36 +0000)
committerMichael Wallner <mike@php.net>
Thu, 13 Oct 2005 14:36:21 +0000 (14:36 +0000)
- 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

http_encoding_api.c
http_headers_api.c
http_response_object.c
http_send_api.c
php_http.h
php_http_encoding_api.h
php_http_headers_api.h
tests/bug_34191.phpt [deleted file]

index 4d08e71c2c2bf5e582e74b0ae31c0dd33512489c..28ea4232d2627dcf2d5d5e61e51f6ec1ac0eafe1 100644 (file)
@@ -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;
index e93418008e3fc41108f36c0f9a86de781fb25d3c..52f2bb8e15cd51a19cd55059d26509c4373f8fc9 100644 (file)
@@ -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;
        
index 9193590266ebbf31cd116c6d8189bffd1e1f05e6..a617c9f1c942b7dc3884a3f9f24c757ebef01bc1 100644 (file)
@@ -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)))
index 0c4306f86afd130eac668d076423f58cdc3f7ed8..f6b3d73467bd78933ffe88ef5afc3766342b83d0 100644 (file)
@@ -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);
 }
index a11d4848323ac5a646341b526f458b1871133955..224a3aa704ef889170f7d48ddc598e5d64320386 100644 (file)
@@ -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 {
index 7e235c7bc739cfabee25ebab86745d0261f69136..60dbc11f26e1c233181993d5f1923a5e4819d5bd 100644 (file)
@@ -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)
index 8b3b95f1771e7309118fb6f25369fd2107c8a4b8..be39e1713a41bcc4d88a996d83e174519aa735e6 100644 (file)
@@ -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 (file)
index 65c2b89..0000000
Binary files a/tests/bug_34191.phpt and /dev/null differ