Skip to content

Commit

Permalink
allow http & https websocket urls (nodejs#2218)
Browse files Browse the repository at this point in the history
* allow http & https websocket urls

* this test no longer throws
  • Loading branch information
KhafraDev authored and crysmags committed Feb 27, 2024
1 parent 7ab1a2a commit aa180f2
Show file tree
Hide file tree
Showing 202 changed files with 608 additions and 333 deletions.
37 changes: 24 additions & 13 deletions lib/websocket/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { webidl } = require('../fetch/webidl')
const { DOMException } = require('../fetch/constants')
const { URLSerializer } = require('../fetch/dataURL')
const { getGlobalOrigin } = require('../fetch/global')
const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = require('./constants')
const {
kWebSocketURL,
Expand Down Expand Up @@ -57,38 +58,48 @@ class WebSocket extends EventTarget {
url = webidl.converters.USVString(url)
protocols = options.protocols

// 1. Let urlRecord be the result of applying the URL parser to url.
// 1. Let baseURL be this's relevant settings object's API base URL.
const baseURL = getGlobalOrigin()

// 1. Let urlRecord be the result of applying the URL parser to url with baseURL.
let urlRecord

try {
urlRecord = new URL(url)
urlRecord = new URL(url, baseURL)
} catch (e) {
// 2. If urlRecord is failure, then throw a "SyntaxError" DOMException.
// 3. If urlRecord is failure, then throw a "SyntaxError" DOMException.
throw new DOMException(e, 'SyntaxError')
}

// 3. If urlRecord’s scheme is not "ws" or "wss", then throw a
// "SyntaxError" DOMException.
// 4. If urlRecord’s scheme is "http", then set urlRecord’s scheme to "ws".
if (urlRecord.protocol === 'http:') {
urlRecord.protocol = 'ws:'
} else if (urlRecord.protocol === 'https:') {
// 5. Otherwise, if urlRecord’s scheme is "https", set urlRecord’s scheme to "wss".
urlRecord.protocol = 'wss:'
}

// 6. If urlRecord’s scheme is not "ws" or "wss", then throw a "SyntaxError" DOMException.
if (urlRecord.protocol !== 'ws:' && urlRecord.protocol !== 'wss:') {
throw new DOMException(
`Expected a ws: or wss: protocol, got ${urlRecord.protocol}`,
'SyntaxError'
)
}

// 4. If urlRecord’s fragment is non-null, then throw a "SyntaxError"
// 7. If urlRecord’s fragment is non-null, then throw a "SyntaxError"
// DOMException.
if (urlRecord.hash) {
if (urlRecord.hash || urlRecord.href.endsWith('#')) {
throw new DOMException('Got fragment', 'SyntaxError')
}

// 5. If protocols is a string, set protocols to a sequence consisting
// 8. If protocols is a string, set protocols to a sequence consisting
// of just that string.
if (typeof protocols === 'string') {
protocols = [protocols]
}

// 6. If any of the values in protocols occur more than once or otherwise
// 9. If any of the values in protocols occur more than once or otherwise
// fail to match the requirements for elements that comprise the value
// of `Sec-WebSocket-Protocol` fields as defined by The WebSocket
// protocol, then throw a "SyntaxError" DOMException.
Expand All @@ -100,12 +111,12 @@ class WebSocket extends EventTarget {
throw new DOMException('Invalid Sec-WebSocket-Protocol value', 'SyntaxError')
}

// 7. Set this's url to urlRecord.
this[kWebSocketURL] = urlRecord
// 10. Set this's url to urlRecord.
this[kWebSocketURL] = new URL(urlRecord.href)

// 8. Let client be this's relevant settings object.
// 11. Let client be this's relevant settings object.

// 9. Run this step in parallel:
// 12. Run this step in parallel:

// 1. Establish a WebSocket connection given urlRecord, protocols,
// and client.
Expand Down
8 changes: 0 additions & 8 deletions test/websocket/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ test('Constructor', (t) => {
}
)

t.throws(
() => new WebSocket('https://www.google.com'),
{
name: 'SyntaxError',
constructor: DOMException
}
)

t.throws(
() => new WebSocket('wss://echo.websocket.events/#a'),
{
Expand Down
4 changes: 3 additions & 1 deletion test/wpt/server/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ const send = (message) => {
}
}

send({ server: `http://localhost:${server.address().port}` })
const url = `http://localhost:${server.address().port}`
console.log('server opened ' + url)
send({ server: url })

process.on('message', (message) => {
if (message === 'shutdown') {
Expand Down
9 changes: 8 additions & 1 deletion test/wpt/server/websocket.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ const wss = new WebSocketServer({
handleProtocols: (protocols) => [...protocols].join(', ')
})

wss.on('connection', (ws) => {
wss.on('connection', (ws, request) => {
ws.on('message', (data, isBinary) => {
const str = data.toString('utf-8')

if (request.url === '/receive-many-with-backpressure') {
setTimeout(() => {
ws.send(str.length.toString(), { binary: false })
}, 100)
return
}

if (str === 'Goodbye') {
// Close-server-initiated-close.any.js sends a "Goodbye" message
// when it wants the server to close the connection.
Expand Down
26 changes: 26 additions & 0 deletions test/wpt/status/websockets.status.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,31 @@
"flaky": [
"Send 0 byte data on a WebSocket - Connection should be closed"
]
},
"send-many-64K-messages-with-backpressure.any.js": {
"note": "probably flaky based on other flaky tests.",
"flaky": [
"sending 50 messages of size 65536 with backpressure applied should not hang"
]
},
"back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js": {
"skip": true,
"note": "browser-only test"
},
"back-forward-cache-with-closed-websocket-connection.window.js": {
"skip": true,
"note": "browser-only test"
},
"back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js": {
"skip": true,
"note": "browser-only test"
},
"back-forward-cache-with-open-websocket-connection.window.js": {
"skip": true,
"note": "browser-only test"
},
"mixed-content.https.any.js": {
"note": "node has no concept of origin, thus there is no 'secure' or 'insecure' contexts",
"skip": true
}
}
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-1000-reason.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-1000-verify-code.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-1000.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-1005-verify-code.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-1005.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-2999-reason.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-3000-reason.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-3000-verify-code.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-4999-reason.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-Reason-124Bytes.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wpt_flags=h2
// META: variant=?wss

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-delayed.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-onlyReason.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-readyState-Closed.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-readyState-Closing.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wpt_flags=h2
// META: variant=?wss

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Close-undefined.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wpt_flags=h2
// META: variant=?wss

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Create-blocked-port.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wss
// META: variant=?wpt_flags=h2

Expand Down
2 changes: 1 addition & 1 deletion test/wpt/tests/websockets/Create-extensions-empty.any.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// META: timeout=long
// META: script=constants.sub.js
// META: variant=
// META: variant=?default
// META: variant=?wpt_flags=h2
// META: variant=?wss

Expand Down
19 changes: 19 additions & 0 deletions test/wpt/tests/websockets/Create-http-urls.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
test(() => {
const url = new URL ("/", location);
url.protocol = "http";
const httpURL = url.href;
url.protocol = "https";
const httpsURL = url.href;
url.protocol = "ws";
const wsURL = url.href;
url.protocol = "wss";
const wssURL = url.href;

let ws = new WebSocket(httpURL);
assert_equals(ws.url, wsURL);
ws.close();

ws = new WebSocket(httpsURL);
assert_equals(ws.url, wssURL);
ws.close();
}, "WebSocket: ensure both HTTP schemes are supported");
48 changes: 14 additions & 34 deletions test/wpt/tests/websockets/Create-invalid-urls.any.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
// META: variant=
// META: variant=?wss
// META: variant=?wpt_flags=h2

var wsocket;
test(function() {
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = new WebSocket("/echo")
});
}, "Url is /echo - should throw SYNTAX_ERR");

test(function() {
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = new WebSocket("mailto:microsoft@microsoft.com")
});
}, "Url is a mail address - should throw SYNTAX_ERR");

test(function() {
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = new WebSocket("about:blank")
});
}, "Url is about:blank - should throw SYNTAX_ERR");

test(function() {
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = new WebSocket("?test")
});
}, "Url is ?test - should throw SYNTAX_ERR");

test(function() {
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = new WebSocket("#test")
});
}, "Url is #test - should throw SYNTAX_ERR");
[
"ws://foo bar.com/",
"wss://foo bar.com/",
"ftp://"+location.host+"/",
"mailto:example@example.org",
"about:blank",
location.origin + "/#",
location.origin + "/#test",
"#test"
].forEach(input => {
test(() => {
assert_throws_dom("SyntaxError", () => new WebSocket(input));
}, `new WebSocket("${input}") should throw a "SyntaxError" DOMException`);
});
25 changes: 14 additions & 11 deletions test/wpt/tests/websockets/Create-non-absolute-url.any.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// META: script=constants.sub.js
// META: variant=
// META: variant=?wss
// META: variant=?wpt_flags=h2

test(function() {
var wsocket;
assert_throws_dom("SYNTAX_ERR", function() {
wsocket = CreateWebSocketNonAbsolute()
});
}, "Create WebSocket - Pass a non absolute URL - SYNTAX_ERR is thrown")
[
"test",
"?",
null,
123,
].forEach(input => {
test(() => {
const url = new URL(input, location);
url.protocol = "ws";
const ws = new WebSocket(input);
assert_equals(ws.url, url.href);
ws.close();
}, `Create WebSocket - Pass a non absolute URL: ${input}`);
});
Loading

0 comments on commit aa180f2

Please sign in to comment.