Do not attempt to rewind unsociable streams when transmitting response

This commit is contained in:
PJ Dietz 2016-02-22 14:45:16 -05:00
parent db7aaa2688
commit 0c61641376
3 changed files with 43 additions and 2 deletions

1
.gitignore vendored
View File

@ -21,6 +21,7 @@ preview
workspace.xml workspace.xml
# Vagrant # Vagrant
.bundle/
.vagrant/ .vagrant/
# Vagrant sandbox site files. # Vagrant sandbox site files.

View File

@ -98,7 +98,9 @@ class Transmitter implements TransmitterInterface
private function outputBody(StreamInterface $body) private function outputBody(StreamInterface $body)
{ {
if ($this->chunkSize > 0) { if ($this->chunkSize > 0) {
$body->rewind(); if ($body->isSeekable()) {
$body->rewind();
}
while (!$body->eof()) { while (!$body->eof()) {
print $body->read($this->chunkSize); print $body->read($this->chunkSize);
} }

View File

@ -135,6 +135,7 @@ class TransmitterTest extends \PHPUnit_Framework_TestCase
$chunkSize = 3; $chunkSize = 3;
$position = 0; $position = 0;
$this->body->isSeekable()->willReturn(true);
$this->body->isReadable()->willReturn(true); $this->body->isReadable()->willReturn(true);
$this->body->rewind()->willReturn(true); $this->body->rewind()->willReturn(true);
$this->body->eof()->willReturn(false); $this->body->eof()->willReturn(false);
@ -154,13 +155,50 @@ class TransmitterTest extends \PHPUnit_Framework_TestCase
$transmitter->setChunkSize($chunkSize); $transmitter->setChunkSize($chunkSize);
ob_start(); ob_start();
$transmitter->transmit($this->request->reveal(), $this->response->reveal(), $chunkSize); $transmitter->transmit($this->request->reveal(), $this->response->reveal());
$captured = ob_get_contents(); $captured = ob_get_contents();
ob_end_clean(); ob_end_clean();
$this->assertEquals($content, $captured); $this->assertEquals($content, $captured);
} }
/**
* @covers ::transmit
* @covers ::setChunkSize
* @covers ::outputBody
*/
public function testOutputsUnseekableStreamInChunks()
{
$content = "Hello, world!";
$chunkSize = 3;
$position = 0;
$this->body->isSeekable()->willReturn(false);
$this->body->isReadable()->willReturn(true);
$this->body->rewind()->willThrow(new \RuntimeException());
$this->body->eof()->willReturn(false);
$this->body->read(Argument::any())->will(
function ($args) use ($content, &$position) {
$chunkSize = $args[0];
$chunk = substr($content, $position, $chunkSize);
$position += $chunkSize;
if ($position >= strlen($content)) {
$this->eof()->willReturn(true);
}
return $chunk;
}
);
$transmitter = new Transmitter();
$transmitter->setChunkSize($chunkSize);
ob_start();
$transmitter->transmit($this->request->reveal(), $this->response->reveal());
$captured = ob_get_contents();
ob_end_clean();
$this->assertEquals($content, $captured);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Preparation // Preparation