Skip to content

Commit

Permalink
Merge pull request #7 from voryx/permessage-deflate
Browse files Browse the repository at this point in the history
Update to new RFC6455
  • Loading branch information
davidwdan committed Aug 17, 2020
2 parents 907cb34 + 349eae9 commit d4a0161
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 14 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ A simple echo server:
```php
use Ratchet\RFC6455\Messaging\Message;
use React\EventLoop\Factory;
use React\Http\MiddlewareRunner;
use React\Http\Server;
use Voryx\WebSocketMiddleware\WebSocketConnection;
use Voryx\WebSocketMiddleware\WebSocketMiddleware;
Expand All @@ -28,3 +27,16 @@ $server->listen(new \React\Socket\Server('127.0.0.1:4321', $loop));

$loop->run();
```
# Options
By default `WebSocketMiddleware` uses the `ratchet/rfc6455` default max sizes for messages and frames and also disables compression.
These settings can be overridden with the `WebSocketOptions` object.
```php
$ws = new WebSocketMiddleware(
[],
$connectionHandler,
[],
WebSocketOptions::getDefault()
->withMaxFramePayloadSize(2048)
->withMaxMessagePayloadSize(4096)
->withPermessageDeflate());
```
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}
],
"require": {
"ratchet/rfc6455": "^0.2.3",
"ratchet/rfc6455": "^0.3",
"react/http": "^1.0"
},
"require-dev":{
Expand Down
36 changes: 30 additions & 6 deletions src/WebSocketConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
use Ratchet\RFC6455\Messaging\CloseFrameChecker;
use Ratchet\RFC6455\Messaging\Frame;
use Ratchet\RFC6455\Messaging\Message;
Expand All @@ -17,9 +18,19 @@ class WebSocketConnection implements EventEmitterInterface

private $stream;

public function __construct(DuplexStreamInterface $stream)
/** @var WebSocketOptions */
private $webSocketOptions;

/** @var PermessageDeflateOptions */
private $permessageDeflateOptions;

private $messageBuffer;

public function __construct(DuplexStreamInterface $stream, WebSocketOptions $webSocketOptions, PermessageDeflateOptions $permessageDeflateOptions)
{
$this->stream = $stream;
$this->stream = $stream;
$this->webSocketOptions = $webSocketOptions;
$this->permessageDeflateOptions = $permessageDeflateOptions;

$mb = new MessageBuffer(
new CloseFrameChecker(),
Expand All @@ -46,19 +57,32 @@ function (Frame $frame) {
return;
}
},
true
true,
null,
$this->webSocketOptions->getMaxMessagePayloadSize(),
$this->webSocketOptions->getMaxFramePayloadSize(),
[$this->stream, 'write'],
$this->permessageDeflateOptions
);

$this->messageBuffer = $mb;

$stream->on('data', [$mb, 'onData']);
}

public function send($data)
{
if (!($data instanceof MessageInterface)) {
$data = new Frame($data, true, Frame::OP_TEXT);
if ($data instanceof Frame) {
$this->messageBuffer->sendFrame($data);
return;
}

if ($data instanceof MessageInterface) {
$this->messageBuffer->sendMessage($data->getPayload(), true, $data->isBinary());
return;
}

$this->stream->write($data->getContents());
$this->messageBuffer->sendMessage($data);
}

public function close($code = 1000, $reason = '')
Expand Down
26 changes: 23 additions & 3 deletions src/WebSocketMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Voryx\WebSocketMiddleware;

use Psr\Http\Message\ServerRequestInterface;
use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
use Ratchet\RFC6455\Handshake\RequestVerifier;
use Ratchet\RFC6455\Handshake\ServerNegotiator;
use React\Http\Message\Response;
Expand All @@ -14,12 +15,14 @@ final class WebSocketMiddleware
private $paths;
private $connectionHandler = null;
private $subProtocols;
private $webSocketOptions = null;

public function __construct(array $paths = [], callable $connectionHandler = null, array $subProtocols = [])
public function __construct(array $paths = [], callable $connectionHandler = null, array $subProtocols = [], WebSocketOptions $webSocketOptions = null)
{
$this->paths = $paths;
$this->connectionHandler = $connectionHandler ?: function () {};
$this->subProtocols = $subProtocols;
$this->webSocketOptions = $webSocketOptions ?? WebSocketOptions::getDefault();
}

public function __invoke(ServerRequestInterface $request, callable $next = null)
Expand All @@ -35,7 +38,7 @@ public function __invoke(ServerRequestInterface $request, callable $next = null)
}
}

$negotiator = new ServerNegotiator(new RequestVerifier());
$negotiator = new ServerNegotiator(new RequestVerifier(), $this->webSocketOptions->isPermessageDeflateEnabled());
$negotiator->setSupportedSubProtocols($this->subProtocols);
$negotiator->setStrictSubProtocolCheck(true);

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

try {
$permessageDeflateOptions = PermessageDeflateOptions::fromRequestOrResponse($request);
} catch (\Exception $e) {
// 500 - Internal server error
return new Response(500, [], 'Error negotiating websocket permessage-deflate: ' . $e->getMessage());
}

if (!$this->webSocketOptions->isPermessageDeflateEnabled()) {
$permessageDeflateOptions = [
PermessageDeflateOptions::createDisabled()
];
}

$inStream = new ThroughStream();
$outStream = new ThroughStream();

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

$conn = new WebSocketConnection(new CompositeStream($inStream, $outStream));
$conn = new WebSocketConnection(
new CompositeStream($inStream, $outStream),
$this->webSocketOptions,
$permessageDeflateOptions[0]
);

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

Expand Down
69 changes: 69 additions & 0 deletions src/WebSocketOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Voryx\WebSocketMiddleware;

use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;

class WebSocketOptions
{
private $permessageDeflateEnabled = false;
private $maxMessagePayloadSize = null;
private $maxFramePayloadSize = null;

private function __construct()
{

}

public static function getDefault()
{
return new self();
}

public function withPermessageDeflate()
{
$c = clone $this;
$c->permessageDeflateEnabled = true;

return $c;
}

public function withoutPermessageDeflate()
{
$c = clone $this;
$c->permessageDeflateEnabled = false;

return $c;
}

public function withMaxMessagePayloadSize($maxSize)
{
$c = clone $this;
$c->maxMessagePayloadSize = $maxSize;

return $c;
}

public function withMaxFramePayloadSize($maxSize)
{
$c = clone $this;
$c->maxFramePayloadSize = $maxSize;

return $c;
}

public function isPermessageDeflateEnabled()
{
return $this->permessageDeflateEnabled;
}

public function getMaxMessagePayloadSize()
{
return $this->maxMessagePayloadSize;
}

public function getMaxFramePayloadSize()
{
return $this->maxFramePayloadSize;
}
}
2 changes: 1 addition & 1 deletion tests/ab/fuzzingclient.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
]

, "cases": ["*"]
, "exclude-cases": ["10.*", "11.*", "12.*", "13.*"]
, "exclude-cases": []
, "exclude-agent-cases": {}
}
4 changes: 2 additions & 2 deletions tests/ab/testServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
$conn->on('message', function (Message $message) use ($conn) {
$conn->send($message);
});
});
}, [], \Voryx\WebSocketMiddleware\WebSocketOptions::getDefault()->withPermessageDeflate());

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

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

$loop->run();

0 comments on commit d4a0161

Please sign in to comment.