diff --git a/src/MessageTrait.php b/src/MessageTrait.php index 831e20d7..b7cf98b5 100644 --- a/src/MessageTrait.php +++ b/src/MessageTrait.php @@ -138,6 +138,11 @@ private function setHeaders(array $headers) { $this->headerNames = $this->headers = []; foreach ($headers as $header => $value) { + if (is_int($header)) { + // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec + // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass. + $header = (string) $header; + } $this->assertHeader($header); $value = $this->normalizeHeaderValue($value); $normalized = strtolower($header); @@ -154,10 +159,6 @@ private function setHeaders(array $headers) private function normalizeHeaderValue($value) { if (!is_array($value)) { - if (!is_string($value)) { - throw new \InvalidArgumentException('Header value must be a string or an array of strings.'); - } - return $this->trimHeaderValues([$value]); } @@ -185,17 +186,28 @@ private function normalizeHeaderValue($value) private function trimHeaderValues(array $values) { return array_map(function ($value) { - if (!is_string($value)) { - throw new \InvalidArgumentException('Header value must be a string.'); + if (!is_string($value) && !is_numeric($value)) { + throw new \InvalidArgumentException(sprintf( + 'Header value must be a string or numeric but %s provided.', + is_object($value) ? get_class($value) : gettype($value) + )); } - return trim($value, " \t"); + + return trim((string) $value, " \t"); }, $values); } private function assertHeader($header) { - if (!is_string($header) || $header === '') { - throw new \InvalidArgumentException('Header must be a non empty string.'); + if (!is_string($header)) { + throw new \InvalidArgumentException(sprintf( + 'Header name must be a string but %s provided.', + is_object($header) ? get_class($header) : gettype($header) + )); + } + + if ($header === '') { + throw new \InvalidArgumentException('Header name can not be empty.'); } } } diff --git a/src/Request.php b/src/Request.php index 355e546b..59f337db 100644 --- a/src/Request.php +++ b/src/Request.php @@ -145,7 +145,7 @@ private function updateHostFromUri() private function assertMethod($method) { if (!is_string($method) || $method === '') { - throw new \InvalidArgumentException('Method should be a non empty string.'); + throw new \InvalidArgumentException('Method must be a non-empty string.'); } } } diff --git a/src/Response.php b/src/Response.php index bea5f260..e7e04d86 100644 --- a/src/Response.php +++ b/src/Response.php @@ -97,7 +97,7 @@ public function __construct( $status = (int) $status; $this->assertStatusCodeRange($status); - $this->statusCode = (int) $status; + $this->statusCode = $status; if ($body !== '' && $body !== null) { $this->stream = stream_for($body); diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index 0fde5600..6496a8d0 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -237,6 +237,12 @@ public function testSameInstanceWhenRemovingMissingHeader() $this->assertSame($r, $r->withoutHeader('foo')); } + public function testPassNumericHeaderNameInConstructor() + { + $r = new Response(200, ['Location' => 'foo', '123' => 'bar']); + $this->assertSame('bar', $r->getHeaderLine('123')); + } + /** * @dataProvider invalidHeaderProvider */ @@ -250,11 +256,9 @@ public function invalidHeaderProvider() { return [ ['foo', [], 'Header value can not be an empty array.'], - ['', '', 'Header must be a non empty string.'], - ['foo', false, 'Header value must be a string or an array of strings.'], - [false, 'foo', 'Header must be a non empty string.'], - ['foo', new \stdClass(), 'Header value must be a string or an array of strings.'], - ['foo', new \ArrayObject(), 'Header value must be a string or an array of strings.'], + ['', '', 'Header name can not be empty.'], + ['foo', false, 'Header value must be a string or numeric but boolean provided'], + ['foo', new \stdClass(), 'Header value must be a string or numeric but stdClass provided.'], ]; } @@ -270,16 +274,11 @@ public function testWithInvalidHeader($header, $headerValue, $expectedMessage) public function invalidWithHeaderProvider() { - return [ - [[], 'foo', 'Header must be a non empty string.'], - ['foo', [], 'Header value can not be an empty array.'], - ['', '', 'Header must be a non empty string.'], - ['foo', false, 'Header value must be a string or an array of strings.'], - [false, 'foo', 'Header must be a non empty string.'], - ['foo', new \stdClass(), 'Header value must be a string or an array of strings.'], - ['foo', new \ArrayObject(), 'Header value must be a string or an array of strings.'], - [new \stdClass(), 'foo', 'Header must be a non empty string.'], - ]; + return array_merge($this->invalidHeaderProvider(), [ + [[], 'foo', 'Header name must be a string but array provided.'], + [false, 'foo', 'Header name must be a string but boolean provided.'], + [new \stdClass(), 'foo', 'Header name must be a string but stdClass provided.'], + ]); } public function testHeaderValuesAreTrimmed()