From 35f5af155f126f7145bab821675ea00ebc991bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Thu, 12 Oct 2017 17:11:40 +0200 Subject: [PATCH] Reverse emitStatusLine() and emitHeaders() calls To ensure that the emitted response will always be correct according with the response object. --- src/Response/SapiEmitter.php | 2 +- src/Response/SapiEmitterTrait.php | 6 ++++++ src/Response/SapiStreamEmitter.php | 2 +- test/Response/AbstractEmitterTest.php | 4 ++-- test/ServerTest.php | 7 +++++++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Response/SapiEmitter.php b/src/Response/SapiEmitter.php index 0b0a7bd6..111e83be 100644 --- a/src/Response/SapiEmitter.php +++ b/src/Response/SapiEmitter.php @@ -26,8 +26,8 @@ public function emit(ResponseInterface $response) { $this->assertNoPreviousOutput(); - $this->emitStatusLine($response); $this->emitHeaders($response); + $this->emitStatusLine($response); $this->emitBody($response); } diff --git a/src/Response/SapiEmitterTrait.php b/src/Response/SapiEmitterTrait.php index 43ec7904..3eeb3a73 100644 --- a/src/Response/SapiEmitterTrait.php +++ b/src/Response/SapiEmitterTrait.php @@ -38,7 +38,13 @@ private function assertNoPreviousOutput() * Emits the status line using the protocol version and status code from * the response; if a reason phrase is available, it, too, is emitted. * + * It's important to mention that, in order to prevent PHP from changing + * the status code of the emitted response, this method should be called + * after `emitHeaders()` + * * @param ResponseInterface $response + * + * @see \Zend\Diactoros\Response\SapiEmitterTrait::emitHeaders() */ private function emitStatusLine(ResponseInterface $response) { diff --git a/src/Response/SapiStreamEmitter.php b/src/Response/SapiStreamEmitter.php index 4175cb07..e06c99f2 100644 --- a/src/Response/SapiStreamEmitter.php +++ b/src/Response/SapiStreamEmitter.php @@ -27,8 +27,8 @@ class SapiStreamEmitter implements EmitterInterface public function emit(ResponseInterface $response, $maxBufferLength = 8192) { $this->assertNoPreviousOutput(); - $this->emitStatusLine($response); $this->emitHeaders($response); + $this->emitStatusLine($response); $range = $this->parseContentRange($response->getHeaderLine('Content-Range')); diff --git a/test/Response/AbstractEmitterTest.php b/test/Response/AbstractEmitterTest.php index 8e52b618..48bb95ee 100644 --- a/test/Response/AbstractEmitterTest.php +++ b/test/Response/AbstractEmitterTest.php @@ -66,9 +66,9 @@ public function testMultipleSetCookieHeadersAreNotReplaced() $this->emitter->emit($response); $expectedStack = [ - ['header' => 'HTTP/1.1 200 OK', 'replace' => true, 'status_code' => 200], ['header' => 'Set-Cookie: foo=bar', 'replace' => false, 'status_code' => 200], ['header' => 'Set-Cookie: bar=baz', 'replace' => false, 'status_code' => 200], + ['header' => 'HTTP/1.1 200 OK', 'replace' => true, 'status_code' => 200], ]; $this->assertSame($expectedStack, HeaderStack::stack()); @@ -84,9 +84,9 @@ public function testDoesNotLetResponseCodeBeOverriddenByPHP() $this->emitter->emit($response); $expectedStack = [ - ['header' => 'HTTP/1.1 202 Accepted', 'replace' => true, 'status_code' => 202], ['header' => 'Location: http://api.my-service.com/12345678', 'replace' => true, 'status_code' => 202], ['header' => 'Content-Type: text/plain', 'replace' => true, 'status_code' => 202], + ['header' => 'HTTP/1.1 202 Accepted', 'replace' => true, 'status_code' => 202], ]; $this->assertSame($expectedStack, HeaderStack::stack()); diff --git a/test/ServerTest.php b/test/ServerTest.php index 9cef932e..5bdac59c 100644 --- a/test/ServerTest.php +++ b/test/ServerTest.php @@ -246,16 +246,23 @@ public function testEmitsHeadersWithMultipleValuesMultipleTimes() */ public function testHeaderOrderIsHonoredWhenEmitted($stack) { + $header = array_pop($stack); + $this->assertContains('Content-Type: text/plain', $header); + $header = array_pop($stack); $this->assertContains( 'Set-Cookie: bar=baz; expires=Wed, 8 Oct 2014 10:30; path=/foo/bar; domain=example.com', $header ); + $header = array_pop($stack); $this->assertContains( 'Set-Cookie: foo=bar; expires=Wed, 1 Oct 2014 10:30; path=/foo; domain=example.com', $header ); + + $header = array_pop($stack); + $this->assertContains('HTTP/1.1 200 OK', $header); } public function testListenPassesCallableArgumentToCallback()