diff --git a/docs/Changelog.md b/docs/Changelog.md index e6392fa..4d98063 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -6,6 +6,10 @@ > PHP version `^7.2|^8.0` +### `1.5.8` + + * Handle read error during handshake (@sirn-se) + ### `1.5.7` * Large header block fix (@sirn-se) diff --git a/lib/Client.php b/lib/Client.php index 89e7810..71d320a 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -180,6 +180,12 @@ function ($key, $value) { $response = ''; do { $buffer = fgets($this->socket, 1024); + if ($buffer === false) { + $meta = stream_get_meta_data($this->socket); + $message = 'Client handshake error'; + $this->logger->error($message, $meta); + throw new ConnectionException($message); + } $response .= $buffer; } while (substr_count($response, "\r\n\r\n") == 0); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index a5c8d84..e0cf94c 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -352,6 +352,16 @@ public function testBrokenRead(): void $client->receive(); } + public function testHandshakeError(): void + { + MockSocket::initialize('client.connect-handshake-error', $this); + $client = new Client('ws://localhost:8000/my/mock/path'); + $this->expectException('WebSocket\ConnectionException'); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('Client handshake error'); + $client->send('Connect'); + } + public function testReadTimeout(): void { MockSocket::initialize('client.connect', $this); diff --git a/tests/scripts/client.connect-handshake-error.json b/tests/scripts/client.connect-handshake-error.json new file mode 100644 index 0000000..f3aaced --- /dev/null +++ b/tests/scripts/client.connect-handshake-error.json @@ -0,0 +1,65 @@ +[ + { + "function": "stream_context_create", + "params": [], + "return": "@mock-stream-context" + }, + { + "function": "stream_socket_client", + "params": [ + "tcp:\/\/localhost:8000", + null, + null, + 5, + 4, + "@mock-stream-context" + ], + "return": "@mock-stream" + }, + { + "function": "get_resource_type", + "params": [ + "@mock-stream" + ], + "return": "stream" + }, + { + "function": "stream_set_timeout", + "params": [ + "@mock-stream", + 5 + ], + "return": true + }, + { + "function": "fwrite", + "params": [ + "@mock-stream" + ], + "return-op": "key-save", + "return": 199 + }, + { + "function": "fgets", + "params": [ + "@mock-stream", + 1024 + ], + "return": false + }, + { + "function": "stream_get_meta_data", + "params": [ + "@mock-stream" + ], + "return": { + "timed_out": true, + "blocked": true, + "eof": false, + "stream_type": "tcp_socket\/ssl", + "mode": "r+", + "unread_bytes": 0, + "seekable": false + } + } +] \ No newline at end of file