diff --git a/README.md b/README.md index f0adae3..b6f0d6a 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Replaces `textalk/websocket`. The client and server provides methods for reading and writing to WebSocket streams. -This fork is maintained by Sören Jensen, who has been maintaining the original textalk/websocket -repo since `v1.3`. +This repo replaces the abandoned `textalk/websocket` repo +and is maintained by Sören Jensen, who has been maintaining the original since `v1.3`. ## Documentation diff --git a/docs/Changelog.md b/docs/Changelog.md index 53b2e61..218d80d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -6,6 +6,11 @@ > PHP version `^8.0` +### `2.1.1` + + * Fix issue with falsy but valid HTTP headers (@axklim) + * Additional check for HTTP headers (@sirn-se) + ### `2.1.0` * Http & Tick middleware support (@sirn-se) diff --git a/docs/Contributing.md b/docs/Contributing.md index eb9981c..1458ea9 100644 --- a/docs/Contributing.md +++ b/docs/Contributing.md @@ -69,7 +69,7 @@ make coverage * Simon Lipp * Quentin Bellus * Patrick McCarren -* swmcdonnell, +* swmcdonnell * Ignas Bernotas * Mark Herhold * Andreas Palm @@ -85,4 +85,5 @@ make coverage * Antonio Mora * Simon Podlipsky * etrinh -* zgrguric \ No newline at end of file +* zgrguric +* axklim \ No newline at end of file diff --git a/docs/Listener.md b/docs/Listener.md index e52e270..fa40449 100644 --- a/docs/Listener.md +++ b/docs/Listener.md @@ -9,7 +9,7 @@ If you use the listener method `->start()` this will be the only way to act on i ## Message listeners The message listeners are called whenever the client or server receives a message of the same type. -All message listeners receive Client|Server, Connection and Message as arguments. +All message listeners receive `Client|Server`, `Connection` and `Message` as arguments. ```php $client_or_server @@ -40,8 +40,8 @@ $client_or_server These listeners are called when the Client or Server connects and disconnects. -* On Client, the onConnect() will receive a Response as last argument -* On Server, the onConnect() will receive a ServerRequest as last argument +* On Client, the `onConnect()` will receive a `Response` as last argument +* On Server, the `onConnect()` will receive a `ServerRequest` as last argument ```php $client_or_server @@ -75,7 +75,7 @@ $client_or_server Using above functions, your Client and Server will be able to receive incoming messages and take action accordingly. But what if your implementation need to process other data, and send unsolicited messages? -The coroutine implementation will regulary call the onTick() method, depending on workload and configuration. +The coroutine implementation will regulary call the `onTick()` method, depending on workload and configuration. ```php $client_or_server diff --git a/docs/Middleware.md b/docs/Middleware.md index 4f8517f..45b8080 100644 --- a/docs/Middleware.md +++ b/docs/Middleware.md @@ -36,7 +36,7 @@ These middlewares are included in library and can be added to provide additional ## Middleware descriptions -Descriptiopn of included middlewares. +Description of included middlewares. ### The CloseHandler middleware diff --git a/docs/Server.md b/docs/Server.md index e2363af..b57973a 100644 --- a/docs/Server.md +++ b/docs/Server.md @@ -162,18 +162,14 @@ $server->close(1000, "Closing now"); When started, the server will continue to run until something tells it so stop. There are some additional methods that control the server. -Start server - It will continuously listen to incoming messages and apply specified callback functions. ```php +// Start server - It will continuously listen to incoming messages and apply specified callback functions $server->start(); -``` -Stop server - When called, server will no longer listen to incoming messages but will not disconnect clients. -```php +// Stop server - When called, server will no longer listen to incoming messages but will not disconnect clients $server->stop(); -``` -Disconnect server - Server will immediately stop and disconnect all clients without normal close procedure. -```php +//Disconnect server - Server will immediately stop and disconnect all clients without normal close procedure $server->disconnect(); ``` diff --git a/src/Http/Message.php b/src/Http/Message.php index d48afd0..1a4ccca 100644 --- a/src/Http/Message.php +++ b/src/Http/Message.php @@ -98,7 +98,7 @@ public function getHeaderLine(string $name): string * @return static * @throws \InvalidArgumentException for invalid header names or values. */ - public function withHeader(string $name, $value): self + public function withHeader(string $name, mixed $value): self { $new = clone $this; if ($this->hasHeader($name)) { @@ -116,7 +116,7 @@ public function withHeader(string $name, $value): self * @throws \InvalidArgumentException for invalid header names. * @throws \InvalidArgumentException for invalid header values. */ - public function withAddedHeader(string $name, $value): self + public function withAddedHeader(string $name, mixed $value): self { $new = clone $this; $new->handleHeader($name, $value); @@ -164,14 +164,20 @@ public function getAsArray(): array return $lines; } - private function handleHeader(string $name, string|array $value): void + private function handleHeader(string $name, mixed $value): void { // @todo: Add all available characters, these are just some of them. if (!preg_match('|^[0-9a-zA-Z#_-]+$|', $name)) { throw new InvalidArgumentException("'{$name}' is not a valid header field name."); } $value = is_array($value) ? $value : [$value]; + if (empty($value)) { + throw new InvalidArgumentException("Invalid header value(s) provided."); + } foreach ($value as $content) { + if (!is_string($content) && !is_numeric($content)) { + throw new InvalidArgumentException("Invalid header value(s) provided."); + } $content = trim($content); if ('' === $content) { throw new InvalidArgumentException("Invalid header value(s) provided."); diff --git a/tests/suites/http/RequestTest.php b/tests/suites/http/RequestTest.php index e89636e..ac6b2b2 100644 --- a/tests/suites/http/RequestTest.php +++ b/tests/suites/http/RequestTest.php @@ -12,6 +12,7 @@ namespace WebSocket\Test\Http; use BadMethodCallException; +use Generator; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Phrity\Net\StreamFactory; @@ -215,7 +216,7 @@ public function testWithBodyError(): void $request->withBody($factory->createStream()); } - public function testHaederNameError(): void + public function testHeaderNameError(): void { $request = new Request(); $this->expectException(InvalidArgumentException::class); @@ -224,48 +225,45 @@ public function testHaederNameError(): void $request->withHeader('.', 'invaid name'); } - public function testHaederValueError(): void - { - $request = new Request(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionCode(0); - $this->expectExceptionMessage("Invalid header value(s) provided."); - $request->withHeader('name', ''); - } - /** * @dataProvider provideInvalidHeaderValues - * @ */ - public function testHeaderValueInvalidVariants($value): void + public function testHeaderValueInvalidVariants(mixed $value): void { $request = new Request(); $this->expectException(InvalidArgumentException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage("Invalid header value(s) provided."); $request->withHeader('name', $value); } - public static function provideInvalidHeaderValues(): \Generator + public static function provideInvalidHeaderValues(): Generator { yield ['']; yield [' ']; + yield [['0', '']]; + yield [[null]]; + yield [[[0]]]; + yield [[]]; } /** * @dataProvider provideValidHeaderValues - * @ */ - public function testHeaderValueValidVariants($value): void + public function testHeaderValueValidVariants(mixed $value, array $expected): void { $request = new Request(); $request = $request->withHeader('name', $value); $this->assertInstanceOf(Request::class, $request); + $this->assertEquals($expected, $request->getHeaders()); } - public static function provideValidHeaderValues(): \Generator + public static function provideValidHeaderValues(): Generator { - yield ['null']; - yield ['0']; - yield [' 0']; - yield ['1']; + yield ['null', ['name' => ['null']]]; + yield ['0 ', ['name' => ['0']]]; + yield [' 0', ['name' => ['0']]]; + yield [['0', '1'], ['name' => ['0', '1']]]; + yield [0, ['name' => ['0']]]; } }