diff --git a/NEWS b/NEWS index 89384217236..0028d6944f8 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ PHP NEWS source file). (ilutov) - Streams: + . Fixed bug GH-10031 ([Stream] STREAM_NOTIFY_PROGRESS over HTTP emitted + irregularly for last chunk of data). (nielsdos) . Fixed bug GH-11175 (Stream Socket Timeout). (nielsdos) . Fixed bug GH-11177 (ASAN UndefinedBehaviorSanitizer when timeout = -1 passed to stream_socket_accept/stream_socket_client). (nielsdos) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 5964efd2f9a..fa0dcb5e689 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -955,6 +955,13 @@ out: if (transfer_encoding) { php_stream_filter_append(&stream->readfilters, transfer_encoding); } + + /* It's possible that the server already sent in more data than just the headers. + * We account for this by adjusting the progress counter by the difference of + * already read header data and the body. */ + if (stream->writepos > stream->readpos) { + php_stream_notify_progress_increment(context, stream->writepos - stream->readpos, 0); + } } return stream; diff --git a/ext/standard/tests/streams/gh10031.phpt b/ext/standard/tests/streams/gh10031.phpt new file mode 100644 index 00000000000..aa3576dab51 --- /dev/null +++ b/ext/standard/tests/streams/gh10031.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-10031 ([Stream] STREAM_NOTIFY_PROGRESS over HTTP emitted irregularly for last chunk of data) +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--CONFLICTS-- +server +--FILE-- + ['ignore_errors' => true,]]); +$lastBytesTransferred = 0; +stream_context_set_params($context, ['notification' => function ($code, $s, $m, $mc, $bytes_transferred, $bytes_max) +use (&$lastBytesTransferred) { + if ($code === STREAM_NOTIFY_FILE_SIZE_IS) echo "expected filesize=$bytes_max".PHP_EOL; + $lastBytesTransferred = $bytes_transferred; + @ob_flush(); +}]); + +$get = file_get_contents("http://".PHP_CLI_SERVER_ADDRESS, false, $context); + +echo "got filesize=" . strlen($get) . PHP_EOL; +var_dump($lastBytesTransferred); + +?> +--EXPECT-- +expected filesize=1000 +got filesize=1000 +int(1000)