From dbb8893f0063e69b77e3c3b0506ca69e0d9ffd62 Mon Sep 17 00:00:00 2001 From: Steve Workman Date: Thu, 17 Apr 2014 11:53:58 -0700 Subject: [PATCH] Bug 504553 - Patch 1 - WebSockets in Workers: Dispatch WebSocketChannel::StartWebsocketConnect to target thread, r=jduell --- content/base/src/WebSocket.cpp | 21 +++---- .../protocol/websocket/BaseWebSocketChannel.h | 4 ++ netwerk/protocol/websocket/PWebSocket.ipdl | 3 +- .../protocol/websocket/WebSocketChannel.cpp | 58 ++++++++++++++----- netwerk/protocol/websocket/WebSocketChannel.h | 7 +++ .../websocket/WebSocketChannelChild.cpp | 44 +++++++++++--- .../websocket/WebSocketChannelChild.h | 11 +++- .../websocket/WebSocketChannelParent.cpp | 12 +++- 8 files changed, 118 insertions(+), 42 deletions(-) diff --git a/content/base/src/WebSocket.cpp b/content/base/src/WebSocket.cpp index 512d07b73b60..97ce874e7fa6 100644 --- a/content/base/src/WebSocket.cpp +++ b/content/base/src/WebSocket.cpp @@ -6,6 +6,7 @@ #include "WebSocket.h" #include "mozilla/dom/WebSocketBinding.h" +#include "mozilla/net/WebSocketChannel.h" #include "jsapi.h" #include "jsfriendapi.h" @@ -41,7 +42,8 @@ #include "nsContentPolicyUtils.h" #include "nsWrapperCacheInlines.h" #include "nsIObserverService.h" -#include "nsIWebSocketChannel.h" + +using namespace mozilla::net; namespace mozilla { namespace dom { @@ -1124,19 +1126,12 @@ nsresult WebSocket::UpdateURI() { // Check for Redirections - nsCOMPtr uri; - nsresult rv = mChannel->GetURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr channel; + channel = static_cast(mChannel.get()); + MOZ_ASSERT(channel); - nsAutoCString spec; - 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; + channel->GetEffectiveURL(mEffectiveURL); + mSecure = channel->IsEncrypted(); return NS_OK; } diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.h b/netwerk/protocol/websocket/BaseWebSocketChannel.h index c3f572619e5a..5da0b573a6d8 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.h +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h @@ -53,6 +53,10 @@ class BaseWebSocketChannel : public nsIWebSocketChannel, NS_IMETHOD GetPingTimeout(uint32_t *aSeconds); NS_IMETHOD SetPingTimeout(uint32_t aSeconds); + // Off main thread URI access. + virtual void GetEffectiveURL(nsAString& aEffectiveURL) const = 0; + virtual bool IsEncrypted() const = 0; + protected: nsCOMPtr mOriginalURI; nsCOMPtr mURI; diff --git a/netwerk/protocol/websocket/PWebSocket.ipdl b/netwerk/protocol/websocket/PWebSocket.ipdl index e8c01d2c8f77..6f427595ece8 100644 --- a/netwerk/protocol/websocket/PWebSocket.ipdl +++ b/netwerk/protocol/websocket/PWebSocket.ipdl @@ -41,7 +41,8 @@ parent: child: // Forwarded notifications corresponding to the nsIWebSocketListener interface - OnStart(nsCString aProtocol, nsCString aExtensions); + OnStart(nsCString aProtocol, nsCString aExtensions, + nsString aEffectiveURL, bool aEncrypted); OnStop(nsresult aStatusCode); OnMessageAvailable(nsCString aMsg); OnBinaryMessageAvailable(nsCString aMsg); diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index d7801ace615d..cdafa1d1f143 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -208,8 +208,6 @@ public: void Add(nsCString &address, int32_t port) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); - if (mDelaysDisabled) return; @@ -222,8 +220,6 @@ public: FailDelay* Lookup(nsCString &address, int32_t port, uint32_t *outIndex = nullptr) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); - if (mDelaysDisabled) return nullptr; @@ -293,8 +289,6 @@ public: // battery life than using a periodic timer. void Remove(nsCString &address, int32_t port) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); - TimeStamp rightNow = TimeStamp::Now(); // iterate from end, to make deletion indexing easier @@ -343,7 +337,6 @@ public: // delay/queue the connection (returns false) static void ConditionallyConnect(WebSocketChannel *ws) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(ws->mConnecting == NOT_CONNECTING, "opening state"); StaticMutexAutoLock lock(sLock); @@ -368,7 +361,6 @@ public: static void OnConnected(WebSocketChannel *aChannel) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(aChannel->mConnecting == CONNECTING_IN_PROGRESS, "Channel completed connect, but not connecting?"); @@ -395,8 +387,6 @@ public: // w/o ever successfully creating a connection) static void OnStopSession(WebSocketChannel *aChannel, nsresult aReason) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); - StaticMutexAutoLock lock(sLock); if (!sManager) { return; @@ -573,7 +563,7 @@ public: NS_IMETHOD Run() { - MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + MOZ_ASSERT(mChannel->IsOnTargetThread()); if (mLen < 0) mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData); @@ -607,7 +597,7 @@ public: NS_IMETHOD Run() { - MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + MOZ_ASSERT(mChannel->IsOnTargetThread()); nsWSAdmissionManager::OnStopSession(mChannel, mReason); @@ -645,7 +635,7 @@ public: NS_IMETHOD Run() { - MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + MOZ_ASSERT(mChannel->IsOnTargetThread()); mChannel->mListener->OnServerClose(mChannel->mContext, mCode, mReason); return NS_OK; @@ -676,7 +666,7 @@ public: NS_IMETHOD Run() { - MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + MOZ_ASSERT(mChannel->IsOnTargetThread()); LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize)); mChannel->mListener->OnAcknowledge(mChannel->mContext, mSize); @@ -1178,6 +1168,28 @@ WebSocketChannel::Shutdown() nsWSAdmissionManager::Shutdown(); } +bool +WebSocketChannel::IsOnTargetThread() +{ + MOZ_ASSERT(mTargetThread); + bool isOnTargetThread = false; + nsresult rv = mTargetThread->IsOnCurrentThread(&isOnTargetThread); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return NS_FAILED(rv) ? false : isOnTargetThread; +} + +void +WebSocketChannel::GetEffectiveURL(nsAString& aEffectiveURL) const +{ + aEffectiveURL = mEffectiveURL; +} + +bool +WebSocketChannel::IsEncrypted() const +{ + return mEncrypted; +} + void WebSocketChannel::BeginOpen() { @@ -2372,6 +2384,12 @@ WebSocketChannel::ApplyForAdmission() nsresult WebSocketChannel::StartWebsocketData() { + if (!IsOnTargetThread()) { + return mTargetThread->Dispatch( + NS_NewRunnableMethod(this, &WebSocketChannel::StartWebsocketData), + NS_DISPATCH_NORMAL); + } + LOG(("WebSocketChannel::StartWebsocketData() %p", this)); NS_ABORT_IF_FALSE(!mDataStarted, "StartWebsocketData twice"); mDataStarted = 1; @@ -2384,8 +2402,9 @@ WebSocketChannel::StartWebsocketData() LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p\n", mListener.get())); - if (mListener) + if (mListener) { mListener->OnStart(mContext); + } // Start keepalive ping timer, if we're using keepalive. if (mPingInterval) { @@ -2974,7 +2993,7 @@ nsresult WebSocketChannel::SendMsgCommon(const nsACString *aMsg, bool aIsBinary, uint32_t aLength, nsIInputStream *aStream) { - NS_ABORT_IF_FALSE(NS_GetCurrentThread() == mTargetThread, "not target thread"); + NS_ABORT_IF_FALSE(IsOnTargetThread(), "not target thread"); if (mRequestedClose) { LOG(("WebSocketChannel:: Error: send when closed\n")); @@ -3190,6 +3209,13 @@ WebSocketChannel::OnStartRequest(nsIRequest *aRequest, if (NS_FAILED(rv)) return rv; + // Update mEffectiveURL for off main thread URI access. + nsCOMPtr uri = mURI ? mURI : mOriginalURI; + nsAutoCString spec; + rv = uri->GetSpec(spec); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + CopyUTF8toUTF16(spec, mEffectiveURL); + mGotUpgradeOK = 1; if (mRecvdHttpUpgradeTransport) return StartWebsocketData(); diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index c57ae30d355d..67579333b5b3 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -18,6 +18,7 @@ #include "nsIProtocolProxyCallback.h" #include "nsIChannelEventSink.h" #include "nsIHttpChannelInternal.h" +#include "nsIStringStream.h" #include "BaseWebSocketChannel.h" #ifdef MOZ_WIDGET_GONK @@ -96,6 +97,11 @@ public: WebSocketChannel(); static void Shutdown(); + bool IsOnTargetThread(); + + // Off main thread URI access. + void GetEffectiveURL(nsAString& aEffectiveURL) const MOZ_OVERRIDE; + bool IsEncrypted() const MOZ_OVERRIDE; enum { // Non Control Frames @@ -185,6 +191,7 @@ private: // Used for off main thread access to the URI string. nsCString mHost; + nsString mEffectiveURL; nsCOMPtr mTransport; nsCOMPtr mSocketIn; diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index d1bdc602debf..1ac8f3a60e54 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -49,13 +49,13 @@ NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild) NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) NS_INTERFACE_MAP_END -WebSocketChannelChild::WebSocketChannelChild(bool aSecure) +WebSocketChannelChild::WebSocketChannelChild(bool aEncrypted) : mIPCOpen(false) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this)); - BaseWebSocketChannel::mEncrypted = aSecure; + mEncrypted = aEncrypted; mEventQ = new ChannelEventQueue(static_cast(this)); } @@ -80,6 +80,18 @@ WebSocketChannelChild::ReleaseIPDLReference() Release(); } +void +WebSocketChannelChild::GetEffectiveURL(nsAString& aEffectiveURL) const +{ + aEffectiveURL = mEffectiveURL; +} + +bool +WebSocketChannelChild::IsEncrypted() const +{ + return mEncrypted; +} + class WrappedChannelEvent : public nsRunnable { public: @@ -113,43 +125,57 @@ class StartEvent : public ChannelEvent public: StartEvent(WebSocketChannelChild* aChild, const nsCString& aProtocol, - const nsCString& aExtensions) + const nsCString& aExtensions, + const nsString& aEffectiveURL, + bool aEncrypted) : mChild(aChild) , mProtocol(aProtocol) , mExtensions(aExtensions) + , mEffectiveURL(aEffectiveURL) + , mEncrypted(aEncrypted) {} void Run() { - mChild->OnStart(mProtocol, mExtensions); + mChild->OnStart(mProtocol, mExtensions, mEffectiveURL, mEncrypted); } private: WebSocketChannelChild* mChild; nsCString mProtocol; nsCString mExtensions; + nsString mEffectiveURL; + bool mEncrypted; }; bool WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol, - const nsCString& aExtensions) + const nsCString& aExtensions, + const nsString& aEffectiveURL, + const bool& aEncrypted) { if (mEventQ->ShouldEnqueue()) { - mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions)); + mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions, + aEffectiveURL, aEncrypted)); } else if (mTargetThread) { - DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions)); + DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions, + aEffectiveURL, aEncrypted)); } else { - OnStart(aProtocol, aExtensions); + OnStart(aProtocol, aExtensions, aEffectiveURL, aEncrypted); } return true; } void WebSocketChannelChild::OnStart(const nsCString& aProtocol, - const nsCString& aExtensions) + const nsCString& aExtensions, + const nsString& aEffectiveURL, + const bool& aEncrypted) { LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this)); SetProtocol(aProtocol); mNegotiatedExtensions = aExtensions; + mEffectiveURL = aEffectiveURL; + mEncrypted = aEncrypted; if (mListener) { AutoEventEnqueuer ensureSerialDispatch(mEventQ);; diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.h b/netwerk/protocol/websocket/WebSocketChannelChild.h index d3a94a72cde4..b77b7862f271 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.h +++ b/netwerk/protocol/websocket/WebSocketChannelChild.h @@ -40,17 +40,23 @@ class WebSocketChannelChild : public BaseWebSocketChannel, void AddIPDLReference(); void ReleaseIPDLReference(); + // Off main thread URI access. + void GetEffectiveURL(nsAString& aEffectiveURL) const MOZ_OVERRIDE; + bool IsEncrypted() const MOZ_OVERRIDE; + private: ~WebSocketChannelChild(); - bool RecvOnStart(const nsCString& aProtocol, const nsCString& aExtensions) MOZ_OVERRIDE; + bool RecvOnStart(const nsCString& aProtocol, const nsCString& aExtensions, + const nsString& aEffectiveURL, const bool& aSecure) MOZ_OVERRIDE; bool RecvOnStop(const nsresult& aStatusCode) MOZ_OVERRIDE; bool RecvOnMessageAvailable(const nsCString& aMsg) MOZ_OVERRIDE; bool RecvOnBinaryMessageAvailable(const nsCString& aMsg) MOZ_OVERRIDE; bool RecvOnAcknowledge(const uint32_t& aSize) MOZ_OVERRIDE; bool RecvOnServerClose(const uint16_t& aCode, const nsCString &aReason) MOZ_OVERRIDE; - void OnStart(const nsCString& aProtocol, const nsCString& aExtensions); + void OnStart(const nsCString& aProtocol, const nsCString& aExtensions, + const nsString& aEffectiveURL, const bool& aSecure); void OnStop(const nsresult& aStatusCode); void OnMessageAvailable(const nsCString& aMsg); void OnBinaryMessageAvailable(const nsCString& aMsg); @@ -62,6 +68,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel, bool IsOnTargetThread(); nsRefPtr mEventQ; + nsString mEffectiveURL; bool mIPCOpen; friend class StartEvent; diff --git a/netwerk/protocol/websocket/WebSocketChannelParent.cpp b/netwerk/protocol/websocket/WebSocketChannelParent.cpp index 9d50bae5e894..d2c9121d5873 100644 --- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp @@ -12,6 +12,7 @@ #include "SerializedLoadContext.h" #include "nsIOService.h" #include "mozilla/net/NeckoCommon.h" +#include "mozilla/net/WebSocketChannel.h" using namespace mozilla::ipc; @@ -189,11 +190,20 @@ WebSocketChannelParent::OnStart(nsISupports *aContext) { LOG(("WebSocketChannelParent::OnStart() %p\n", this)); nsAutoCString protocol, extensions; + nsString effectiveURL; + bool encrypted = false; if (mChannel) { mChannel->GetProtocol(protocol); mChannel->GetExtensions(extensions); + + nsRefPtr channel; + channel = static_cast(mChannel.get()); + MOZ_ASSERT(channel); + + channel->GetEffectiveURL(effectiveURL); + encrypted = channel->IsEncrypted(); } - if (!mIPCOpen || !SendOnStart(protocol, extensions)) { + if (!mIPCOpen || !SendOnStart(protocol, extensions, effectiveURL, encrypted)) { return NS_ERROR_FAILURE; } return NS_OK;