X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_filter_api.c;h=23b71190acebb730a3d5002b734d4f108299e9ed;hp=648c509adff7d66177a9f07bed22b04704796156;hb=refs%2Fheads%2Fv1.7.x;hpb=05c863a6faa9a3ddd83ac1bdf62edbfc7a6ccf4f diff --git a/http_filter_api.c b/http_filter_api.c index 648c509..23b7119 100644 --- a/http_filter_api.c +++ b/http_filter_api.c @@ -6,16 +6,12 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2005, Michael Wallner | + | Copyright (c) 2004-2010, Michael Wallner | +--------------------------------------------------------------------+ */ /* $Id$ */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #define HTTP_WANT_ZLIB #include "php_http.h" @@ -78,17 +74,14 @@ PHP_MINIT_FUNCTION(http_filter) php_stream_bucket_append(buckets_out, __buck TSRMLS_CC); \ } -typedef struct { +typedef struct _http_chunked_decode_filter_buffer_t { phpstr buffer; ulong hexlen; } 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 */ @@ -112,7 +105,7 @@ static HTTP_FILTER_FUNCTION(chunked_decode) *bytes_consumed += ptr->buflen; } - if ((size_t) -1 == phpstr_append(PHPSTR(buffer), ptr->buf, ptr->buflen)) { + if (PHPSTR_NOMEM == phpstr_append(PHPSTR(buffer), ptr->buf, ptr->buflen)) { return PSFS_ERR_FATAL; } @@ -134,7 +127,7 @@ static HTTP_FILTER_FUNCTION(chunked_decode) if (PHPSTR_LEN(buffer) < buffer->hexlen) { /* flush anyway? */ - if (flags == PSFS_FLAG_FLUSH_INC) { + if (flags & PSFS_FLAG_FLUSH_INC) { /* flush all data (should only be chunk data) */ out_avail = 1; @@ -172,8 +165,8 @@ static HTTP_FILTER_FUNCTION(chunked_decode) /* ignore preceeding CRLFs (too loose?) */ while (off < PHPSTR_LEN(buffer) && ( - PHPSTR_VAL(buffer)[off] == 0xa || - PHPSTR_VAL(buffer)[off] == 0xd)) { + PHPSTR_VAL(buffer)[off] == '\n' || + PHPSTR_VAL(buffer)[off] == '\r')) { ++off; } if (off) { @@ -213,7 +206,7 @@ static HTTP_FILTER_FUNCTION(chunked_decode) } /* flush before close, but only if we are already waiting for more data */ - if (flags == PSFS_FLAG_FLUSH_CLOSE && buffer->hexlen && PHPSTR_LEN(buffer)) { + if ((flags & PSFS_FLAG_FLUSH_CLOSE) && buffer->hexlen && PHPSTR_LEN(buffer)) { out_avail = 1; NEW_BUCKET(PHPSTR_VAL(buffer), PHPSTR_LEN(buffer)); phpstr_reset(PHPSTR(buffer)); @@ -272,7 +265,7 @@ static HTTP_FILTER_FUNCTION(chunked_encode) } /* terminate with "0" */ - if (flags == PSFS_FLAG_FLUSH_CLOSE) { + if (flags & PSFS_FLAG_FLUSH_CLOSE) { out_avail = 1; NEW_BUCKET("0" HTTP_CRLF, lenof("0" HTTP_CRLF)); } @@ -293,50 +286,110 @@ 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) { + if (encoded_len) { + 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_INC) { 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_flush(buffer, &encoded, &encoded_len); + if (encoded) { + if (encoded_len) { + out_avail = 1; + NEW_BUCKET(encoded, encoded_len); + } + efree(encoded); + } + } + + if (flags & PSFS_FLAG_FLUSH_CLOSE) { + char *encoded = NULL; + size_t encoded_len = 0; + http_encoding_deflate_stream_finish(buffer, &encoded, &encoded_len); if (encoded) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); - pefree(encoded, this->is_persistent); + if (encoded_len) { + out_avail = 1; + NEW_BUCKET(encoded, encoded_len); + } + 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) { + if (decoded_len) { + out_avail = 1; + NEW_BUCKET(decoded, decoded_len); + } + efree(decoded); + } } php_stream_bucket_unlink(ptr TSRMLS_CC); @@ -345,42 +398,66 @@ static HTTP_FILTER_FUNCTION(gzip) } /* flush & close */ - if (flags == PSFS_FLAG_FLUSH_CLOSE) { - char *encoded = NULL; - size_t encoded_len = 0; + if (flags & PSFS_FLAG_FLUSH_INC) { + char *decoded = NULL; + size_t decoded_len = 0; - http_encoding_stream_finish(&buffer->stream, &encoded, &encoded_len); - if (encoded) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); + http_encoding_inflate_stream_flush(buffer, &decoded, &decoded_len); + if (decoded) { + if (decoded_len) { + out_avail = 1; + NEW_BUCKET(decoded, decoded_len); + } + efree(decoded); + } + } + + if (flags & PSFS_FLAG_FLUSH_CLOSE) { + char *decoded = NULL; + size_t decoded_len = 0; + + http_encoding_inflate_stream_finish(buffer, &decoded, &decoded_len); + if (decoded) { + if (decoded_len) { + out_avail = 1; + 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) { + zval **tmp = ¶ms; php_stream_filter *f = NULL; if (!strcasecmp(name, "http.chunked_decode")) { @@ -399,29 +476,40 @@ 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 (!(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)) { + case IS_ARRAY: + case IS_OBJECT: + if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) { + break; + } + default: + { + zval *num = http_zsep(IS_LONG, *tmp); + + flags |= (Z_LVAL_P(num) & 0x0fffffff); + zval_ptr_dtor(&num); + } } + } + 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 */