From: Sara Golemon Date: Wed, 31 Mar 2004 23:48:59 +0000 (+0000) Subject: BugFix#27619 X-Git-Tag: php-5.0.0RC2RC1~133 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=72616e6eae1e6005698b9acff6cbcaa8538ac009;p=php BugFix#27619 Filters not applied to pre-buffered stream data. (esp. http:// streams) --- diff --git a/NEWS b/NEWS index 84c841b08f..7f1b89cd89 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ PHP NEWS (Dmitry, Andi) - Fixed bug #27628 (Simplify the process of making a POST request via stream context). (Ilia) +- Fixed bug #27619 (filters not applied to pre-buffered stream data). (Sara) - Fixed bug #27469 (serialize() objects of incomplete class). (Dmitry) - Fixed bug #27457 (handling of numeric indexes in strtr()). (Dmitry) diff --git a/ext/standard/tests/file/bug27619.phpt b/ext/standard/tests/file/bug27619.phpt new file mode 100644 index 0000000000..095a18c199 --- /dev/null +++ b/ext/standard/tests/file/bug27619.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #27619 (filters not applied to pre-buffered data) +--FILE-- + +--EXPECT-- +this IS A LOWERCASE STRING. diff --git a/main/streams/filter.c b/main/streams/filter.c index ff0549972c..708889f97c 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -283,7 +283,7 @@ PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC) pefree(filter, filter->is_persistent); } -PHPAPI void php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter) +PHPAPI void php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC) { filter->next = chain->head; filter->prev = NULL; @@ -297,8 +297,10 @@ PHPAPI void php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream filter->chain = chain; } -PHPAPI void php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter) +PHPAPI void php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC) { + php_stream *stream = chain->stream; + filter->prev = chain->tail; filter->next = NULL; if (chain->tail) { @@ -308,6 +310,75 @@ PHPAPI void php_stream_filter_append(php_stream_filter_chain *chain, php_stream_ } chain->tail = filter; filter->chain = chain; + + if ((stream->writepos - stream->readpos) > 0) { + /* Let's going ahead and wind anything in the buffer through this filter */ + php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL }; + php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out; + php_stream_filter_status_t status; + php_stream_bucket *bucket; + size_t consumed = 0; + + bucket = php_stream_bucket_new(stream, stream->readbuf + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC); + php_stream_bucket_append(brig_inp, bucket TSRMLS_CC); + status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC); + + if (stream->readpos + consumed > stream->writepos || consumed < 0) { + /* No behaving filter should cause this. */ + status = PSFS_ERR_FATAL; + } + + switch (status) { + case PSFS_ERR_FATAL: + /* If this first cycle simply fails then there's something wrong with the filter. + Pull the filter off the chain and leave the read buffer alone. */ + if (chain->head == filter) { + chain->head = NULL; + chain->tail = NULL; + } else { + filter->prev->next = NULL; + chain->tail = filter->prev; + } + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data. Not adding to filterchain."); + break; + case PSFS_FEED_ME: + /* We don't actually need data yet, + leave this filter in a feed me state until data is needed. + Reset stream's internal read buffer since the filter is "holding" it. */ + stream->readpos = 0; + stream->writepos = 0; + break; + case PSFS_PASS_ON: + /* Put any filtered data onto the readbuffer stack. + Previously read data has been at least partially consumed. */ + stream->readpos += consumed; + + if (stream->writepos == stream->readpos) { + /* Entirely consumed */ + stream->writepos = 0; + stream->readpos = 0; + } + + while (brig_outp->head) { + bucket = brig_outp->head; + /* Grow buffer to hold this bucket if need be. + TODO: See warning in main/stream/streams.c::php_stream_fill_read_buffer */ + if (stream->readbuflen - stream->writepos < bucket->buflen) { + stream->readbuflen += bucket->buflen; + stream->readbuf = perealloc(stream->readbuf, stream->readbuflen, stream->is_persistent); + } + memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen); + stream->writepos += bucket->buflen; + + php_stream_bucket_unlink(bucket TSRMLS_CC); + php_stream_bucket_delref(bucket TSRMLS_CC); + } + break; + } + } + } PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC) diff --git a/main/streams/php_stream_filter_api.h b/main/streams/php_stream_filter_api.h index dcab09efd6..2cbe6a775a 100644 --- a/main/streams/php_stream_filter_api.h +++ b/main/streams/php_stream_filter_api.h @@ -100,6 +100,9 @@ typedef struct _php_stream_filter_ops { typedef struct _php_stream_filter_chain { php_stream_filter *head, *tail; + + /* Owning stream */ + php_stream *stream; } php_stream_filter_chain; struct _php_stream_filter { @@ -118,14 +121,16 @@ struct _php_stream_filter { /* stack filter onto a stream */ BEGIN_EXTERN_C() -PHPAPI void php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter); -PHPAPI void php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter); +PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC); +PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC); PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC); PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC); PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC); END_EXTERN_C() #define php_stream_filter_alloc(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_CC TSRMLS_CC) #define php_stream_filter_alloc_rel(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_REL_CC TSRMLS_CC) +#define php_stream_fitler_prepend(chain, filter) _php_stream_filter_prepend((chain), (filter) TSRMLS_CC) +#define php_stream_fitler_append(chain, filter) _php_stream_filter_append((chain), (filter) TSRMLS_CC) #define php_stream_is_filtered(stream) ((stream)->readfilters.head || (stream)->writefilters.head) diff --git a/main/streams/streams.c b/main/streams/streams.c index af5caa93a7..fd67eea27d 100755 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -216,6 +216,9 @@ PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, const memset(ret, 0, sizeof(php_stream)); + ret->readfilters.stream = ret; + ret->writefilters.stream = ret; + #if STREAM_DEBUG fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persistent_id); #endif