slimphp / Slim

Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs.
http://slimframework.com
MIT License
11.98k stars 1.95k forks source link

Connection closed unexpectedly when returning a stream #1836

Closed Rudloff closed 8 years ago

Rudloff commented 8 years ago

Hello,

I am trying to return a Guzzle stream:

$client = new \GuzzleHttp\Client();
$response = $client->request('GET', $video->url, array('stream'=>true));
return $response->withHeader('Content-Disposition', 'inline; filename="'.$video->_filename.'"');

But it seems the connection is always closed before the end of the file is sent:

2016-04-07 02:14:36 (2.43 MB/s) - Connection closed at byte 2111778. Giving up.

Do you have any idea what could cause this?

Rudloff commented 8 years ago

The problem seems to come from here: https://github.com/slimphp/Slim/blob/3.x/Slim/App.php#L386 If I remove the first condition and use the simpler way (without $totalChunks), it seems to work correctly.

Could it be a problem with the way Slim calculates the chunks?

Rudloff commented 8 years ago

OK so for some reasion $body->read($chunkSize); only reads 1631 bytes, even though $chunkSize is 4096. If I set it to something lower like 1024, it seems to work fine.

I guess it only reads the content of one packet so the whole chunk size thing is not really relevant here. One solution would be to check $response->getBody()->getMetadata()['stream_type'] to see if the stream has a distant source.

llvdl commented 8 years ago

I guess this is because the chunked reading, in the case of a known content length, assumes that when reading a chunk, the chunk will always be the given size:

echo $body->read($chunkSize);

As the documentation for StreamInterface::read states, the size could be less than $chunkSize, and the amount of data will fall short of the expected amount. Instead of counting chunks, the amount of received bytes should be counted or the amount of chunks to read should be recalculated based on the actual amount of bytes read.

I am also not sure why there is a different implementation for reading chunks when the content length is known. I would expect the simpler way you mentioned to work for both cases.

Rudloff commented 8 years ago

It works, thanks!

akrabat commented 8 years ago

That's great!