Skip to content

Commit 772e465

Browse files
committed
Merge commit '6df0bd1b68df5b9774b79c036b9ba31d85ad0d01' into v0.4
# Conflicts: # composer.json # src/Handshake/ClientNegotiator.php # src/Handshake/ServerNegotiator.php # tests/ab/clientRunner.php # tests/ab/startServer.php # tests/unit/Handshake/ServerNegotiatorTest.php
2 parents 4304337 + 6df0bd1 commit 772e465

File tree

7 files changed

+70
-44
lines changed

7 files changed

+70
-44
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
"require": {
2929
"php": ">=7.4",
30-
"guzzlehttp/psr7": "^2 || ^1.7",
30+
"psr/http-factory-implementation": "^1.0",
3131
"symfony/polyfill-php80": "^1.15"
3232
},
3333
"require-dev": {

src/Handshake/ClientNegotiator.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,28 @@
33
use Psr\Http\Message\RequestInterface;
44
use Psr\Http\Message\ResponseInterface;
55
use Psr\Http\Message\UriInterface;
6-
use GuzzleHttp\Psr7\Request;
6+
use Psr\Http\Message\RequestFactoryInterface;
77

88
class ClientNegotiator {
99
private ResponseVerifier $verifier;
1010

1111
private RequestInterface $defaultHeader;
1212

13-
public function __construct(PermessageDeflateOptions $perMessageDeflateOptions = null) {
13+
private RequestFactoryInterface $requestFactory;
14+
15+
public function __construct(
16+
RequestFactoryInterface $requestFactory,
17+
PermessageDeflateOptions $perMessageDeflateOptions = null
18+
) {
1419
$this->verifier = new ResponseVerifier;
20+
$this->requestFactory = $requestFactory;
1521

16-
$this->defaultHeader = new Request('GET', '', [
17-
'Connection' => 'Upgrade'
18-
, 'Upgrade' => 'websocket'
19-
, 'Sec-WebSocket-Version' => $this->getVersion()
20-
, 'User-Agent' => "Ratchet"
21-
]);
22+
$this->defaultHeader = $this->requestFactory
23+
->createRequest('GET', '')
24+
->withHeader('Connection' , 'Upgrade')
25+
->withHeader('Upgrade' , 'websocket')
26+
->withHeader('Sec-WebSocket-Version', $this->getVersion())
27+
->withHeader('User-Agent' , 'Ratchet');
2228

2329
$perMessageDeflateOptions ??= PermessageDeflateOptions::createDisabled();
2430

@@ -38,7 +44,7 @@ public function __construct(PermessageDeflateOptions $perMessageDeflateOptions =
3844

3945
public function generateRequest(UriInterface $uri): RequestInterface {
4046
return $this->defaultHeader->withUri($uri)
41-
->withHeader("Sec-WebSocket-Key", $this->generateKey());
47+
->withHeader('Sec-WebSocket-Key', $this->generateKey());
4248
}
4349

4450
public function validateResponse(RequestInterface $request, ResponseInterface $response): bool {

src/Handshake/ServerNegotiator.php

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace Ratchet\RFC6455\Handshake;
33
use Psr\Http\Message\RequestInterface;
4+
use Psr\Http\Message\ResponseFactoryInterface;
45
use GuzzleHttp\Psr7\Response;
56
use Psr\Http\Message\ResponseInterface;
67

@@ -11,14 +12,21 @@
1112
class ServerNegotiator implements NegotiatorInterface {
1213
private RequestVerifier $verifier;
1314

15+
private ResponseFactoryInterface $responseFactory;
16+
1417
private array $_supportedSubProtocols = [];
1518

1619
private bool $_strictSubProtocols = false;
1720

1821
private bool $enablePerMessageDeflate = false;
1922

20-
public function __construct(RequestVerifier $requestVerifier, $enablePerMessageDeflate = false) {
23+
public function __construct(
24+
RequestVerifier $requestVerifier,
25+
ResponseFactoryInterface $responseFactory,
26+
$enablePerMessageDeflate = false
27+
) {
2128
$this->verifier = $requestVerifier;
29+
$this->responseFactory = $responseFactory;
2230

2331
// https://bugs.php.net/bug.php?id=73373
2432
// https://bugs.php.net/bug.php?id=74240 - need >=7.1.4 or >=7.0.18
@@ -51,68 +59,70 @@ public function getVersionNumber(): int {
5159
* {@inheritdoc}
5260
*/
5361
public function handshake(RequestInterface $request): ResponseInterface {
62+
$response = $this->responseFactory->createResponse();
5463
if (true !== $this->verifier->verifyMethod($request->getMethod())) {
55-
return new Response(405, ['Allow' => 'GET']);
64+
return $response->withHeader('Allow', 'GET')->withStatus(405);
5665
}
5766

5867
if (true !== $this->verifier->verifyHTTPVersion($request->getProtocolVersion())) {
59-
return new Response(505);
68+
return $response->withStatus(505);
6069
}
6170

6271
if (true !== $this->verifier->verifyRequestURI($request->getUri()->getPath())) {
63-
return new Response(400);
72+
return $response->withStatus(400);
6473
}
6574

6675
if (true !== $this->verifier->verifyHost($request->getHeader('Host'))) {
67-
return new Response(400);
76+
return $response->withStatus(400);
6877
}
6978

70-
$upgradeSuggestion = [
71-
'Connection' => 'Upgrade',
72-
'Upgrade' => 'websocket',
73-
'Sec-WebSocket-Version' => $this->getVersionNumber()
74-
];
79+
$upgradeResponse = $response
80+
->withHeader('Connection' , 'Upgrade')
81+
->withHeader('Upgrade' , 'websocket')
82+
->withHeader('Sec-WebSocket-Version', $this->getVersionNumber());
83+
7584
if (count($this->_supportedSubProtocols) > 0) {
76-
$upgradeSuggestion['Sec-WebSocket-Protocol'] = implode(', ', array_keys($this->_supportedSubProtocols));
85+
$upgradeResponse = $upgradeResponse->withHeader(
86+
'Sec-WebSocket-Protocol', implode(', ', array_keys($this->_supportedSubProtocols))
87+
);
7788
}
7889
if (true !== $this->verifier->verifyUpgradeRequest($request->getHeader('Upgrade'))) {
79-
return new Response(426, $upgradeSuggestion, null, '1.1', 'Upgrade header MUST be provided');
90+
return $upgradeResponse->withStatus(426, 'Upgrade header MUST be provided');
8091
}
8192

8293
if (true !== $this->verifier->verifyConnection($request->getHeader('Connection'))) {
83-
return new Response(400, [], null, '1.1', 'Connection Upgrade MUST be requested');
94+
return $response->withStatus(400, 'Connection Upgrade MUST be requested');
8495
}
8596

8697
if (true !== $this->verifier->verifyKey($request->getHeader('Sec-WebSocket-Key'))) {
87-
return new Response(400, [], null, '1.1', 'Invalid Sec-WebSocket-Key');
98+
return $response->withStatus(400, 'Invalid Sec-WebSocket-Key');
8899
}
89100

90101
if (true !== $this->verifier->verifyVersion($request->getHeader('Sec-WebSocket-Version'))) {
91-
return new Response(426, $upgradeSuggestion);
102+
return $upgradeResponse->withStatus(426);
92103
}
93104

94-
$headers = [];
95105
$subProtocols = $request->getHeader('Sec-WebSocket-Protocol');
96106
if (count($subProtocols) > 0 || (count($this->_supportedSubProtocols) > 0 && $this->_strictSubProtocols)) {
97107
$subProtocols = array_map('trim', explode(',', implode(',', $subProtocols)));
98108

99109
$match = array_reduce($subProtocols, fn ($accumulator, $protocol) => $accumulator ?: (isset($this->_supportedSubProtocols[$protocol]) ? $protocol : null), null);
100110

101111
if ($this->_strictSubProtocols && null === $match) {
102-
return new Response(426, $upgradeSuggestion, null, '1.1', 'No Sec-WebSocket-Protocols requested supported');
112+
return $upgradeResponse->withStatus(426, 'No Sec-WebSocket-Protocols requested supported');
103113
}
104114

105115
if (null !== $match) {
106-
$headers['Sec-WebSocket-Protocol'] = $match;
116+
$response = $response->withHeader('Sec-WebSocket-Protocol', $match);
107117
}
108118
}
109119

110-
$response = new Response(101, array_merge($headers, [
111-
'Upgrade' => 'websocket'
112-
, 'Connection' => 'Upgrade'
113-
, 'Sec-WebSocket-Accept' => $this->sign((string)$request->getHeader('Sec-WebSocket-Key')[0])
114-
, 'X-Powered-By' => 'Ratchet'
115-
]));
120+
$response = $response
121+
->withStatus(101)
122+
->withHeader('Upgrade' , 'websocket')
123+
->withHeader('Connection' , 'Upgrade')
124+
->withHeader('Sec-WebSocket-Accept', $this->sign((string)$request->getHeader('Sec-WebSocket-Key')[0]))
125+
->withHeader('X-Powered-By' , 'Ratchet');
116126

117127
try {
118128
$perMessageDeflateRequest = PermessageDeflateOptions::fromRequestOrResponse($request)[0];

tests/ab/clientRunner.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use React\Promise\Deferred;
1313
use Ratchet\RFC6455\Messaging\Frame;
1414
use React\Promise\PromiseInterface;
15+
use GuzzleHttp\Psr7\HttpFactory;
1516
use React\Socket\ConnectionInterface;
1617
use React\Socket\Connector;
1718

@@ -58,7 +59,7 @@ function getTestCases(): PromiseInterface {
5859
$deferred = new Deferred();
5960

6061
$connector->connect($testServer . ':9002')->then(static function (ConnectionInterface $connection) use ($deferred, $testServer): void {
61-
$cn = new ClientNegotiator();
62+
$cn = new ClientNegotiator(new HttpFactory());
6263
$cnRequest = $cn->generateRequest(new Uri('ws://' . $testServer . ':9002/getCaseCount'));
6364

6465
$rawResponse = "";
@@ -110,6 +111,7 @@ static function (): void {}
110111
}
111112

112113
$cn = new ClientNegotiator(
114+
new HttpFactory(),
113115
PermessageDeflateOptions::permessageDeflateSupported() ? PermessageDeflateOptions::createEnabled() : null);
114116

115117
function runTest(int $case)
@@ -124,6 +126,7 @@ function runTest(int $case)
124126

125127
$connector->connect($testServer . ':9002')->then(static function (ConnectionInterface $connection) use ($deferred, $casePath, $case, $testServer): void {
126128
$cn = new ClientNegotiator(
129+
new HttpFactory(),
127130
PermessageDeflateOptions::permessageDeflateSupported() ? PermessageDeflateOptions::createEnabled() : null);
128131
$cnRequest = $cn->generateRequest(new Uri('ws://' . $testServer . ':9002' . $casePath));
129132

@@ -185,7 +188,7 @@ function createReport(): PromiseInterface {
185188
// $reportPath = "/updateReports?agent=" . AGENT . "&shutdownOnComplete=true";
186189
// we will stop it using docker now instead of just shutting down
187190
$reportPath = "/updateReports?agent=" . AGENT;
188-
$cn = new ClientNegotiator();
191+
$cn = new ClientNegotiator(new HttpFactory());
189192
$cnRequest = $cn->generateRequest(new Uri('ws://' . $testServer . ':9002' . $reportPath));
190193

191194
$rawResponse = "";

tests/ab/run_ab_tests.sh

100644100755
File mode changed.

tests/ab/startServer.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Ratchet\RFC6455\Messaging\MessageInterface;
1111
use Ratchet\RFC6455\Messaging\FrameInterface;
1212
use Ratchet\RFC6455\Messaging\Frame;
13+
use GuzzleHttp\Psr7\HttpFactory;
1314

1415
require_once __DIR__ . "/../bootstrap.php";
1516

@@ -18,7 +19,12 @@
1819
$socket = new \React\Socket\Server('0.0.0.0:9001', $loop);
1920

2021
$closeFrameChecker = new CloseFrameChecker;
21-
$negotiator = new ServerNegotiator(new RequestVerifier, PermessageDeflateOptions::permessageDeflateSupported());
22+
23+
$negotiator = new ServerNegotiator(
24+
new RequestVerifier,
25+
new HttpFactory(),
26+
PermessageDeflateOptions::permessageDeflateSupported()
27+
);
2228

2329
$uException = new \UnderflowException;
2430

tests/unit/Handshake/ServerNegotiatorTest.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Ratchet\RFC6455\Test\Unit\Handshake;
44

55
use GuzzleHttp\Psr7\Message;
6+
use GuzzleHttp\Psr7\HttpFactory;
67
use Ratchet\RFC6455\Handshake\RequestVerifier;
78
use Ratchet\RFC6455\Handshake\ServerNegotiator;
89
use PHPUnit\Framework\TestCase;
@@ -13,7 +14,7 @@
1314
class ServerNegotiatorTest extends TestCase
1415
{
1516
public function testNoUpgradeRequested(): void {
16-
$negotiator = new ServerNegotiator(new RequestVerifier());
17+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
1718

1819
$requestText = 'GET / HTTP/1.1
1920
Host: 127.0.0.1:6789
@@ -41,7 +42,7 @@ public function testNoUpgradeRequested(): void {
4142
}
4243

4344
public function testNoConnectionUpgradeRequested(): void {
44-
$negotiator = new ServerNegotiator(new RequestVerifier());
45+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
4546

4647
$requestText = 'GET / HTTP/1.1
4748
Host: 127.0.0.1:6789
@@ -67,7 +68,7 @@ public function testNoConnectionUpgradeRequested(): void {
6768
}
6869

6970
public function testInvalidSecWebsocketKey(): void {
70-
$negotiator = new ServerNegotiator(new RequestVerifier());
71+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
7172

7273
$requestText = 'GET / HTTP/1.1
7374
Host: 127.0.0.1:6789
@@ -94,7 +95,7 @@ public function testInvalidSecWebsocketKey(): void {
9495
}
9596

9697
public function testInvalidSecWebsocketVersion(): void {
97-
$negotiator = new ServerNegotiator(new RequestVerifier());
98+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
9899

99100
$requestText = 'GET / HTTP/1.1
100101
Host: 127.0.0.1:6789
@@ -124,7 +125,7 @@ public function testInvalidSecWebsocketVersion(): void {
124125
}
125126

126127
public function testBadSubprotocolResponse(): void {
127-
$negotiator = new ServerNegotiator(new RequestVerifier());
128+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
128129
$negotiator->setStrictSubProtocolCheck(true);
129130
$negotiator->setSupportedSubProtocols([]);
130131

@@ -158,7 +159,7 @@ public function testBadSubprotocolResponse(): void {
158159
}
159160

160161
public function testNonStrictSubprotocolDoesNotIncludeHeaderWhenNoneAgreedOn(): void {
161-
$negotiator = new ServerNegotiator(new RequestVerifier());
162+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
162163
$negotiator->setStrictSubProtocolCheck(false);
163164
$negotiator->setSupportedSubProtocols(['someproto']);
164165

@@ -192,7 +193,7 @@ public function testNonStrictSubprotocolDoesNotIncludeHeaderWhenNoneAgreedOn():
192193

193194
public function testSuggestsAppropriateSubprotocol(): void
194195
{
195-
$negotiator = new ServerNegotiator(new RequestVerifier());
196+
$negotiator = new ServerNegotiator(new RequestVerifier(), new HttpFactory());
196197
$negotiator->setStrictSubProtocolCheck(true);
197198
$negotiator->setSupportedSubProtocols(['someproto']);
198199

0 commit comments

Comments
 (0)