Skip to content

Commit d4a0161

Browse files
authored
Merge pull request #7 from voryx/permessage-deflate
Update to new RFC6455
2 parents 907cb34 + 349eae9 commit d4a0161

7 files changed

Lines changed: 139 additions & 14 deletions

File tree

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ A simple echo server:
77
```php
88
use Ratchet\RFC6455\Messaging\Message;
99
use React\EventLoop\Factory;
10-
use React\Http\MiddlewareRunner;
1110
use React\Http\Server;
1211
use Voryx\WebSocketMiddleware\WebSocketConnection;
1312
use Voryx\WebSocketMiddleware\WebSocketMiddleware;
@@ -28,3 +27,16 @@ $server->listen(new \React\Socket\Server('127.0.0.1:4321', $loop));
2827

2928
$loop->run();
3029
```
30+
# Options
31+
By default `WebSocketMiddleware` uses the `ratchet/rfc6455` default max sizes for messages and frames and also disables compression.
32+
These settings can be overridden with the `WebSocketOptions` object.
33+
```php
34+
$ws = new WebSocketMiddleware(
35+
[],
36+
$connectionHandler,
37+
[],
38+
WebSocketOptions::getDefault()
39+
->withMaxFramePayloadSize(2048)
40+
->withMaxMessagePayloadSize(4096)
41+
->withPermessageDeflate());
42+
```

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
}
2323
],
2424
"require": {
25-
"ratchet/rfc6455": "^0.2.3",
25+
"ratchet/rfc6455": "^0.3",
2626
"react/http": "^1.0"
2727
},
2828
"require-dev":{

src/WebSocketConnection.php

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Evenement\EventEmitterInterface;
66
use Evenement\EventEmitterTrait;
7+
use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
78
use Ratchet\RFC6455\Messaging\CloseFrameChecker;
89
use Ratchet\RFC6455\Messaging\Frame;
910
use Ratchet\RFC6455\Messaging\Message;
@@ -17,9 +18,19 @@ class WebSocketConnection implements EventEmitterInterface
1718

1819
private $stream;
1920

20-
public function __construct(DuplexStreamInterface $stream)
21+
/** @var WebSocketOptions */
22+
private $webSocketOptions;
23+
24+
/** @var PermessageDeflateOptions */
25+
private $permessageDeflateOptions;
26+
27+
private $messageBuffer;
28+
29+
public function __construct(DuplexStreamInterface $stream, WebSocketOptions $webSocketOptions, PermessageDeflateOptions $permessageDeflateOptions)
2130
{
22-
$this->stream = $stream;
31+
$this->stream = $stream;
32+
$this->webSocketOptions = $webSocketOptions;
33+
$this->permessageDeflateOptions = $permessageDeflateOptions;
2334

2435
$mb = new MessageBuffer(
2536
new CloseFrameChecker(),
@@ -46,19 +57,32 @@ function (Frame $frame) {
4657
return;
4758
}
4859
},
49-
true
60+
true,
61+
null,
62+
$this->webSocketOptions->getMaxMessagePayloadSize(),
63+
$this->webSocketOptions->getMaxFramePayloadSize(),
64+
[$this->stream, 'write'],
65+
$this->permessageDeflateOptions
5066
);
5167

68+
$this->messageBuffer = $mb;
69+
5270
$stream->on('data', [$mb, 'onData']);
5371
}
5472

5573
public function send($data)
5674
{
57-
if (!($data instanceof MessageInterface)) {
58-
$data = new Frame($data, true, Frame::OP_TEXT);
75+
if ($data instanceof Frame) {
76+
$this->messageBuffer->sendFrame($data);
77+
return;
78+
}
79+
80+
if ($data instanceof MessageInterface) {
81+
$this->messageBuffer->sendMessage($data->getPayload(), true, $data->isBinary());
82+
return;
5983
}
6084

61-
$this->stream->write($data->getContents());
85+
$this->messageBuffer->sendMessage($data);
6286
}
6387

6488
public function close($code = 1000, $reason = '')

src/WebSocketMiddleware.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Voryx\WebSocketMiddleware;
44

55
use Psr\Http\Message\ServerRequestInterface;
6+
use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
67
use Ratchet\RFC6455\Handshake\RequestVerifier;
78
use Ratchet\RFC6455\Handshake\ServerNegotiator;
89
use React\Http\Message\Response;
@@ -14,12 +15,14 @@ final class WebSocketMiddleware
1415
private $paths;
1516
private $connectionHandler = null;
1617
private $subProtocols;
18+
private $webSocketOptions = null;
1719

18-
public function __construct(array $paths = [], callable $connectionHandler = null, array $subProtocols = [])
20+
public function __construct(array $paths = [], callable $connectionHandler = null, array $subProtocols = [], WebSocketOptions $webSocketOptions = null)
1921
{
2022
$this->paths = $paths;
2123
$this->connectionHandler = $connectionHandler ?: function () {};
2224
$this->subProtocols = $subProtocols;
25+
$this->webSocketOptions = $webSocketOptions ?? WebSocketOptions::getDefault();
2326
}
2427

2528
public function __invoke(ServerRequestInterface $request, callable $next = null)
@@ -35,7 +38,7 @@ public function __invoke(ServerRequestInterface $request, callable $next = null)
3538
}
3639
}
3740

38-
$negotiator = new ServerNegotiator(new RequestVerifier());
41+
$negotiator = new ServerNegotiator(new RequestVerifier(), $this->webSocketOptions->isPermessageDeflateEnabled());
3942
$negotiator->setSupportedSubProtocols($this->subProtocols);
4043
$negotiator->setStrictSubProtocolCheck(true);
4144

@@ -50,6 +53,19 @@ public function __invoke(ServerRequestInterface $request, callable $next = null)
5053
return $next($request);
5154
}
5255

56+
try {
57+
$permessageDeflateOptions = PermessageDeflateOptions::fromRequestOrResponse($request);
58+
} catch (\Exception $e) {
59+
// 500 - Internal server error
60+
return new Response(500, [], 'Error negotiating websocket permessage-deflate: ' . $e->getMessage());
61+
}
62+
63+
if (!$this->webSocketOptions->isPermessageDeflateEnabled()) {
64+
$permessageDeflateOptions = [
65+
PermessageDeflateOptions::createDisabled()
66+
];
67+
}
68+
5369
$inStream = new ThroughStream();
5470
$outStream = new ThroughStream();
5571

@@ -62,7 +78,11 @@ public function __invoke(ServerRequestInterface $request, callable $next = null)
6278
)
6379
);
6480

65-
$conn = new WebSocketConnection(new CompositeStream($inStream, $outStream));
81+
$conn = new WebSocketConnection(
82+
new CompositeStream($inStream, $outStream),
83+
$this->webSocketOptions,
84+
$permessageDeflateOptions[0]
85+
);
6686

6787
call_user_func($this->connectionHandler, $conn, $request, $response);
6888

src/WebSocketOptions.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace Voryx\WebSocketMiddleware;
4+
5+
use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
6+
7+
class WebSocketOptions
8+
{
9+
private $permessageDeflateEnabled = false;
10+
private $maxMessagePayloadSize = null;
11+
private $maxFramePayloadSize = null;
12+
13+
private function __construct()
14+
{
15+
16+
}
17+
18+
public static function getDefault()
19+
{
20+
return new self();
21+
}
22+
23+
public function withPermessageDeflate()
24+
{
25+
$c = clone $this;
26+
$c->permessageDeflateEnabled = true;
27+
28+
return $c;
29+
}
30+
31+
public function withoutPermessageDeflate()
32+
{
33+
$c = clone $this;
34+
$c->permessageDeflateEnabled = false;
35+
36+
return $c;
37+
}
38+
39+
public function withMaxMessagePayloadSize($maxSize)
40+
{
41+
$c = clone $this;
42+
$c->maxMessagePayloadSize = $maxSize;
43+
44+
return $c;
45+
}
46+
47+
public function withMaxFramePayloadSize($maxSize)
48+
{
49+
$c = clone $this;
50+
$c->maxFramePayloadSize = $maxSize;
51+
52+
return $c;
53+
}
54+
55+
public function isPermessageDeflateEnabled()
56+
{
57+
return $this->permessageDeflateEnabled;
58+
}
59+
60+
public function getMaxMessagePayloadSize()
61+
{
62+
return $this->maxMessagePayloadSize;
63+
}
64+
65+
public function getMaxFramePayloadSize()
66+
{
67+
return $this->maxFramePayloadSize;
68+
}
69+
}

tests/ab/fuzzingclient.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
]
88

99
, "cases": ["*"]
10-
, "exclude-cases": ["10.*", "11.*", "12.*", "13.*"]
10+
, "exclude-cases": []
1111
, "exclude-agent-cases": {}
1212
}

tests/ab/testServer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
$conn->on('message', function (Message $message) use ($conn) {
1515
$conn->send($message);
1616
});
17-
});
17+
}, [], \Voryx\WebSocketMiddleware\WebSocketOptions::getDefault()->withPermessageDeflate());
1818

1919
$server = new Server($loop, $ws);
2020

21-
$server->listen(new \React\Socket\Server('127.0.0.1:4321', $loop));
21+
$server->listen(new \React\Socket\Server('0.0.0.0:4321', $loop));
2222

2323
$loop->run();
2424

0 commit comments

Comments
 (0)