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 209869 e72ed2e97e83b574adead215e9e01888ffa6aec9
parent 209868 a1a6b6736374d0e886ca14940ca9b7ae5bad18d8
child 209870 e7950dac9a28912c5a7bacba0d3d06ad889c1b11
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjduell
bugs504553
milestone35.0a1
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)
 {