From a19f558421040b5396b3d76e6c4878d7eda85aba Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 20 Dec 2005 23:31:24 +0000 Subject: [PATCH] - CURLOPT_COOKIELIST needs curl 7.15 - fixed typo in phpstr.h - reimplemented encoding api - removed http_gzencode()/http_gzdecode(); zlib *can* do that - http_deflate() accepts various flags now, pass HTTP_DEFLATE_TYPE_GZIP for gzip encoding; HTTP_DEFLATE_TYPE_ZLIB (default) for HTTP deflate (AKA zlib) encoding HTTP_DEFLATE_TYPE_RAW for raw deflate encoding (same as PHPs gzdeflate); - http_inflate() can decode all 3 formats --- http.c | 8 +- http_api.c | 2 +- http_encoding_api.c | 605 ++++++++++++++++++++++------------ http_filter_api.c | 183 +++++----- http_functions.c | 78 +---- http_message_api.c | 2 +- http_request_api.c | 4 +- http_send_api.c | 23 +- http_util_object.c | 2 - php_http.h | 2 - php_http_encoding_api.h | 75 +++-- php_http_util_object.h | 2 - phpstr/phpstr.h | 2 +- tests/build_url_002.phpt | 2 +- tests/stream_filters_002.phpt | 16 +- 15 files changed, 581 insertions(+), 425 deletions(-) diff --git a/http.c b/http.c index d0617b6..00f8774 100644 --- a/http.c +++ b/http.c @@ -35,6 +35,9 @@ #ifdef HTTP_HAVE_CURL # include "php_http_request_api.h" #endif +#ifdef HTTP_HAVE_ZLIB +# include "php_http_encoding_api.h" +#endif #ifdef ZEND_ENGINE_2 # include "php_http_filter_api.h" @@ -103,8 +106,6 @@ zend_function_entry http_functions[] = { #endif PHP_FE(ob_etaghandler, NULL) #ifdef HTTP_HAVE_ZLIB - PHP_FE(http_gzencode, NULL) - PHP_FE(http_gzdecode, NULL) PHP_FE(http_deflate, NULL) PHP_FE(http_inflate, NULL) #endif @@ -223,6 +224,9 @@ PHP_MINIT_FUNCTION(http) #ifdef HTTP_HAVE_CURL (SUCCESS != PHP_MINIT_CALL(http_request)) || #endif /* HTTP_HAVE_CURL */ +#ifdef HTTP_HAVE_ZLIB + (SUCCESS != PHP_MINIT_CALL(http_encoding)) || +#endif (SUCCESS != PHP_MINIT_CALL(http_request_method))) { return FAILURE; } diff --git a/http_api.c b/http_api.c index 22d622c..a5ecb12 100644 --- a/http_api.c +++ b/http_api.c @@ -55,7 +55,7 @@ PHP_HTTP_API long _http_support(long feature) #ifdef HTTP_HAVE_MAGIC support |= HTTP_SUPPORT_MAGICMIME; #endif -#if defined(HTTP_HAVE_ZLIB) || defined(HAVE_ZLIB) +#ifdef HTTP_HAVE_ZLIB support |= HTTP_SUPPORT_ENCODINGS; #endif diff --git a/http_encoding_api.c b/http_encoding_api.c index efbaa7f..53c14d3 100644 --- a/http_encoding_api.c +++ b/http_encoding_api.c @@ -26,6 +26,24 @@ ZEND_EXTERN_MODULE_GLOBALS(http); +#ifdef HTTP_HAVE_ZLIB +PHP_MINIT_FUNCTION(http_encoding) +{ + HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF); + HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT); + 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); + return SUCCESS; +} +#endif + static inline int eol_match(char **line, int *eol_len) { char *ptr = *line; @@ -116,187 +134,429 @@ PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t enco #ifdef HTTP_HAVE_ZLIB -static const char http_encoding_gzip_header[] = { - (const char) 0x1f, // fixed value - (const char) 0x8b, // fixed value - (const char) Z_DEFLATED, // compression algorithm - (const char) 0, // none of the possible flags defined by the GZIP "RFC" - (const char) 0, // MTIME - (const char) 0, // =*= - (const char) 0, // =*= - (const char) 0, // =*= - (const char) 0, // two possible flag values for 9 compression levels? o_O -#ifdef PHP_WIN32 - (const char) 0x0b // OS_CODE -#else - (const char) 0x03 // OS_CODE -#endif -}; +#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; \ + } + +#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; \ + } -PHP_HTTP_API STATUS _http_encoding_gzencode(int level, int mtime, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) +#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; \ + } + +#define HTTP_WINDOW_BITS_ZLIB 0x0000000f +#define HTTP_WINDOW_BITS_GZIP 0x0000001f +#define HTTP_WINDOW_BITS_ANY 0x0000002f +#define HTTP_WINDOW_BITS_RAW -0x000000f + +STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) { + int status, level, wbits, strategy; z_stream Z; - STATUS status = Z_OK; - if (!(data && data_len)) { - return FAILURE; - } + HTTP_DEFLATE_LEVEL_SET(flags, level); + HTTP_DEFLATE_WBITS_SET(flags, wbits); + HTTP_DEFLATE_STRATEGY_SET(flags, strategy); + memset(&Z, 0, sizeof(z_stream)); *encoded = NULL; *encoded_len = 0; - memset(&Z, 0, sizeof(z_stream)); - Z.next_in = (Bytef *) data; - Z.avail_in = data_len; - Z.avail_out = HTTP_ENCODING_BUFLEN(data_len) + HTTP_ENCODING_SAFPAD - 1; + status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy); + if (Z_OK == status) { + *encoded_len = HTTP_ENCODING_BUFLEN(data_len); + *encoded = emalloc(*encoded_len); + + Z.next_in = (Bytef *) data; + Z.next_out = (Bytef *) *encoded; + Z.avail_in = data_len; + Z.avail_out = *encoded_len; + + status = deflate(&Z, Z_FINISH); + if (Z_STREAM_END == status) { + /* size buffer down to actual length */ + *encoded = erealloc(*encoded, Z.total_out + 1); + (*encoded)[*encoded_len = Z.total_out] = '\0'; + deflateEnd(&Z); + return SUCCESS; + } else { + STR_SET(*encoded, NULL); + *encoded_len = 0; + } + } - *encoded = emalloc(HTTP_ENCODING_BUFLEN(data_len) + sizeof(http_encoding_gzip_header) + HTTP_ENCODING_SAFPAD); - memcpy(*encoded, http_encoding_gzip_header, sizeof(http_encoding_gzip_header)); + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not deflate data: %s (%s)", zError(status), Z.msg); + deflateEnd(&Z); + return FAILURE; +} + +STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + int status, max = 0, wbits = HTTP_WINDOW_BITS_ANY; + z_stream Z; + phpstr buffer; - if (mtime) { - (*encoded)[4] = (char) (mtime & 0xFF); - (*encoded)[5] = (char) ((mtime >> 8) & 0xFF); - (*encoded)[6] = (char) ((mtime >> 16) & 0xFF); - (*encoded)[7] = (char) ((mtime >> 24) & 0xFF); - } + memset(&Z, 0, sizeof(z_stream)); + *decoded = NULL; + *decoded_len = 0; - Z.next_out = (Bytef *) *encoded + sizeof(http_encoding_gzip_header); + phpstr_init_ex(&buffer, data_len << 2, PHPSTR_INIT_PREALLOC); + buffer.size = data_len; - if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) { - status = deflate(&Z, Z_FINISH); - deflateEnd(&Z); +retry_inflate: + status = inflateInit2(&Z, wbits); + if (Z_OK == status) { + Z.next_in = (Bytef *) data; + Z.avail_in = data_len; - if (Z_STREAM_END == status) { - ulong crc; - char *trailer; - - crc = crc32(0L, Z_NULL, 0); - crc = crc32(crc, (const Bytef *) data, data_len); - - trailer = *encoded + sizeof(http_encoding_gzip_header) + Z.total_out; - - /* LSB */ - trailer[0] = (char) (crc & 0xFF); - trailer[1] = (char) ((crc >> 8) & 0xFF); - trailer[2] = (char) ((crc >> 16) & 0xFF); - trailer[3] = (char) ((crc >> 24) & 0xFF); - trailer[4] = (char) ((Z.total_in) & 0xFF); - trailer[5] = (char) ((Z.total_in >> 8) & 0xFF); - trailer[6] = (char) ((Z.total_in >> 16) & 0xFF); - trailer[7] = (char) ((Z.total_in >> 24) & 0xFF); + do { + phpstr_resize(&buffer, data_len); + + do { + Z.next_out = buffer.data + (buffer.used += Z.total_out); + Z.avail_out = (buffer.free -= Z.total_out); + status = inflate(&Z, Z_NO_FLUSH); + } while (Z_OK == status); - *encoded_len = Z.total_out + sizeof(http_encoding_gzip_header) + 8; - (*encoded)[*encoded_len] = '\0'; + } while (Z_BUF_ERROR == status && ++max < HTTP_ENCODING_MAXTRY); + + if (Z_DATA_ERROR == status && HTTP_WINDOW_BITS_ANY == wbits) { + /* raw deflated data? */ + inflateEnd(&Z); + wbits = HTTP_WINDOW_BITS_RAW; + goto retry_inflate; + } + + if (Z_STREAM_END == status) { + *decoded = erealloc(buffer.data, (buffer.used += Z.total_out) + 1); + (*decoded)[*decoded_len = buffer.used] = '\0'; + inflateEnd(&Z); return SUCCESS; + } else { + phpstr_dtor(&buffer); } } - STR_SET(*encoded, NULL); - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not gzencode data: %s", zError(status)); + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s (%s)", zError(status), Z.msg); + inflateEnd(&Z); return FAILURE; } -PHP_HTTP_API STATUS _http_encoding_gzdecode(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) + +http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags TSRMLS_DC) { - const char *encoded; - size_t encoded_len; + int status, level, wbits, strategy, free_stream; - if ( (data && data_len) && - (SUCCESS == http_encoding_gzencode_verify(data, data_len, &encoded, &encoded_len)) && - (SUCCESS == http_encoding_inflate(encoded, encoded_len, decoded, decoded_len))) { - http_encoding_gzdecode_verify(data, data_len, *decoded, *decoded_len); - return SUCCESS; + if ((free_stream = !s)) { + s = pemalloc(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT)); } + memset(s, 0, sizeof(http_encoding_stream)); + s->flags = flags; - return FAILURE; + HTTP_DEFLATE_LEVEL_SET(flags, level); + HTTP_DEFLATE_WBITS_SET(flags, wbits); + HTTP_DEFLATE_STRATEGY_SET(flags, strategy); + + if (Z_OK == (status = deflateInit2(&s->stream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) { + int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0; + + if ((s->stream.opaque = phpstr_init_ex(NULL, 0x8000, p))) { + return s; + } + deflateEnd(&s->stream); + status = Z_MEM_ERROR; + } + + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize deflate encoding stream: %s", zError(status)); + if (free_stream) { + efree(s); + } + return NULL; } -PHP_HTTP_API STATUS _http_encoding_deflate(int level, int zhdr, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) +http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags TSRMLS_DC) { - z_stream Z; - STATUS status = Z_OK; + int status, wbits, free_stream; - *encoded = NULL; - *encoded_len = 0; - memset(&Z, 0, sizeof(z_stream)); - - Z.data_type = Z_UNKNOWN; - Z.next_in = (Bytef *) data; - Z.avail_in = data_len; - Z.avail_out = HTTP_ENCODING_BUFLEN(data_len) - 1; - Z.next_out = emalloc(HTTP_ENCODING_BUFLEN(data_len)); + if ((free_stream = !s)) { + s = emalloc(sizeof(http_encoding_stream)); + } + memset(s, 0, sizeof(http_encoding_stream)); + s->flags = flags; - *encoded = (char *) Z.next_out; + HTTP_INFLATE_WBITS_SET(flags, wbits); - if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, zhdr ? MAX_WBITS : -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) { - status = deflate(&Z, Z_FINISH); - deflateEnd(&Z); + if (Z_OK == (status = inflateInit2(&s->stream, wbits))) { + int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0; - if (Z_STREAM_END == status) { - (*encoded)[*encoded_len = Z.total_out] = '\0'; - return SUCCESS; + if ((s->stream.opaque = phpstr_init_ex(NULL, 0x8000, p))) { + return s; } + inflateEnd(&s->stream); + status = Z_MEM_ERROR; + } + + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize inflate stream: %s", zError(status)); + if (free_stream) { + efree(s); + } + return NULL; +} + +STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) +{ + int status; + + /* append input to our buffer */ + phpstr_append(PHPSTR(s->stream.opaque), data, data_len); + + s->stream.next_in = PHPSTR_VAL(s->stream.opaque); + s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); + + /* deflate */ + s->stream.avail_out = *encoded_len = HTTP_ENCODING_BUFLEN(data_len); + s->stream.next_out = *encoded = emalloc(*encoded_len); + + switch (status = deflate(&s->stream, Z_NO_FLUSH)) + { + case Z_OK: + case Z_STREAM_END: + /* cut processed chunk off the buffer */ + phpstr_cut(PHPSTR(s->stream.opaque), 0, data_len - s->stream.avail_in); + + /* size buffer down to actual size */ + *encoded_len -= s->stream.avail_out; + *encoded = erealloc(*encoded, *encoded_len + 1); + (*encoded)[*encoded_len] = '\0'; + return SUCCESS; + break; } STR_SET(*encoded, NULL); - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not deflate data: %s", zError(status)); + *encoded_len = 0; + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update deflate stream: %s", zError(status)); return FAILURE; } -PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) +STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) { - int max = 0, wbits = -MAX_WBITS; - STATUS status; - z_stream Z; + int status, max = 0; + + /* append input to buffer */ + phpstr_append(PHPSTR(s->stream.opaque), data, data_len); + /* for realloc() */ *decoded = NULL; - *decoded_len = 0; - memset(&Z, 0, sizeof(z_stream)); + *decoded_len = data_len << 1; + /* inflate */ do { - if (!max) { - *decoded_len = data_len * 2; - *decoded = emalloc(*decoded_len + 1); - } else { - size_t new_len = *decoded_len << 2; - char *new_ptr = erealloc_recoverable(*decoded, new_len + 1); - - if (new_ptr) { - *decoded = new_ptr; - *decoded_len = new_len; - } else { - max = INT_MAX-1; /* avoid integer overflow on increment op */ - } - } + *decoded_len <<= 1; + *decoded = erealloc(*decoded, *decoded_len); -retry_inflate: - Z.next_in = (Bytef *) data; - Z.avail_in = data_len; - Z.next_out = (Bytef *) *decoded; - Z.avail_out = *decoded_len; +retry_raw_inflate: + s->stream.next_in = PHPSTR_VAL(s->stream.opaque); + s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); + + s->stream.next_out = *decoded; + s->stream.avail_out = *decoded_len; - if (Z_OK == (status = inflateInit2(&Z, wbits))) { - status = inflate(&Z, Z_FINISH); - inflateEnd(&Z); - - /* retry if it looks like we've got a zlib header */ - if (wbits == -MAX_WBITS && status == Z_DATA_ERROR) { - wbits = MAX_WBITS; - goto retry_inflate; - } - - if (Z_STREAM_END == status) { - (*decoded)[*decoded_len = Z.total_out] = '\0'; + switch (status = inflate(&s->stream, Z_NO_FLUSH)) + { + case Z_OK: + case Z_STREAM_END: + /* cut off */ + phpstr_cut(PHPSTR(s->stream.opaque), 0, data_len - s->stream.avail_in); + + /* size down */ + *decoded_len -= s->stream.avail_out; + *decoded = erealloc(*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 (status == Z_BUF_ERROR && ++max < HTTP_ENCODING_MAXTRY); + if (Z_BUF_ERROR == status) DebugBreak(); + } while (Z_BUF_ERROR == status && ++max < HTTP_ENCODING_MAXTRY); + + STR_SET(*decoded, NULL); + *decoded_len = 0; + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not update inflate stream: %s", zError(status)); + return FAILURE; +} + +STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len TSRMLS_DC) +{ + int status; + + /* deflate remaining input */ + s->stream.next_in = PHPSTR_VAL(s->stream.opaque); + s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); + + s->stream.avail_out = *encoded_len = 0x800; + s->stream.next_out = *encoded = emalloc(*encoded_len); + + do { + status = deflate(&s->stream, Z_FINISH); + } while (Z_OK == status); + + if (Z_STREAM_END == status) { + /* cut processed intp off */ + phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); + + /* size down */ + *encoded_len -= s->stream.avail_out; + *encoded = erealloc(*encoded, *encoded_len + 1); + (*encoded)[*encoded_len] = '\0'; + return SUCCESS; + } + + STR_SET(*encoded, NULL); + *encoded_len = 0; + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish deflate stream: %s", zError(status)); + return FAILURE; +} + +STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + int status; + + /* inflate remaining input */ + s->stream.next_in = PHPSTR_VAL(s->stream.opaque); + s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); + + s->stream.avail_out = *decoded_len = s->stream.avail_in << 2; + s->stream.next_out = *decoded = emalloc(*decoded_len); + + if (Z_STREAM_END == (status = inflate(&s->stream, Z_FINISH))) { + /* cut processed input off */ + 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(*decoded, *decoded_len + 1); + (*decoded)[*decoded_len] = '\0'; + return SUCCESS; + } STR_SET(*decoded, NULL); - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s", zError(status)); + *decoded_len = 0; + http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish inflate stream: %s", zError(status)); return FAILURE; } +void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC) +{ + if (s) { + if (s->stream.opaque) { + phpstr_free((phpstr **) &s->stream.opaque); + } + deflateEnd(&s->stream); + } +} + +void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC) +{ + if (s) { + if (s->stream.opaque) { + phpstr_free((phpstr **) &s->stream.opaque); + } + inflateEnd(&s->stream); + } +} + +void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC) +{ + if (s) { + http_encoding_deflate_stream_dtor(*s); + if (*s) { + pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT); + } + *s = NULL; + } +} + +void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC) +{ + if (s) { + http_encoding_inflate_stream_dtor(*s); + if (*s) { + pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT); + } + *s = NULL; + } +} + +static const char http_encoding_gzip_header[] = { + (const char) 0x1f, // fixed value + (const char) 0x8b, // fixed value + (const char) Z_DEFLATED, // compression algorithm + (const char) 0, // none of the possible flags defined by the GZIP "RFC" + (const char) 0, // MTIME + (const char) 0, // =*= + (const char) 0, // =*= + (const char) 0, // =*= + (const char) 0, // two possible flag values for 9 compression levels? o_O +#ifdef PHP_WIN32 + (const char) 0x0b // OS_CODE +#else + (const char) 0x03 // OS_CODE +#endif +}; + PHP_HTTP_API STATUS _http_encoding_gzencode_verify(const char *data, size_t data_len, const char **encoded, size_t *encoded_len, int error_level TSRMLS_DC) { size_t offset = sizeof(http_encoding_gzip_header); @@ -406,95 +666,6 @@ PHP_HTTP_API STATUS _http_encoding_gzdecode_verify(const char *data, size_t data return status; } -#define HTTP_ENCODING_STREAM_ERROR(status, tofree) \ - { \ - if (tofree) efree(tofree); \ - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "GZIP stream error: %s", zError(status)); \ - return FAILURE; \ - } - -PHP_HTTP_API STATUS _http_encoding_stream_init(http_encoding_stream *s, int flags, int level, char **encoded, size_t *encoded_len TSRMLS_DC) -{ - STATUS status; - int wbits = (flags & HTTP_ENCODING_STREAM_ZLIB_HEADER) ? MAX_WBITS : -MAX_WBITS; - - memset(s, 0, sizeof(http_encoding_stream)); - if (Z_OK != (status = deflateInit2(&s->Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) { - HTTP_ENCODING_STREAM_ERROR(status, NULL); - } - - s->persistent = (flags & HTTP_ENCODING_STREAM_PERSISTENT); - if ((s->gzip = (flags & HTTP_ENCODING_STREAM_GZIP_HEADER))) { - s->crc = crc32(0L, Z_NULL, 0); - *encoded_len = sizeof(http_encoding_gzip_header); - *encoded = pemalloc(*encoded_len, s->persistent); - memcpy(*encoded, http_encoding_gzip_header, *encoded_len); - } else { - *encoded_len = 0; - *encoded = NULL; - } - - return SUCCESS; -} - -PHP_HTTP_API STATUS _http_encoding_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) -{ - STATUS status; - - *encoded_len = HTTP_ENCODING_BUFLEN(data_len); - *encoded = pemalloc(*encoded_len, s->persistent); - - s->Z.next_in = (Bytef *) data; - s->Z.avail_in = data_len; - s->Z.next_out = (Bytef *) *encoded; - s->Z.avail_out = *encoded_len; - - status = deflate(&s->Z, Z_SYNC_FLUSH); - - if (Z_OK != status && Z_STREAM_END != status) { - HTTP_ENCODING_STREAM_ERROR(status, *encoded); - } - *encoded_len -= s->Z.avail_out; - - if (s->gzip) { - s->crc = crc32(s->crc, (const Bytef *) data, data_len); - } - - return SUCCESS; -} - -PHP_HTTP_API STATUS _http_encoding_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len TSRMLS_DC) -{ - STATUS status; - - *encoded_len = 1024; - *encoded = pemalloc(*encoded_len, s->persistent); - - s->Z.next_out = (Bytef *) *encoded; - s->Z.avail_out = *encoded_len; - - if (Z_STREAM_END != (status = deflate(&s->Z, Z_FINISH)) || Z_OK != (status = deflateEnd(&s->Z))) { - HTTP_ENCODING_STREAM_ERROR(status, *encoded); - } - - *encoded_len -= s->Z.avail_out; - if (s->gzip) { - if (s->Z.avail_out < 8) { - *encoded = perealloc(*encoded, *encoded_len + 8, s->persistent); - } - (*encoded)[(*encoded_len)++] = (char) (s->crc & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->crc >> 8) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->crc >> 16) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->crc >> 24) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->Z.total_in) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->Z.total_in >> 8) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->Z.total_in >> 16) & 0xFF); - (*encoded)[(*encoded_len)++] = (char) ((s->Z.total_in >> 24) & 0xFF); - } - - return SUCCESS; -} - #endif /* HTTP_HAVE_ZLIB */ PHP_HTTP_API zend_bool _http_encoding_response_start(size_t content_length TSRMLS_DC) diff --git a/http_filter_api.c b/http_filter_api.c index 4b54998..1836b27 100644 --- a/http_filter_api.c +++ b/http_filter_api.c @@ -84,11 +84,8 @@ typedef struct { } HTTP_FILTER_BUFFER(chunked_decode); #ifdef HTTP_HAVE_ZLIB -typedef struct { - int init; - int flags; - http_encoding_stream stream; -} HTTP_FILTER_BUFFER(gzip); +typedef http_encoding_stream HTTP_FILTER_BUFFER(deflate); +typedef http_encoding_stream HTTP_FILTER_BUFFER(inflate); #endif /* HTTP_HAVE_ZLIB */ @@ -293,50 +290,90 @@ static HTTP_FILTER_OPS(chunked_encode) = { }; #ifdef HTTP_HAVE_ZLIB -static HTTP_FILTER_FUNCTION(gzip) + +static HTTP_FILTER_FUNCTION(deflate) { int out_avail = 0; php_stream_bucket *ptr, *nxt; - HTTP_FILTER_BUFFER(gzip) *buffer = (HTTP_FILTER_BUFFER(gzip) *) this->abstract; + HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract; if (bytes_consumed) { *bytes_consumed = 0; } - /* first round */ - if (!buffer->init) { + /* new data available? */ + if (buckets_in->head) { + + /* fetch available bucket data */ + for (ptr = buckets_in->head; ptr; ptr = nxt) { + char *encoded = NULL; + size_t encoded_len = 0; + + nxt = ptr->next; + if (bytes_consumed) { + *bytes_consumed += ptr->buflen; + } + + if (ptr->buflen) { + http_encoding_deflate_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len); + if (encoded) { + out_avail = 1; + NEW_BUCKET(encoded, encoded_len); + efree(encoded); + } + } + + php_stream_bucket_unlink(ptr TSRMLS_CC); + php_stream_bucket_delref(ptr TSRMLS_CC); + } + } + + /* flush & close */ + if (flags == PSFS_FLAG_FLUSH_CLOSE) { char *encoded = NULL; size_t encoded_len = 0; - buffer->init = 1; - http_encoding_stream_init(&buffer->stream, buffer->flags, -1, &encoded, &encoded_len); - + http_encoding_deflate_stream_finish(buffer, &encoded, &encoded_len); if (encoded) { out_avail = 1; NEW_BUCKET(encoded, encoded_len); - pefree(encoded, this->is_persistent); + efree(encoded); } } + return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; +} + +static HTTP_FILTER_FUNCTION(inflate) +{ + int out_avail = 0; + php_stream_bucket *ptr, *nxt; + HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract; + + if (bytes_consumed) { + *bytes_consumed = 0; + } + /* new data available? */ if (buckets_in->head) { /* fetch available bucket data */ for (ptr = buckets_in->head; ptr; ptr = nxt) { - char *encoded = NULL; - size_t encoded_len = 0; + char *decoded = NULL; + size_t decoded_len = 0; nxt = ptr->next; if (bytes_consumed) { *bytes_consumed += ptr->buflen; } - /* this is actually flushing implicitly */ - http_encoding_stream_update(&buffer->stream, ptr->buf, ptr->buflen, &encoded, &encoded_len); - if (encoded) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); - pefree(encoded, this->is_persistent); + if (ptr->buflen) { + http_encoding_inflate_stream_update(buffer, ptr->buf, ptr->buflen, &decoded, &decoded_len); + if (decoded) { + out_avail = 1; + NEW_BUCKET(decoded, decoded_len); + efree(decoded); + } } php_stream_bucket_unlink(ptr TSRMLS_CC); @@ -346,37 +383,44 @@ static HTTP_FILTER_FUNCTION(gzip) /* flush & close */ if (flags == PSFS_FLAG_FLUSH_CLOSE) { - char *encoded = NULL; - size_t encoded_len = 0; + char *decoded = NULL; + size_t decoded_len = 0; - http_encoding_stream_finish(&buffer->stream, &encoded, &encoded_len); - if (encoded) { + http_encoding_inflate_stream_finish(buffer, &decoded, &decoded_len); + if (decoded) { out_avail = 1; - NEW_BUCKET(encoded, encoded_len); + NEW_BUCKET(decoded, decoded_len); + efree(decoded); } } return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; } -static HTTP_FILTER_DESTRUCTOR(gzip) +static HTTP_FILTER_DESTRUCTOR(deflate) { - HTTP_FILTER_BUFFER(gzip) *buffer = (HTTP_FILTER_BUFFER(gzip) *) this->abstract; - - pefree(buffer, this->is_persistent); + HTTP_FILTER_BUFFER(deflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract; + http_encoding_deflate_stream_free(&buffer); } -static HTTP_FILTER_OPS(gzencode) = { - HTTP_FILTER_FUNC(gzip), - HTTP_FILTER_DTOR(gzip), - "http.gzencode" -}; +static HTTP_FILTER_DESTRUCTOR(inflate) +{ + HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract; + http_encoding_inflate_stream_free(&buffer); +} static HTTP_FILTER_OPS(deflate) = { - HTTP_FILTER_FUNC(gzip), - HTTP_FILTER_DTOR(gzip), + HTTP_FILTER_FUNC(deflate), + HTTP_FILTER_DTOR(deflate), "http.deflate" }; + +static HTTP_FILTER_OPS(inflate) = { + HTTP_FILTER_FUNC(inflate), + HTTP_FILTER_DTOR(inflate), + "http.inflate" +}; + #endif /* HTTP_HAVE_ZLIB */ static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC) @@ -400,57 +444,42 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int #ifdef HTTP_HAVE_ZLIB } else - if (!strcasecmp(name, "http.gzencode")) { - HTTP_FILTER_BUFFER(gzip) *b = NULL; + if (!strcasecmp(name, "http.inflate")) { + int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0; + HTTP_FILTER_BUFFER(inflate) *b = NULL; - if ((b = pecalloc(1, sizeof(HTTP_FILTER_BUFFER(gzip)), p))) { - b->flags = HTTP_ENCODING_STREAM_GZIP_HEADER; - if (p) { - b->flags |= HTTP_ENCODING_STREAM_PERSISTENT; - } - if (params) { - switch (Z_TYPE_P(params)) - { - case IS_ARRAY: - case IS_OBJECT: - if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) { - break; - } - default: - if (zval_is_true(*tmp)) { - b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER; - } - } - } - if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(gzencode), b, p))) { - pefree(b, p); + if ((b = http_encoding_inflate_stream_init(NULL, flags))) { + if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(inflate), b, p))) { + http_encoding_inflate_stream_free(&b); } } } else if (!strcasecmp(name, "http.deflate")) { - HTTP_FILTER_BUFFER(gzip) *b = NULL; + int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0; + HTTP_FILTER_BUFFER(deflate) *b = NULL; - if ((b = pecalloc(1, sizeof(HTTP_FILTER_BUFFER(gzip)), p))) { - if (p) { - b->flags |= HTTP_ENCODING_STREAM_PERSISTENT; - } - if (params) { - switch (Z_TYPE_P(params)) + if (params) { + switch (Z_TYPE_P(params)) + { + case IS_ARRAY: + case IS_OBJECT: + if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void **) &tmp)) { + break; + } + default: { - case IS_ARRAY: - case IS_OBJECT: - if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) { - break; - } - default: - if (zval_is_true(*tmp)) { - b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER; - } + zval *orig = *tmp; + + convert_to_long_ex(tmp); + flags |= (Z_LVAL_PP(tmp) & 0x0fffffff); + if (orig != *tmp) zval_ptr_dtor(tmp); } } + } + if ((b = http_encoding_deflate_stream_init(NULL, flags))) { if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(deflate), b, p))) { - pefree(b, p); + http_encoding_deflate_stream_free(&b); } } #endif /* HTTP_HAVE_ZLIB */ diff --git a/http_functions.c b/http_functions.c index 1b71506..39327d1 100644 --- a/http_functions.c +++ b/http_functions.c @@ -1578,73 +1578,12 @@ PHP_FUNCTION(http_build_query) /* {{{ */ #ifdef HTTP_HAVE_ZLIB -/* {{{ proto string http_gzencode(string data[, int level = -1[, int mtime = 0]]) +/* {{{ proto string http_deflate(string data[, int flags = 0]) * - * Compress data with the HTTP compatible GZIP encoding. - * - * Expects the first parameter to be a string which contains the data that - * should be encoded. Additionally accepts an optional in paramter specifying - * the compression level, where -1 is default, 0 is no compression and 9 is - * best compression ratio. - * - * Returns the encoded string on success, or NULL on failure. - */ -PHP_FUNCTION(http_gzencode) -{ - char *data; - int data_len; - long level = -1, mtime = 0; - - RETVAL_NULL(); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &data, &data_len, &level, &mtime)) { - HTTP_CHECK_GZIP_LEVEL(level, return); - { - char *encoded; - size_t encoded_len; - - if (SUCCESS == http_encoding_gzencode(level, mtime, data, data_len, &encoded, &encoded_len)) { - RETURN_STRINGL(encoded, (int) encoded_len, 0); - } - } - } -} -/* }}} */ - -/* {{{ proto string http_gzdecode(string data) - * - * Uncompress data compressed with the HTTP compatible GZIP encoding. - * - * Expects a string as parameter containing the compressed data. - * - * Returns the decoded string on success, or NULL on failure. - */ -PHP_FUNCTION(http_gzdecode) -{ - char *data; - int data_len; - - RETVAL_NULL(); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { - char *decoded; - size_t decoded_len; - - if (SUCCESS == http_encoding_gzdecode(data, data_len, &decoded, &decoded_len)) { - RETURN_STRINGL(decoded, (int) decoded_len, 0); - } - } -} -/* }}} */ - -/* {{{ proto string http_deflate(string data[, int level = -1[, bool zlib_header = false]]) - * - * Compress data with the HTTP compatible DEFLATE encoding. + * Compress data with gzip, zlib AKA deflate or raw deflate encoding. * * Expects the first parameter to be a string containing the data that should - * be encoded. Additionally accepts an optional int parameter specifying the - * compression level, where -1 is default, 0 is no compression and 9 is best - * compression ratio. + * be encoded. * * Returns the encoded string on success, or NULL on failure. */ @@ -1652,18 +1591,16 @@ PHP_FUNCTION(http_deflate) { char *data; int data_len; - long level = -1; - zend_bool zhdr = 0; + long flags = 0; RETVAL_NULL(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lb", &data, &data_len, &level, &zhdr)) { - HTTP_CHECK_GZIP_LEVEL(level, return); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags)) { { char *encoded; size_t encoded_len; - if (SUCCESS == http_encoding_deflate(level, zhdr, data, data_len, &encoded, &encoded_len)) { + if (SUCCESS == http_encoding_deflate(flags, data, data_len, &encoded, &encoded_len)) { RETURN_STRINGL(encoded, (int) encoded_len, 0); } } @@ -1673,7 +1610,8 @@ PHP_FUNCTION(http_deflate) /* {{{ proto string http_inflate(string data) * - * Uncompress data compressed with the HTTP compatible DEFLATE encoding. + * Uncompress data compressed with either gzip, deflate AKA zlib or raw + * deflate encoding. * * Expects a string as parameter containing the compressed data. * diff --git a/http_message_api.c b/http_message_api.c index fee445b..182b289 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -254,7 +254,7 @@ PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char # ifndef HTTP_HAVE_ZLIB DECODE_WITH_EXT_ZLIB("gzinflate", PHPSTR_VAL(msg) + 10, PHPSTR_LEN(msg) - 18); # else - http_encoding_gzdecode(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len); + http_encoding_inflate(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len); } else if (!strcasecmp(Z_STRVAL_P(c), "deflate") || !strcasecmp(Z_STRVAL_P(c), "compress") || !strcasecmp(Z_STRVAL_P(c), "x-compress")) { http_encoding_inflate(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len); # endif /* HTTP_HAVE_ZLIB */ diff --git a/http_request_api.c b/http_request_api.c index c12edb2..c3e6128 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -523,11 +523,13 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti } } +#if LIBCURL_VERSIONNUM >= 0x070f01 /* reset cookies */ if ((zoption = http_request_option(request, options, "resetcookies", IS_BOOL)) && Z_LVAL_P(zoption)) { HTTP_CURL_OPT(COOKIELIST, "ALL"); } - +#endif + /* session cookies */ if ((zoption = http_request_option(request, options, "cookiesession", IS_BOOL))) { if (Z_LVAL_P(zoption)) { diff --git a/http_send_api.c b/http_send_api.c index c376b05..3b7a74a 100644 --- a/http_send_api.c +++ b/http_send_api.c @@ -71,17 +71,14 @@ static inline void _http_flush(const char *data, size_t data_len TSRMLS_DC) #define http_send_response_start(b, cl) _http_send_response_start((b), (cl) TSRMLS_CC) static inline void _http_send_response_start(void **buffer, size_t content_length TSRMLS_DC) { - if (http_encoding_response_start(content_length)) { + int encoding; + + if ((encoding = http_encoding_response_start(content_length))) { + //DebugBreak(); #ifdef HTTP_HAVE_ZLIB - char *encoded; - size_t encoded_len; - int gzip = (HTTP_G(send).gzip_encoding == HTTP_ENCODING_GZIP); - http_encoding_stream *s = emalloc(sizeof(http_encoding_stream)); - - http_encoding_stream_init(s, gzip?HTTP_ENCODING_STREAM_GZIP_HEADER:0, -1, &encoded, &encoded_len); - phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G(send).buffer_size, _http_flush TSRMLS_CC); - STR_FREE(encoded); - *buffer = s; + *buffer = http_encoding_deflate_stream_init(NULL, + (encoding == HTTP_ENCODING_GZIP) ? + HTTP_DEFLATE_TYPE_GZIP : HTTP_DEFLATE_TYPE_ZLIB); #endif } } @@ -97,7 +94,7 @@ static inline void _http_send_response_data_plain(void **buffer, const char *dat size_t encoded_len; http_encoding_stream *s = *((http_encoding_stream **) buffer); - http_encoding_stream_update(s, data, data_len, &encoded, &encoded_len); + http_encoding_deflate_stream_update(s, data, data_len, &encoded, &encoded_len); phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G(send).buffer_size, _http_flush TSRMLS_CC); efree(encoded); #else @@ -168,10 +165,10 @@ static inline void _http_send_response_finish(void **buffer TSRMLS_DC) size_t encoded_len = 0; http_encoding_stream *s = *((http_encoding_stream **) buffer); - http_encoding_stream_finish(s, &encoded, &encoded_len); + http_encoding_deflate_stream_finish(s, &encoded, &encoded_len); phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, 0, _http_flush TSRMLS_CC); + http_encoding_deflate_stream_free(&s); STR_FREE(encoded); - efree(s); #else http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug"); #endif diff --git a/http_util_object.c b/http_util_object.c index 110ff08..2e1d11b 100644 --- a/http_util_object.c +++ b/http_util_object.c @@ -124,8 +124,6 @@ zend_function_entry http_util_object_fe[] = { HTTP_UTIL_ALIAS(parseCookie, http_parse_cookie) HTTP_UTIL_ALIAS(chunkedDecode, http_chunked_decode) #ifdef HTTP_HAVE_ZLIB - HTTP_UTIL_ALIAS(gzEncode, http_gzencode) - HTTP_UTIL_ALIAS(gzDecode, http_gzdecode) HTTP_UTIL_ALIAS(deflate, http_deflate) HTTP_UTIL_ALIAS(inflate, http_inflate) #endif /* HTTP_HAVE_ZLIB */ diff --git a/php_http.h b/php_http.h index 6f623ff..f74af3c 100644 --- a/php_http.h +++ b/php_http.h @@ -148,8 +148,6 @@ PHP_FUNCTION(http_build_query); #endif /* ZEND_ENGINE_2 */ PHP_FUNCTION(ob_etaghandler); #ifdef HTTP_HAVE_ZLIB -PHP_FUNCTION(http_gzencode); -PHP_FUNCTION(http_gzdecode); PHP_FUNCTION(http_deflate); PHP_FUNCTION(http_inflate); #endif diff --git a/php_http_encoding_api.h b/php_http_encoding_api.h index 8c18f3a..5fc5231 100644 --- a/php_http_encoding_api.h +++ b/php_http_encoding_api.h @@ -23,52 +23,72 @@ PHP_HTTP_API zend_bool _http_encoding_response_start(size_t content_length TSRML #ifdef HTTP_HAVE_ZLIB +extern PHP_MINIT_FUNCTION(http_encoding); + /* max count of uncompress trials, alloc_size <<= 2 for each try */ #define HTTP_ENCODING_MAXTRY 10 /* safe padding */ -#define HTTP_ENCODING_SAFPAD 10 +#define HTTP_ENCODING_SAFPAD 28 /* add 1% extra space in case we need to encode widely differing (binary) data */ #define HTTP_ENCODING_BUFLEN(l) (l + (l / 100) + HTTP_ENCODING_SAFPAD) typedef enum { - HTTP_ENCODING_NONE = 0, + HTTP_ENCODING_NONE, HTTP_ENCODING_GZIP, HTTP_ENCODING_DEFLATE, } http_encoding_type; -#define HTTP_ENCODING_STREAM_GZIP_HEADER 0x1 -#define HTTP_ENCODING_STREAM_ZLIB_HEADER 0x2 -#define HTTP_ENCODING_STREAM_PERSISTENT 0x4 +#define HTTP_DEFLATE_LEVEL_DEF 0x00000000 +#define HTTP_DEFLATE_LEVEL_MIN 0x00000001 +#define HTTP_DEFLATE_LEVEL_MAX 0x00000002 +#define HTTP_DEFLATE_TYPE_ZLIB 0x00000000 +#define HTTP_DEFLATE_TYPE_GZIP 0x00000010 +#define HTTP_DEFLATE_TYPE_RAW 0x00000020 +#define HTTP_DEFLATE_STRATEGY_DEF 0x00000000 +#define HTTP_DEFLATE_STRATEGY_FILT 0x00000100 +#define HTTP_DEFLATE_STRATEGY_HUFF 0x00000200 +#define HTTP_DEFLATE_STRATEGY_RLE 0x00000300 +#define HTTP_DEFLATE_STRATEGY_FIXED 0x00000400 + +#define HTTP_INFLATE_TYPE_ZLIB 0x00000000 +#define HTTP_INFLATE_TYPE_GZIP 0x00000000 +#define HTTP_INFLATE_TYPE_RAW 0x00000001 + +#define HTTP_ENCODING_STREAM_PERSISTENT 0x01000000 typedef struct { - z_stream Z; - int gzip; - int persistent; - ulong crc; + z_stream stream; + int flags; void *storage; } http_encoding_stream; -#define http_encoding_stream_init(s, g, l, e, el) _http_encoding_stream_init((s), (g), (l), (e), (el) TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_stream_init(http_encoding_stream *s, int flags, int level, char **encoded, size_t *encoded_len TSRMLS_DC); -#define http_encoding_stream_update(s, d, dl, e, el) _http_encoding_stream_update((s), (d), (dl), (e), (el) TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); -#define http_encoding_stream_finish(s, e, el) _http_encoding_stream_finish((s), (e), (el) TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len TSRMLS_DC); - -#define http_encoding_gzencode_verify(d, dl, e, el) _http_encoding_gzencode_verify((d), (dl), (e), (el), HE_NOTICE) -PHP_HTTP_API STATUS _http_encoding_gzencode_verify(const char *data, size_t data_len, const char **encoded, size_t *encoded_len, int error_level TSRMLS_DC); -#define http_encoding_gzdecode_verify(e, el, d, dl) _http_encoding_gzdecode_verify((e), (el), (d), (dl), HE_NOTICE) -PHP_HTTP_API STATUS _http_encoding_gzdecode_verify(const char *data, size_t data_len, const char *decoded, size_t decoded_len, int error_level TSRMLS_DC); - -#define http_encoding_gzencode(l, m, d, dl, r, rl) _http_encoding_gzencode((l), (m), (d), (dl), (r), (rl) TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_gzencode(int level, int mtime, 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) -PHP_HTTP_API STATUS _http_encoding_gzdecode(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC); -#define http_encoding_deflate(l, h, d, dl, r, rl) _http_encoding_deflate((l), (h), (d), (dl), (r), (rl) TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_deflate(int level, int zhdr, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); +#define http_encoding_deflate(f, d, dl, r, rl) _http_encoding_deflate((f), (d), (dl), (r), (rl) TSRMLS_CC) +PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); #define http_encoding_inflate(d, dl, r, rl) _http_encoding_inflate((d), (dl), (r), (rl) TSRMLS_CC) PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC); +#define http_encoding_deflate_stream_init(s, f) _http_encoding_deflate_stream_init((s), (f) TSRMLS_CC) +PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags TSRMLS_DC); +#define http_encoding_deflate_stream_update(s, d, dl, e, el) _http_encoding_deflate_stream_update((s), (d), (dl), (e), (el) TSRMLS_CC) +PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); +#define http_encoding_deflate_stream_finish(s, e, el) _http_encoding_deflate_stream_finish((s), (e), (el) TSRMLS_CC) +PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len TSRMLS_DC); +#define http_encoding_deflate_stream_dtor(s) _http_encoding_deflate_stream_dtor((s) TSRMLS_CC) +PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC); +#define http_encoding_deflate_stream_free(s) _http_encoding_deflate_stream_free((s) TSRMLS_CC) +PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC); + +#define http_encoding_inflate_stream_init(s, f) _http_encoding_inflate_stream_init((s), (f) TSRMLS_CC) +PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags TSRMLS_DC); +#define http_encoding_inflate_stream_update(s, d, dl, e, el) _http_encoding_inflate_stream_update((s), (d), (dl), (e), (el) TSRMLS_CC) +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 TSRMLS_DC); +#define http_encoding_inflate_stream_finish(s, e, el) _http_encoding_inflate_stream_finish((s), (e), (el) TSRMLS_CC) +PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len TSRMLS_DC); +#define http_encoding_inflate_stream_dtor(s) _http_encoding_inflate_stream_dtor((s) TSRMLS_CC) +PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC); +#define http_encoding_inflate_stream_free(s) _http_encoding_inflate_stream_free((s) TSRMLS_CC) +PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC); + #endif /* HTTP_HAVE_ZLIB */ #endif @@ -81,4 +101,3 @@ PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, ch * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ - diff --git a/php_http_util_object.h b/php_http_util_object.h index eff4817..25263b8 100644 --- a/php_http_util_object.h +++ b/php_http_util_object.h @@ -32,8 +32,6 @@ PHP_METHOD(HttpUtil, parseHeaders); PHP_METHOD(HttpUtil, parseMessage); PHP_METHOD(HttpUtil, parseCookie); PHP_METHOD(HttpUtil, chunkedDecode); -PHP_METHOD(HttpUtil, gzEncode); -PHP_METHOD(HttpUtil, gzDecode); PHP_METHOD(HttpUtil, deflate); PHP_METHOD(HttpUtil, inflate); PHP_METHOD(HttpUtil, support); diff --git a/phpstr/phpstr.h b/phpstr/phpstr.h index 03d024e..565b72b 100644 --- a/phpstr/phpstr.h +++ b/phpstr/phpstr.h @@ -57,7 +57,7 @@ #define RETURN_PHPSTR_DUP(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 1) #define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR, 0) #define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 0) -#define RETVAL_PHPSTR_DUP(STR) RETVAƖ_PHPSTR((STR), PHPSTR_FREE_NOT, 1) +#define RETVAL_PHPSTR_DUP(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 1) /* RETURN_PHPSTR(buf, PHPSTR_FREE_PTR, 0) */ #define RETURN_PHPSTR(STR, free, dup) \ RETVAL_PHPSTR((STR), (free), (dup)); \ diff --git a/tests/build_url_002.phpt b/tests/build_url_002.phpt index 6dc55f0..9edac56 100644 --- a/tests/build_url_002.phpt +++ b/tests/build_url_002.phpt @@ -18,7 +18,7 @@ echo "Done\n"; %sTEST https://www.example.com:9999/replaced?q=1#n https://www.example.com:9999/replaced?q=1#n -Array +Array ( [scheme] => https [host] => www.example.com diff --git a/tests/stream_filters_002.phpt b/tests/stream_filters_002.phpt index e490f07..bd2f81b 100644 --- a/tests/stream_filters_002.phpt +++ b/tests/stream_filters_002.phpt @@ -15,21 +15,22 @@ $d = file_get_contents(__FILE__); $n = tempnam(dirname(__FILE__), 'hsf'); $f = fopen($n, 'wb'); -stream_filter_append($f, 'http.gzencode', STREAM_FILTER_WRITE); +stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE, HTTP_DEFLATE_TYPE_GZIP); fwrite($f, $d); -fflush($f); fclose($f); -$gzencoded = file_get_contents($n); +var_dump($d == http_inflate(file_get_contents($n))); $f = fopen($n, 'wb'); stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE); fwrite($f, $d); -fflush($f); fclose($f); -$deflated = file_get_contents($n); +var_dump($d == http_inflate(file_get_contents($n))); -var_dump($d == http_gzdecode($gzencoded)); -var_dump($d == http_inflate($deflated)); +$f = fopen($n, 'wb'); +stream_filter_append($f, 'http.deflate', STREAM_FILTER_WRITE, HTTP_DEFLATE_TYPE_RAW); +fwrite($f, $d); +fclose($f); +var_dump($d == http_inflate(file_get_contents($n))); unlink($n); @@ -39,4 +40,5 @@ echo "Done\n"; %sTEST bool(true) bool(true) +bool(true) Done -- 2.30.2