Skip to content

Fix #77069: stream filter loses final block of data #6001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions ext/standard/tests/streams/bug77069.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
Bug #77069 (stream filter loses final block of data)
--FILE--
<?php
class MyFilter extends php_user_filter {
private $data = '';

public function filter($in, $out, &$consumed, $closing) {
$return = PSFS_FEED_ME;

// While input data is available, continue to read it.
while ($bucket_in = stream_bucket_make_writeable($in)) {
$this->data .= $bucket_in->data;
$consumed += $bucket_in->datalen;

// Process whole lines.
while (preg_match('/(.*?)[\r\n]+(.*)/s', $this->data, $match) === 1) {
list(, $data, $this->data) = $match;
// Send this record output.
$data = strrev($data) . PHP_EOL;
$bucket_out = stream_bucket_new($this->stream, $data);
$return = PSFS_PASS_ON;
stream_bucket_append($out, $bucket_out);
}
}

// Process the final line.
if ($closing && $this->data !== '') {
$data = strrev($this->data) . PHP_EOL;
$bucket_out = stream_bucket_new($this->stream, $data);
$return = PSFS_PASS_ON;
stream_bucket_append($out, $bucket_out);
}

return $return;
}
}

stream_filter_register('my-filter', 'MyFilter');

$input = "Line one\nLine two\nLine three";

$stream = fopen('data://text/plain,' . $input, 'r');
stream_filter_append($stream, 'my-filter');

$output = '';
while (!feof($stream)) {
$output .= fread($stream, 16);
}
fclose($stream);

echo $output;
?>
--EXPECT--
eno eniL
owt eniL
eerht eniL
16 changes: 16 additions & 0 deletions ext/standard/tests/streams/bug77080.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Bug #77080 (Deflate not working)
--SKIPIF--
<?php
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--FILE--
<?php
$string = str_repeat("0123456789", 100);
$stream = fopen('data://text/plain,' . $string,'r');
stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ, 6);
$compressed = stream_get_contents($stream);
var_dump(gzinflate($compressed) === $string);
?>
--EXPECT--
bool(true)
57 changes: 57 additions & 0 deletions ext/standard/tests/streams/bug79984.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
Bug #79984 (Stream filter is not called with closing arg)
--FILE--
<?php

class F extends php_user_filter
{
public function onCreate()
{
echo 'filter onCreate' . PHP_EOL;
return true;
}

public function onClose()
{
echo 'filter onClose' . PHP_EOL;
}

public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = strtoupper($bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
echo 'filtered ' . ($consumed ? $consumed : 0) . ' bytes';
if ($closing) {
echo ' and closing.';
} else {
echo '.';
}
if (feof($this->stream)) {
echo ' Stream has reached end-of-file.';
}
echo PHP_EOL;
return PSFS_PASS_ON;
}
}

stream_filter_register('f', 'F');

$str = str_repeat('a', 8320);

$f2 = fopen('php://temp', 'r+b');
fwrite($f2, $str);
fseek($f2, 0, SEEK_SET);
stream_filter_append($f2, 'f', STREAM_FILTER_READ);
var_dump(strlen(stream_get_contents($f2)));
fclose($f2);

?>
--EXPECT--
filter onCreate
filtered 8192 bytes.
filtered 128 bytes and closing.
int(8320)
filter onClose
15 changes: 15 additions & 0 deletions ext/zlib/tests/bug48725_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Bug #48725 (Support for flushing in zlib stream)
--SKIPIF--
<?php
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--FILE--
<?php
$stream = fopen('data://text/plain;base64,' . base64_encode('Foo bar baz'),
'r');
stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ);
print bin2hex(stream_get_contents($stream));
?>
--EXPECT--
72cbcf57484a2c02e22a00000000ffff0300
2 changes: 1 addition & 1 deletion ext/zlib/zlib_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
inflateEnd(&(data->strm));
data->finished = '\1';
exit_status = PSFS_PASS_ON;
} else if (status != Z_OK) {
} else if (status != Z_OK && status != Z_BUF_ERROR) {
/* Something bad happened */
php_stream_bucket_delref(bucket);
/* reset these because despite the error the filter may be used again */
Expand Down
2 changes: 1 addition & 1 deletion main/streams/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ PHPAPI int _php_stream_fill_read_buffer(php_stream *stream, size_t size)
/* after this call, bucket is owned by the brigade */
php_stream_bucket_append(brig_inp, bucket);

flags = PSFS_FLAG_NORMAL;
flags = stream->eof ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_NORMAL;
} else {
flags = stream->eof ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC;
}
Expand Down