2010-06-17 11:34:24 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set sw=2 ts=8 et tw=80 : */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
#include "WebSocket.h"
|
|
|
|
#include "mozilla/dom/WebSocketBinding.h"
|
2011-05-23 09:46:36 -07:00
|
|
|
|
2013-08-26 19:05:20 -07:00
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jsfriendapi.h"
|
|
|
|
#include "js/OldDebugAPI.h"
|
2014-03-31 23:13:50 -07:00
|
|
|
#include "mozilla/DOMEventTargetHelper.h"
|
2014-05-23 00:47:46 -07:00
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
2010-06-17 11:34:24 -07:00
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIDOMWindow.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsXPCOM.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "nsContentUtils.h"
|
2012-07-27 07:03:27 -07:00
|
|
|
#include "nsError.h"
|
2010-06-17 11:34:24 -07:00
|
|
|
#include "nsIScriptObjectPrincipal.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsIUnicodeEncoder.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsIDOMMessageEvent.h"
|
|
|
|
#include "nsIPromptFactory.h"
|
|
|
|
#include "nsIWindowWatcher.h"
|
|
|
|
#include "nsIPrompt.h"
|
|
|
|
#include "nsIStringBundle.h"
|
|
|
|
#include "nsIConsoleService.h"
|
2014-06-30 16:00:31 -07:00
|
|
|
#include "mozilla/dom/CloseEvent.h"
|
2010-06-17 11:36:01 -07:00
|
|
|
#include "nsICryptoHash.h"
|
2010-12-21 09:05:34 -08:00
|
|
|
#include "nsJSUtils.h"
|
|
|
|
#include "nsIScriptError.h"
|
2011-05-21 18:27:52 -07:00
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsILoadGroup.h"
|
2011-05-24 23:31:59 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
2011-09-29 09:06:36 -07:00
|
|
|
#include "xpcpublic.h"
|
2011-12-07 15:19:43 -08:00
|
|
|
#include "nsContentPolicyUtils.h"
|
2014-10-07 10:16:11 -07:00
|
|
|
#include "nsDOMFile.h"
|
2012-01-26 07:55:30 -08:00
|
|
|
#include "nsWrapperCacheInlines.h"
|
2012-02-21 14:57:10 -08:00
|
|
|
#include "nsIObserverService.h"
|
2013-09-05 23:43:12 -07:00
|
|
|
#include "nsIWebSocketChannel.h"
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2014-01-04 07:02:17 -08:00
|
|
|
#define UTF_8_REPLACEMENT_CHAR static_cast<char16_t>(0xFFFD)
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
class CallDispatchConnectionCloseEvents: public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
2014-09-01 17:49:25 -07:00
|
|
|
explicit CallDispatchConnectionCloseEvents(WebSocket* aWebSocket)
|
|
|
|
: mWebSocket(aWebSocket)
|
2012-06-04 16:38:32 -07:00
|
|
|
{}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
mWebSocket->DispatchConnectionCloseEvents();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-09-10 06:48:14 -07:00
|
|
|
nsRefPtr<WebSocket> mWebSocket;
|
2012-06-04 16:38:32 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket
|
2012-06-04 16:38:32 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::PrintErrorOnConsole(const char *aBundleURI,
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t *aError,
|
|
|
|
const char16_t **aFormatStrings,
|
2012-09-10 06:48:14 -07:00
|
|
|
uint32_t aFormatStringsLen)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv;
|
2011-05-21 18:27:52 -07:00
|
|
|
nsCOMPtr<nsIStringBundleService> bundleService =
|
|
|
|
do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsCOMPtr<nsIStringBundle> strBundle;
|
|
|
|
rv = bundleService->CreateBundle(aBundleURI, getter_AddRefs(strBundle));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsCOMPtr<nsIConsoleService> console(
|
|
|
|
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-12-21 13:51:29 -08:00
|
|
|
nsCOMPtr<nsIScriptError> errorObject(
|
2011-05-21 18:27:52 -07:00
|
|
|
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
// Localize the error message
|
|
|
|
nsXPIDLString message;
|
|
|
|
if (aFormatStrings) {
|
|
|
|
rv = strBundle->FormatStringFromName(aError, aFormatStrings,
|
|
|
|
aFormatStringsLen,
|
|
|
|
getter_Copies(message));
|
2010-06-17 11:34:24 -07:00
|
|
|
} else {
|
2011-05-21 18:27:52 -07:00
|
|
|
rv = strBundle->GetStringFromName(aError, getter_Copies(message));
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-09 16:29:12 -07:00
|
|
|
rv = errorObject->InitWithWindowID(message,
|
|
|
|
NS_ConvertUTF8toUTF16(mScriptFile),
|
|
|
|
EmptyString(), mScriptLine, 0,
|
2011-12-21 13:51:29 -08:00
|
|
|
nsIScriptError::errorFlag, "Web Socket",
|
|
|
|
mInnerWindowID);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
// print the error message directly to the JS console
|
2011-12-21 13:51:29 -08:00
|
|
|
rv = console->LogMessage(errorObject);
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::CloseConnection(uint16_t aReasonCode,
|
2012-01-31 20:41:43 -08:00
|
|
|
const nsACString& aReasonString)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CLOSING ||
|
|
|
|
mReadyState == WebSocket::CLOSED) {
|
2011-06-08 05:27:11 -07:00
|
|
|
return NS_OK;
|
2012-06-04 16:38:32 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// The common case...
|
|
|
|
if (mChannel) {
|
2012-09-10 06:48:14 -07:00
|
|
|
mReadyState = WebSocket::CLOSING;
|
2012-06-04 16:38:32 -07:00
|
|
|
return mChannel->Close(aReasonCode, aReasonString);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// No channel, but not disconnected: canceled or failed early
|
|
|
|
//
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState == WebSocket::CONNECTING,
|
2012-06-04 16:38:32 -07:00
|
|
|
"Should only get here for early websocket cancel/error");
|
2011-05-21 18:27:52 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// Server won't be sending us a close code, so use what's passed in here.
|
|
|
|
mCloseEventCode = aReasonCode;
|
|
|
|
CopyUTF8toUTF16(aReasonString, mCloseEventReason);
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
mReadyState = WebSocket::CLOSING;
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// Can be called from Cancel() or Init() codepaths, so need to dispatch
|
|
|
|
// onerror/onclose asynchronously
|
|
|
|
ScheduleConnectionCloseEvents(
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr,
|
2012-06-04 16:38:32 -07:00
|
|
|
(aReasonCode == nsIWebSocketChannel::CLOSE_NORMAL ||
|
|
|
|
aReasonCode == nsIWebSocketChannel::CLOSE_GOING_AWAY) ?
|
|
|
|
NS_OK : NS_ERROR_FAILURE,
|
|
|
|
false);
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::ConsoleError()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString targetSpec;
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = mURI->GetSpec(targetSpec);
|
2011-05-21 18:27:52 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to get targetSpec");
|
|
|
|
} else {
|
|
|
|
NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t* formatStrings[] = { specUTF16.get() };
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState < WebSocket::OPEN) {
|
2011-05-21 18:27:52 -07:00
|
|
|
PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
2013-12-12 17:50:01 -08:00
|
|
|
MOZ_UTF16("connectionFailure"),
|
2011-10-10 22:50:08 -07:00
|
|
|
formatStrings, ArrayLength(formatStrings));
|
2011-05-21 18:27:52 -07:00
|
|
|
} else {
|
|
|
|
PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
2013-12-12 17:50:01 -08:00
|
|
|
MOZ_UTF16("netInterrupt"),
|
2011-10-10 22:50:08 -07:00
|
|
|
formatStrings, ArrayLength(formatStrings));
|
2011-05-21 18:27:52 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
2011-08-02 16:55:17 -07:00
|
|
|
/// todo some specific errors - like for message too large
|
2011-05-21 18:27:52 -07:00
|
|
|
return rv;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-22 00:04:08 -08:00
|
|
|
void
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::FailConnection(uint16_t aReasonCode,
|
|
|
|
const nsACString& aReasonString)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
ConsoleError();
|
|
|
|
mFailed = true;
|
2012-02-21 14:57:10 -08:00
|
|
|
CloseConnection(aReasonCode, aReasonString);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::Disconnect()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
if (mDisconnected)
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
|
|
GetLoadGroup(getter_AddRefs(loadGroup));
|
|
|
|
if (loadGroup)
|
2012-07-30 07:20:58 -07:00
|
|
|
loadGroup->RemoveRequest(this, nullptr, NS_OK);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-02-21 14:57:10 -08:00
|
|
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
|
|
if (os) {
|
|
|
|
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
|
|
|
|
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
|
|
|
|
}
|
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
// DontKeepAliveAnyMore() can release the object. So hold a reference to this
|
|
|
|
// until the end of the method.
|
2012-09-10 06:48:14 -07:00
|
|
|
nsRefPtr<WebSocket> kungfuDeathGrip = this;
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
DontKeepAliveAnyMore();
|
2012-07-30 07:20:58 -07:00
|
|
|
mChannel = nullptr;
|
2011-10-20 01:27:13 -07:00
|
|
|
mDisconnected = true;
|
2011-06-08 05:27:11 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_OK;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket::nsIWebSocketListener methods:
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2011-12-20 00:20:12 -08:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2012-06-04 16:38:32 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CLOSED) {
|
2012-06-04 16:38:32 -07:00
|
|
|
NS_ERROR("Received message after CLOSED");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::OPEN) {
|
2011-12-20 00:20:12 -08:00
|
|
|
// Dispatch New Message
|
|
|
|
nsresult rv = CreateAndDispatchMessageEvent(aMsg, isBinary);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to dispatch the message event");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// CLOSING should be the only other state where it's possible to get msgs
|
|
|
|
// from channel: Spec says to drop them.
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState == WebSocket::CLOSING,
|
2012-06-04 16:38:32 -07:00
|
|
|
"Received message while CONNECTING or CLOSED");
|
2010-06-17 11:36:01 -07:00
|
|
|
}
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-06-17 11:36:01 -07:00
|
|
|
|
2011-12-20 00:20:12 -08:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnMessageAvailable(nsISupports* aContext, const nsACString& aMsg)
|
2011-12-20 00:20:12 -08:00
|
|
|
{
|
|
|
|
return DoOnMessageAvailable(aMsg, false);
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnBinaryMessageAvailable(nsISupports* aContext,
|
|
|
|
const nsACString& aMsg)
|
2011-05-21 18:27:52 -07:00
|
|
|
{
|
2011-12-20 00:20:12 -08:00
|
|
|
return DoOnMessageAvailable(aMsg, true);
|
2011-05-21 18:27:52 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnStart(nsISupports* aContext)
|
2011-05-21 18:27:52 -07:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2012-06-04 16:38:32 -07:00
|
|
|
|
|
|
|
// This is the only function that sets OPEN, and should be called only once
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState != WebSocket::OPEN,
|
2012-06-04 16:38:32 -07:00
|
|
|
"readyState already OPEN! OnStart called twice?");
|
|
|
|
|
|
|
|
// Nothing to do if we've already closed/closing
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState != WebSocket::CONNECTING) {
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_OK;
|
2012-06-04 16:38:32 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-02-21 14:57:10 -08:00
|
|
|
// Attempt to kill "ghost" websocket: but usually too early for check to fail
|
|
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-06-04 16:38:32 -07:00
|
|
|
CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
2012-02-21 14:57:10 -08:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-12-15 15:19:01 -08:00
|
|
|
if (!mRequestedProtocolList.IsEmpty()) {
|
|
|
|
mChannel->GetProtocol(mEstablishedProtocol);
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-12-15 15:19:01 -08:00
|
|
|
mChannel->GetExtensions(mEstablishedExtensions);
|
2011-12-15 15:23:00 -08:00
|
|
|
UpdateURI();
|
2011-08-03 20:46:13 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
mReadyState = WebSocket::OPEN;
|
2012-06-04 16:38:32 -07:00
|
|
|
|
|
|
|
// Call 'onopen'
|
|
|
|
rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to dispatch the open event");
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateMustKeepAlive();
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnStop(nsISupports* aContext, nsresult aStatusCode)
|
2012-06-04 16:38:32 -07:00
|
|
|
{
|
|
|
|
// We can be CONNECTING here if connection failed.
|
|
|
|
// We can be OPEN if we have encountered a fatal protocol error
|
|
|
|
// We can be CLOSING if close() was called and/or server initiated close.
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState != WebSocket::CLOSED,
|
2012-06-04 16:38:32 -07:00
|
|
|
"Shouldn't already be CLOSED when OnStop called");
|
|
|
|
|
|
|
|
// called by network stack, not JS, so can dispatch JS events synchronously
|
|
|
|
return ScheduleConnectionCloseEvents(aContext, aStatusCode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::ScheduleConnectionCloseEvents(nsISupports* aContext,
|
|
|
|
nsresult aStatusCode,
|
|
|
|
bool sync)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2014-05-23 12:53:17 -07:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// no-op if some other code has already initiated close event
|
|
|
|
if (!mOnCloseScheduled) {
|
|
|
|
mCloseEventWasClean = NS_SUCCEEDED(aStatusCode);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
if (aStatusCode == NS_BASE_STREAM_CLOSED) {
|
|
|
|
// don't generate an error event just because of an unclean close
|
|
|
|
aStatusCode = NS_OK;
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
if (NS_FAILED(aStatusCode)) {
|
|
|
|
ConsoleError();
|
|
|
|
mFailed = true;
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
mOnCloseScheduled = true;
|
|
|
|
|
|
|
|
if (sync) {
|
|
|
|
DispatchConnectionCloseEvents();
|
|
|
|
} else {
|
2014-05-23 12:53:17 -07:00
|
|
|
NS_DispatchToCurrentThread(new CallDispatchConnectionCloseEvents(this));
|
2012-06-04 16:38:32 -07:00
|
|
|
}
|
|
|
|
}
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
if (aSize > mOutgoingBufferedAmount)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
mOutgoingBufferedAmount -= aSize;
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::OnServerClose(nsISupports *aContext, uint16_t aCode,
|
2011-10-20 01:27:13 -07:00
|
|
|
const nsACString &aReason)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState != WebSocket::CONNECTING,
|
2012-06-04 16:38:32 -07:00
|
|
|
"Received server close before connected?");
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState != WebSocket::CLOSED,
|
2012-06-04 16:38:32 -07:00
|
|
|
"Received server close after already closed!");
|
2012-02-21 14:57:13 -08:00
|
|
|
|
2012-01-31 20:41:43 -08:00
|
|
|
// store code/string for onclose DOM event
|
|
|
|
mCloseEventCode = aCode;
|
|
|
|
CopyUTF8toUTF16(aReason, mCloseEventReason);
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::OPEN) {
|
2012-06-04 16:38:32 -07:00
|
|
|
// Server initiating close.
|
2012-05-16 17:09:42 -07:00
|
|
|
// RFC 6455, 5.5.1: "When sending a Close frame in response, the endpoint
|
|
|
|
// typically echos the status code it received".
|
|
|
|
// But never send certain codes, per section 7.4.1
|
|
|
|
if (aCode == 1005 || aCode == 1006 || aCode == 1015) {
|
|
|
|
CloseConnection(0, EmptyCString());
|
|
|
|
} else {
|
|
|
|
CloseConnection(aCode, aReason);
|
|
|
|
}
|
2012-02-21 14:57:13 -08:00
|
|
|
} else {
|
2012-06-04 16:38:32 -07:00
|
|
|
// We initiated close, and server has replied: OnStop does rest of the work.
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState == WebSocket::CLOSING, "unknown state");
|
2012-02-21 14:57:13 -08:00
|
|
|
}
|
2012-01-31 20:41:43 -08:00
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket::nsIInterfaceRequestor
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::GetInterface(const nsIID& aIID, void** aResult)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CLOSED)
|
2011-06-08 05:27:11 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
|
|
|
|
aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
|
|
|
|
nsresult rv;
|
2012-03-12 17:56:07 -07:00
|
|
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
nsCOMPtr<nsIDocument> doc =
|
2012-03-12 17:56:07 -07:00
|
|
|
nsContentUtils::GetDocumentFromScriptContext(sc);
|
2011-10-20 01:27:13 -07:00
|
|
|
if (!doc)
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPromptFactory> wwatch =
|
|
|
|
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> outerWindow = doc->GetWindow();
|
|
|
|
return wwatch->GetPrompt(outerWindow, aIID, aResult);
|
|
|
|
}
|
|
|
|
|
2012-02-21 14:57:10 -08:00
|
|
|
return QueryInterface(aIID, aResult);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket
|
2010-06-17 11:34:24 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-01-06 18:53:23 -08:00
|
|
|
WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
|
2014-03-31 23:13:50 -07:00
|
|
|
: DOMEventTargetHelper(aOwnerWindow),
|
2014-01-06 18:53:23 -08:00
|
|
|
mKeepingAlive(false),
|
2012-09-10 06:48:14 -07:00
|
|
|
mCheckMustKeepAlive(true),
|
|
|
|
mOnCloseScheduled(false),
|
|
|
|
mFailed(false),
|
|
|
|
mDisconnected(false),
|
|
|
|
mCloseEventWasClean(false),
|
|
|
|
mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL),
|
|
|
|
mReadyState(WebSocket::CONNECTING),
|
|
|
|
mOutgoingBufferedAmount(0),
|
2013-05-06 12:28:13 -07:00
|
|
|
mBinaryType(dom::BinaryType::Blob),
|
2012-09-10 06:48:14 -07:00
|
|
|
mScriptLine(0),
|
|
|
|
mInnerWindowID(0)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2014-01-06 18:53:23 -08:00
|
|
|
MOZ_ASSERT(aOwnerWindow);
|
|
|
|
MOZ_ASSERT(aOwnerWindow->IsInnerWindow());
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::~WebSocket()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-12-08 00:31:14 -08:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
// If we threw during Init we never called disconnect
|
|
|
|
if (!mDisconnected) {
|
|
|
|
Disconnect();
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
JSObject*
|
2014-04-08 15:27:18 -07:00
|
|
|
WebSocket::WrapObject(JSContext* cx)
|
2012-09-10 06:48:14 -07:00
|
|
|
{
|
Bug 991742 part 6. Remove the "aScope" argument of binding Wrap() methods. r=bholley
This patch was mostly generated with this command:
find . -name "*.h" -o -name "*.cpp" | xargs sed -e 's/Binding::Wrap(aCx, aScope, this/Binding::Wrap(aCx, this/' -e 's/Binding_workers::Wrap(aCx, aScope, this/Binding_workers::Wrap(aCx, this/' -e 's/Binding::Wrap(cx, scope, this/Binding::Wrap(cx, this/' -i ""
plus a few manual fixes to dom/bindings/Codegen.py, js/xpconnect/src/event_impl_gen.py, and a few C++ files that were not caught in the search-and-replace above.
2014-04-08 15:27:17 -07:00
|
|
|
return WebSocketBinding::Wrap(cx, this);
|
2012-09-10 06:48:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// WebIDL
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Constructor:
|
|
|
|
already_AddRefed<WebSocket>
|
2012-12-03 08:07:49 -08:00
|
|
|
WebSocket::Constructor(const GlobalObject& aGlobal,
|
2012-09-10 06:48:14 -07:00
|
|
|
const nsAString& aUrl,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
Sequence<nsString> protocols;
|
2013-08-30 10:14:19 -07:00
|
|
|
return WebSocket::Constructor(aGlobal, aUrl, protocols, aRv);
|
2012-09-10 06:48:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<WebSocket>
|
2012-12-03 08:07:49 -08:00
|
|
|
WebSocket::Constructor(const GlobalObject& aGlobal,
|
2012-09-10 06:48:14 -07:00
|
|
|
const nsAString& aUrl,
|
|
|
|
const nsAString& aProtocol,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
Sequence<nsString> protocols;
|
|
|
|
protocols.AppendElement(aProtocol);
|
2013-08-30 10:14:19 -07:00
|
|
|
return WebSocket::Constructor(aGlobal, aUrl, protocols, aRv);
|
2012-09-10 06:48:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<WebSocket>
|
2012-12-03 08:07:49 -08:00
|
|
|
WebSocket::Constructor(const GlobalObject& aGlobal,
|
2012-09-10 06:48:14 -07:00
|
|
|
const nsAString& aUrl,
|
|
|
|
const Sequence<nsString>& aProtocols,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (!PrefEnabled()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-12-03 08:07:49 -08:00
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
|
2013-08-22 22:17:08 -07:00
|
|
|
do_QueryInterface(aGlobal.GetAsSupports());
|
2012-09-10 06:48:14 -07:00
|
|
|
if (!scriptPrincipal) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
|
|
|
|
if (!principal) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-08-22 22:17:08 -07:00
|
|
|
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
|
2012-09-10 06:48:14 -07:00
|
|
|
if (!sgo) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-08-22 22:17:08 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
|
2012-09-10 06:48:14 -07:00
|
|
|
if (!ownerWindow) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsTArray<nsString> protocolArray;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (protocolArray.Contains(protocolElement)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (protocolElement.FindChar(',') != -1) /* interferes w/list */ {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
protocolArray.AppendElement(protocolElement);
|
|
|
|
}
|
|
|
|
|
2014-01-06 18:53:23 -08:00
|
|
|
nsRefPtr<WebSocket> webSocket = new WebSocket(ownerWindow);
|
2014-06-16 11:08:00 -07:00
|
|
|
nsresult rv = webSocket->Init(aGlobal.Context(), principal,
|
2013-08-30 10:14:19 -07:00
|
|
|
aUrl, protocolArray);
|
2012-09-10 06:48:14 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return webSocket.forget();
|
|
|
|
}
|
|
|
|
|
2013-08-01 18:29:05 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(WebSocket)
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(WebSocket)
|
2012-02-16 08:45:25 -08:00
|
|
|
bool isBlack = tmp->IsBlack();
|
|
|
|
if (isBlack|| tmp->mKeepingAlive) {
|
2012-01-26 07:55:30 -08:00
|
|
|
if (tmp->mListenerManager) {
|
2012-10-16 18:22:02 -07:00
|
|
|
tmp->mListenerManager->MarkForCC();
|
2012-01-26 07:55:30 -08:00
|
|
|
}
|
2012-03-14 07:22:10 -07:00
|
|
|
if (!isBlack && tmp->PreservingWrapper()) {
|
2013-09-08 20:28:48 -07:00
|
|
|
// This marks the wrapper black.
|
|
|
|
tmp->GetWrapper();
|
2012-02-16 08:45:25 -08:00
|
|
|
}
|
2012-01-26 07:55:30 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(WebSocket)
|
2012-01-26 07:55:30 -08:00
|
|
|
return tmp->IsBlack();
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(WebSocket)
|
2012-01-26 07:55:30 -08:00
|
|
|
return tmp->IsBlack();
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WebSocket,
|
2014-03-31 23:13:50 -07:00
|
|
|
DOMEventTargetHelper)
|
2012-01-26 07:55:30 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WebSocket,
|
2014-03-31 23:13:50 -07:00
|
|
|
DOMEventTargetHelper)
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mURI)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
|
2010-06-17 11:34:24 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WebSocket,
|
2014-03-31 23:13:50 -07:00
|
|
|
DOMEventTargetHelper)
|
2011-10-20 01:27:13 -07:00
|
|
|
tmp->Disconnect();
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mURI)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)
|
2010-06-17 11:34:24 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WebSocket)
|
2011-10-20 01:27:13 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebSocketListener)
|
2012-02-21 14:57:10 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2011-10-20 01:27:13 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
2014-03-31 23:13:50 -07:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2014-03-31 23:13:50 -07:00
|
|
|
NS_IMPL_ADDREF_INHERITED(WebSocket, DOMEventTargetHelper)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(WebSocket, DOMEventTargetHelper)
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-03-12 17:56:07 -07:00
|
|
|
void
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::DisconnectFromOwner()
|
2012-03-12 17:56:07 -07:00
|
|
|
{
|
2014-03-31 23:13:50 -07:00
|
|
|
DOMEventTargetHelper::DisconnectFromOwner();
|
2012-06-04 16:38:32 -07:00
|
|
|
CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
2012-03-12 17:56:07 -07:00
|
|
|
DontKeepAliveAnyMore();
|
|
|
|
}
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket:: initialization
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult
|
|
|
|
WebSocket::Init(JSContext* aCx,
|
|
|
|
nsIPrincipal* aPrincipal,
|
|
|
|
const nsAString& aURL,
|
|
|
|
nsTArray<nsString>& aProtocolArray)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(aPrincipal);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2010-12-08 14:12:51 -08:00
|
|
|
if (!PrefEnabled()) {
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
mPrincipal = aPrincipal;
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// Attempt to kill "ghost" websocket: but usually too early for check to fail
|
|
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// Shut down websocket if window is frozen or destroyed (only needed for
|
|
|
|
// "ghost" websockets--see bug 696085)
|
|
|
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
|
|
NS_ENSURE_STATE(os);
|
|
|
|
rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-12-03 00:24:17 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
unsigned lineno;
|
2014-02-25 07:43:14 -08:00
|
|
|
JS::AutoFilename file;
|
|
|
|
if (JS::DescribeScriptedCaller(aCx, &file, &lineno)) {
|
|
|
|
mScriptFile = file.get();
|
2012-09-10 06:48:14 -07:00
|
|
|
mScriptLine = lineno;
|
2010-12-03 00:24:17 -08:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// Get WindowID
|
|
|
|
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aCx);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// parses the url
|
|
|
|
rv = ParseURL(PromiseFlatString(aURL));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// Don't allow https:// to open ws://
|
|
|
|
if (!mSecure &&
|
|
|
|
!Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
|
|
|
|
false)) {
|
|
|
|
// Confirmed we are opening plain ws:// and want to prevent this from a
|
2014-07-18 12:04:28 -07:00
|
|
|
// secure context (e.g. https). Check the principal's uri to determine if
|
|
|
|
// we were loaded from https.
|
2014-08-19 12:02:05 -07:00
|
|
|
nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
|
2014-07-18 12:04:28 -07:00
|
|
|
if (globalObject) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal(globalObject->PrincipalOrNull());
|
|
|
|
if (principal) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
principal->GetURI(getter_AddRefs(uri));
|
|
|
|
if (uri) {
|
|
|
|
bool originIsHttps = false;
|
|
|
|
rv = uri->SchemeIs("https", &originIsHttps);
|
|
|
|
NS_ENSURE_SUCCESS(rv,rv);
|
|
|
|
if (originIsHttps) {
|
|
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-10 06:48:14 -07:00
|
|
|
}
|
|
|
|
}
|
2011-08-03 09:42:02 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// 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) {
|
2014-01-04 07:02:17 -08:00
|
|
|
if (aProtocolArray[index][i] < static_cast<char16_t>(0x0021) ||
|
|
|
|
aProtocolArray[index][i] > static_cast<char16_t>(0x007E))
|
2011-08-03 09:42:02 -07:00
|
|
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
|
|
}
|
2012-09-10 06:48:14 -07:00
|
|
|
|
|
|
|
if (!mRequestedProtocolList.IsEmpty()) {
|
2014-05-21 20:48:50 -07:00
|
|
|
mRequestedProtocolList.AppendLiteral(", ");
|
2012-09-10 06:48:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
AppendUTF16toUTF8(aProtocolArray[index], mRequestedProtocolList);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check content policy.
|
|
|
|
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
2014-07-18 12:04:28 -07:00
|
|
|
nsCOMPtr<nsIDocument> originDoc = nsContentUtils::GetDocumentFromScriptContext(sc);
|
2014-08-13 13:26:17 -07:00
|
|
|
mOriginDocument = do_GetWeakReference(originDoc);
|
2012-09-10 06:48:14 -07:00
|
|
|
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
|
|
|
|
mURI,
|
|
|
|
mPrincipal,
|
|
|
|
originDoc,
|
|
|
|
EmptyCString(),
|
|
|
|
nullptr,
|
|
|
|
&shouldLoad,
|
|
|
|
nsContentUtils::GetContentPolicy(),
|
|
|
|
nsContentUtils::GetSecurityManager());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (NS_CP_REJECTED(shouldLoad)) {
|
|
|
|
// Disallowed by content policy.
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
2011-08-03 09:42:02 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// the constructor should throw a SYNTAX_ERROR only if it fails to parse the
|
|
|
|
// url parameter, so don't throw if EstablishConnection fails, and call
|
|
|
|
// onerror/onclose asynchronously
|
|
|
|
if (NS_FAILED(EstablishConnection())) {
|
|
|
|
FailConnection(nsIWebSocketChannel::CLOSE_ABNORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket methods:
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
class nsAutoCloseWS
|
|
|
|
{
|
|
|
|
public:
|
2014-09-01 17:49:25 -07:00
|
|
|
explicit nsAutoCloseWS(WebSocket* aWebSocket)
|
2011-10-20 01:27:13 -07:00
|
|
|
: mWebSocket(aWebSocket)
|
|
|
|
{}
|
|
|
|
|
|
|
|
~nsAutoCloseWS()
|
|
|
|
{
|
2011-12-15 15:19:01 -08:00
|
|
|
if (!mWebSocket->mChannel) {
|
2012-01-31 20:41:43 -08:00
|
|
|
mWebSocket->CloseConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR);
|
2011-10-20 01:27:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
2012-09-10 06:48:14 -07:00
|
|
|
nsRefPtr<WebSocket> mWebSocket;
|
2011-10-20 01:27:13 -07:00
|
|
|
};
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::EstablishConnection()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-12-15 15:19:01 -08:00
|
|
|
NS_ABORT_IF_FALSE(!mChannel, "mChannel should be null");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
nsCOMPtr<nsIWebSocketChannel> wsChannel;
|
|
|
|
nsAutoCloseWS autoClose(this);
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv;
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
if (mSecure) {
|
|
|
|
wsChannel =
|
|
|
|
do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
|
|
|
|
} else {
|
|
|
|
wsChannel =
|
|
|
|
do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = wsChannel->SetNotificationCallbacks(this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// add ourselves to the document's load group and
|
|
|
|
// provide the http stack the loadgroup info too
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
|
|
rv = GetLoadGroup(getter_AddRefs(loadGroup));
|
|
|
|
if (loadGroup) {
|
|
|
|
rv = wsChannel->SetLoadGroup(loadGroup);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-07-30 07:20:58 -07:00
|
|
|
rv = loadGroup->AddRequest(this, nullptr);
|
2011-10-20 01:27:13 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2014-08-13 13:26:17 -07:00
|
|
|
// manually adding loadinfo to the channel since it
|
|
|
|
// was not set during channel creation.
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mOriginDocument);
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo =
|
|
|
|
new LoadInfo(mPrincipal,
|
|
|
|
doc,
|
|
|
|
nsILoadInfo::SEC_NORMAL,
|
|
|
|
nsIContentPolicy::TYPE_WEBSOCKET);
|
|
|
|
rv = wsChannel->SetLoadInfo(loadInfo);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
if (!mRequestedProtocolList.IsEmpty()) {
|
|
|
|
rv = wsChannel->SetProtocol(mRequestedProtocolList);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-08-02 16:55:17 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-10-20 01:27:13 -07:00
|
|
|
nsCString asciiOrigin;
|
|
|
|
rv = nsContentUtils::GetASCIIOrigin(mPrincipal, asciiOrigin);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
ToLowerCase(asciiOrigin);
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
rv = wsChannel->AsyncOpen(mURI, asciiOrigin, this, nullptr);
|
2011-10-20 01:27:13 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-12-15 15:19:01 -08:00
|
|
|
mChannel = wsChannel;
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
void
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::DispatchConnectionCloseEvents()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
mReadyState = WebSocket::CLOSED;
|
2012-06-04 16:38:32 -07:00
|
|
|
|
|
|
|
// Call 'onerror' if needed
|
|
|
|
if (mFailed) {
|
|
|
|
nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to dispatch the error event");
|
|
|
|
}
|
2010-06-17 11:36:01 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = CreateAndDispatchCloseEvent(mCloseEventWasClean, mCloseEventCode,
|
|
|
|
mCloseEventReason);
|
2012-06-04 16:38:32 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to dispatch the close event");
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateMustKeepAlive();
|
|
|
|
Disconnect();
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2010-06-17 11:36:01 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::CreateAndDispatchSimpleEvent(const nsString& aName)
|
2010-06-17 11:36:01 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
2010-06-17 11:36:01 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
2013-03-09 03:34:29 -08:00
|
|
|
rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
|
|
|
// it doesn't bubble, and it isn't cancelable
|
2011-10-17 07:59:28 -07:00
|
|
|
rv = event->InitEvent(aName, false, false);
|
2010-06-17 11:36:01 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-22 00:18:08 -08:00
|
|
|
event->SetTrusted(true);
|
2010-06-17 11:36:01 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
|
|
|
|
bool isBinary)
|
2010-06-17 11:36:01 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-10-20 01:27:13 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
2011-12-15 15:19:01 -08:00
|
|
|
if (NS_FAILED(rv))
|
2010-06-17 11:36:01 -07:00
|
|
|
return NS_OK;
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2014-06-19 00:21:14 -07:00
|
|
|
AutoJSAPI jsapi;
|
2014-06-25 03:17:17 -07:00
|
|
|
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
|
2014-05-23 00:47:46 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
JSContext* cx = jsapi.cx();
|
2011-05-23 11:53:31 -07:00
|
|
|
|
2011-12-15 15:19:01 -08:00
|
|
|
// Create appropriate JS object for message
|
2013-05-07 19:34:56 -07:00
|
|
|
JS::Rooted<JS::Value> jsData(cx);
|
2013-05-22 09:05:28 -07:00
|
|
|
if (isBinary) {
|
|
|
|
if (mBinaryType == dom::BinaryType::Blob) {
|
2014-10-08 09:15:22 -07:00
|
|
|
rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
|
2013-05-22 09:05:28 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else if (mBinaryType == dom::BinaryType::Arraybuffer) {
|
|
|
|
JS::Rooted<JSObject*> arrayBuf(cx);
|
|
|
|
rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
jsData = OBJECT_TO_JSVAL(arrayBuf);
|
2011-12-15 15:19:01 -08:00
|
|
|
} else {
|
2013-05-22 09:05:28 -07:00
|
|
|
NS_RUNTIMEABORT("Unknown binary type!");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
2013-05-22 09:05:28 -07:00
|
|
|
} else {
|
|
|
|
// JS string
|
|
|
|
NS_ConvertUTF8toUTF16 utf16Data(aData);
|
|
|
|
JSString* jsString;
|
|
|
|
jsString = JS_NewUCStringCopyN(cx, utf16Data.get(), utf16Data.Length());
|
|
|
|
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
jsData = STRING_TO_JSVAL(jsString);
|
2011-05-23 11:53:31 -07:00
|
|
|
}
|
|
|
|
|
2010-06-17 11:36:01 -07:00
|
|
|
// create an event that uses the MessageEvent interface,
|
|
|
|
// which does not bubble, is not cancelable, and has no default action
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
2013-03-09 03:34:29 -08:00
|
|
|
rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
|
|
|
|
rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
|
2011-10-17 07:59:28 -07:00
|
|
|
false, false,
|
2011-05-23 11:53:31 -07:00
|
|
|
jsData,
|
2011-05-21 18:27:52 -07:00
|
|
|
mUTF16Origin,
|
2012-07-30 07:20:58 -07:00
|
|
|
EmptyString(), nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-22 00:18:08 -08:00
|
|
|
event->SetTrusted(true);
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
|
|
|
|
uint16_t aCode,
|
|
|
|
const nsString &aReason)
|
2010-06-17 11:36:01 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:36:01 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
2010-06-17 11:36:01 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-06-30 16:00:31 -07:00
|
|
|
CloseEventInit init;
|
|
|
|
init.mBubbles = false;
|
|
|
|
init.mCancelable = false;
|
|
|
|
init.mWasClean = aWasClean;
|
|
|
|
init.mCode = aCode;
|
|
|
|
init.mReason = aReason;
|
2010-06-17 11:36:01 -07:00
|
|
|
|
2014-06-30 16:00:31 -07:00
|
|
|
nsRefPtr<CloseEvent> event =
|
|
|
|
CloseEvent::Constructor(this, NS_LITERAL_STRING("close"), init);
|
2012-12-22 00:18:08 -08:00
|
|
|
event->SetTrusted(true);
|
2010-06-17 11:36:01 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
2010-06-17 11:36:01 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2014-02-06 10:28:14 -08:00
|
|
|
WebSocket::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
|
2010-12-08 14:12:51 -08:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
return Preferences::GetBool("network.websocket.enabled", true);
|
2010-12-08 14:12:51 -08:00
|
|
|
}
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::ParseURL(const nsString& aURL)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(!aURL.IsEmpty(), NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
|
2010-06-17 11:34:24 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsCOMPtr<nsIURL> parsedURL = do_QueryInterface(uri, &rv);
|
2010-06-17 11:34:24 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString fragment;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetRef(fragment);
|
|
|
|
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && fragment.IsEmpty(),
|
|
|
|
NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString scheme;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetScheme(scheme);
|
|
|
|
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !scheme.IsEmpty(),
|
|
|
|
NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString host;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetAsciiHost(host);
|
|
|
|
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !host.IsEmpty(), NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t port;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetPort(&port);
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
|
|
|
rv = NS_CheckPortSafety(port, scheme.get());
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString filePath;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetFilePath(filePath);
|
|
|
|
if (filePath.IsEmpty()) {
|
2014-05-26 11:55:08 -07:00
|
|
|
filePath.Assign('/');
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString query;
|
2010-06-17 11:34:24 -07:00
|
|
|
rv = parsedURL->GetQuery(query);
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
|
|
|
if (scheme.LowerCaseEqualsLiteral("ws")) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mSecure = false;
|
2010-06-17 11:34:24 -07:00
|
|
|
mPort = (port == -1) ? DEFAULT_WS_SCHEME_PORT : port;
|
|
|
|
} else if (scheme.LowerCaseEqualsLiteral("wss")) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mSecure = true;
|
2010-06-17 11:34:24 -07:00
|
|
|
mPort = (port == -1) ? DEFAULT_WSS_SCHEME_PORT : port;
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
|
|
}
|
|
|
|
|
2011-08-03 17:32:23 -07:00
|
|
|
rv = nsContentUtils::GetUTFOrigin(parsedURL, mUTF16Origin);
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
mAsciiHost = host;
|
|
|
|
ToLowerCase(mAsciiHost);
|
|
|
|
|
|
|
|
mResource = filePath;
|
|
|
|
if (!query.IsEmpty()) {
|
2014-05-21 20:48:51 -07:00
|
|
|
mResource.Append('?');
|
2010-06-17 11:34:24 -07:00
|
|
|
mResource.Append(query);
|
|
|
|
}
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t length = mResource.Length();
|
|
|
|
uint32_t i;
|
2010-06-17 11:34:24 -07:00
|
|
|
for (i = 0; i < length; ++i) {
|
2014-01-04 07:02:17 -08:00
|
|
|
if (mResource[i] < static_cast<char16_t>(0x0021) ||
|
|
|
|
mResource[i] > static_cast<char16_t>(0x007E)) {
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mOriginalURL = aURL;
|
|
|
|
mURI = parsedURL;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-06-27 14:09:29 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
2010-07-21 09:05:56 -07:00
|
|
|
// Methods that keep alive the WebSocket object when:
|
|
|
|
// 1. the object has registered event listeners that can be triggered
|
|
|
|
// ("strong event listeners");
|
|
|
|
// 2. there are outgoing not sent messages.
|
2010-06-27 14:09:29 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::UpdateMustKeepAlive()
|
2010-06-27 14:09:29 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-07-21 09:05:56 -07:00
|
|
|
if (!mCheckMustKeepAlive) {
|
2010-06-27 14:09:29 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool shouldKeepAlive = false;
|
2010-07-21 09:05:56 -07:00
|
|
|
|
|
|
|
if (mListenerManager) {
|
|
|
|
switch (mReadyState)
|
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
case WebSocket::CONNECTING:
|
2010-07-21 09:05:56 -07:00
|
|
|
{
|
2012-10-28 21:33:51 -07:00
|
|
|
if (mListenerManager->HasListenersFor(nsGkAtoms::onopen) ||
|
|
|
|
mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
|
|
|
|
mListenerManager->HasListenersFor(nsGkAtoms::onerror) ||
|
|
|
|
mListenerManager->HasListenersFor(nsGkAtoms::onclose)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
shouldKeepAlive = true;
|
2010-07-21 09:05:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
case WebSocket::OPEN:
|
|
|
|
case WebSocket::CLOSING:
|
2010-07-21 09:05:56 -07:00
|
|
|
{
|
2012-10-28 21:33:51 -07:00
|
|
|
if (mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
|
|
|
|
mListenerManager->HasListenersFor(nsGkAtoms::onerror) ||
|
|
|
|
mListenerManager->HasListenersFor(nsGkAtoms::onclose) ||
|
2011-10-20 01:27:13 -07:00
|
|
|
mOutgoingBufferedAmount != 0) {
|
2011-10-17 07:59:28 -07:00
|
|
|
shouldKeepAlive = true;
|
2010-07-21 09:05:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
case WebSocket::CLOSED:
|
2010-07-21 09:05:56 -07:00
|
|
|
{
|
2012-06-04 16:38:32 -07:00
|
|
|
shouldKeepAlive = false;
|
2010-07-21 09:05:56 -07:00
|
|
|
}
|
2010-06-27 14:09:29 -07:00
|
|
|
}
|
|
|
|
}
|
2010-07-21 09:05:56 -07:00
|
|
|
|
|
|
|
if (mKeepingAlive && !shouldKeepAlive) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mKeepingAlive = false;
|
2013-04-19 15:18:33 -07:00
|
|
|
static_cast<EventTarget*>(this)->Release();
|
2010-07-21 09:05:56 -07:00
|
|
|
} else if (!mKeepingAlive && shouldKeepAlive) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mKeepingAlive = true;
|
2013-04-19 15:18:33 -07:00
|
|
|
static_cast<EventTarget*>(this)->AddRef();
|
2010-07-21 09:05:56 -07:00
|
|
|
}
|
2010-06-27 14:09:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::DontKeepAliveAnyMore()
|
2010-06-27 14:09:29 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-07-21 09:05:56 -07:00
|
|
|
if (mKeepingAlive) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mKeepingAlive = false;
|
2013-04-19 15:18:33 -07:00
|
|
|
static_cast<EventTarget*>(this)->Release();
|
2010-06-27 14:09:29 -07:00
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
mCheckMustKeepAlive = false;
|
2010-06-27 14:09:29 -07:00
|
|
|
}
|
|
|
|
|
2011-12-15 15:23:00 -08:00
|
|
|
nsresult
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::UpdateURI()
|
2011-12-15 15:23:00 -08:00
|
|
|
{
|
|
|
|
// Check for Redirections
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString spec;
|
2011-12-15 15:23:00 -08:00
|
|
|
rv = uri->GetSpec(spec);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
CopyUTF8toUTF16(spec, mEffectiveURL);
|
|
|
|
|
|
|
|
bool isWSS = false;
|
|
|
|
rv = uri->SchemeIs("wss", &isWSS);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mSecure = isWSS ? true : false;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-04-16 14:16:08 -07:00
|
|
|
void
|
2013-05-23 04:41:32 -07:00
|
|
|
WebSocket::EventListenerAdded(nsIAtom* aType)
|
2013-04-16 14:16:08 -07:00
|
|
|
{
|
2013-05-23 04:41:32 -07:00
|
|
|
UpdateMustKeepAlive();
|
2010-06-27 14:09:29 -07:00
|
|
|
}
|
|
|
|
|
2013-04-16 14:16:08 -07:00
|
|
|
void
|
2013-05-23 04:41:32 -07:00
|
|
|
WebSocket::EventListenerRemoved(nsIAtom* aType)
|
2013-04-16 14:16:08 -07:00
|
|
|
{
|
2013-05-23 04:41:32 -07:00
|
|
|
UpdateMustKeepAlive();
|
2013-04-16 14:16:08 -07:00
|
|
|
}
|
2013-05-23 04:41:32 -07:00
|
|
|
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket - methods
|
2010-06-17 11:34:24 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// webIDL: readonly attribute DOMString url
|
|
|
|
void
|
|
|
|
WebSocket::GetUrl(nsAString& aURL)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-12-15 15:23:00 -08:00
|
|
|
if (mEffectiveURL.IsEmpty()) {
|
|
|
|
aURL = mOriginalURL;
|
|
|
|
} else {
|
|
|
|
aURL = mEffectiveURL;
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// webIDL: readonly attribute DOMString extensions;
|
|
|
|
void
|
|
|
|
WebSocket::GetExtensions(nsAString& aExtensions)
|
2011-08-03 20:46:13 -07:00
|
|
|
{
|
|
|
|
CopyUTF8toUTF16(mEstablishedExtensions, aExtensions);
|
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// webIDL: readonly attribute DOMString protocol;
|
|
|
|
void
|
|
|
|
WebSocket::GetProtocol(nsAString& aProtocol)
|
2011-05-21 18:27:52 -07:00
|
|
|
{
|
2011-08-03 09:42:02 -07:00
|
|
|
CopyUTF8toUTF16(mEstablishedProtocol, aProtocol);
|
2011-05-21 18:27:52 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// webIDL: void send(DOMString data);
|
|
|
|
void
|
|
|
|
WebSocket::Send(const nsAString& aData,
|
|
|
|
ErrorResult& aRv)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_ConvertUTF16toUTF8 msgString(aData);
|
|
|
|
Send(nullptr, msgString, msgString.Length(), false, aRv);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
void
|
2014-10-08 09:15:22 -07:00
|
|
|
WebSocket::Send(DOMFile& aData,
|
2014-10-07 10:16:11 -07:00
|
|
|
ErrorResult& aRv)
|
2011-12-15 15:19:01 -08:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> msgStream;
|
2014-10-08 09:15:22 -07:00
|
|
|
nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
|
2012-09-10 06:48:14 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
uint64_t msgLength;
|
2014-10-08 09:15:22 -07:00
|
|
|
rv = aData.GetSize(&msgLength);
|
2012-09-10 06:48:14 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
|
2012-09-27 23:57:33 -07:00
|
|
|
if (msgLength > UINT32_MAX) {
|
2012-09-10 06:48:14 -07:00
|
|
|
aRv.Throw(NS_ERROR_FILE_TOO_BIG);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Send(msgStream, EmptyCString(), msgLength, true, aRv);
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
void
|
2013-08-05 10:40:01 -07:00
|
|
|
WebSocket::Send(const ArrayBuffer& aData,
|
2012-09-10 06:48:14 -07:00
|
|
|
ErrorResult& aRv)
|
2011-08-03 12:15:25 -07:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
|
|
|
|
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff
2014-05-27 14:32:41 -07:00
|
|
|
aData.ComputeLengthAndData();
|
|
|
|
|
|
|
|
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
uint32_t len = aData.Length();
|
|
|
|
char* data = reinterpret_cast<char*>(aData.Data());
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsDependentCSubstring msgString(data, len);
|
|
|
|
Send(nullptr, msgString, len, true, aRv);
|
|
|
|
}
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
void
|
2013-08-05 10:40:01 -07:00
|
|
|
WebSocket::Send(const ArrayBufferView& aData,
|
2012-09-10 06:48:14 -07:00
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-12-15 15:19:01 -08:00
|
|
|
|
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff
2014-05-27 14:32:41 -07:00
|
|
|
aData.ComputeLengthAndData();
|
|
|
|
|
|
|
|
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
uint32_t len = aData.Length();
|
|
|
|
char* data = reinterpret_cast<char*>(aData.Data());
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsDependentCSubstring msgString(data, len);
|
|
|
|
Send(nullptr, msgString, len, true, aRv);
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
void
|
|
|
|
WebSocket::Send(nsIInputStream* aMsgStream,
|
|
|
|
const nsACString& aMsgString,
|
|
|
|
uint32_t aMsgLength,
|
|
|
|
bool aIsBinary,
|
|
|
|
ErrorResult& aRv)
|
2011-12-15 15:19:01 -08:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CONNECTING) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// Always increment outgoing buffer len, even if closed
|
|
|
|
mOutgoingBufferedAmount += aMsgLength;
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CLOSING ||
|
|
|
|
mReadyState == WebSocket::CLOSED) {
|
|
|
|
return;
|
|
|
|
}
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState == WebSocket::OPEN,
|
|
|
|
"Unknown state in WebSocket::Send");
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsresult rv;
|
|
|
|
if (aMsgStream) {
|
|
|
|
rv = mChannel->SendBinaryStream(aMsgStream, aMsgLength);
|
|
|
|
} else {
|
|
|
|
if (aIsBinary) {
|
|
|
|
rv = mChannel->SendBinaryMsg(aMsgString);
|
|
|
|
} else {
|
|
|
|
rv = mChannel->SendMsg(aMsgString);
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
2011-12-15 15:19:01 -08:00
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
UpdateMustKeepAlive();
|
2011-12-15 15:19:01 -08:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
// webIDL: void close(optional unsigned short code, optional DOMString reason):
|
|
|
|
void
|
|
|
|
WebSocket::Close(const Optional<uint16_t>& aCode,
|
|
|
|
const Optional<nsAString>& aReason,
|
|
|
|
ErrorResult& aRv)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2011-08-03 12:15:25 -07:00
|
|
|
|
|
|
|
// the reason code is optional, but if provided it must be in a specific range
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t closeCode = 0;
|
2012-09-10 06:48:14 -07:00
|
|
|
if (aCode.WasPassed()) {
|
|
|
|
if (aCode.Value() != 1000 && (aCode.Value() < 3000 || aCode.Value() > 4999)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
|
|
|
return;
|
2012-01-31 20:41:43 -08:00
|
|
|
}
|
2012-09-10 06:48:14 -07:00
|
|
|
closeCode = aCode.Value();
|
2011-08-03 12:15:25 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
nsCString closeReason;
|
|
|
|
if (aReason.WasPassed()) {
|
|
|
|
CopyUTF16toUTF8(aReason.Value(), closeReason);
|
2011-08-03 12:15:25 -07:00
|
|
|
|
|
|
|
// The API requires the UTF-8 string to be 123 or less bytes
|
2012-01-31 20:41:43 -08:00
|
|
|
if (closeReason.Length() > 123) {
|
2012-09-10 06:48:14 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return;
|
2012-01-31 20:41:43 -08:00
|
|
|
}
|
2011-08-03 12:15:25 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CLOSING ||
|
|
|
|
mReadyState == WebSocket::CLOSED) {
|
|
|
|
return;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
if (mReadyState == WebSocket::CONNECTING) {
|
2012-01-31 20:41:43 -08:00
|
|
|
FailConnection(closeCode, closeReason);
|
2012-09-10 06:48:14 -07:00
|
|
|
return;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 06:48:14 -07:00
|
|
|
MOZ_ASSERT(mReadyState == WebSocket::OPEN);
|
2012-01-31 20:41:43 -08:00
|
|
|
CloseConnection(closeCode, closeReason);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
2012-02-21 14:57:10 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket::nsIObserver
|
2012-02-21 14:57:10 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::Observe(nsISupports* aSubject,
|
|
|
|
const char* aTopic,
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t* aData)
|
2012-02-21 14:57:10 -08:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
if ((mReadyState == WebSocket::CLOSING) ||
|
|
|
|
(mReadyState == WebSocket::CLOSED)) {
|
2012-02-21 14:57:10 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
|
2012-03-12 17:56:07 -07:00
|
|
|
if (!GetOwner() || window != GetOwner()) {
|
2012-02-21 14:57:10 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
|
|
|
|
(strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0))
|
|
|
|
{
|
2012-06-04 16:38:32 -07:00
|
|
|
CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
2012-02-21 14:57:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-09-10 06:48:14 -07:00
|
|
|
// WebSocket::nsIRequest
|
2011-05-21 18:27:52 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
2010-06-17 11:34:24 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::GetName(nsACString& aName)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-10-20 01:27:13 -07:00
|
|
|
CopyUTF16toUTF8(mOriginalURL, aName);
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::IsPending(bool* aValue)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2012-09-10 06:48:14 -07:00
|
|
|
*aValue = (mReadyState != WebSocket::CLOSED);
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::GetStatus(nsresult* aStatus)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
*aStatus = NS_OK;
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-08-07 06:44:19 -07:00
|
|
|
// Window closed, stop/reload button pressed, user navigated away from page, etc.
|
2010-06-17 11:34:24 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::Cancel(nsresult aStatus)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2012-06-04 16:38:32 -07:00
|
|
|
if (mReadyState == CLOSING || mReadyState == CLOSED) {
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_OK;
|
2012-06-04 16:38:32 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
ConsoleError();
|
2012-06-04 16:38:32 -07:00
|
|
|
|
2012-01-31 20:41:43 -08:00
|
|
|
return CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::Suspend()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::Resume()
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
2010-06-17 11:34:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::GetLoadGroup(nsILoadGroup** aLoadGroup)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
*aLoadGroup = nullptr;
|
2011-05-21 18:27:52 -07:00
|
|
|
|
2012-03-12 17:56:07 -07:00
|
|
|
nsresult rv;
|
|
|
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
2011-05-21 18:27:52 -07:00
|
|
|
nsCOMPtr<nsIDocument> doc =
|
2012-03-12 17:56:07 -07:00
|
|
|
nsContentUtils::GetDocumentFromScriptContext(sc);
|
2011-05-21 18:27:52 -07:00
|
|
|
|
|
|
|
if (doc) {
|
2014-03-15 12:00:15 -07:00
|
|
|
*aLoadGroup = doc->GetDocumentLoadGroup().take();
|
2011-05-21 18:27:52 -07:00
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-21 18:27:52 -07:00
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
2011-05-21 18:27:52 -07:00
|
|
|
{
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2010-06-17 11:34:24 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::GetLoadFlags(nsLoadFlags* aLoadFlags)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
*aLoadFlags = nsIRequest::LOAD_BACKGROUND;
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-09-10 06:48:14 -07:00
|
|
|
WebSocket::SetLoadFlags(nsLoadFlags aLoadFlags)
|
2010-06-17 11:34:24 -07:00
|
|
|
{
|
2011-05-21 18:27:52 -07:00
|
|
|
// we won't change the load flags at all.
|
2010-06-17 11:34:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-09-10 06:48:14 -07:00
|
|
|
|
|
|
|
} // dom namespace
|
|
|
|
} // mozilla namespace
|