Bug 1797449 - [websocket] Allow relative URLs and http(s) scheme r=valentin

Add support to WebSocket for http: and https: URLs,
as well as having them be relative to a base URI.

Spec: https://github.com/whatwg/websockets/issues/20

Passes new WPT tests for this in /websockets, with other tests unaffected.

Also updated our tests to expect these URLs to be successful instead of fail.

Differential Revision: https://phabricator.services.mozilla.com/D160330
This commit is contained in:
Oliver Medhurst 2024-01-23 17:23:17 +00:00
parent 6f9048f788
commit 1dbadb53c7
8 changed files with 53 additions and 112 deletions

View File

@ -70,6 +70,7 @@
#include "nsProxyRelease.h"
#include "nsWeakReference.h"
#include "nsIWebSocketImpl.h"
#include "nsIURIMutator.h"
#define OPEN_EVENT_STRING u"open"_ns
#define MESSAGE_EVENT_STRING u"message"_ns
@ -163,7 +164,7 @@ class WebSocketImpl final : public nsIInterfaceRequestor,
const nsACString& aNegotiatedExtensions,
UniquePtr<SerializedStackHolder> aOriginStack);
nsresult ParseURL(const nsAString& aURL);
nsresult ParseURL(const nsAString& aURL, nsIURI* aBaseURI);
nsresult InitializeConnection(nsIPrincipal* aPrincipal,
nsICookieJarSettings* aCookieJarSettings);
@ -1130,11 +1131,11 @@ class InitRunnable final : public WebSocketMainThreadRunnable {
return true;
}
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
mErrorCode = mImpl->Init(
jsapi.cx(), mWorkerPrivate->GetPrincipal()->SchemeIs("https"),
doc->NodePrincipal(), mClientInfo, mWorkerPrivate->CSPEventListener(),
mIsServerSide, mURL, mProtocolArray, mScriptFile, mScriptLine,
mScriptColumn);
jsapi.cx(), principal->SchemeIs("https"), principal, mClientInfo,
mWorkerPrivate->CSPEventListener(), mIsServerSide, mURL, mProtocolArray,
mScriptFile, mScriptLine, mScriptColumn);
return true;
}
@ -1650,7 +1651,8 @@ nsresult WebSocketImpl::Init(JSContext* aCx, bool aIsSecure,
mIsChromeContext = aPrincipal->IsSystemPrincipal();
// parses the url
rv = ParseURL(aURL);
nsCOMPtr<nsIURI> baseURI = aPrincipal->GetURI();
rv = ParseURL(aURL, baseURI);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Document> originDoc = mWebSocket->GetDocumentIfCurrent();
@ -2100,7 +2102,7 @@ nsresult WebSocket::CreateAndDispatchCloseEvent(bool aWasClean, uint16_t aCode,
return err.StealNSResult();
}
nsresult WebSocketImpl::ParseURL(const nsAString& aURL) {
nsresult WebSocketImpl::ParseURL(const nsAString& aURL, nsIURI* aBaseURI) {
AssertIsOnMainThread();
NS_ENSURE_TRUE(!aURL.IsEmpty(), NS_ERROR_DOM_SYNTAX_ERR);
@ -2112,21 +2114,35 @@ nsresult WebSocketImpl::ParseURL(const nsAString& aURL) {
}
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBaseURI);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
nsCOMPtr<nsIURL> parsedURL = do_QueryInterface(uri, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
bool hasRef;
rv = parsedURL->GetHasRef(&hasRef);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !hasRef, NS_ERROR_DOM_SYNTAX_ERR);
nsAutoCString scheme;
rv = parsedURL->GetScheme(scheme);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !scheme.IsEmpty(),
NS_ERROR_DOM_SYNTAX_ERR);
// If |urlRecord|'s [=url/scheme=] is "`http`", then set |urlRecord|'s
// [=url/scheme=] to "`ws`". Otherwise, if |urlRecord|'s [=url/scheme=] is
// "`https`", set |urlRecord|'s [=url/scheme=] to "`wss`".
// https://websockets.spec.whatwg.org/#dom-websocket-websocket
if (scheme == "http" || scheme == "https") {
scheme = scheme == "https" ? "wss"_ns : "ws"_ns;
NS_MutateURI mutator(parsedURL);
mutator.SetScheme(scheme);
rv = mutator.Finalize(parsedURL);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
}
bool hasRef;
rv = parsedURL->GetHasRef(&hasRef);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !hasRef, NS_ERROR_DOM_SYNTAX_ERR);
nsAutoCString host;
rv = parsedURL->GetAsciiHost(host);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !host.IsEmpty(), NS_ERROR_DOM_SYNTAX_ERR);

View File

@ -50,7 +50,10 @@ def web_socket_passive_closing_handshake(request):
def web_socket_transfer_data(request):
if request.ws_protocol == "test-2.1" or request.ws_protocol == "test-2.2":
if request.ws_protocol == "test-1" or request.ws_protocol == "test-4":
msgutil.send_message(request, "server data")
msgutil.close_connection(request)
elif request.ws_protocol == "test-2.1" or request.ws_protocol == "test-2.2":
msgutil.close_connection(request)
elif request.ws_protocol == "test-6":
resp = "wrong message"

View File

@ -1,16 +1,19 @@
// test1: client tries to connect to a http scheme location;
function test1() {
return new Promise(function (resolve, reject) {
try {
var ws = CreateTestWS(
"http://mochi.test:8888/tests/dom/websocket/tests/file_websocket"
);
ok(false, "test1 failed");
} catch (e) {
ok(true, "test1 failed");
}
var ws = CreateTestWS(
"http://mochi.test:8888/tests/dom/websocket/tests/file_websocket",
"test-1"
);
resolve();
ws.onmessage = function () {
ok(true, "created websocket with http scheme");
};
ws.onclose = function (e) {
shouldCloseCleanly(e);
resolve();
};
});
}
@ -86,14 +89,16 @@ function test3() {
// test4: client tries to connect using a relative url;
function test4() {
return new Promise(function (resolve, reject) {
try {
var ws = CreateTestWS("file_websocket");
ok(false, "test-4 failed");
} catch (e) {
ok(true, "test-4 failed");
}
var ws = CreateTestWS("file_websocket", "test-4");
resolve();
ws.onmessage = function () {
ok(true, "created websocket with relative scheme");
};
ws.onclose = function (e) {
shouldCloseCleanly(e);
resolve();
};
});
}

View File

@ -1,8 +0,0 @@
[Create-http-urls.any.worker.html]
[WebSocket: ensure both HTTP schemes are supported]
expected: FAIL
[Create-http-urls.any.html]
[WebSocket: ensure both HTTP schemes are supported]
expected: FAIL

View File

@ -1,23 +0,0 @@
[Create-invalid-urls.any.worker.html?wpt_flags=h2]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-invalid-urls.any.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-invalid-urls.any.html?wss]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-invalid-urls.any.worker.html?wss]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-invalid-urls.any.worker.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-invalid-urls.any.html?wpt_flags=h2]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@ -1,46 +0,0 @@
[Create-non-absolute-url.any.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create WebSocket - Pass a non absolute URL: test]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: ?]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: null]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: 123]
expected: FAIL
[Create-non-absolute-url.any.html?wpt_flags=h2]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-non-absolute-url.any.html?wss]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-non-absolute-url.any.worker.html?wpt_flags=h2]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-non-absolute-url.any.worker.html?wss]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create-non-absolute-url.any.worker.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Create WebSocket - Pass a non absolute URL: test]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: ?]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: null]
expected: FAIL
[Create WebSocket - Pass a non absolute URL: 123]
expected: FAIL

View File

@ -1,3 +0,0 @@
[Create-url-with-windows-1252-encoding.html]
[URL's percent-encoding is always in UTF-8 for WebSocket]
expected: FAIL

View File

@ -1,3 +0,0 @@
[url-parsing.html]
[Multiple globals for base URL in WebSocket constructor]
expected: FAIL