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;
}
/* }}} */
-/* {{{ 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;
}
/* 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)))
#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);
}
}
/* }}} */
+#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) { \
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)
{
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);
{
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;
{
HashTable ranges;
http_range_status range_status;
- int cache_etag = 0;
+ int cache_etag = 0, external_gzip_handlers = 0;
if (!data_ptr) {
return FAILURE;
/* 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");
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);
}
#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
char *content_type;
char *unquoted_etag;
time_t last_modified;
+ zend_bool gzip_encoding;
} send;
struct _http_globals_request {
#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)
#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);