mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 674716 - websockets API close reason codes and messages r=sicking r=biesi sr=bz
--HG-- extra : rebase_source : f7a0eb6b310f29f8e697c26ff5e0ef9d2fde559a
This commit is contained in:
parent
2adea969f2
commit
c9a6067c84
@ -58,7 +58,7 @@ class nsString;
|
|||||||
* http://dev.w3.org/html5/websockets/
|
* http://dev.w3.org/html5/websockets/
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(d50eb158-30a1-4692-8664-fdd479fa24b3)]
|
[scriptable, uuid(8fa080c7-934a-4040-90cb-31055798b35d)]
|
||||||
interface nsIMozWebSocket : nsISupports
|
interface nsIMozWebSocket : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute DOMString url;
|
readonly attribute DOMString url;
|
||||||
@ -92,7 +92,8 @@ interface nsIMozWebSocket : nsISupports
|
|||||||
* Closes the Web Socket connection or connection attempt, if any.
|
* Closes the Web Socket connection or connection attempt, if any.
|
||||||
* If the connection is already closed, it does nothing.
|
* If the connection is already closed, it does nothing.
|
||||||
*/
|
*/
|
||||||
void close();
|
[optional_argc] void close([optional] in unsigned short code,
|
||||||
|
[optional] in DOMString reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the object for use from C++ code with the principal, script
|
* Initialize the object for use from C++ code with the principal, script
|
||||||
|
@ -390,7 +390,8 @@ nsWebSocketEstablishedConnection::Close()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mWebSocketChannel->Close();
|
return mWebSocketChannel->Close(mOwner->mClientReasonCode,
|
||||||
|
mOwner->mClientReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -561,9 +562,15 @@ nsWebSocketEstablishedConnection::OnAcknowledge(nsISupports *aContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWebSocketEstablishedConnection::OnServerClose(nsISupports *aContext)
|
nsWebSocketEstablishedConnection::OnServerClose(nsISupports *aContext,
|
||||||
|
PRUint16 aCode,
|
||||||
|
const nsACString &aReason)
|
||||||
{
|
{
|
||||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||||
|
if (mOwner) {
|
||||||
|
mOwner->mServerReasonCode = aCode;
|
||||||
|
CopyUTF8toUTF16(aReason, mOwner->mServerReason);
|
||||||
|
}
|
||||||
|
|
||||||
Close(); /* reciprocate! */
|
Close(); /* reciprocate! */
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -611,6 +618,8 @@ nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID,
|
|||||||
nsWebSocket::nsWebSocket() : mKeepingAlive(PR_FALSE),
|
nsWebSocket::nsWebSocket() : mKeepingAlive(PR_FALSE),
|
||||||
mCheckMustKeepAlive(PR_TRUE),
|
mCheckMustKeepAlive(PR_TRUE),
|
||||||
mTriggeredCloseEvent(PR_FALSE),
|
mTriggeredCloseEvent(PR_FALSE),
|
||||||
|
mClientReasonCode(0),
|
||||||
|
mServerReasonCode(nsIWebSocketChannel::CLOSE_ABNORMAL),
|
||||||
mReadyState(nsIMozWebSocket::CONNECTING),
|
mReadyState(nsIMozWebSocket::CONNECTING),
|
||||||
mOutgoingBufferedAmount(0),
|
mOutgoingBufferedAmount(0),
|
||||||
mScriptLine(0),
|
mScriptLine(0),
|
||||||
@ -806,7 +815,7 @@ nsWebSocket::EstablishConnection()
|
|||||||
rv = conn->Init(this);
|
rv = conn->Init(this);
|
||||||
mConnection = conn;
|
mConnection = conn;
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
Close();
|
Close(0, EmptyString(), 0);
|
||||||
mConnection = nsnull;
|
mConnection = nsnull;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -817,14 +826,18 @@ nsWebSocket::EstablishConnection()
|
|||||||
class nsWSCloseEvent : public nsRunnable
|
class nsWSCloseEvent : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsWSCloseEvent(nsWebSocket *aWebSocket, PRBool aWasClean)
|
nsWSCloseEvent(nsWebSocket *aWebSocket, PRBool aWasClean,
|
||||||
|
PRUint16 aCode, const nsString &aReason)
|
||||||
: mWebSocket(aWebSocket),
|
: mWebSocket(aWebSocket),
|
||||||
mWasClean(aWasClean)
|
mWasClean(aWasClean),
|
||||||
|
mCode(aCode),
|
||||||
|
mReason(aReason)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
NS_IMETHOD Run()
|
NS_IMETHOD Run()
|
||||||
{
|
{
|
||||||
nsresult rv = mWebSocket->CreateAndDispatchCloseEvent(mWasClean);
|
nsresult rv = mWebSocket->CreateAndDispatchCloseEvent(mWasClean,
|
||||||
|
mCode, mReason);
|
||||||
mWebSocket->UpdateMustKeepAlive();
|
mWebSocket->UpdateMustKeepAlive();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -832,6 +845,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
nsRefPtr<nsWebSocket> mWebSocket;
|
nsRefPtr<nsWebSocket> mWebSocket;
|
||||||
PRBool mWasClean;
|
PRBool mWasClean;
|
||||||
|
PRUint16 mCode;
|
||||||
|
nsString mReason;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -919,7 +934,9 @@ nsWebSocket::CreateAndDispatchMessageEvent(const nsACString& aData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsWebSocket::CreateAndDispatchCloseEvent(PRBool aWasClean)
|
nsWebSocket::CreateAndDispatchCloseEvent(PRBool aWasClean,
|
||||||
|
PRUint16 aCode,
|
||||||
|
const nsString &aReason)
|
||||||
{
|
{
|
||||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
@ -941,7 +958,7 @@ nsWebSocket::CreateAndDispatchCloseEvent(PRBool aWasClean)
|
|||||||
nsCOMPtr<nsIDOMCloseEvent> closeEvent = do_QueryInterface(event);
|
nsCOMPtr<nsIDOMCloseEvent> closeEvent = do_QueryInterface(event);
|
||||||
rv = closeEvent->InitCloseEvent(NS_LITERAL_STRING("close"),
|
rv = closeEvent->InitCloseEvent(NS_LITERAL_STRING("close"),
|
||||||
PR_FALSE, PR_FALSE,
|
PR_FALSE, PR_FALSE,
|
||||||
aWasClean);
|
aWasClean, aCode, aReason);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
|
||||||
@ -999,7 +1016,10 @@ nsWebSocket::SetReadyState(PRUint16 aNewReadyState)
|
|||||||
if (mConnection) {
|
if (mConnection) {
|
||||||
// The close event must be dispatched asynchronously.
|
// The close event must be dispatched asynchronously.
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
new nsWSCloseEvent(this, mConnection->ClosedCleanly());
|
new nsWSCloseEvent(this,
|
||||||
|
mConnection->ClosedCleanly(),
|
||||||
|
mServerReasonCode,
|
||||||
|
mServerReason);
|
||||||
mOutgoingBufferedAmount += mConnection->GetOutgoingBufferedAmount();
|
mOutgoingBufferedAmount += mConnection->GetOutgoingBufferedAmount();
|
||||||
mConnection = nsnull; // this is no longer necessary
|
mConnection = nsnull; // this is no longer necessary
|
||||||
|
|
||||||
@ -1257,6 +1277,26 @@ NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(error, mOnErrorListener)
|
|||||||
NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(message, mOnMessageListener)
|
NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(message, mOnMessageListener)
|
||||||
NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(close, mOnCloseListener)
|
NS_WEBSOCKET_IMPL_DOMEVENTLISTENER(close, mOnCloseListener)
|
||||||
|
|
||||||
|
static PRBool
|
||||||
|
ContainsUnpairedSurrogates(const nsAString& aData)
|
||||||
|
{
|
||||||
|
// Check for unpaired surrogates.
|
||||||
|
PRUint32 i, length = aData.Length();
|
||||||
|
for (i = 0; i < length; ++i) {
|
||||||
|
if (NS_IS_LOW_SURROGATE(aData[i])) {
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
if (NS_IS_HIGH_SURROGATE(aData[i])) {
|
||||||
|
++i;
|
||||||
|
if (i == length || !NS_IS_LOW_SURROGATE(aData[i])) {
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWebSocket::Send(const nsAString& aData)
|
nsWebSocket::Send(const nsAString& aData)
|
||||||
{
|
{
|
||||||
@ -1266,20 +1306,8 @@ nsWebSocket::Send(const nsAString& aData)
|
|||||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for unpaired surrogates.
|
if (ContainsUnpairedSurrogates(aData))
|
||||||
PRUint32 i, length = aData.Length();
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
for (i = 0; i < length; ++i) {
|
|
||||||
if (NS_IS_LOW_SURROGATE(aData[i])) {
|
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
||||||
}
|
|
||||||
if (NS_IS_HIGH_SURROGATE(aData[i])) {
|
|
||||||
if (i + 1 == length || !NS_IS_LOW_SURROGATE(aData[i + 1])) {
|
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mReadyState == nsIMozWebSocket::CLOSING ||
|
if (mReadyState == nsIMozWebSocket::CLOSING ||
|
||||||
mReadyState == nsIMozWebSocket::CLOSED) {
|
mReadyState == nsIMozWebSocket::CLOSED) {
|
||||||
@ -1293,9 +1321,34 @@ nsWebSocket::Send(const nsAString& aData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWebSocket::Close()
|
nsWebSocket::Close(PRUint16 code, const nsAString & reason, PRUint8 argc)
|
||||||
{
|
{
|
||||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||||
|
|
||||||
|
// the reason code is optional, but if provided it must be in a specific range
|
||||||
|
if (argc >= 1) {
|
||||||
|
if (code != 1000 && (code < 3000 || code > 4999))
|
||||||
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCAutoString utf8Reason;
|
||||||
|
if (argc >= 2) {
|
||||||
|
if (ContainsUnpairedSurrogates(reason))
|
||||||
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
|
|
||||||
|
CopyUTF16toUTF8(reason, utf8Reason);
|
||||||
|
|
||||||
|
// The API requires the UTF-8 string to be 123 or less bytes
|
||||||
|
if (utf8Reason.Length() > 123)
|
||||||
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format checks for reason and code both passed, they can now be assigned.
|
||||||
|
if (argc >= 1)
|
||||||
|
mClientReasonCode = code;
|
||||||
|
if (argc >= 2)
|
||||||
|
mClientReason = utf8Reason;
|
||||||
|
|
||||||
if (mReadyState == nsIMozWebSocket::CLOSING ||
|
if (mReadyState == nsIMozWebSocket::CLOSING ||
|
||||||
mReadyState == nsIMozWebSocket::CLOSED) {
|
mReadyState == nsIMozWebSocket::CLOSED) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -109,7 +109,8 @@ protected:
|
|||||||
|
|
||||||
nsresult CreateAndDispatchSimpleEvent(const nsString& aName);
|
nsresult CreateAndDispatchSimpleEvent(const nsString& aName);
|
||||||
nsresult CreateAndDispatchMessageEvent(const nsACString& aData);
|
nsresult CreateAndDispatchMessageEvent(const nsACString& aData);
|
||||||
nsresult CreateAndDispatchCloseEvent(PRBool aWasClean);
|
nsresult CreateAndDispatchCloseEvent(PRBool aWasClean, PRUint16 aCode,
|
||||||
|
const nsString &aReason);
|
||||||
|
|
||||||
// called from mConnection accordingly to the situation
|
// called from mConnection accordingly to the situation
|
||||||
void SetReadyState(PRUint16 aNewReadyState);
|
void SetReadyState(PRUint16 aNewReadyState);
|
||||||
@ -136,6 +137,11 @@ protected:
|
|||||||
PRPackedBool mCheckMustKeepAlive;
|
PRPackedBool mCheckMustKeepAlive;
|
||||||
PRPackedBool mTriggeredCloseEvent;
|
PRPackedBool mTriggeredCloseEvent;
|
||||||
|
|
||||||
|
nsCString mClientReason;
|
||||||
|
PRUint16 mClientReasonCode;
|
||||||
|
nsString mServerReason;
|
||||||
|
PRUint16 mServerReasonCode;
|
||||||
|
|
||||||
nsCString mAsciiHost; // hostname
|
nsCString mAsciiHost; // hostname
|
||||||
PRUint32 mPort;
|
PRUint32 mPort;
|
||||||
nsCString mResource; // [filepath[?query]]
|
nsCString mResource; // [filepath[?query]]
|
||||||
|
@ -96,5 +96,25 @@ def web_socket_transfer_data(request):
|
|||||||
elif request.ws_protocol == "test-20":
|
elif request.ws_protocol == "test-20":
|
||||||
msgutil.send_message(request, "server data")
|
msgutil.send_message(request, "server data")
|
||||||
msgutil.close_connection(request)
|
msgutil.close_connection(request)
|
||||||
|
elif request.ws_protocol == "test-34":
|
||||||
|
request.ws_stream.close_connection(1001, "going away now")
|
||||||
|
elif request.ws_protocol == "test-35a":
|
||||||
|
while not request.client_terminated:
|
||||||
|
msgutil.receive_message(request)
|
||||||
|
global test35code
|
||||||
|
test35code = request.ws_close_code
|
||||||
|
global test35reason
|
||||||
|
test35reason = request.ws_close_reason
|
||||||
|
elif request.ws_protocol == "test-35b":
|
||||||
|
request.ws_stream.close_connection(test35code + 1, test35reason)
|
||||||
|
elif request.ws_protocol == "test-37b":
|
||||||
|
while not request.client_terminated:
|
||||||
|
msgutil.receive_message(request)
|
||||||
|
global test37code
|
||||||
|
test37code = request.ws_close_code
|
||||||
|
global test37reason
|
||||||
|
test37reason = request.ws_close_reason
|
||||||
|
elif request.ws_protocol == "test-37c":
|
||||||
|
request.ws_stream.close_connection(test37code, test37reason)
|
||||||
while not request.client_terminated:
|
while not request.client_terminated:
|
||||||
msgutil.receive_message(request)
|
msgutil.receive_message(request)
|
||||||
|
@ -56,10 +56,15 @@
|
|||||||
* 31. ctor using valid 2 element sub-protocol array with 1 element server
|
* 31. ctor using valid 2 element sub-protocol array with 1 element server
|
||||||
* will reject and one server will accept.
|
* will reject and one server will accept.
|
||||||
* 32. ctor using invalid sub-protocol array that contains duplicate items
|
* 32. ctor using invalid sub-protocol array that contains duplicate items
|
||||||
|
* 33. default close code test
|
||||||
|
* 34. test for receiving custom close code and reason
|
||||||
|
* 35. test for sending custom close code and reason
|
||||||
|
* 36. negative test for sending out of range close code
|
||||||
|
* 37. negative test for too long of a close reason
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var first_test = 1;
|
var first_test = 1;
|
||||||
var last_test = 32;
|
var last_test = 37;
|
||||||
|
|
||||||
var current_test = first_test;
|
var current_test = first_test;
|
||||||
|
|
||||||
@ -884,6 +889,173 @@ function test32()
|
|||||||
doTest(33);
|
doTest(33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test33()
|
||||||
|
{
|
||||||
|
var prots=["test33"];
|
||||||
|
|
||||||
|
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||||
|
ws.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 33 open");
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 33 close");
|
||||||
|
ok(e.wasClean, "test 33 closed cleanly");
|
||||||
|
ok(e.code == 1000, "test 33 had normal 1000 error code");
|
||||||
|
doTest(34);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function test34()
|
||||||
|
{
|
||||||
|
var prots=["test-34"];
|
||||||
|
|
||||||
|
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||||
|
ws.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 34 open");
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 34 close");
|
||||||
|
ok(e.wasClean, "test 34 closed cleanly");
|
||||||
|
ok(e.code == 1001, "test 34 custom server code");
|
||||||
|
ok(e.reason == "going away now", "test 34 custom server reason");
|
||||||
|
doTest(35);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function test35()
|
||||||
|
{
|
||||||
|
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-35a");
|
||||||
|
|
||||||
|
ws.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 35a open");
|
||||||
|
ws.close(3500, "my code");
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 35a close");
|
||||||
|
ok(e.wasClean, "test 35a closed cleanly");
|
||||||
|
current_test--; // CreateTestWS for 35a incremented this
|
||||||
|
var wsb = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-35b");
|
||||||
|
|
||||||
|
wsb.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 35b open");
|
||||||
|
wsb.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
wsb.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 35b close");
|
||||||
|
ok(e.wasClean, "test 35b closed cleanly");
|
||||||
|
ok(e.code == 3501, "test 35 custom server code");
|
||||||
|
ok(e.reason == "my code", "test 35 custom server reason");
|
||||||
|
doTest(36);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test36()
|
||||||
|
{
|
||||||
|
var prots=["test-36"];
|
||||||
|
|
||||||
|
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||||
|
ws.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 36 open");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ws.close(13200);
|
||||||
|
ok(false, "testing custom close code out of range");
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
ok(true, "testing custom close code out of range");
|
||||||
|
ws.close(3200);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 36 close");
|
||||||
|
ok(e.wasClean, "test 36 closed cleanly");
|
||||||
|
doTest(37);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function test37()
|
||||||
|
{
|
||||||
|
var prots=["test-37"];
|
||||||
|
|
||||||
|
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
|
||||||
|
ws.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 37 open");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ws.close(3100,"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123");
|
||||||
|
ok(false, "testing custom close reason out of range");
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
ok(true, "testing custom close reason out of range");
|
||||||
|
ws.close(3100,"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 37 close");
|
||||||
|
ok(e.wasClean, "test 37 closed cleanly");
|
||||||
|
|
||||||
|
current_test--; // CreateTestWS for 37 incremented this
|
||||||
|
var wsb = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-37b");
|
||||||
|
|
||||||
|
wsb.onopen = function(e)
|
||||||
|
{
|
||||||
|
// now test that a rejected close code and reason dont persist
|
||||||
|
ok(true, "test 37b open");
|
||||||
|
try {
|
||||||
|
wsb.close(3101,"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123");
|
||||||
|
ok(false, "testing custom close reason out of range 37b");
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
ok(true, "testing custom close reason out of range 37b");
|
||||||
|
wsb.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wsb.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 37b close");
|
||||||
|
ok(e.wasClean, "test 37b closed cleanly");
|
||||||
|
|
||||||
|
current_test--; // CreateTestWS for 37 incremented this
|
||||||
|
var wsc = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-37c");
|
||||||
|
|
||||||
|
wsc.onopen = function(e)
|
||||||
|
{
|
||||||
|
ok(true, "test 37c open");
|
||||||
|
wsc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
wsc.onclose = function(e)
|
||||||
|
{
|
||||||
|
ok(e.code != 3101, "test 37c custom server code not present");
|
||||||
|
ok(e.reason == "", "test 37c custom server reason not present");
|
||||||
|
doTest(38);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ranAllTests = false;
|
var ranAllTests = false;
|
||||||
|
|
||||||
function maybeFinished()
|
function maybeFinished()
|
||||||
|
@ -56,16 +56,34 @@ nsDOMCloseEvent::GetWasClean(PRBool *aWasClean)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMCloseEvent::GetCode(PRUint16 *aCode)
|
||||||
|
{
|
||||||
|
*aCode = mReasonCode;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMCloseEvent::GetReason(nsAString & aReason)
|
||||||
|
{
|
||||||
|
aReason = mReason;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMCloseEvent::InitCloseEvent(const nsAString& aType,
|
nsDOMCloseEvent::InitCloseEvent(const nsAString& aType,
|
||||||
PRBool aCanBubble,
|
PRBool aCanBubble,
|
||||||
PRBool aCancelable,
|
PRBool aCancelable,
|
||||||
PRBool aWasClean)
|
PRBool aWasClean,
|
||||||
|
PRUint16 aReasonCode,
|
||||||
|
const nsAString &aReason)
|
||||||
{
|
{
|
||||||
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
|
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mWasClean = aWasClean;
|
mWasClean = aWasClean;
|
||||||
|
mReasonCode = aReasonCode;
|
||||||
|
mReason = aReason;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,9 @@ class nsDOMCloseEvent : public nsDOMEvent,
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsDOMCloseEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
nsDOMCloseEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||||
: nsDOMEvent(aPresContext, aEvent), mWasClean(PR_FALSE)
|
: nsDOMEvent(aPresContext, aEvent),
|
||||||
{
|
mWasClean(PR_FALSE),
|
||||||
}
|
mReasonCode(1005) {}
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
|
|
||||||
@ -66,6 +66,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PRBool mWasClean;
|
PRBool mWasClean;
|
||||||
|
PRUint16 mReasonCode;
|
||||||
|
nsString mReason;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsDOMCloseEvent_h__
|
#endif // nsDOMCloseEvent_h__
|
||||||
|
@ -45,13 +45,17 @@
|
|||||||
* For more information on this interface, please see
|
* For more information on this interface, please see
|
||||||
* http://dev.w3.org/html5/websockets/#closeevent
|
* http://dev.w3.org/html5/websockets/#closeevent
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(a94d4379-eba2-45f4-be3a-6cc2fa1453a8)]
|
[scriptable, uuid(f83d9d6d-6c0c-418c-b12a-438e76d5866b)]
|
||||||
interface nsIDOMCloseEvent : nsIDOMEvent
|
interface nsIDOMCloseEvent : nsIDOMEvent
|
||||||
{
|
{
|
||||||
readonly attribute boolean wasClean;
|
readonly attribute boolean wasClean;
|
||||||
|
readonly attribute unsigned short code;
|
||||||
|
readonly attribute DOMString reason;
|
||||||
|
|
||||||
void initCloseEvent(in DOMString aType,
|
void initCloseEvent(in DOMString aType,
|
||||||
in boolean aCanBubble,
|
in boolean aCanBubble,
|
||||||
in boolean aCancelable,
|
in boolean aCancelable,
|
||||||
in boolean aWasClean);
|
in boolean aWasClean,
|
||||||
|
in unsigned short aReasonCode,
|
||||||
|
in DOMString aReason);
|
||||||
};
|
};
|
||||||
|
@ -55,7 +55,7 @@ async protocol PWebSocket
|
|||||||
parent:
|
parent:
|
||||||
// Forwarded methods corresponding to methods on nsIWebSocketChannel
|
// Forwarded methods corresponding to methods on nsIWebSocketChannel
|
||||||
AsyncOpen(URI aURI, nsCString aOrigin, nsCString aProtocol, bool aSecure);
|
AsyncOpen(URI aURI, nsCString aOrigin, nsCString aProtocol, bool aSecure);
|
||||||
Close();
|
Close(PRUint16 code, nsCString reason);
|
||||||
SendMsg(nsCString aMsg);
|
SendMsg(nsCString aMsg);
|
||||||
SendBinaryMsg(nsCString aMsg);
|
SendBinaryMsg(nsCString aMsg);
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ child:
|
|||||||
OnMessageAvailable(nsCString aMsg);
|
OnMessageAvailable(nsCString aMsg);
|
||||||
OnBinaryMessageAvailable(nsCString aMsg);
|
OnBinaryMessageAvailable(nsCString aMsg);
|
||||||
OnAcknowledge(PRUint32 aSize);
|
OnAcknowledge(PRUint32 aSize);
|
||||||
OnServerClose();
|
OnServerClose(PRUint16 code, nsCString aReason);
|
||||||
|
|
||||||
__delete__();
|
__delete__();
|
||||||
|
|
||||||
|
@ -179,13 +179,17 @@ public:
|
|||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
CallOnServerClose(nsIWebSocketListener *aListener,
|
CallOnServerClose(nsIWebSocketListener *aListener,
|
||||||
nsISupports *aContext)
|
nsISupports *aContext,
|
||||||
|
PRUint16 aCode,
|
||||||
|
nsCString &aReason)
|
||||||
: mListener(aListener),
|
: mListener(aListener),
|
||||||
mContext(aContext) {}
|
mContext(aContext),
|
||||||
|
mCode(aCode),
|
||||||
|
mReason(aReason) {}
|
||||||
|
|
||||||
NS_SCRIPTABLE NS_IMETHOD Run()
|
NS_SCRIPTABLE NS_IMETHOD Run()
|
||||||
{
|
{
|
||||||
mListener->OnServerClose(mContext);
|
mListener->OnServerClose(mContext, mCode, mReason);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +198,8 @@ private:
|
|||||||
|
|
||||||
nsCOMPtr<nsIWebSocketListener> mListener;
|
nsCOMPtr<nsIWebSocketListener> mListener;
|
||||||
nsCOMPtr<nsISupports> mContext;
|
nsCOMPtr<nsISupports> mContext;
|
||||||
|
PRUint16 mCode;
|
||||||
|
nsCString mReason;
|
||||||
};
|
};
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(CallOnServerClose, nsIRunnable)
|
NS_IMPL_THREADSAFE_ISUPPORTS1(CallOnServerClose, nsIRunnable)
|
||||||
|
|
||||||
@ -502,7 +508,8 @@ WebSocketChannel::WebSocketChannel() :
|
|||||||
mTCPClosed(0),
|
mTCPClosed(0),
|
||||||
mMaxMessageSize(16000000),
|
mMaxMessageSize(16000000),
|
||||||
mStopOnClose(NS_OK),
|
mStopOnClose(NS_OK),
|
||||||
mCloseCode(kCloseAbnormal),
|
mServerCloseCode(CLOSE_ABNORMAL),
|
||||||
|
mScriptCloseCode(0),
|
||||||
mFragmentOpcode(0),
|
mFragmentOpcode(0),
|
||||||
mFragmentAccumulator(0),
|
mFragmentAccumulator(0),
|
||||||
mBuffered(0),
|
mBuffered(0),
|
||||||
@ -869,26 +876,29 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count)
|
|||||||
LOG(("WebSocketChannel:: close received\n"));
|
LOG(("WebSocketChannel:: close received\n"));
|
||||||
mServerClosed = 1;
|
mServerClosed = 1;
|
||||||
|
|
||||||
mCloseCode = kCloseNoStatus;
|
mServerCloseCode = CLOSE_NO_STATUS;
|
||||||
if (payloadLength >= 2) {
|
if (payloadLength >= 2) {
|
||||||
memcpy(&mCloseCode, payload, 2);
|
memcpy(&mServerCloseCode, payload, 2);
|
||||||
mCloseCode = PR_ntohs(mCloseCode);
|
mServerCloseCode = PR_ntohs(mServerCloseCode);
|
||||||
LOG(("WebSocketChannel:: close recvd code %u\n", mCloseCode));
|
LOG(("WebSocketChannel:: close recvd code %u\n", mServerCloseCode));
|
||||||
PRUint16 msglen = payloadLength - 2;
|
PRUint16 msglen = payloadLength - 2;
|
||||||
if (msglen > 0) {
|
if (msglen > 0) {
|
||||||
nsCString utf8Data((const char *)payload + 2, msglen);
|
mServerCloseReason.SetLength(msglen);
|
||||||
|
memcpy(mServerCloseReason.BeginWriting(),
|
||||||
|
(const char *)payload + 2, msglen);
|
||||||
|
|
||||||
// section 8.1 says to replace received non utf-8 sequences
|
// section 8.1 says to replace received non utf-8 sequences
|
||||||
// (which are non-conformant to send) with u+fffd,
|
// (which are non-conformant to send) with u+fffd,
|
||||||
// but secteam feels that silently rewriting messages is
|
// but secteam feels that silently rewriting messages is
|
||||||
// inappropriate - so we will fail the connection instead.
|
// inappropriate - so we will fail the connection instead.
|
||||||
if (!IsUTF8(utf8Data)) {
|
if (!IsUTF8(mServerCloseReason)) {
|
||||||
LOG(("WebSocketChannel:: close frame invalid utf-8\n"));
|
LOG(("WebSocketChannel:: close frame invalid utf-8\n"));
|
||||||
AbortSession(NS_ERROR_ILLEGAL_VALUE);
|
AbortSession(NS_ERROR_ILLEGAL_VALUE);
|
||||||
return NS_ERROR_ILLEGAL_VALUE;
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(("WebSocketChannel:: close msg %s\n", utf8Data.get()));
|
LOG(("WebSocketChannel:: close msg %s\n",
|
||||||
|
mServerCloseReason.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,7 +907,9 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count)
|
|||||||
mCloseTimer = nsnull;
|
mCloseTimer = nsnull;
|
||||||
}
|
}
|
||||||
if (mListener)
|
if (mListener)
|
||||||
NS_DispatchToMainThread(new CallOnServerClose(mListener, mContext));
|
NS_DispatchToMainThread(
|
||||||
|
new CallOnServerClose(mListener, mContext,
|
||||||
|
mServerCloseCode, mServerCloseReason));
|
||||||
|
|
||||||
if (mClientClosed)
|
if (mClientClosed)
|
||||||
ReleaseSession();
|
ReleaseSession();
|
||||||
@ -1058,16 +1070,16 @@ PRUint16
|
|||||||
WebSocketChannel::ResultToCloseCode(nsresult resultCode)
|
WebSocketChannel::ResultToCloseCode(nsresult resultCode)
|
||||||
{
|
{
|
||||||
if (NS_SUCCEEDED(resultCode))
|
if (NS_SUCCEEDED(resultCode))
|
||||||
return kCloseNormal;
|
return CLOSE_NORMAL;
|
||||||
if (resultCode == NS_ERROR_FILE_TOO_BIG)
|
if (resultCode == NS_ERROR_FILE_TOO_BIG)
|
||||||
return kCloseTooLarge;
|
return CLOSE_TOO_LARGE;
|
||||||
if (resultCode == NS_BASE_STREAM_CLOSED ||
|
if (resultCode == NS_BASE_STREAM_CLOSED ||
|
||||||
resultCode == NS_ERROR_NET_TIMEOUT ||
|
resultCode == NS_ERROR_NET_TIMEOUT ||
|
||||||
resultCode == NS_ERROR_CONNECTION_REFUSED) {
|
resultCode == NS_ERROR_CONNECTION_REFUSED) {
|
||||||
return kCloseAbnormal;
|
return CLOSE_ABNORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kCloseProtocolError;
|
return CLOSE_PROTOCOL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1107,16 +1119,34 @@ WebSocketChannel::PrimeNewOutgoingMessage()
|
|||||||
LOG(("WebSocketChannel:: PrimeNewOutgoingMessage() found close request\n"));
|
LOG(("WebSocketChannel:: PrimeNewOutgoingMessage() found close request\n"));
|
||||||
mClientClosed = 1;
|
mClientClosed = 1;
|
||||||
mOutHeader[0] = kFinalFragBit | kClose;
|
mOutHeader[0] = kFinalFragBit | kClose;
|
||||||
mOutHeader[1] = 0x02; // payload len = 2
|
mOutHeader[1] = 0x02; // payload len = 2, maybe more for reason
|
||||||
mOutHeader[1] |= kMaskBit;
|
mOutHeader[1] |= kMaskBit;
|
||||||
|
|
||||||
// payload is offset 6 including 4 for the mask
|
// payload is offset 6 including 4 for the mask
|
||||||
payload = mOutHeader + 6;
|
payload = mOutHeader + 6;
|
||||||
|
|
||||||
// The close reason code sits in the first 2 bytes of payload
|
// length is 8 plus any reason information
|
||||||
*((PRUint16 *)payload) = PR_htons(ResultToCloseCode(mStopOnClose));
|
|
||||||
|
|
||||||
mHdrOutToSend = 8;
|
mHdrOutToSend = 8;
|
||||||
|
|
||||||
|
// The close reason code sits in the first 2 bytes of payload
|
||||||
|
// If the channel user provided a code and reason during Close()
|
||||||
|
// and there isn't an internal error, use that.
|
||||||
|
if (NS_SUCCEEDED(mStopOnClose) && mScriptCloseCode) {
|
||||||
|
*((PRUint16 *)payload) = PR_htons(mScriptCloseCode);
|
||||||
|
if (!mScriptCloseReason.IsEmpty()) {
|
||||||
|
NS_ABORT_IF_FALSE(mScriptCloseReason.Length() <= 123,
|
||||||
|
"Close Reason Too Long");
|
||||||
|
mOutHeader[1] += mScriptCloseReason.Length();
|
||||||
|
mHdrOutToSend += mScriptCloseReason.Length();
|
||||||
|
memcpy (payload + 2,
|
||||||
|
mScriptCloseReason.BeginReading(),
|
||||||
|
mScriptCloseReason.Length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*((PRUint16 *)payload) = PR_htons(ResultToCloseCode(mStopOnClose));
|
||||||
|
}
|
||||||
|
|
||||||
if (mServerClosed) {
|
if (mServerClosed) {
|
||||||
/* bidi close complete */
|
/* bidi close complete */
|
||||||
mReleaseOnTransmit = 1;
|
mReleaseOnTransmit = 1;
|
||||||
@ -1984,7 +2014,7 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
WebSocketChannel::Close()
|
WebSocketChannel::Close(PRUint16 code, const nsACString & reason)
|
||||||
{
|
{
|
||||||
LOG(("WebSocketChannel::Close() %p\n", this));
|
LOG(("WebSocketChannel::Close() %p\n", this));
|
||||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||||
@ -2000,8 +2030,14 @@ WebSocketChannel::Close()
|
|||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRequestedClose = 1;
|
// The API requires the UTF-8 string to be 123 or less bytes
|
||||||
|
if (reason.Length() > 123)
|
||||||
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
|
|
||||||
|
mRequestedClose = 1;
|
||||||
|
mScriptCloseReason = reason;
|
||||||
|
mScriptCloseCode = code;
|
||||||
|
|
||||||
return mSocketThread->Dispatch(new nsPostMessage(this, kFinMessage, -1),
|
return mSocketThread->Dispatch(new nsPostMessage(this, kFinMessage, -1),
|
||||||
nsIEventTarget::DISPATCH_NORMAL);
|
nsIEventTarget::DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ public:
|
|||||||
const nsACString &aOrigin,
|
const nsACString &aOrigin,
|
||||||
nsIWebSocketListener *aListener,
|
nsIWebSocketListener *aListener,
|
||||||
nsISupports *aContext);
|
nsISupports *aContext);
|
||||||
NS_IMETHOD Close();
|
NS_IMETHOD Close(PRUint16 aCode, const nsACString & aReason);
|
||||||
NS_IMETHOD SendMsg(const nsACString &aMsg);
|
NS_IMETHOD SendMsg(const nsACString &aMsg);
|
||||||
NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
|
NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
|
||||||
NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
|
NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
|
||||||
@ -123,15 +123,6 @@ public:
|
|||||||
const static PRUint8 kMaskBit = 0x80;
|
const static PRUint8 kMaskBit = 0x80;
|
||||||
const static PRUint8 kFinalFragBit = 0x80;
|
const static PRUint8 kFinalFragBit = 0x80;
|
||||||
|
|
||||||
// section 7.4.1 defines these
|
|
||||||
const static PRUint16 kCloseNormal = 1000;
|
|
||||||
const static PRUint16 kCloseGoingAway = 1001;
|
|
||||||
const static PRUint16 kCloseProtocolError = 1002;
|
|
||||||
const static PRUint16 kCloseUnsupported = 1003;
|
|
||||||
const static PRUint16 kCloseTooLarge = 1004;
|
|
||||||
const static PRUint16 kCloseNoStatus = 1005;
|
|
||||||
const static PRUint16 kCloseAbnormal = 1006;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~WebSocketChannel();
|
virtual ~WebSocketChannel();
|
||||||
|
|
||||||
@ -252,7 +243,10 @@ private:
|
|||||||
|
|
||||||
PRInt32 mMaxMessageSize;
|
PRInt32 mMaxMessageSize;
|
||||||
nsresult mStopOnClose;
|
nsresult mStopOnClose;
|
||||||
PRUint16 mCloseCode;
|
PRUint16 mServerCloseCode;
|
||||||
|
nsCString mServerCloseReason;
|
||||||
|
PRUint16 mScriptCloseCode;
|
||||||
|
nsCString mScriptCloseReason;
|
||||||
|
|
||||||
// These are for the read buffers
|
// These are for the read buffers
|
||||||
PRUint8 *mFramePtr;
|
PRUint8 *mFramePtr;
|
||||||
|
@ -291,36 +291,44 @@ WebSocketChannelChild::OnAcknowledge(const PRUint32& aSize)
|
|||||||
class ServerCloseEvent : public ChannelEvent
|
class ServerCloseEvent : public ChannelEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServerCloseEvent(WebSocketChannelChild* aChild)
|
ServerCloseEvent(WebSocketChannelChild* aChild,
|
||||||
|
const PRUint16 aCode,
|
||||||
|
const nsCString &aReason)
|
||||||
: mChild(aChild)
|
: mChild(aChild)
|
||||||
|
, mCode(aCode)
|
||||||
|
, mReason(aReason)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
mChild->OnServerClose();
|
mChild->OnServerClose(mCode, mReason);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
WebSocketChannelChild* mChild;
|
WebSocketChannelChild* mChild;
|
||||||
|
PRUint16 mCode;
|
||||||
|
nsCString mReason;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebSocketChannelChild::RecvOnServerClose()
|
WebSocketChannelChild::RecvOnServerClose(const PRUint16& aCode,
|
||||||
|
const nsCString& aReason)
|
||||||
{
|
{
|
||||||
if (mEventQ.ShouldEnqueue()) {
|
if (mEventQ.ShouldEnqueue()) {
|
||||||
mEventQ.Enqueue(new ServerCloseEvent(this));
|
mEventQ.Enqueue(new ServerCloseEvent(this, aCode, aReason));
|
||||||
} else {
|
} else {
|
||||||
OnServerClose();
|
OnServerClose(aCode, aReason);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WebSocketChannelChild::OnServerClose()
|
WebSocketChannelChild::OnServerClose(const PRUint16& aCode,
|
||||||
|
const nsCString& aReason)
|
||||||
{
|
{
|
||||||
LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
|
LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
|
||||||
if (mListener) {
|
if (mListener) {
|
||||||
AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
|
AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
|
||||||
mListener->OnServerClose(mContext);
|
mListener->OnServerClose(mContext, aCode, aReason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,11 +369,11 @@ WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
WebSocketChannelChild::Close()
|
WebSocketChannelChild::Close(PRUint16 code, const nsACString & reason)
|
||||||
{
|
{
|
||||||
LOG(("WebSocketChannelChild::Close() %p\n", this));
|
LOG(("WebSocketChannelChild::Close() %p\n", this));
|
||||||
|
|
||||||
if (!mIPCOpen || !SendClose())
|
if (!mIPCOpen || !SendClose(code, nsCString(reason)))
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel,
|
|||||||
const nsACString &aOrigin,
|
const nsACString &aOrigin,
|
||||||
nsIWebSocketListener *aListener,
|
nsIWebSocketListener *aListener,
|
||||||
nsISupports *aContext);
|
nsISupports *aContext);
|
||||||
NS_SCRIPTABLE NS_IMETHOD Close();
|
NS_SCRIPTABLE NS_IMETHOD Close(PRUint16 code, const nsACString & reason);
|
||||||
NS_SCRIPTABLE NS_IMETHOD SendMsg(const nsACString &aMsg);
|
NS_SCRIPTABLE NS_IMETHOD SendMsg(const nsACString &aMsg);
|
||||||
NS_SCRIPTABLE NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
|
NS_SCRIPTABLE NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
|
||||||
NS_SCRIPTABLE NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
|
NS_SCRIPTABLE NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
|
||||||
@ -78,7 +78,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel,
|
|||||||
bool RecvOnMessageAvailable(const nsCString& aMsg);
|
bool RecvOnMessageAvailable(const nsCString& aMsg);
|
||||||
bool RecvOnBinaryMessageAvailable(const nsCString& aMsg);
|
bool RecvOnBinaryMessageAvailable(const nsCString& aMsg);
|
||||||
bool RecvOnAcknowledge(const PRUint32& aSize);
|
bool RecvOnAcknowledge(const PRUint32& aSize);
|
||||||
bool RecvOnServerClose();
|
bool RecvOnServerClose(const PRUint16& aCode, const nsCString &aReason);
|
||||||
bool RecvAsyncOpenFailed();
|
bool RecvAsyncOpenFailed();
|
||||||
|
|
||||||
void OnStart(const nsCString& aProtocol);
|
void OnStart(const nsCString& aProtocol);
|
||||||
@ -86,7 +86,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel,
|
|||||||
void OnMessageAvailable(const nsCString& aMsg);
|
void OnMessageAvailable(const nsCString& aMsg);
|
||||||
void OnBinaryMessageAvailable(const nsCString& aMsg);
|
void OnBinaryMessageAvailable(const nsCString& aMsg);
|
||||||
void OnAcknowledge(const PRUint32& aSize);
|
void OnAcknowledge(const PRUint32& aSize);
|
||||||
void OnServerClose();
|
void OnServerClose(const PRUint16& aCode, const nsCString& aReason);
|
||||||
void AsyncOpenFailed();
|
void AsyncOpenFailed();
|
||||||
|
|
||||||
ChannelEventQueue mEventQ;
|
ChannelEventQueue mEventQ;
|
||||||
|
@ -105,11 +105,11 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebSocketChannelParent::RecvClose()
|
WebSocketChannelParent::RecvClose(const PRUint16& code, const nsCString& reason)
|
||||||
{
|
{
|
||||||
LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
|
LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
|
||||||
if (mChannel) {
|
if (mChannel) {
|
||||||
nsresult rv = mChannel->Close();
|
nsresult rv = mChannel->Close(code, reason);
|
||||||
NS_ENSURE_SUCCESS(rv, true);
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -203,10 +203,11 @@ WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, PRUint32 aSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
WebSocketChannelParent::OnServerClose(nsISupports *aContext)
|
WebSocketChannelParent::OnServerClose(nsISupports *aContext,
|
||||||
|
PRUint16 code, const nsACString & reason)
|
||||||
{
|
{
|
||||||
LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
|
LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
|
||||||
if (!mIPCOpen || !SendOnServerClose()) {
|
if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -67,7 +67,7 @@ class WebSocketChannelParent : public PWebSocketParent,
|
|||||||
const nsCString& aOrigin,
|
const nsCString& aOrigin,
|
||||||
const nsCString& aProtocol,
|
const nsCString& aProtocol,
|
||||||
const bool& aSecure);
|
const bool& aSecure);
|
||||||
bool RecvClose();
|
bool RecvClose(const PRUint16 & code, const nsCString & reason);
|
||||||
bool RecvSendMsg(const nsCString& aMsg);
|
bool RecvSendMsg(const nsCString& aMsg);
|
||||||
bool RecvSendBinaryMsg(const nsCString& aMsg);
|
bool RecvSendBinaryMsg(const nsCString& aMsg);
|
||||||
bool RecvDeleteSelf();
|
bool RecvDeleteSelf();
|
||||||
|
@ -44,7 +44,7 @@ interface nsIWebSocketListener;
|
|||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
[scriptable, uuid(398a2460-a46d-11e0-8264-0800200c9a66)]
|
[scriptable, uuid(783029cf-75b5-439e-8e47-86b390202b4c)]
|
||||||
interface nsIWebSocketChannel : nsISupports
|
interface nsIWebSocketChannel : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -106,9 +106,22 @@ interface nsIWebSocketChannel : nsISupports
|
|||||||
* Close the websocket connection for writing - no more calls to sendMsg
|
* Close the websocket connection for writing - no more calls to sendMsg
|
||||||
* or sendBinaryMsg should be made after calling this. The listener object
|
* or sendBinaryMsg should be made after calling this. The listener object
|
||||||
* may receive more messages if a server close has not yet been received.
|
* may receive more messages if a server close has not yet been received.
|
||||||
|
*
|
||||||
|
* @param aCode the websocket closing handshake close code. Set to 0 if
|
||||||
|
* you are not providing a code.
|
||||||
|
* @param aReason the websocket closing handshake close reason
|
||||||
*/
|
*/
|
||||||
void close();
|
void close(in unsigned short aCode, in AUTF8String aReason);
|
||||||
|
|
||||||
|
// section 7.4.1 defines these close codes
|
||||||
|
const unsigned short CLOSE_NORMAL = 1000;
|
||||||
|
const unsigned short CLOSE_GOING_AWAY = 1001;
|
||||||
|
const unsigned short CLOSE_PROTOCOL_ERROR = 1002;
|
||||||
|
const unsigned short CLOSE_UNSUPPORTED = 1003;
|
||||||
|
const unsigned short CLOSE_TOO_LARGE = 1004;
|
||||||
|
const unsigned short CLOSE_NO_STATUS = 1005;
|
||||||
|
const unsigned short CLOSE_ABNORMAL = 1006;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use to send text message down the connection to WebSocket peer.
|
* Use to send text message down the connection to WebSocket peer.
|
||||||
*
|
*
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
* nsIWebSocketListener: passed to nsIWebSocketChannel::AsyncOpen. Receives
|
* nsIWebSocketListener: passed to nsIWebSocketChannel::AsyncOpen. Receives
|
||||||
* websocket traffic events as they arrive.
|
* websocket traffic events as they arrive.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(b0c27050-31e9-42e5-bc59-499d54b52f99)]
|
[scriptable, uuid(d74c96b2-65b3-4e39-9e39-c577de5d7a73)]
|
||||||
interface nsIWebSocketListener : nsISupports
|
interface nsIWebSocketListener : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -101,8 +101,14 @@ interface nsIWebSocketListener : nsISupports
|
|||||||
* onBinaryMessageAvailable() or onAcknowledge() will be delievered
|
* onBinaryMessageAvailable() or onAcknowledge() will be delievered
|
||||||
* to the listener after onServerClose(), though outgoing messages can still
|
* to the listener after onServerClose(), though outgoing messages can still
|
||||||
* be sent through the nsIWebSocketChannel connection.
|
* be sent through the nsIWebSocketChannel connection.
|
||||||
|
*
|
||||||
|
* @param aContext user defined context
|
||||||
|
* @param aCode the websocket closing handshake close code.
|
||||||
|
* @param aReason the websocket closing handshake close reason
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void onServerClose(in nsISupports aContext);
|
void onServerClose(in nsISupports aContext, in unsigned short aCode,
|
||||||
|
in AUTF8String aReason);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user