mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 674527 - websockets sub-protocol array implementation and tests r=sicking sr=bz
This commit is contained in:
parent
2bc2762f54
commit
b363c5480c
@ -43,6 +43,13 @@ interface nsIDOMEventListener;
|
||||
interface nsIPrincipal;
|
||||
interface nsIScriptContext;
|
||||
interface nsPIDOMWindow;
|
||||
interface nsIDOMDOMStringList;
|
||||
|
||||
%{C++
|
||||
#include "nsTArray.h"
|
||||
class nsString;
|
||||
%}
|
||||
[ref] native nsStringTArrayRef(nsTArray<nsString>);
|
||||
|
||||
/**
|
||||
* The nsIMozWebSocket interface enables Web applications to maintain
|
||||
@ -51,7 +58,7 @@ interface nsPIDOMWindow;
|
||||
* http://dev.w3.org/html5/websockets/
|
||||
*
|
||||
*/
|
||||
[scriptable, uuid(662691db-2b99-4461-801b-fbb72d99a4b9)]
|
||||
[scriptable, uuid(d50eb158-30a1-4692-8664-fdd479fa24b3)]
|
||||
interface nsIMozWebSocket : nsISupports
|
||||
{
|
||||
readonly attribute DOMString url;
|
||||
@ -98,13 +105,16 @@ interface nsIMozWebSocket : nsISupports
|
||||
* @param ownerWindow The associated window for the request. May be null.
|
||||
* @param url The url for opening the socket. This must not be empty, and
|
||||
* must have an absolute url, using either the ws or wss schemes.
|
||||
* @param protocol Specifies a sub-protocol that the server must support for
|
||||
* the connection to be successful. If empty, no protocol is
|
||||
* specified.
|
||||
* @param protocol Specifies array of sub-protocols acceptable to the client.
|
||||
* If the length of the array is at least one, the server
|
||||
* must select one of the listed sub-protocols for the
|
||||
* connection to be successful. If empty, no sub-protocol is
|
||||
* specified. The server selected sub-protocol can be read
|
||||
* from the protocol attribute after connection.
|
||||
*/
|
||||
[noscript] void init(in nsIPrincipal principal,
|
||||
in nsIScriptContext scriptContext,
|
||||
in nsPIDOMWindow ownerWindow,
|
||||
in DOMString url,
|
||||
in DOMString protocol);
|
||||
in nsStringTArrayRef protocol);
|
||||
};
|
||||
|
@ -77,6 +77,7 @@
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsDOMLists.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -295,9 +296,10 @@ nsWebSocketEstablishedConnection::Init(nsWebSocket *aOwner)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!mOwner->mProtocol.IsEmpty())
|
||||
rv = mWebSocketChannel->SetProtocol(mOwner->mProtocol);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!mOwner->mRequestedProtocolList.IsEmpty()) {
|
||||
rv = mWebSocketChannel->SetProtocol(mOwner->mRequestedProtocolList);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCString utf8Origin;
|
||||
CopyUTF16toUTF8(mOwner->mUTF16Origin, utf8Origin);
|
||||
@ -503,8 +505,8 @@ nsWebSocketEstablishedConnection::OnStart(nsISupports *aContext)
|
||||
if (!mOwner)
|
||||
return NS_OK;
|
||||
|
||||
if (!mOwner->mProtocol.IsEmpty())
|
||||
mWebSocketChannel->GetProtocol(mOwner->mProtocol);
|
||||
if (!mOwner->mRequestedProtocolList.IsEmpty())
|
||||
mWebSocketChannel->GetProtocol(mOwner->mEstablishedProtocol);
|
||||
|
||||
mStatus = CONN_CONNECTED_AND_READY;
|
||||
mOwner->SetReadyState(nsIMozWebSocket::OPEN);
|
||||
@ -676,8 +678,9 @@ NS_IMPL_RELEASE_INHERITED(nsWebSocket, nsDOMEventTargetWrapperCache)
|
||||
/**
|
||||
* This Initialize method is called from XPConnect via nsIJSNativeInitializer.
|
||||
* It is used for constructing our nsWebSocket from JavaScript. It expects a URL
|
||||
* string parameter and an optional protocol parameter. It also initializes the
|
||||
* principal, the script context and the window owner.
|
||||
* string parameter and an optional protocol parameter which may be a string or
|
||||
* an array of strings. It also initializes the principal, the script context and
|
||||
* the window owner.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsWebSocket::Initialize(nsISupports* aOwner,
|
||||
@ -687,7 +690,7 @@ nsWebSocket::Initialize(nsISupports* aOwner,
|
||||
jsval* aArgv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsAutoString urlParam, protocolParam;
|
||||
nsAutoString urlParam;
|
||||
|
||||
if (!PrefEnabled()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
@ -714,24 +717,6 @@ nsWebSocket::Initialize(nsISupports* aOwner,
|
||||
urlParam.Assign(chars, length);
|
||||
deleteProtector.clear();
|
||||
|
||||
if (aArgc == 2) {
|
||||
jsstr = JS_ValueToString(aContext, aArgv[1]);
|
||||
if (!jsstr) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
deleteProtector.set(jsstr);
|
||||
chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||
if (!chars) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
protocolParam.Assign(chars, length);
|
||||
if (protocolParam.IsEmpty()) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
|
||||
NS_ENSURE_STATE(ownerWindow);
|
||||
|
||||
@ -745,7 +730,62 @@ nsWebSocket::Initialize(nsISupports* aOwner,
|
||||
nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
|
||||
NS_ENSURE_STATE(principal);
|
||||
|
||||
return Init(principal, scriptContext, ownerWindow, urlParam, protocolParam);
|
||||
nsTArray<nsString> protocolArray;
|
||||
|
||||
if (aArgc == 2) {
|
||||
JSObject *jsobj;
|
||||
|
||||
if (JSVAL_IS_OBJECT(aArgv[1]) &&
|
||||
(jsobj = JSVAL_TO_OBJECT(aArgv[1])) &&
|
||||
JS_IsArrayObject(aContext, jsobj)) {
|
||||
jsuint len;
|
||||
JS_GetArrayLength(aContext, jsobj, &len);
|
||||
|
||||
for (PRUint32 index = 0; index < len; ++index) {
|
||||
jsval value;
|
||||
|
||||
if (!JS_GetElement(aContext, jsobj, index, &value))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
jsstr = JS_ValueToString(aContext, value);
|
||||
if (!jsstr)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
deleteProtector.set(jsstr);
|
||||
chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||
if (!chars)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsDependentString protocolElement(chars, length);
|
||||
if (protocolElement.IsEmpty())
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
if (protocolArray.Contains(protocolElement))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
if (protocolElement.FindChar(',') != -1) /* interferes w/list */
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
protocolArray.AppendElement(protocolElement);
|
||||
deleteProtector.clear();
|
||||
}
|
||||
} else {
|
||||
jsstr = JS_ValueToString(aContext, aArgv[1]);
|
||||
if (!jsstr)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
deleteProtector.set(jsstr);
|
||||
chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
|
||||
if (!chars)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsDependentString protocolElement(chars, length);
|
||||
if (protocolElement.IsEmpty())
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
if (protocolElement.FindChar(',') != -1) /* interferes w/list */
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
protocolArray.AppendElement(protocolElement);
|
||||
}
|
||||
}
|
||||
|
||||
return Init(principal, scriptContext, ownerWindow, urlParam, protocolArray);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1058,26 +1098,6 @@ nsWebSocket::ParseURL(const nsString& aURL)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsWebSocket::SetProtocol(const nsString& aProtocol)
|
||||
{
|
||||
if (aProtocol.IsEmpty()) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
PRUint32 length = aProtocol.Length();
|
||||
PRUint32 i;
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (aProtocol[i] < static_cast<PRUnichar>(0x0021) ||
|
||||
aProtocol[i] > static_cast<PRUnichar>(0x007E)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
CopyUTF16toUTF8(aProtocol, mProtocol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods that keep alive the WebSocket object when:
|
||||
// 1. the object has registered event listeners that can be triggered
|
||||
@ -1196,7 +1216,7 @@ nsWebSocket::GetUrl(nsAString& aURL)
|
||||
NS_IMETHODIMP
|
||||
nsWebSocket::GetProtocol(nsAString& aProtocol)
|
||||
{
|
||||
CopyUTF8toUTF16(mProtocol, aProtocol);
|
||||
CopyUTF8toUTF16(mEstablishedProtocol, aProtocol);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1306,7 +1326,7 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
|
||||
nsIScriptContext* aScriptContext,
|
||||
nsPIDOMWindow* aOwnerWindow,
|
||||
const nsAString& aURL,
|
||||
const nsAString& aProtocol)
|
||||
nsTArray<nsString> & protocolArray)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsresult rv;
|
||||
@ -1364,10 +1384,17 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// sets the protocol
|
||||
if (!aProtocol.IsEmpty()) {
|
||||
rv = SetProtocol(PromiseFlatString(aProtocol));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Assign the sub protocol list and scan it for illegal values
|
||||
for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
|
||||
for (PRUint32 i = 0; i < protocolArray[index].Length(); ++i) {
|
||||
if (protocolArray[index][i] < static_cast<PRUnichar>(0x0021) ||
|
||||
protocolArray[index][i] > static_cast<PRUnichar>(0x007E))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
if (!mRequestedProtocolList.IsEmpty())
|
||||
mRequestedProtocolList.Append(NS_LITERAL_CSTRING(", "));
|
||||
AppendUTF16toUTF8(protocolArray[index], mRequestedProtocolList);
|
||||
}
|
||||
|
||||
// the constructor should throw a SYNTAX_ERROR only if it fails to parse the
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsDOMEventTargetWrapperCache.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
|
||||
#define DEFAULT_WS_SCHEME_PORT 80
|
||||
#define DEFAULT_WSS_SCHEME_PORT 443
|
||||
@ -104,7 +105,6 @@ public:
|
||||
|
||||
protected:
|
||||
nsresult ParseURL(const nsString& aURL);
|
||||
nsresult SetProtocol(const nsString& aProtocol);
|
||||
nsresult EstablishConnection();
|
||||
|
||||
nsresult CreateAndDispatchSimpleEvent(const nsString& aName);
|
||||
@ -142,7 +142,8 @@ protected:
|
||||
nsString mUTF16Origin;
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCString mProtocol;
|
||||
nsCString mRequestedProtocolList;
|
||||
nsCString mEstablishedProtocol;
|
||||
|
||||
PRUint16 mReadyState;
|
||||
|
||||
|
@ -7,7 +7,10 @@ import sys
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
# must set request.ws_protocol to the selected version from ws_requested_protocols
|
||||
request.ws_protocol = request.ws_requested_protocols[0]
|
||||
for x in request.ws_requested_protocols:
|
||||
if x != "test-does-not-exist":
|
||||
request.ws_protocol = x
|
||||
break
|
||||
|
||||
if request.ws_protocol == "test-2.1":
|
||||
time.sleep(5)
|
||||
|
@ -45,10 +45,21 @@
|
||||
* 22. server takes too long to establish the ws connection;
|
||||
* 23. see bug 664692 - feature detection should detect MozWebSocket but not
|
||||
* WebSocket on window object;
|
||||
* 24. server rejects sub-protocol string
|
||||
* 25. ctor with valid empty sub-protocol array
|
||||
* 26. ctor with invalid sub-protocol array containing 1 empty element
|
||||
* 27. ctor with invalid sub-protocol array containing an empty element in list
|
||||
* 28. ctor using valid 1 element sub-protocol array
|
||||
* 29. ctor using all valid 5 element sub-protocol array
|
||||
* 30. ctor using valid 1 element sub-protocol array with element server will
|
||||
* reject
|
||||
* 31. ctor using valid 2 element sub-protocol array with 1 element server
|
||||
* will reject and one server will accept.
|
||||
* 32. ctor using invalid sub-protocol array that contains duplicate items
|
||||
*/
|
||||
|
||||
var first_test = 1;
|
||||
var last_test = 23;
|
||||
var last_test = 32;
|
||||
|
||||
var current_test = first_test;
|
||||
|
||||
@ -309,6 +320,7 @@ function test8()
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-8");
|
||||
ws.onopen = function()
|
||||
{
|
||||
ok(ws.protocol == "test-8", "test-8 subprotocol selection");
|
||||
ws.close();
|
||||
}
|
||||
ws.onclose = function(e)
|
||||
@ -635,11 +647,159 @@ function test22()
|
||||
|
||||
function test23()
|
||||
{
|
||||
current_test++;
|
||||
is(false, "WebSocket" in window, "WebSocket shouldn't be available on window object");
|
||||
is(true, "MozWebSocket" in window, "MozWebSocket should be available on window object");
|
||||
doTest(24);
|
||||
}
|
||||
|
||||
function test24()
|
||||
{
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-does-not-exist");
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
shouldCloseNotCleanly(e);
|
||||
doTest(25);
|
||||
};
|
||||
ws.onerror = function()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
function test25()
|
||||
{
|
||||
var prots=[];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ws.onopen = function(e)
|
||||
{
|
||||
ok(true, "test 25 protocol array open");
|
||||
ws.close();
|
||||
};
|
||||
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
ok(ws.protocol == "", "test25 subprotocol selection");
|
||||
ok(true, "test 25 protocol array close");
|
||||
doTest(26);
|
||||
};
|
||||
}
|
||||
|
||||
function test26()
|
||||
{
|
||||
var prots=[""];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ok(false, "testing empty element sub protocol array");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "testing empty sub element protocol array");
|
||||
}
|
||||
doTest(27);
|
||||
}
|
||||
|
||||
function test27()
|
||||
{
|
||||
var prots=["test27", ""];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ok(false, "testing empty element mixed sub protocol array");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "testing empty element mixed sub protocol array");
|
||||
}
|
||||
doTest(28);
|
||||
}
|
||||
|
||||
function test28()
|
||||
{
|
||||
var prots=["test28"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ws.onopen = function(e)
|
||||
{
|
||||
ok(true, "test 28 protocol array open");
|
||||
ws.close();
|
||||
};
|
||||
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
ok(ws.protocol == "test28", "test28 subprotocol selection");
|
||||
ok(true, "test 28 protocol array close");
|
||||
doTest(29);
|
||||
};
|
||||
}
|
||||
|
||||
function test29()
|
||||
{
|
||||
var prots=["test29a", "test29b"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ws.onopen = function(e)
|
||||
{
|
||||
ok(true, "test 29 protocol array open");
|
||||
ws.close();
|
||||
};
|
||||
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
ok(true, "test 29 protocol array close");
|
||||
doTest(30);
|
||||
};
|
||||
}
|
||||
|
||||
function test30()
|
||||
{
|
||||
var prots=["test-does-not-exist"];
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
shouldCloseNotCleanly(e);
|
||||
doTest(31);
|
||||
};
|
||||
ws.onerror = function()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
function test31()
|
||||
{
|
||||
var prots=["test-does-not-exist", "test31"];
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e)
|
||||
{
|
||||
ok(true, "test 31 protocol array open");
|
||||
ws.close();
|
||||
};
|
||||
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
ok(ws.protocol == "test31", "test31 subprotocol selection");
|
||||
ok(true, "test 31 protocol array close");
|
||||
doTest(32);
|
||||
};
|
||||
}
|
||||
|
||||
function test32()
|
||||
{
|
||||
var prots=["test32","test32"];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||
ok(false, "testing duplicated element sub protocol array");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "testing duplicated sub element protocol array");
|
||||
}
|
||||
doTest(33);
|
||||
}
|
||||
|
||||
function finishWSTest()
|
||||
{
|
||||
for (i = 0; i < all_ws.length; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user