зеркало из https://github.com/mozilla/pjs.git
Bug 696085: WebSocket connection opening across page loads r=smaug
This commit is contained in:
Родитель
cde59a53a2
Коммит
80872a0825
|
@ -84,6 +84,7 @@
|
||||||
#include "nsDOMFile.h"
|
#include "nsDOMFile.h"
|
||||||
#include "nsWrapperCacheInlines.h"
|
#include "nsWrapperCacheInlines.h"
|
||||||
#include "nsDOMEventTargetHelper.h"
|
#include "nsDOMEventTargetHelper.h"
|
||||||
|
#include "nsIObserverService.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ using namespace mozilla;
|
||||||
#define TRUE_OR_FAIL_WEBSOCKET(x, ret) \
|
#define TRUE_OR_FAIL_WEBSOCKET(x, ret) \
|
||||||
PR_BEGIN_MACRO \
|
PR_BEGIN_MACRO \
|
||||||
if (NS_UNLIKELY(!(x))) { \
|
if (NS_UNLIKELY(!(x))) { \
|
||||||
NS_WARNING("ENSURE_TRUE_AND_FAIL_IF_FAILED(" #x ") failed"); \
|
NS_WARNING("TRUE_OR_FAIL_WEBSOCKET(" #x ") failed"); \
|
||||||
FailConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR); \
|
FailConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR); \
|
||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
|
@ -227,10 +228,9 @@ nsWebSocket::FailConnection(PRUint16 aReasonCode,
|
||||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||||
ConsoleError();
|
ConsoleError();
|
||||||
|
|
||||||
nsresult rv = CloseConnection(aReasonCode, aReasonString);
|
CloseConnection(aReasonCode, aReasonString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
|
nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
NS_WARNING("Failed to dispatch the error event");
|
NS_WARNING("Failed to dispatch the error event");
|
||||||
|
|
||||||
|
@ -250,6 +250,12 @@ nsWebSocket::Disconnect()
|
||||||
if (loadGroup)
|
if (loadGroup)
|
||||||
loadGroup->RemoveRequest(this, nsnull, NS_OK);
|
loadGroup->RemoveRequest(this, nsnull, NS_OK);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||||
|
if (os) {
|
||||||
|
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
|
||||||
|
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
|
||||||
|
}
|
||||||
|
|
||||||
// DontKeepAliveAnyMore() can release the object. So hold a reference to this
|
// DontKeepAliveAnyMore() can release the object. So hold a reference to this
|
||||||
// until the end of the method.
|
// until the end of the method.
|
||||||
nsRefPtr<nsWebSocket> kungfuDeathGrip = this;
|
nsRefPtr<nsWebSocket> kungfuDeathGrip = this;
|
||||||
|
@ -307,6 +313,13 @@ nsWebSocket::OnStart(nsISupports *aContext)
|
||||||
if (mDisconnected)
|
if (mDisconnected)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
|
// Attempt to kill "ghost" websocket: but usually too early for check to fail
|
||||||
|
nsresult rv = CheckInnerWindowCorrectness();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
FailConnectionQuietly();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mRequestedProtocolList.IsEmpty()) {
|
if (!mRequestedProtocolList.IsEmpty()) {
|
||||||
mChannel->GetProtocol(mEstablishedProtocol);
|
mChannel->GetProtocol(mEstablishedProtocol);
|
||||||
}
|
}
|
||||||
|
@ -405,7 +418,7 @@ nsWebSocket::GetInterface(const nsIID &aIID, void **aResult)
|
||||||
return wwatch->GetPrompt(outerWindow, aIID, aResult);
|
return wwatch->GetPrompt(outerWindow, aIID, aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
return QueryInterface(aIID, aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -499,6 +512,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsWebSocket)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
|
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIWebSocketListener)
|
NS_INTERFACE_MAP_ENTRY(nsIWebSocketListener)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
||||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebSocket)
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebSocket)
|
||||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||||
|
@ -1085,6 +1100,14 @@ nsWebSocket::DontKeepAliveAnyMore()
|
||||||
mCheckMustKeepAlive = false;
|
mCheckMustKeepAlive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsWebSocket::FailConnectionQuietly()
|
||||||
|
{
|
||||||
|
// Fail without console error or JS onerror message: onmessage/onclose will
|
||||||
|
// also be blocked so long as CheckInnerWindowCorrectness is failing.
|
||||||
|
CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsWebSocket::UpdateURI()
|
nsWebSocket::UpdateURI()
|
||||||
{
|
{
|
||||||
|
@ -1496,6 +1519,19 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
|
||||||
mOwner = nsnull;
|
mOwner = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt to kill "ghost" websocket: but usually too early for check to fail
|
||||||
|
rv = CheckInnerWindowCorrectness();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
nsCOMPtr<nsIJSContextStack> stack =
|
nsCOMPtr<nsIJSContextStack> stack =
|
||||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
|
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
|
||||||
JSContext* cx = nsnull;
|
JSContext* cx = nsnull;
|
||||||
|
@ -1571,6 +1607,35 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// nsWebSocket::nsIObserver
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWebSocket::Observe(nsISupports* aSubject,
|
||||||
|
const char* aTopic,
|
||||||
|
const PRUnichar* aData)
|
||||||
|
{
|
||||||
|
if ((mReadyState == nsIWebSocket::CLOSING) ||
|
||||||
|
(mReadyState == nsIWebSocket::CLOSED)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
|
||||||
|
if (!mOwner || window != mOwner) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
|
||||||
|
(strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0))
|
||||||
|
{
|
||||||
|
FailConnectionQuietly();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsWebSocket::nsIRequest
|
// nsWebSocket::nsIRequest
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -54,7 +54,9 @@
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsIWebSocketChannel.h"
|
#include "nsIWebSocketChannel.h"
|
||||||
#include "nsIWebSocketListener.h"
|
#include "nsIWebSocketListener.h"
|
||||||
|
#include "nsIObserver.h"
|
||||||
#include "nsIRequest.h"
|
#include "nsIRequest.h"
|
||||||
|
#include "nsWeakReference.h"
|
||||||
|
|
||||||
#define DEFAULT_WS_SCHEME_PORT 80
|
#define DEFAULT_WS_SCHEME_PORT 80
|
||||||
#define DEFAULT_WSS_SCHEME_PORT 443
|
#define DEFAULT_WSS_SCHEME_PORT 443
|
||||||
|
@ -74,6 +76,8 @@ class nsWebSocket: public nsDOMEventTargetHelper,
|
||||||
public nsIJSNativeInitializer,
|
public nsIJSNativeInitializer,
|
||||||
public nsIInterfaceRequestor,
|
public nsIInterfaceRequestor,
|
||||||
public nsIWebSocketListener,
|
public nsIWebSocketListener,
|
||||||
|
public nsIObserver,
|
||||||
|
public nsSupportsWeakReference,
|
||||||
public nsIRequest
|
public nsIRequest
|
||||||
{
|
{
|
||||||
friend class nsWSCloseEvent;
|
friend class nsWSCloseEvent;
|
||||||
|
@ -88,6 +92,7 @@ public:
|
||||||
NS_DECL_NSIWEBSOCKET
|
NS_DECL_NSIWEBSOCKET
|
||||||
NS_DECL_NSIINTERFACEREQUESTOR
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
NS_DECL_NSIWEBSOCKETLISTENER
|
NS_DECL_NSIWEBSOCKETLISTENER
|
||||||
|
NS_DECL_NSIOBSERVER
|
||||||
NS_DECL_NSIREQUEST
|
NS_DECL_NSIREQUEST
|
||||||
|
|
||||||
// nsIJSNativeInitializer
|
// nsIJSNativeInitializer
|
||||||
|
@ -114,6 +119,7 @@ protected:
|
||||||
// These methods when called can release the WebSocket object
|
// These methods when called can release the WebSocket object
|
||||||
nsresult FailConnection(PRUint16 reasonCode,
|
nsresult FailConnection(PRUint16 reasonCode,
|
||||||
const nsACString& aReasonString = EmptyCString());
|
const nsACString& aReasonString = EmptyCString());
|
||||||
|
void FailConnectionQuietly();
|
||||||
nsresult CloseConnection(PRUint16 reasonCode,
|
nsresult CloseConnection(PRUint16 reasonCode,
|
||||||
const nsACString& aReasonString = EmptyCString());
|
const nsACString& aReasonString = EmptyCString());
|
||||||
nsresult Disconnect();
|
nsresult Disconnect();
|
||||||
|
|
|
@ -2319,17 +2319,16 @@ 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");
|
||||||
|
|
||||||
|
if (mRequestedClose) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mTransport) {
|
if (!mTransport) {
|
||||||
LOG(("WebSocketChannel::Close() without transport - aborting."));
|
LOG(("WebSocketChannel::Close() without transport - aborting."));
|
||||||
AbortSession(NS_ERROR_NOT_CONNECTED);
|
AbortSession(NS_ERROR_NOT_CONNECTED);
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRequestedClose) {
|
|
||||||
LOG(("WebSocketChannel:: Double close error\n"));
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The API requires the UTF-8 string to be 123 or less bytes
|
// The API requires the UTF-8 string to be 123 or less bytes
|
||||||
if (reason.Length() > 123)
|
if (reason.Length() > 123)
|
||||||
return NS_ERROR_ILLEGAL_VALUE;
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче