diff --git a/src/MessageTrait.php b/src/MessageTrait.php index 17bc2d29..7647c29a 100644 --- a/src/MessageTrait.php +++ b/src/MessageTrait.php @@ -70,6 +70,7 @@ public function getProtocolVersion() */ public function withProtocolVersion($version) { + $this->validateProtocolVersion($version); $new = clone $this; $new->protocol = $version; return $new; @@ -400,4 +401,32 @@ private static function assertValidHeaderValue(array $values) { array_walk($values, __NAMESPACE__ . '\HeaderSecurity::assertValid'); } + + /** + * Validate the HTTP protocol version + * + * @param string $version + * @throws InvalidArgumentException on invalid HTTP protocol version + */ + private function validateProtocolVersion($version) + { + if (empty($version)) { + throw new InvalidArgumentException(sprintf( + 'HTTP protocol version can not be empty' + )); + } + if (! is_string($version)) { + throw new InvalidArgumentException(sprintf( + 'Unsupported HTTP protocol version; must be a string, received %s', + (is_object($version) ? get_class($version) : gettype($version)) + )); + } + //HTTP uses a "." numbering scheme to indicate versions of the protocol + if (! preg_match('~^\d+\.\d+$~', $version)) { + throw new InvalidArgumentException(sprintf( + 'Unsupported HTTP protocol version "%s" provided', + $version + )); + } + } } diff --git a/src/Request/Serializer.php b/src/Request/Serializer.php index d7c8d131..b7ef5350 100644 --- a/src/Request/Serializer.php +++ b/src/Request/Serializer.php @@ -76,6 +76,10 @@ public static function fromStream(StreamInterface $stream) */ public static function toString(RequestInterface $request) { + $httpMethod = $request->getMethod(); + if (empty($httpMethod)) { + throw new UnexpectedValueException('Object can not be serialized because HTTP method is empty'); + } $headers = self::serializeHeaders($request->getHeaders()); $body = (string) $request->getBody(); $format = '%s %s HTTP/%s%s%s'; @@ -89,7 +93,7 @@ public static function toString(RequestInterface $request) return sprintf( $format, - $request->getMethod(), + $httpMethod, $request->getRequestTarget(), $request->getProtocolVersion(), $headers, diff --git a/test/MessageTraitTest.php b/test/MessageTraitTest.php index 500eb1c4..26b8ebc4 100644 --- a/test/MessageTraitTest.php +++ b/test/MessageTraitTest.php @@ -39,6 +39,30 @@ public function testProtocolMutatorReturnsCloneWithChanges() $this->assertEquals('1.0', $message->getProtocolVersion()); } + + public function invalidProtocolVersionProvider() + { + return [ + 'true' => [ true ], + 'false' => [ false ], + 'int' => [ 1 ], + 'float' => [ 1.1 ], + 'array' => [ ['1.1'] ], + 'stdClass' => [ (object) [ 'version' => '1.0'] ], + 'wrong-format' => [ '1'], + 'wrong-format2' => [ '1.2.3'], + ]; + } + /** + * @dataProvider invalidProtocolVersionProvider + */ + public function testWithProtocolVersionRaisesExceptionForInvalidVersion($version) + { + $this->setExpectedException('InvalidArgumentException'); + $request = new Request(); + $request->withProtocolVersion($version); + } + public function testUsesStreamProvidedInConstructorAsBody() { $stream = $this->getMock('Psr\Http\Message\StreamInterface'); diff --git a/test/Request/SerializerTest.php b/test/Request/SerializerTest.php index 462433c6..ba1ed2a9 100644 --- a/test/Request/SerializerTest.php +++ b/test/Request/SerializerTest.php @@ -15,6 +15,7 @@ use Zend\Diactoros\Request\Serializer; use Zend\Diactoros\Stream; use Zend\Diactoros\Uri; +use UnexpectedValueException; class SerializerTest extends TestCase { @@ -326,4 +327,14 @@ public function testFromStreamStopsReadingAfterScanningHeader() $stream = Serializer::fromStream($stream); $this->assertInstanceOf('Zend\Diactoros\RelativeStream', $stream->getBody()); } + + /** + * @expectedException UnexpectedValueException + */ + public function testToStringRaisesExceptionOnEmptyMethod() + { + $request = (new Request()) + ->withUri(new Uri('http://example.com/foo/bar?baz=bat')); + $message = Serializer::toString($request); + } }