Skip to content

Commit 3679912

Browse files
committed
Throw client read timeout earlier and don’t close connection
1 parent 62bc84e commit 3679912

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

lib/Base.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,12 @@ protected function read(string $length): string
443443
while (strlen($data) < $length) {
444444
$buffer = @fread($this->socket, $length - strlen($data));
445445
if ($buffer === false) {
446+
$meta = stream_get_meta_data($this->socket);
447+
if (!empty($meta['timed_out'])) {
448+
$message = 'Client read timeout';
449+
$this->logger->error($message, $meta);
450+
throw new TimeoutException($message, ConnectionException::TIMED_OUT, $meta);
451+
}
446452
$read = strlen($data);
447453
$this->throwException("Broken frame, read {$read} of stated {$length} bytes.");
448454
}
@@ -464,7 +470,6 @@ protected function throwException(string $message, int $code = 0): void
464470
fclose($this->socket);
465471
$this->socket = null;
466472
}
467-
$json_meta = json_encode($meta);
468473
if (!empty($meta['timed_out'])) {
469474
$this->logger->error($message, $meta);
470475
throw new TimeoutException($message, ConnectionException::TIMED_OUT, $meta);

tests/ClientTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,18 @@ public function testBrokenRead(): void
353353
$client->receive();
354354
}
355355

356+
public function testReadTimeout(): void
357+
{
358+
MockSocket::initialize('client.connect', $this);
359+
$client = new Client('ws://localhost:8000/my/mock/path');
360+
$client->send('Connect');
361+
MockSocket::initialize('receive-client-timeout', $this);
362+
$this->expectException('WebSocket\TimeoutException');
363+
$this->expectExceptionCode(1024);
364+
$this->expectExceptionMessage('Client read timeout');
365+
$client->receive();
366+
}
367+
356368
public function testEmptyRead(): void
357369
{
358370
MockSocket::initialize('client.connect', $this);

tests/scripts/receive-broken-read.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
"params": [],
1212
"return": false
1313
},
14+
{
15+
"function": "stream_get_meta_data",
16+
"params": [
17+
"@mock-stream"
18+
],
19+
"return": {
20+
"timed_out": false,
21+
"blocked": true,
22+
"eof": true,
23+
"stream_type": "tcp_socket\/ssl",
24+
"mode": "r+",
25+
"unread_bytes": 2,
26+
"seekable": false
27+
}
28+
},
1429
{
1530
"function": "get_resource_type",
1631
"params": [
@@ -40,4 +55,4 @@
4055
],
4156
"return":true
4257
}
43-
]
58+
]
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[
2+
{
3+
"function": "get_resource_type",
4+
"params": [
5+
"@mock-stream"
6+
],
7+
"return": "stream"
8+
},
9+
{
10+
"function": "fread",
11+
"params": [],
12+
"return": false
13+
},
14+
{
15+
"function": "stream_get_meta_data",
16+
"params": [
17+
"@mock-stream"
18+
],
19+
"return": {
20+
"timed_out": true,
21+
"blocked": true,
22+
"eof": false,
23+
"stream_type": "tcp_socket\/ssl",
24+
"mode": "r+",
25+
"unread_bytes": 0,
26+
"seekable": false
27+
}
28+
},
29+
{
30+
"function": "get_resource_type",
31+
"params": [
32+
"@mock-stream"
33+
],
34+
"return": "stream"
35+
},
36+
{
37+
"function": "get_resource_type",
38+
"params": [
39+
"@mock-stream"
40+
],
41+
"return": "stream"
42+
},
43+
{
44+
"function": "fclose",
45+
"params": [
46+
"@mock-stream"
47+
],
48+
"return":true
49+
}
50+
]

0 commit comments

Comments
 (0)