diff --git a/dom/websocket/WebSocket.cpp b/dom/websocket/WebSocket.cpp index 0be040fadf2b..09e4d56b4772 100644 --- a/dom/websocket/WebSocket.cpp +++ b/dom/websocket/WebSocket.cpp @@ -1255,6 +1255,34 @@ class AsyncOpenRunnable final : public WebSocketMainThreadRunnable { } // namespace +// Check a protocol entry contains only valid characters +bool WebSocket::IsValidProtocolString(const nsString& aValue) { + // RFC 6455 (4.1): "not including separator characters as defined in RFC 2616" + const char16_t illegalCharacters[] = {0x28, 0x29, 0x3C, 0x3E, 0x40, 0x2C, + 0x3B, 0x3A, 0x5C, 0x22, 0x2F, 0x5B, + 0x5D, 0x3F, 0x3D, 0x7B, 0x7D}; + + // Cannot be empty string + if (aValue.IsEmpty()) { + return false; + } + + const auto* start = aValue.BeginReading(); + const auto* end = aValue.EndReading(); + + auto charFilter = [&](char16_t c) { + // RFC 6455 (4.1 P18): "in the range U+0021 to U+007E" + if (c < 0x21 || c > 0x7E) { + return true; + } + + return std::find(std::begin(illegalCharacters), std::end(illegalCharacters), + c) != std::end(illegalCharacters); + }; + + return std::find_if(start, end, charFilter) == end; +} + already_AddRefed WebSocket::ConstructorCommon( const GlobalObject& aGlobal, const nsAString& aUrl, const Sequence& aProtocols, @@ -1291,15 +1319,14 @@ already_AddRefed WebSocket::ConstructorCommon( for (uint32_t index = 0, len = aProtocols.Length(); index < len; ++index) { const nsString& protocolElement = aProtocols[index]; - if (protocolElement.IsEmpty()) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); - return nullptr; - } + // Repeated protocols are not allowed if (protocolArray.Contains(protocolElement)) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } - if (protocolElement.FindChar(',') != -1) /* interferes w/list */ { + + // Protocol string value must match constraints + if (!IsValidProtocolString(protocolElement)) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } @@ -1718,11 +1745,8 @@ nsresult WebSocketImpl::Init(JSContext* aCx, bool aIsSecure, // Assign the sub protocol list and scan it for illegal values for (uint32_t index = 0; index < aProtocolArray.Length(); ++index) { - for (uint32_t i = 0; i < aProtocolArray[index].Length(); ++i) { - if (aProtocolArray[index][i] < static_cast(0x0021) || - aProtocolArray[index][i] > static_cast(0x007E)) { - return NS_ERROR_DOM_SYNTAX_ERR; - } + if (!WebSocket::IsValidProtocolString(aProtocolArray[index])) { + return NS_ERROR_DOM_SYNTAX_ERR; } if (!mRequestedProtocolList.IsEmpty()) { diff --git a/dom/websocket/WebSocket.h b/dom/websocket/WebSocket.h index c4a67a3e140a..a290750cf033 100644 --- a/dom/websocket/WebSocket.h +++ b/dom/websocket/WebSocket.h @@ -140,6 +140,8 @@ class WebSocket final : public DOMEventTargetHelper { nsresult CreateAndDispatchCloseEvent(bool aWasClean, uint16_t aCode, const nsAString& aReason); + static bool IsValidProtocolString(const nsString& aValue); + // if there are "strong event listeners" (see comment in WebSocket.cpp) or // outgoing not sent messages then this method keeps the object alive // when js doesn't have strong references to it. diff --git a/testing/web-platform/meta/websockets/Create-asciiSep-protocol-string.any.js.ini b/testing/web-platform/meta/websockets/Create-asciiSep-protocol-string.any.js.ini index ba1a2dc61487..3e498ba47cfc 100644 --- a/testing/web-platform/meta/websockets/Create-asciiSep-protocol-string.any.js.ini +++ b/testing/web-platform/meta/websockets/Create-asciiSep-protocol-string.any.js.ini @@ -1,40 +1,23 @@ [Create-asciiSep-protocol-string.any.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL - [Create-asciiSep-protocol-string.any.worker.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL - [Create-asciiSep-protocol-string.any.html?wss] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL - [Create-asciiSep-protocol-string.any.worker.html?wss] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL - [Create-asciiSep-protocol-string.any.worker.html?wpt_flags=h2] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL - [Create-asciiSep-protocol-string.any.html?wpt_flags=h2] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown] - expected: FAIL diff --git a/testing/web-platform/meta/websockets/binaryType-wrong-value.any.js.ini b/testing/web-platform/meta/websockets/binaryType-wrong-value.any.js.ini index 8b52edb59ffd..ee1b12428f06 100644 --- a/testing/web-platform/meta/websockets/binaryType-wrong-value.any.js.ini +++ b/testing/web-platform/meta/websockets/binaryType-wrong-value.any.js.ini @@ -16,24 +16,11 @@ [binaryType-wrong-value.any.worker.html?wpt_flags=h2] expected: - if (os == "android") and debug and not swgl: [OK, ERROR, TIMEOUT] - if (os == "win") and debug: [OK, ERROR, TIMEOUT] - if (os == "android") and not debug: [OK, ERROR] - [Create WebSocket - set binaryType to something other than blob or arraybuffer - SYNTAX_ERR is returned - Connection should be closed] - expected: - if os == "mac": [PASS, NOTRUN] - + [OK, ERROR, TIMEOUT] [binaryType-wrong-value.any.html?wpt_flags=h2] expected: - if (os == "win") and debug and (processor == "x86_64") and swgl: [OK, ERROR, TIMEOUT] - if (os == "android") and debug and not swgl: [OK, ERROR, TIMEOUT] - if (os == "win") and debug and (processor == "x86"): [OK, ERROR, TIMEOUT] - if (os == "android") and not debug: [OK, TIMEOUT] - [Create WebSocket - set binaryType to something other than blob or arraybuffer - SYNTAX_ERR is returned - Connection should be closed] - expected: - if os == "mac": [PASS, NOTRUN] - + [OK, ERROR, TIMEOUT] [binaryType-wrong-value.any.html] expected: