Skip to content

Commit 9f7f097

Browse files
authored
Merge pull request #7 from xp-forge/feature/path-argument
Add ability to pass path to constructor
2 parents cca1f6e + 4dd11f6 commit 9f7f097

File tree

3 files changed

+79
-20
lines changed

3 files changed

+79
-20
lines changed

ChangeLog.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ WebSockets change log
33

44
## ?.?.? / ????-??-??
55

6-
* Fix "Call to a member function message() on null" errors when using an
7-
already connected socket in the `WebSocket` constructor.
6+
* **Heads up**: Deprecated passing origin to `WebSocket` constructor. It
7+
should be passed inside the headers when calling *connect()*.
8+
(@thekid)
9+
* Merged PR #7: Added ability to pass path and query string to `WebSocket`
10+
constructor
11+
(@thekid)
12+
* Fixed "Call to a member function message() on null" errors when using
13+
an already connected socket in the `WebSocket` constructor.
814
(@thekid)
915

1016
## 4.0.0 / 2024-10-05

src/main/php/websocket/WebSocket.class.php

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @test websocket.unittest.WebSocketTest
1212
*/
1313
class WebSocket implements Closeable {
14-
private $socket, $path, $origin;
14+
private $socket, $path, $headers;
1515
private $conn= null;
1616
private $listener= null;
1717
private $random= 'random_bytes';
@@ -20,14 +20,16 @@ class WebSocket implements Closeable {
2020
* Creates a new instance
2121
*
2222
* @param peer.Socket|string $endpoint, e.g. "wss://example.com"
23-
* @param string $origin
23+
* @param ?string $path
2424
*/
25-
public function __construct($endpoint, $origin= 'localhost') {
25+
public function __construct($endpoint, $path= null) {
2626
if ($endpoint instanceof Socket) {
2727
$this->socket= $endpoint;
28+
$this->headers= ['Host' => $this->socket->host];
2829
$this->path= '/';
2930
} else {
3031
$url= parse_url($endpoint);
32+
$this->headers= ['Host' => $url['host']];
3133
if ('wss' === $url['scheme']) {
3234
$this->socket= new CryptoSocket($url['host'], $url['port'] ?? 443);
3335
$this->socket->cryptoImpl= STREAM_CRYPTO_METHOD_ANY_CLIENT;
@@ -37,7 +39,16 @@ public function __construct($endpoint, $origin= 'localhost') {
3739
$this->path= $url['path'] ?? '/';
3840
isset($url['query']) && $this->path.= '?'.$url['query'];
3941
}
40-
$this->origin= $origin;
42+
43+
// BC: Older versions accepted origin as second parameter
44+
if (null === $path) {
45+
// NOOP
46+
} else if ('/' === $path[0] ?? null) {
47+
$this->path= $path;
48+
} else {
49+
$this->path= '/';
50+
$this->headers['Origin']= $path;
51+
}
4152
}
4253

4354
/** @return peer.Socket */
@@ -46,8 +57,13 @@ public function socket() { return $this->socket; }
4657
/** @return string */
4758
public function path() { return $this->path; }
4859

49-
/** @return string */
50-
public function origin() { return $this->origin; }
60+
/**
61+
* Returns origin set via constructor
62+
*
63+
* @deprecated Pass the origin to `connect()` instead!
64+
* @return ?string
65+
*/
66+
public function origin() { return $this->headers['Origin'] ?? null; }
5167

5268
/** @return bool */
5369
public function connected() { return null !== $this->conn; }
@@ -80,7 +96,6 @@ public function connect($headers= []) {
8096
if ($this->conn) return;
8197

8298
$key= base64_encode(($this->random)(16));
83-
$headers+= ['Host' => $this->socket->host, 'Origin' => $this->origin];
8499
$this->socket->isConnected() || $this->socket->connect();
85100
$this->socket->write(
86101
"GET {$this->path} HTTP/1.1\r\n".
@@ -89,7 +104,7 @@ public function connect($headers= []) {
89104
"Sec-WebSocket-Version: 13\r\n".
90105
"Connection: Upgrade\r\n"
91106
);
92-
foreach ($headers as $name => $values) {
107+
foreach ($headers + $this->headers as $name => $values) {
93108
foreach ((array)$values as $value) {
94109
$this->socket->write("{$name}: {$value}\r\n");
95110
}
@@ -194,7 +209,6 @@ public function receive($timeout= null) {
194209
$close= unpack('ncode/a*reason', $packet);
195210
$this->conn->close($close['code'], $close['reason']);
196211
$this->conn= null;
197-
$this->socket->close();
198212

199213
// 1000 is a normal close, all others indicate an error
200214
if (1000 === $close['code']) return null;
@@ -222,7 +236,6 @@ public function close($code= 1000, $reason= '') {
222236

223237
$this->conn->close($code, $reason);
224238
$this->conn= null;
225-
$this->socket->close();
226239
}
227240

228241
/** Destructor - ensures connection is closed */

src/test/php/websocket/unittest/WebSocketTest.class.php

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ public function query($url, $expected) {
3131
Assert::equals($expected, (new WebSocket($url))->path());
3232
}
3333

34+
/** @deprecated */
3435
#[Test]
3536
public function default_origin() {
36-
Assert::equals('localhost', (new WebSocket('ws://example.com'))->origin());
37+
Assert::null((new WebSocket('ws://example.com'))->origin());
3738
}
3839

40+
/** @deprecated */
3941
#[Test]
40-
public function origin() {
42+
public function origin_via_constructor() {
4143
Assert::equals('example.com', (new WebSocket('ws://example.com', 'example.com'))->origin());
4244
}
4345

@@ -47,6 +49,12 @@ public function socket_argument() {
4749
Assert::equals($s, (new WebSocket($s))->socket());
4850
}
4951

52+
#[Test, Values([[null, '/'], ['/', '/'], ['/sub', '/sub'], ['/?test=1&l=de', '/?test=1&l=de']])]
53+
public function socket_path($path, $expected) {
54+
$s= new Socket('example.com', 8443);
55+
Assert::equals($expected, (new WebSocket($s, $path))->path());
56+
}
57+
5058
#[Test, Values([['ws://example.com', 80], ['wss://example.com', 443]])]
5159
public function default_port($url, $expected) {
5260
Assert::equals($expected, (new WebSocket($url))->socket()->port);
@@ -153,6 +161,41 @@ public function handle_server_error() {
153161
Assert::false($fixture->connected());
154162
}
155163

164+
#[Test]
165+
public function handshake() {
166+
$fixture= $this->fixture();
167+
$fixture->connect();
168+
169+
Assert::equals(
170+
"GET / HTTP/1.1\r\n".
171+
"Upgrade: websocket\r\n".
172+
"Sec-WebSocket-Key: KioqKioqKioqKioqKioqKg==\r\n".
173+
"Sec-WebSocket-Version: 13\r\n".
174+
"Connection: Upgrade\r\n".
175+
"Host: test\r\n\r\n",
176+
$fixture->socket()->out
177+
);
178+
}
179+
180+
#[Test]
181+
public function sends_headers() {
182+
$fixture= $this->fixture();
183+
$fixture->connect(['Origin' => 'example.com', 'Sec-WebSocket-Protocol' => ['wamp', 'soap']]);
184+
185+
Assert::equals(
186+
"GET / HTTP/1.1\r\n".
187+
"Upgrade: websocket\r\n".
188+
"Sec-WebSocket-Key: KioqKioqKioqKioqKioqKg==\r\n".
189+
"Sec-WebSocket-Version: 13\r\n".
190+
"Connection: Upgrade\r\n".
191+
"Origin: example.com\r\n".
192+
"Sec-WebSocket-Protocol: wamp\r\n".
193+
"Sec-WebSocket-Protocol: soap\r\n".
194+
"Host: test\r\n\r\n",
195+
$fixture->socket()->out
196+
);
197+
}
198+
156199
#[Test]
157200
public function send_text() {
158201
$fixture= $this->fixture();
@@ -165,8 +208,7 @@ public function send_text() {
165208
"Sec-WebSocket-Key: KioqKioqKioqKioqKioqKg==\r\n".
166209
"Sec-WebSocket-Version: 13\r\n".
167210
"Connection: Upgrade\r\n".
168-
"Host: test\r\n".
169-
"Origin: localhost\r\n\r\n".
211+
"Host: test\r\n\r\n".
170212
"\x81\x84****\176\117\131\136",
171213
$fixture->socket()->out
172214
);
@@ -184,8 +226,7 @@ public function send_bytes() {
184226
"Sec-WebSocket-Key: KioqKioqKioqKioqKioqKg==\r\n".
185227
"Sec-WebSocket-Version: 13\r\n".
186228
"Connection: Upgrade\r\n".
187-
"Host: test\r\n".
188-
"Origin: localhost\r\n\r\n".
229+
"Host: test\r\n\r\n".
189230
"\x82\x88****\155\143\154\022\023\004\004\004",
190231
$fixture->socket()->out
191232
);
@@ -203,8 +244,7 @@ public function pings_are_answered() {
203244
"Sec-WebSocket-Key: KioqKioqKioqKioqKioqKg==\r\n".
204245
"Sec-WebSocket-Version: 13\r\n".
205246
"Connection: Upgrade\r\n".
206-
"Host: test\r\n".
207-
"Origin: localhost\r\n\r\n".
247+
"Host: test\r\n\r\n".
208248
"\x8a\x81****\013",
209249
$fixture->socket()->out
210250
);

0 commit comments

Comments
 (0)