cvs: php-src(PHP_5_3) / NEWS /ext/standard filters.c http_fopen_wrapper.c /ext/standard/tests/filters chunked_001.phpt

From: Date: Thu, 16 Apr 2009 10:16:27 +0000
Subject: cvs: php-src(PHP_5_3) / NEWS /ext/standard filters.c http_fopen_wrapper.c /ext/standard/tests/filters chunked_001.phpt
Groups: php.cvs 
Request: Send a blank email to [email protected] to get a copy of this message
dmitry		Thu Apr 16 10:16:27 2009 UTC

  Added files:                 (Branch: PHP_5_3)
    /php-src/ext/standard/tests/filters	chunked_001.phpt 

  Modified files:              
    /php-src	NEWS 
    /php-src/ext/standard	filters.c http_fopen_wrapper.c 
  Log:
  - Added "dechunk" filter which can decode HTTP responces with chunked transfer-encoding.
HTTP streams use this filter automatically in case "Transfer-Encoding: chunked" header
presents in responce. It's possible to disable this behaviour using
"http"=>array("auto_decode"=>0) in stream context
  - Fixed bug #47021 (SoapClient stumbles over WSDL delivered with "Transfer-Encoding:
chunked")
  
  


http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.559&r2=1.2027.2.547.2.965.2.560&diff_format=u Index: php-src/NEWS diff -u php-src/NEWS:1.2027.2.547.2.965.2.559 php-src/NEWS:1.2027.2.547.2.965.2.560 --- php-src/NEWS:1.2027.2.547.2.965.2.559 Thu Apr 16 06:47:36 2009 +++ php-src/NEWS Thu Apr 16 10:16:26 2009 @@ -6,6 +6,11 @@ - Upgraded bundled PCRE to version 7.9. (Nuno) - Added 'n' flag to fopen to allow passing O_NONBLOCK to the underlying open(2) system call. (Mikko) +- Added "dechunk" filter which can decode HTTP responces with chunked + transfer-encoding. HTTP streams use this filter automatically in case + "Transfer-Encoding: chunked" header presents in responce. It's possible to + disable this behaviour using "http"=>array("auto_decode"=>0) in stream + context. (Dmitry) - Fixed bug #47880 (crashes in call_user_func_array()). (Dmitry) - Fixed bug #47856 (stristr() converts needle to lower-case). (Ilia) @@ -28,6 +33,8 @@ - Fixed bug #47516 (nowdoc can not be embed in heredoc but can be embed in double quote). (Dmitry) - Fixed bug #47038 (Memory leak in include). (Dmitry) +- Fixed bug #47021 (SoapClient stumbles over WSDL delivered with + "Transfer-Encoding: chunked"). (Dmitry) - Fixed bug #46108 (DateTime - Memory leak when unserializing). (Felipe) - Fixed bug #44861 (scrollable cursor don't work with pgsql). (Matteo) - Fixed bug #44409 (PDO::FETCH_SERIALIZE calls __construct()). (Matteo) http://cvs.php.net/viewvc.cgi/php-src/ext/standard/filters.c?r1=1.44.2.6.2.4.2.3&r2=1.44.2.6.2.4.2.4&diff_format=u Index: php-src/ext/standard/filters.c diff -u php-src/ext/standard/filters.c:1.44.2.6.2.4.2.3 php-src/ext/standard/filters.c:1.44.2.6.2.4.2.4 --- php-src/ext/standard/filters.c:1.44.2.6.2.4.2.3 Wed Dec 31 11:15:45 2008 +++ php-src/ext/standard/filters.c Thu Apr 16 10:16:27 2009 @@ -20,7 +20,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: filters.c,v 1.44.2.6.2.4.2.3 2008/12/31 11:15:45 sebastian Exp $ */ +/* $Id: filters.c,v 1.44.2.6.2.4.2.4 2009/04/16 10:16:27 dmitry Exp $ */ #include "php.h" #include "php_globals.h" @@ -1897,6 +1897,220 @@ /* }}} */ +/* {{{ chunked filter implementation */ +typedef enum _php_chunked_filter_state { + CHUNK_SIZE_START, + CHUNK_SIZE, + CHUNK_SIZE_EXT_START, + CHUNK_SIZE_EXT, + CHUNK_SIZE_CR, + CHUNK_SIZE_LF, + CHUNK_BODY, + CHUNK_BODY_CR, + CHUNK_BODY_LF, + CHUNK_TRAILER, + CHUNK_ERROR +} php_chunked_filter_state; + +typedef struct _php_chunked_filter_data { + php_chunked_filter_state state; + int chunk_size; + int persistent; +} php_chunked_filter_data; + +static int php_dechunk(char *buf, int len, php_chunked_filter_data *data) +{ + char *p = buf; + char *end = p + len; + char *out = buf; + int out_len = 0; + + while (p < end) { + switch (data->state) { + case CHUNK_SIZE_START: + data->chunk_size = 0; + case CHUNK_SIZE: + while (p < end) { + if (*p >= '0' && *p <= '9') { + data->chunk_size = (data->chunk_size * 16) + (*p - '0'); + } else if (*p >= 'A' && *p <= 'F') { + data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10); + } else if (*p >= 'a' && *p <= 'f') { + data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10); + } else if (data->state == CHUNK_SIZE_START) { + data->state = CHUNK_ERROR; + break; + } else { + data->state = CHUNK_SIZE_EXT_START; + break; + } + data->state = CHUNK_SIZE; + p++; + } + if (data->state == CHUNK_ERROR) { + continue; + } else if (p == end) { + return out_len; + } + case CHUNK_SIZE_EXT_START: + if (*p == ';'|| *p == '\r' || *p == '\n') { + data->state = CHUNK_SIZE_EXT; + } else { + data->state = CHUNK_ERROR; + continue; + } + case CHUNK_SIZE_EXT: + /* skip extension */ + while (p < end && *p != '\r' && *p != '\n') { + p++; + } + if (p == end) { + return out_len; + } + case CHUNK_SIZE_CR: + if (*p == '\r') { + p++; + if (p == end) { + data->state = CHUNK_SIZE_LF; + return out_len; + } + } + case CHUNK_SIZE_LF: + if (*p == '\n') { + p++; + if (data->chunk_size == 0) { + /* last chunk */ + data->state = CHUNK_TRAILER; + continue; + } else if (p == end) { + data->state = CHUNK_BODY; + return out_len; + } + } else { + data->state = CHUNK_ERROR; + continue; + } + case CHUNK_BODY: + if (end - p >= data->chunk_size) { + if (p != out) { + memmove(out, p, data->chunk_size); + } + out += data->chunk_size; + out_len += data->chunk_size; + p += data->chunk_size; + if (p == end) { + data->state = CHUNK_BODY_CR; + return out_len; + } + } else { + if (p != out) { + memmove(out, p, end - p); + } + data->chunk_size -= end - p; + out_len += end - p; + return out_len; + } + case CHUNK_BODY_CR: + if (*p == '\r') { + p++; + if (p == end) { + data->state = CHUNK_BODY_LF; + return out_len; + } + } + case CHUNK_BODY_LF: + if (*p == '\n') { + p++; + data->state = CHUNK_SIZE_START; + continue; + } else { + data->state = CHUNK_ERROR; + continue; + } + case CHUNK_TRAILER: + /* ignore trailer */ + p = end; + continue; + case CHUNK_ERROR: + if (p != out) { + memmove(out, p, end - p); + } + out_len += end - p; + return out_len; + } + } + return out_len; +} + +static php_stream_filter_status_t php_chunked_filter( + php_stream *stream, + php_stream_filter *thisfilter, + php_stream_bucket_brigade *buckets_in, + php_stream_bucket_brigade *buckets_out, + size_t *bytes_consumed, + int flags + TSRMLS_DC) +{ + php_stream_bucket *bucket; + size_t consumed = 0; + php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract; + + while (buckets_in->head) { + bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); + consumed += bucket->buflen; + bucket->buflen = php_dechunk(bucket->buf, bucket->buflen, data); + php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); + } + + if (bytes_consumed) { + *bytes_consumed = consumed; + } + + return PSFS_PASS_ON; +} + +static void php_chunked_dtor(php_stream_filter *thisfilter TSRMLS_DC) +{ + if (thisfilter && thisfilter->abstract) { + php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract; + pefree(data, data->persistent); + } +} + +static php_stream_filter_ops chunked_filter_ops = { + php_chunked_filter, + php_chunked_dtor, + "dechunk" +}; + +static php_stream_filter *chunked_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC) +{ + php_stream_filter_ops *fops = NULL; + php_chunked_filter_data *data; + + if (strcasecmp(filtername, "dechunk")) { + return NULL; + } + + /* Create this filter */ + data = (php_chunked_filter_data *)pecalloc(1, sizeof(php_chunked_filter_data), persistent); + if (!data) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_chunked_filter_data)); + return NULL; + } + data->state = CHUNK_SIZE_START; + data->chunk_size = 0; + data->persistent = persistent; + fops = &chunked_filter_ops; + + return php_stream_filter_alloc(fops, data, persistent); +} + +static php_stream_filter_factory chunked_filter_factory = { + chunked_filter_create +}; +/* }}} */ + static const struct { php_stream_filter_ops *ops; php_stream_filter_factory *factory; @@ -1907,6 +2121,7 @@ { &strfilter_strip_tags_ops, &strfilter_strip_tags_factory }, { &strfilter_convert_ops, &strfilter_convert_factory }, { &consumed_filter_ops, &consumed_filter_factory }, + { &chunked_filter_ops, &chunked_filter_factory }, /* additional filters to go here */ { NULL, NULL } }; http://cvs.php.net/viewvc.cgi/php-src/ext/standard/http_fopen_wrapper.c?r1=1.99.2.12.2.9.2.12&r2=1.99.2.12.2.9.2.13&diff_format=u Index: php-src/ext/standard/http_fopen_wrapper.c diff -u php-src/ext/standard/http_fopen_wrapper.c:1.99.2.12.2.9.2.12 php-src/ext/standard/http_fopen_wrapper.c:1.99.2.12.2.9.2.13 --- php-src/ext/standard/http_fopen_wrapper.c:1.99.2.12.2.9.2.12 Wed Dec 31 11:15:45 2008 +++ php-src/ext/standard/http_fopen_wrapper.c Thu Apr 16 10:16:27 2009 @@ -19,7 +19,7 @@ | Sara Golemon <[email protected]> | +----------------------------------------------------------------------+ */ -/* $Id: http_fopen_wrapper.c,v 1.99.2.12.2.9.2.12 2008/12/31 11:15:45 sebastian Exp $ */ +/* $Id: http_fopen_wrapper.c,v 1.99.2.12.2.9.2.13 2009/04/16 10:16:27 dmitry Exp $ */ #include "php.h" #include "php_globals.h" @@ -111,6 +111,7 @@ char *user_headers = NULL; int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0); int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0); + php_stream_filter *transfer_encoding = NULL; tmp_line[0] = '\0'; @@ -597,6 +598,25 @@ } else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) { file_size = atoi(http_header_line + 16); php_stream_notify_file_size(context, file_size, http_header_line, 0); + } else if (!strncasecmp(http_header_line, "Transfer-Encoding: chunked", sizeof("Transfer-Encoding: chunked"))) { + + /* create filter to decode response body */ + if (!(options & STREAM_ONLY_GET_HEADERS)) { + long decode = 1; + + if (context && php_stream_context_get_option(context, "http", "auto_decode", &tmpzval) == SUCCESS) { + SEPARATE_ZVAL(tmpzval); + convert_to_boolean(*tmpzval); + decode = Z_LVAL_PP(tmpzval); + } + if (decode) { + transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream) TSRMLS_CC); + if (transfer_encoding) { + /* don't store transfer-encodeing header */ + continue; + } + } + } } if (http_header_line[0] == '\0') { @@ -740,6 +760,11 @@ * the stream */ stream->position = 0; + if (transfer_encoding) { + php_stream_filter_append(&stream->readfilters, transfer_encoding); + } + } else if (transfer_encoding) { + php_stream_filter_free(transfer_encoding TSRMLS_CC); } return stream; http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/filters/chunked_001.phpt?view=markup&rev=1.1 Index: php-src/ext/standard/tests/filters/chunked_001.phpt +++ php-src/ext/standard/tests/filters/chunked_001.phpt

Thread (3 messages)

« previous php.cvs (#57042) next »