From b68b1fdadcfb0c7a91060ea94e02db10e30c11a9 Mon Sep 17 00:00:00 2001 From: mapogolions Date: Thu, 15 Aug 2019 14:18:02 +0500 Subject: [PATCH 1/3] Fix incorrect emit non-seekable streams --- Slim/ResponseEmitter.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Slim/ResponseEmitter.php b/Slim/ResponseEmitter.php index c762a74f2..6f0f159b3 100644 --- a/Slim/ResponseEmitter.php +++ b/Slim/ResponseEmitter.php @@ -133,7 +133,11 @@ public function isResponseEmpty(ResponseInterface $response): bool if (in_array($response->getStatusCode(), [204, 205, 304], true)) { return true; } - $contents = (string) $response->getBody(); - return !strlen($contents); + $stream = $response->getBody(); + $seekable = $stream->isSeekable(); + if ($seekable) { + $stream->rewind(); + } + return $seekable ? $stream->read(1) === '' : $stream->eof(); } } From d10ac819436dcfbac05d46e1d7cb4a241ff6f9aa Mon Sep 17 00:00:00 2001 From: mapogolions Date: Thu, 15 Aug 2019 14:26:28 +0500 Subject: [PATCH 2/3] Add tests for emit different stream types --- tests/ResponseEmitterTest.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/tests/ResponseEmitterTest.php b/tests/ResponseEmitterTest.php index 32e8daff0..8fcee3680 100644 --- a/tests/ResponseEmitterTest.php +++ b/tests/ResponseEmitterTest.php @@ -38,7 +38,7 @@ public function testRespond() $this->expectOutputString('Hello'); } - public function testRespondNoContent() + public function testResposeWithNoContentSkipsContentTypeAndContentLength() { $response = $this ->createResponse() @@ -55,7 +55,7 @@ public function testRespondNoContent() $this->expectOutputString(''); } - public function testNonEmptyResponse() + public function testNonEmptyResponseDoesNotSkipContentTypeAndContentLength() { $response = $this ->createResponse() @@ -197,7 +197,34 @@ public function testIsResponseEmptyWithNonEmptyBodyAndTriggeringStatusCode() $this->assertTrue($responseEmitter->isResponseEmpty($response)); } - public function testAvoidReadFromSlowStreamAccordingStatus() + public function testIsResponseEmptyDoesNotReadAllDataFromNonEmptySeekableResponse() + { + $body = $this->createStream('Hello'); + $response = $this + ->createResponse(200) + ->withBody($body); + $responseEmitter = new ResponseEmitter(); + + $responseEmitter->isResponseEmpty($response); + + $this->assertTrue($body->isSeekable()); + $this->assertFalse($body->eof()); + } + + public function testIsResponseEmptyDoesNotDrainNonSeekableResponseWithContent() + { + $resource = popen('echo 12', 'r'); + $body = $this->getStreamFactory()->createStreamFromResource($resource); + $response = $this->createResponse(200)->withBody($body); + $responseEmitter = new ResponseEmitter(); + + $responseEmitter->isResponseEmpty($response); + + $this->assertFalse($body->isSeekable()); + $this->assertSame('12', trim((string) $body)); + } + + public function testAvoidReadFromSlowStreamAccordingToStatus() { $body = new SlowPokeStream(); $response = $this From a023af2e387d4ed169eadb81803602361f983063 Mon Sep 17 00:00:00 2001 From: mapogolions Date: Thu, 15 Aug 2019 14:31:43 +0500 Subject: [PATCH 3/3] Make changes to legacy prophecy objects --- tests/AppTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/AppTest.php b/tests/AppTest.php index d987a4315..571d17ec1 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -1564,6 +1564,7 @@ public function testRun() $body .= $args[0]; $this->__toString()->willReturn($body); }); + $streamProphecy->read(1)->willReturn('_'); $streamProphecy->read('11')->will(function () { $this->eof()->willReturn(true); return $this->reveal()->__toString(); @@ -1616,6 +1617,7 @@ public function testRunWithoutPassingInServerRequest() $body .= $args[0]; $this->__toString()->willReturn($body); }); + $streamProphecy->read(1)->willReturn('_'); $streamProphecy->read('11')->will(function () { $this->eof()->willReturn(true); return $this->reveal()->__toString();