Skip to content

Commit 45be5ab

Browse files
authored
Merge pull request #140 from marcroberts/master
Throw client read timeout earlier and don’t close connection
2 parents 62bc84e + 953a5c6 commit 45be5ab

File tree

5 files changed

+102
-2
lines changed

5 files changed

+102
-2
lines changed

lib/Base.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,15 @@ protected function read(string $length): string
442442
$data = '';
443443
while (strlen($data) < $length) {
444444
$buffer = @fread($this->socket, $length - strlen($data));
445+
446+
if (!$buffer) {
447+
$meta = stream_get_meta_data($this->socket);
448+
if (!empty($meta['timed_out'])) {
449+
$message = 'Client read timeout';
450+
$this->logger->error($message, $meta);
451+
throw new TimeoutException($message, ConnectionException::TIMED_OUT, $meta);
452+
}
453+
}
445454
if ($buffer === false) {
446455
$read = strlen($data);
447456
$this->throwException("Broken frame, read {$read} of stated {$length} bytes.");
@@ -464,7 +473,6 @@ protected function throwException(string $message, int $code = 0): void
464473
fclose($this->socket);
465474
$this->socket = null;
466475
}
467-
$json_meta = json_encode($meta);
468476
if (!empty($meta['timed_out'])) {
469477
$this->logger->error($message, $meta);
470478
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+
]

tests/scripts/receive-empty-read.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
"params": [],
1212
"return": ""
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": false,
23+
"stream_type": "tcp_socket\/ssl",
24+
"mode": "r+",
25+
"unread_bytes": 0,
26+
"seekable": false
27+
}
28+
},
1429
{
1530
"function": "get_resource_type",
1631
"params": [

0 commit comments

Comments
 (0)