Bug 504553 - Patch 1 - WebSockets in Workers: Dispatch WebSocketChannel::StartWebsocketConnect to target thread, r=jduell
authorSteve Workman <sworkman@mozilla.com>
Thu, 17 Apr 2014 11:53:58 -0700
changeset 234404 e72ed2e97e83b574adead215e9e01888ffa6aec9
parent 234403 a1a6b6736374d0e886ca14940ca9b7ae5bad18d8
child 234405 e7950dac9a28912c5a7bacba0d3d06ad889c1b11
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs504553
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 504553 - Patch 1 - WebSockets in Workers: Dispatch WebSocketChannel::StartWebsocketConnect to target thread, r=jduell
content/base/src/WebSocket.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.h
netwerk/protocol/websocket/PWebSocket.ipdl
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelChild.h
netwerk/protocol/websocket/WebSocketChannelParent.cpp
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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/. */
 
 #include "WebSocket.h"
 #include "mozilla/dom/WebSocketBinding.h"
+#include "mozilla/net/WebSocketChannel.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsIScriptGlobalObject.h"
@@ -36,17 +37,18 @@
 #include "nsIScriptError.h"
 #include "nsNetUtil.h"
 #include "nsILoadGroup.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsContentPolicyUtils.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIObserverService.h"
-#include "nsIWebSocketChannel.h"
+
+using namespace mozilla::net;
 
 namespace mozilla {
 namespace dom {
 
 #define UTF_8_REPLACEMENT_CHAR    static_cast<char16_t>(0xFFFD)
 
 class CallDispatchConnectionCloseEvents: public nsRunnable
 {
@@ -1119,29 +1121,22 @@ WebSocket::DontKeepAliveAnyMore()
   }
   mCheckMustKeepAlive = false;
 }
 
 nsresult
 WebSocket::UpdateURI()
 {
   // Check for Redirections
-  nsCOMPtr<nsIURI> uri;
-  nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<BaseWebSocketChannel> channel;
+  channel = static_cast<BaseWebSocketChannel*>(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;
 }
 
 void
 WebSocket::EventListenerAdded(nsIAtom* aType)
 {
   UpdateMustKeepAlive();
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.h
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h
@@ -48,16 +48,20 @@ class BaseWebSocketChannel : public nsIW
   NS_IMETHOD GetExtensions(nsACString &aExtensions);
   NS_IMETHOD GetProtocol(nsACString &aProtocol);
   NS_IMETHOD SetProtocol(const nsACString &aProtocol);
   NS_IMETHOD GetPingInterval(uint32_t *aSeconds);
   NS_IMETHOD SetPingInterval(uint32_t aSeconds);
   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<nsIURI>                mOriginalURI;
   nsCOMPtr<nsIURI>                mURI;
   nsCOMPtr<nsIWebSocketListener>  mListener;
   nsCOMPtr<nsISupports>           mContext;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   nsCOMPtr<nsILoadGroup>          mLoadGroup;
   nsCOMPtr<nsILoadInfo>           mLoadInfo;
--- a/netwerk/protocol/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -36,17 +36,18 @@ parent:
   SendMsg(nsCString aMsg);
   SendBinaryMsg(nsCString aMsg);
   SendBinaryStream(InputStreamParams aStream, uint32_t aLength);
 
   DeleteSelf();
 
 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);
   OnAcknowledge(uint32_t aSize);
   OnServerClose(uint16_t code, nsCString aReason);
 
   __delete__();
 
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -203,32 +203,28 @@ public:
     MOZ_COUNT_DTOR(FailDelayManager);
     for (uint32_t i = 0; i < mEntries.Length(); i++) {
       delete mEntries[i];
     }
   }
 
   void Add(nsCString &address, int32_t port)
   {
-    NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
-
     if (mDelaysDisabled)
       return;
 
     FailDelay *record = new FailDelay(address, port);
     mEntries.AppendElement(record);
   }
 
   // Element returned may not be valid after next main thread event: don't keep
   // pointer to it around
   FailDelay* Lookup(nsCString &address, int32_t port,
                     uint32_t *outIndex = nullptr)
   {
-    NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
-
     if (mDelaysDisabled)
       return nullptr;
 
     FailDelay *result = nullptr;
     TimeStamp rightNow = TimeStamp::Now();
 
     // We also remove expired entries during search: iterate from end to make
     // indexing simpler
@@ -288,18 +284,16 @@ public:
     // delay interval has passed: connect.
     ws->BeginOpen();
   }
 
   // Remove() also deletes all expired entries as it iterates: better for
   // 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
     for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
       FailDelay *entry = mEntries[i];
       if ((entry->mAddress.Equals(address) && entry->mPort == port) ||
           entry->IsExpired(rightNow)) {
         mEntries.RemoveElementAt(i);
@@ -338,17 +332,16 @@ public:
     delete sManager;
     sManager = nullptr;
   }
 
   // Determine if we will open connection immediately (returns true), or
   // 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);
     if (!sManager) {
       return;
     }
 
     // If there is already another WS channel connecting to this IP address,
@@ -363,17 +356,16 @@ public:
       ws->mConnecting = CONNECTING_QUEUED;
     } else {
       sManager->mFailures.DelayOrBegin(ws);
     }
   }
 
   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?");
 
     StaticMutexAutoLock lock(sLock);
     if (!sManager) {
       return;
     }
 
@@ -390,18 +382,16 @@ public:
     // host may have different port
     sManager->ConnectNext(aChannel->mAddress);
   }
 
   // Called every time a websocket channel ends its session (including going away
   // 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;
     }
 
     if (NS_FAILED(aReason)) {
       // Have we seen this failure before?
       FailDelay *knownFailure = sManager->mFailures.Lookup(aChannel->mAddress,
@@ -568,17 +558,17 @@ public:
                          nsCString        &aData,
                          int32_t           aLen)
     : mChannel(aChannel),
       mData(aData),
       mLen(aLen) {}
 
   NS_IMETHOD Run()
   {
-    MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread);
+    MOZ_ASSERT(mChannel->IsOnTargetThread());
 
     if (mLen < 0)
       mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData);
     else
       mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData);
     return NS_OK;
   }
 
@@ -602,17 +592,17 @@ public:
 
   CallOnStop(WebSocketChannel *aChannel,
              nsresult          aReason)
     : mChannel(aChannel),
       mReason(aReason) {}
 
   NS_IMETHOD Run()
   {
-    MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread);
+    MOZ_ASSERT(mChannel->IsOnTargetThread());
 
     nsWSAdmissionManager::OnStopSession(mChannel, mReason);
 
     if (mChannel->mListener) {
       mChannel->mListener->OnStop(mChannel->mContext, mReason);
       mChannel->mListener = nullptr;
       mChannel->mContext = nullptr;
     }
@@ -640,17 +630,17 @@ public:
                     uint16_t          aCode,
                     nsCString        &aReason)
     : mChannel(aChannel),
       mCode(aCode),
       mReason(aReason) {}
 
   NS_IMETHOD Run()
   {
-    MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread);
+    MOZ_ASSERT(mChannel->IsOnTargetThread());
 
     mChannel->mListener->OnServerClose(mChannel->mContext, mCode, mReason);
     return NS_OK;
   }
 
 private:
   ~CallOnServerClose() {}
 
@@ -671,17 +661,17 @@ public:
 
   CallAcknowledge(WebSocketChannel *aChannel,
                   uint32_t          aSize)
     : mChannel(aChannel),
       mSize(aSize) {}
 
   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);
     return NS_OK;
   }
 
 private:
   ~CallAcknowledge() {}
@@ -1173,16 +1163,38 @@ WebSocketChannel::Observe(nsISupports *s
 }
 
 void
 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()
 {
   LOG(("WebSocketChannel::BeginOpen() %p\n", this));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
   nsresult rv;
 
@@ -2367,30 +2379,37 @@ WebSocketChannel::ApplyForAdmission()
 }
 
 // Called after both OnStartRequest and OnTransportAvailable have
 // executed. This essentially ends the handshake and starts the websockets
 // protocol state machine.
 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;
 
   // We're now done CONNECTING, which means we can now open another,
   // perhaps parallel, connection to the same host if one
   // is pending
   nsWSAdmissionManager::OnConnected(this);
 
   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) {
     nsresult rv;
     mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     if (NS_FAILED(rv)) {
       NS_WARNING("unable to create ping timer. Carrying on.");
     } else {
@@ -2969,17 +2988,17 @@ WebSocketChannel::SendBinaryStream(nsIIn
 
   return SendMsgCommon(nullptr, true, aLength, aStream);
 }
 
 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"));
     return NS_ERROR_UNEXPECTED;
   }
 
   if (mStopped) {
     LOG(("WebSocketChannel:: Error: send when stopped\n"));
@@ -3185,16 +3204,23 @@ WebSocketChannel::OnStartRequest(nsIRequ
       mProtocol.Truncate();
     }
   }
 
   rv = HandleExtensions();
   if (NS_FAILED(rv))
     return rv;
 
+  // Update mEffectiveURL for off main thread URI access.
+  nsCOMPtr<nsIURI> uri = mURI ? mURI : mOriginalURI;
+  nsAutoCString spec;
+  rv = uri->GetSpec(spec);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  CopyUTF8toUTF16(spec, mEffectiveURL);
+
   mGotUpgradeOK = 1;
   if (mRecvdHttpUpgradeTransport)
     return StartWebsocketData();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -13,16 +13,17 @@
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsITimer.h"
 #include "nsIDNSListener.h"
 #include "nsIObserver.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsIChannelEventSink.h"
 #include "nsIHttpChannelInternal.h"
+#include "nsIStringStream.h"
 #include "BaseWebSocketChannel.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #include "nsProxyRelease.h"
 #endif
 
 #include "nsCOMPtr.h"
@@ -91,16 +92,21 @@ public:
   NS_IMETHOD Close(uint16_t aCode, const nsACString & aReason);
   NS_IMETHOD SendMsg(const nsACString &aMsg);
   NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
   NS_IMETHOD SendBinaryStream(nsIInputStream *aStream, uint32_t length);
   NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
 
   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
     kContinuation = 0x0,
     kText =         0x1,
     kBinary =       0x2,
 
     // Control Frames
@@ -180,16 +186,17 @@ private:
 
   // Used as key for connection managment: Initially set to hostname from URI,
   // then to IP address (unless we're leaving DNS resolution to a proxy server)
   nsCString                       mAddress;
   int32_t                         mPort;          // WS server port
 
   // Used for off main thread access to the URI string.
   nsCString                       mHost;
+  nsString                        mEffectiveURL;
 
   nsCOMPtr<nsISocketTransport>    mTransport;
   nsCOMPtr<nsIAsyncInputStream>   mSocketIn;
   nsCOMPtr<nsIAsyncOutputStream>  mSocketOut;
 
   nsCOMPtr<nsITimer>              mCloseTimer;
   uint32_t                        mCloseTimeout;  /* milliseconds */
 
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -44,23 +44,23 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
 
 NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild)
   NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel)
   NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel)
   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<nsIWebSocketChannel*>(this));
 }
 
 WebSocketChannelChild::~WebSocketChannelChild()
 {
   LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
 }
 
@@ -75,16 +75,28 @@ WebSocketChannelChild::AddIPDLReference(
 void
 WebSocketChannelChild::ReleaseIPDLReference()
 {
   NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
   mIPCOpen = false;
   Release();
 }
 
+void
+WebSocketChannelChild::GetEffectiveURL(nsAString& aEffectiveURL) const
+{
+  aEffectiveURL = mEffectiveURL;
+}
+
+bool
+WebSocketChannelChild::IsEncrypted() const
+{
+  return mEncrypted;
+}
+
 class WrappedChannelEvent : public nsRunnable
 {
 public:
   explicit WrappedChannelEvent(ChannelEvent *aChannelEvent)
     : mChannelEvent(aChannelEvent)
   {
     MOZ_RELEASE_ASSERT(aChannelEvent);
   }
@@ -108,53 +120,67 @@ WebSocketChannelChild::DispatchToTargetT
                           NS_DISPATCH_NORMAL);
 }
 
 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);;
     mListener->OnStart(mContext);
   }
 }
 
 class StopEvent : public ChannelEvent
--- a/netwerk/protocol/websocket/WebSocketChannelChild.h
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.h
@@ -35,38 +35,45 @@ class WebSocketChannelChild : public Bas
   NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
   NS_IMETHOD SendBinaryStream(nsIInputStream *aStream, uint32_t aLength);
   nsresult SendBinaryStream(OptionalInputStreamParams *aStream, uint32_t aLength);
   NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
 
   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);
   void OnAcknowledge(const uint32_t& aSize);
   void OnServerClose(const uint16_t& aCode, const nsCString& aReason);
   void AsyncOpenFailed();  
 
   void DispatchToTargetThread(ChannelEvent *aChannelEvent);
   bool IsOnTargetThread();
 
   nsRefPtr<ChannelEventQueue> mEventQ;
+  nsString mEffectiveURL;
   bool mIPCOpen;
 
   friend class StartEvent;
   friend class StopEvent;
   friend class MessageEvent;
   friend class AcknowledgeEvent;
   friend class ServerCloseEvent;
   friend class AsyncOpenFailedEvent;
--- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp
@@ -7,16 +7,17 @@
 #include "WebSocketLog.h"
 #include "WebSocketChannelParent.h"
 #include "nsIAuthPromptProvider.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "SerializedLoadContext.h"
 #include "nsIOService.h"
 #include "mozilla/net/NeckoCommon.h"
+#include "mozilla/net/WebSocketChannel.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS(WebSocketChannelParent,
                   nsIWebSocketListener,
@@ -184,21 +185,30 @@ WebSocketChannelParent::RecvSendBinarySt
 // WebSocketChannelParent::nsIRequestObserver
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 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<WebSocketChannel> channel;
+    channel = static_cast<WebSocketChannel*>(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;
 }
 
 NS_IMETHODIMP
 WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode)
 {