Skip to content

Commit ace7ed3

Browse files
committed
fix - sub-protocol handling
1 parent 9f48553 commit ace7ed3

9 files changed

Lines changed: 82 additions & 24 deletions

File tree

README.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ <h2 id="usage">Usage</h2>
203203
&lt;/body&gt;
204204
&lt;/html&gt;
205205
</code></pre>
206-
<p>Complete example of use on the server and client side can be found in the <a href="https://github.com/manuel-lohmus/ws13/tree/master/examples/Server">examples/Server</a> directory.</p>
206+
<p>Complete example of use on the server and client side can be found in the <a href="https://github.com/manuel-lohmus/ws13/tree/master/examples/chat">examples/chat</a> directory.</p>
207207
<p><strong>Secure communication</strong></p>
208208
<p>To use secure communication, you need to use the <code>https</code> module and the <code>wss</code> protocol.</p>
209209
<p><strong>Example of use on a <code>https</code> server</strong></p>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ const ws = createWebSocket({
219219
</html>
220220
```
221221

222-
Complete example of use on the server and client side can be found in the [examples/Server](https://github.com/manuel-lohmus/ws13/tree/master/examples/Server) directory.
222+
Complete example of use on the server and client side can be found in the [examples/chat](https://github.com/manuel-lohmus/ws13/tree/master/examples/chat) directory.
223223

224224
**Secure communication**
225225

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import fs from 'node:fs';
66
import { pipeline } from 'node:stream';
77

88
var server = new http.createServer(),
9-
wsList = [];
9+
chatList = [],
10+
superchatList = [];
1011

1112
// upgrade event for WebSocket
1213
server.on('upgrade', function upgrade(request) {
1314

14-
// creates WebSocket
15+
// create WebSocket for sub-protocol: 'chat'
1516
var websocket = createWebSocket({
1617

1718
// upgrade request
@@ -21,7 +22,7 @@ server.on('upgrade', function upgrade(request) {
2122
isDebug: true,
2223

2324
// the sub-protocol the server is ready to communicate with the client (optional)
24-
/*protocol = '',*/
25+
protocol: 'chat',
2526

2627
// the origin of the request (optional)
2728
origin: 'http://localhost:3000',
@@ -37,7 +38,7 @@ server.on('upgrade', function upgrade(request) {
3738
if (websocket) {
3839

3940
// inserts a WebSocket from the list
40-
wsList.push(websocket);
41+
chatList.push(websocket);
4142

4243
// add listeners to the WebSocket
4344
websocket
@@ -52,21 +53,63 @@ server.on('upgrade', function upgrade(request) {
5253
.on('message', (event) => {
5354

5455
// send to everyone
55-
wsList.forEach(function (socket) {
56+
chatList.forEach(function (socket) {
5657

5758
// send message to the client
58-
socket.send(`ws-${wsList.indexOf(websocket)}: ${event.data}`);
59+
socket.send(`chat-${chatList.indexOf(websocket)}: ${event.data}`);
5960
});
6061
})
6162
// connection closed with the client
6263
.on('close', function (event) {
6364

6465
// removing an WebSocket from list
65-
wsList = wsList.filter(ws => ws !== websocket);
66+
chatList = chatList.filter(ws => ws !== websocket);
6667
});
68+
69+
return;
6770
}
68-
// handshake not accepted, close the connection with the client
69-
else { request.socket.end(); }
71+
72+
73+
// create WebSocket for sub-protocol: 'superchat'
74+
websocket = createWebSocket({ request, protocol: 'superchat' });
75+
76+
// has WebSocket, the handshake is done
77+
if (websocket) {
78+
79+
// inserts a WebSocket from the list
80+
superchatList.push(websocket);
81+
82+
// add listeners to the WebSocket
83+
websocket
84+
// error handling
85+
.on('error', console.error)
86+
// connection established with the client (handshake done)
87+
.on('open', () => {
88+
89+
/* now you can send and receive messages */
90+
})
91+
// message received from the client (event.isBinary is boolean) (event.data is string or buffer)
92+
.on('message', (event) => {
93+
94+
// send to everyone
95+
superchatList.forEach(function (socket) {
96+
97+
// send message to the client
98+
socket.send(`superchat-${superchatList.indexOf(websocket)}: ${event.data}`);
99+
});
100+
})
101+
// connection closed with the client
102+
.on('close', function (event) {
103+
104+
// removing an WebSocket from list
105+
superchatList = superchatList.filter(ws => ws !== websocket);
106+
});
107+
108+
return;
109+
}
110+
111+
// handshake not accepted, close the connection with the client
112+
request.socket.end();
70113

71114
});
72115

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@
2929

3030
if (!wsHost) { return; }
3131

32-
const host = location.protocol.replace('http', 'ws') + '//' + wsHost;
32+
const host = location.protocol.replace('http', 'ws') + '//' + wsHost,
33+
protocol = $('#subProtocol')?.value ? $('#subProtocol')?.value.split(' ') : [];
3334

3435
try {
35-
socket = new WebSocket(host);
36+
socket = new WebSocket(host, protocol);
3637
state();
3738

3839
socket.onmessage = function (event) {
@@ -58,7 +59,10 @@
5859

5960
setTimeout(function () {
6061

61-
$('#status').innerHTML = 'WebSocket - ' + (socket === null ? 'CLOSED' : constants[socket.readyState]);
62+
$('#status').innerHTML = '<b>Status:</b> <code>' + (socket === null ? 'CLOSED' : constants[socket.readyState]) + '</code>';
63+
$('#selectProtocol').innerHTML = socket === null || !socket.protocol
64+
? ''
65+
: ' <b>Sub-Protocol:</b> <code>' + socket.protocol + '</code> <b>Extensions:</b> <code>' + socket.extensions + '</code>';
6266

6367
if (socket && constants[socket.readyState] === "OPEN") {
6468

@@ -134,10 +138,16 @@
134138
<body onload="init()">
135139
<h3>WebSocket Test</h3>
136140
<table>
137-
<tr><td><span id="status"></span></td></tr>
141+
<tr><td><span id="status"></span> <span id="selectProtocol"></span></td></tr>
138142
<tr><td><div id="log"></div></td></tr>
139143
<tr>
140144
<td>
145+
<select id="subProtocol">
146+
<option value="chat" selected>chat</option>
147+
<option value="superchat">superchat</option>
148+
<option value="">none</option>
149+
<option value="superchat chat">any</option>
150+
</select>
141151
<input id="msg" list="commands" type="text" onkeypress="onkey(event)" />
142152
<datalist id="commands"></datalist>
143153
<button id="btnSend" onclick="send()">Send</button>
Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,15 @@ function createWebSocket({
200200

201201
request.on('upgrade', function (response) {
202202

203-
var err = validateHandshake(response.headers);
203+
var err = validateHandshake(response?.headers);
204204

205205
if (err) { return destroy(err); }
206206

207+
if (response?.headers?.["sec-websocket-protocol"]) {
208+
209+
protocol = response.headers["sec-websocket-protocol"];
210+
}
211+
207212
if (response?.headers?.["sec-websocket-extensions"]) {
208213

209214
if (typeof extension?.activate === 'function') {
@@ -298,8 +303,8 @@ function createWebSocket({
298303
if (!socket
299304
|| headers?.["sec-websocket-version"] !== '13'
300305
|| !headers?.["sec-websocket-key"]) { return false; }
301-
// TODO > protocol accept > Done
302-
if (protocol && headers && headers?.["sec-websocket-protocol"] !== protocol) {
306+
if (protocol && headers && headers["sec-websocket-protocol"]
307+
&& headers["sec-websocket-protocol"] !== protocol) {
303308

304309
var offerProtocols = headers?.["sec-websocket-protocol"].split(',')
305310
.map(entry => (entry + '').trim().toLowerCase()),

index.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ testRunner("WS - Tests ", { skip: false }, (test) => {
222222
/**
223223
* Test runner. Function to run unit tests in the console.
224224
* @author Manuel Lõhmus 2024 (MIT License)
225-
* @version 1.1.0
226-
* [2024-12-29] adde d functionality to select tests by ID in the command line arguments (e.g. --testID=1 2 3)
225+
* @version 1.1.1
226+
* [2024-12-29] adde d functionality to select tests by ID in the command line arguments (e.g. --testIDs=1 2 3)
227227
* @example `npm test '--'` or `node index.test.js`
228228
* @example `npm test '--' --help` or `node index.test.js --help`
229229
* @example `npm test '--' --testIDs=1 2 3` or `node index.test.js --testIDs=1 2 3`
@@ -285,7 +285,7 @@ node index.test.js [OPTION1=VALUE1] [OPTION2=VALUE2] ...
285285
286286
The following options are supported:
287287
--help Display this help
288-
--testID Number of the test to run
288+
--testIDs Number of the test to run (e.g. node index.test.js --testIDs=1 2 3)
289289
`);
290290

291291
if (process.argv[1].endsWith(".js")) { exitPressKey(); }

0 commit comments

Comments
 (0)