Bug 1164567 - Get rid of mPrincipal from WebSocket. r=smaug, a=2.2+
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 20 May 2015 11:10:41 -0400
changeset 238429 08fb23c0597ffa818652db61d63ffe19fa8a364d
parent 238428 e5df85ba6839d6b0e50689205f477c452dc53f36
child 238430 e69a7847952fc3a70e514d5d421d73052a7e3eb1
push id620
push userryanvm@gmail.com
push dateWed, 20 May 2015 15:13:56 +0000
treeherdermozilla-b2g37_v2_2@08fb23c0597f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, 2.2
bugs1164567
milestone37.0
Bug 1164567 - Get rid of mPrincipal from WebSocket. r=smaug, a=2.2+
dom/base/WebSocket.cpp
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -110,20 +110,20 @@ public:
             nsIPrincipal* aPrincipal,
             const nsAString& aURL,
             nsTArray<nsString>& aProtocolArray,
             const nsACString& aScriptFile,
             uint32_t aScriptLine,
             ErrorResult& aRv,
             bool* aConnectionFailed);
 
-  void AsyncOpen(ErrorResult& aRv);
+  void AsyncOpen(nsIPrincipal* aPrincipal, ErrorResult& aRv);
 
   nsresult ParseURL(const nsAString& aURL);
-  nsresult InitializeConnection();
+  nsresult InitializeConnection(nsIPrincipal* aPrincipal);
 
   // These methods when called can release the WebSocket object
   void FailConnection(uint16_t reasonCode,
                       const nsACString& aReasonString = EmptyCString());
   nsresult CloseConnection(uint16_t reasonCode,
                            const nsACString& aReasonString = EmptyCString());
   nsresult Disconnect();
   void DisconnectInternal();
@@ -179,18 +179,17 @@ public:
   nsCString mAsciiHost;  // hostname
   uint32_t  mPort;
   nsCString mResource; // [filepath[?query]]
   nsString  mUTF16Origin;
 
   nsCString mURI;
   nsCString mRequestedProtocolList;
 
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  nsWeakPtr              mOriginDocument;
+  nsWeakPtr mOriginDocument;
 
   // Web Socket owner information:
   // - the script file name, UTF8 encoded.
   // - source code line number where the Web Socket object was constructed.
   // - the ID of the inner window where the script lives. Note that this may not
   //   be the same as the Web Socket owner window.
   // These attributes are used for error reporting.
   nsCString mScriptFile;
@@ -943,34 +942,24 @@ public:
   {
     JS_ClearPendingException(mCx);
   }
 
 private:
   JSContext* mCx;
 };
 
-class InitRunnable MOZ_FINAL : public WorkerMainThreadRunnable
+class MainThreadRunnable : public WorkerMainThreadRunnable
 {
 public:
-  InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
-               nsTArray<nsString>& aProtocolArray,
-               const nsACString& aScriptFile, uint32_t aScriptLine,
-               ErrorResult& aRv, bool* aConnectionFailed)
-    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
-    , mImpl(aImpl)
-    , mURL(aURL)
-    , mProtocolArray(aProtocolArray)
-    , mScriptFile(aScriptFile)
-    , mScriptLine(aScriptLine)
-    , mRv(aRv)
-    , mConnectionFailed(aConnectionFailed)
+  MainThreadRunnable(WorkerPrivate* aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
   {
-    MOZ_ASSERT(mWorkerPrivate);
-    mWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool MainThreadRun() MOZ_OVERRIDE
   {
     AssertIsOnMainThread();
 
     // Walk up to our containing page
     WorkerPrivate* wp = mWorkerPrivate;
@@ -978,21 +967,47 @@ public:
       wp = wp->GetParent();
     }
 
     nsPIDOMWindow* window = wp->GetWindow();
     if (window) {
       return InitWithWindow(window);
     }
 
-    return InitWindowless();
+    return InitWindowless(wp);
   }
 
-private:
-  bool InitWithWindow(nsPIDOMWindow* aWindow)
+protected:
+  virtual bool InitWithWindow(nsPIDOMWindow* aWindow) = 0;
+
+  virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate) = 0;
+};
+
+class InitRunnable MOZ_FINAL : public MainThreadRunnable
+{
+public:
+  InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
+               nsTArray<nsString>& aProtocolArray,
+               const nsACString& aScriptFile, uint32_t aScriptLine,
+               ErrorResult& aRv, bool* aConnectionFailed)
+    : MainThreadRunnable(aImpl->mWorkerPrivate)
+    , mImpl(aImpl)
+    , mURL(aURL)
+    , mProtocolArray(aProtocolArray)
+    , mScriptFile(aScriptFile)
+    , mScriptLine(aScriptLine)
+    , mRv(aRv)
+    , mConnectionFailed(aConnectionFailed)
+  {
+    MOZ_ASSERT(mWorkerPrivate);
+    mWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool InitWithWindow(nsPIDOMWindow* aWindow) MOZ_OVERRIDE
   {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(aWindow))) {
       mRv.Throw(NS_ERROR_FAILURE);
       return true;
     }
 
     ClearException ce(jsapi.cx());
@@ -1009,59 +1024,78 @@ private:
       return true;
     }
 
     mImpl->Init(jsapi.cx(), principal, mURL, mProtocolArray, mScriptFile,
                 mScriptLine, mRv, mConnectionFailed);
     return true;
   }
 
-  bool InitWindowless()
+  virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    WorkerPrivate* wp = mWorkerPrivate;
-    while (wp->GetParent()) {
-      wp = wp->GetParent();
-    }
-
-    MOZ_ASSERT(!wp->GetWindow());
-
-    mImpl->Init(nullptr, wp->GetPrincipal(), mURL, mProtocolArray, mScriptFile,
-                mScriptLine, mRv, mConnectionFailed);
+    MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
+
+    mImpl->Init(nullptr, aTopLevelWorkerPrivate->GetPrincipal(), mURL,
+                mProtocolArray, mScriptFile, mScriptLine, mRv,
+                mConnectionFailed);
     return true;
   }
 
   // Raw pointer. This worker runs synchronously.
   WebSocketImpl* mImpl;
 
   const nsAString& mURL;
   nsTArray<nsString>& mProtocolArray;
   nsCString mScriptFile;
   uint32_t mScriptLine;
   ErrorResult& mRv;
   bool* mConnectionFailed;
 };
 
-class AsyncOpenRunnable MOZ_FINAL : public WorkerMainThreadRunnable
+class AsyncOpenRunnable MOZ_FINAL : public MainThreadRunnable
 {
 public:
   AsyncOpenRunnable(WebSocketImpl* aImpl, ErrorResult& aRv)
-    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
+    : MainThreadRunnable(aImpl->mWorkerPrivate)
     , mImpl(aImpl)
     , mRv(aRv)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  bool MainThreadRun() MOZ_OVERRIDE
+protected:
+  virtual bool InitWithWindow(nsPIDOMWindow* aWindow) MOZ_OVERRIDE
   {
     AssertIsOnMainThread();
-    mImpl->AsyncOpen(mRv);
+
+    nsIDocument* doc = aWindow->GetExtantDoc();
+    if (!doc) {
+      mRv.Throw(NS_ERROR_FAILURE);
+      return true;
+    }
+
+    nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
+    if (!principal) {
+      mRv.Throw(NS_ERROR_FAILURE);
+      return true;
+    }
+
+    mImpl->AsyncOpen(principal, mRv);
+    return true;
+  }
+
+  virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
+
+    mImpl->AsyncOpen(aTopLevelWorkerPrivate->GetPrincipal(), mRv);
     return true;
   }
 
 private:
   // Raw pointer. This worker runs synchronously.
   WebSocketImpl* mImpl;
 
   ErrorResult& mRv;
@@ -1211,17 +1245,18 @@ WebSocket::Constructor(const GlobalObjec
   // This operation must be done on the correct thread. The rest must run on the
   // main-thread.
   aRv = webSocket->mImpl->mChannel->SetNotificationCallbacks(webSocket->mImpl);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   if (NS_IsMainThread()) {
-    webSocket->mImpl->AsyncOpen(aRv);
+    MOZ_ASSERT(principal);
+    webSocket->mImpl->AsyncOpen(principal, aRv);
   } else {
     nsRefPtr<AsyncOpenRunnable> runnable =
       new AsyncOpenRunnable(webSocket->mImpl, aRv);
     runnable->Dispatch(aGlobal.Context());
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -1264,25 +1299,23 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_E
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WebSocket,
                                                DOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WebSocket,
                                                   DOMEventTargetHelper)
   if (tmp->mImpl) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl->mPrincipal)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl->mChannel)
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WebSocket,
                                                 DOMEventTargetHelper)
   if (tmp->mImpl) {
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl->mPrincipal)
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl->mChannel)
     tmp->mImpl->Disconnect();
     MOZ_ASSERT(!tmp->mImpl);
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WebSocket)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@@ -1319,18 +1352,16 @@ WebSocketImpl::Init(JSContext* aCx,
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrincipal);
 
   // We need to keep the implementation alive in case the init disconnects it
   // because of some error.
   nsRefPtr<WebSocketImpl> kungfuDeathGrip = this;
 
-  mPrincipal = aPrincipal;
-
   // Attempt to kill "ghost" websocket: but usually too early for check to fail
   aRv = mWebSocket->CheckInnerWindowCorrectness();
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   // Shut down websocket if window is frozen or destroyed (only needed for
   // "ghost" websockets--see bug 696085)
@@ -1447,17 +1478,17 @@ WebSocketImpl::Init(JSContext* aCx,
   }
 
   // Check content policy.
   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
   nsCOMPtr<nsIDocument> originDoc = nsContentUtils::GetDocumentFromScriptContext(sc);
   mOriginDocument = do_GetWeakReference(originDoc);
   aRv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
                                   uri,
-                                  mPrincipal,
+                                  aPrincipal,
                                   originDoc,
                                   EmptyCString(),
                                   nullptr,
                                   &shouldLoad,
                                   nsContentUtils::GetContentPolicy(),
                                   nsContentUtils::GetSecurityManager());
   if (NS_WARN_IF(aRv.Failed())) {
     return;
@@ -1467,30 +1498,30 @@ WebSocketImpl::Init(JSContext* aCx,
     // Disallowed by content policy.
     aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
     return;
   }
 
   // the constructor should throw a SYNTAX_ERROR only if it fails to parse the
   // url parameter, so don't throw if InitializeConnection fails, and call
   // onerror/onclose asynchronously
-  if (NS_FAILED(InitializeConnection())) {
+  if (NS_FAILED(InitializeConnection(aPrincipal))) {
     *aConnectionFailed = true;
   } else {
     *aConnectionFailed = false;
   }
 }
 
 void
-WebSocketImpl::AsyncOpen(ErrorResult& aRv)
+WebSocketImpl::AsyncOpen(nsIPrincipal* aPrincipal, ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsCString asciiOrigin;
-  aRv = nsContentUtils::GetASCIIOrigin(mPrincipal, asciiOrigin);
+  aRv = nsContentUtils::GetASCIIOrigin(aPrincipal, asciiOrigin);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   ToLowerCase(asciiOrigin);
 
   nsCOMPtr<nsIURI> uri;
   aRv = NS_NewURI(getter_AddRefs(uri), mURI);
@@ -1519,17 +1550,17 @@ public:
       mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR);
     }
   }
 private:
   nsRefPtr<WebSocketImpl> mWebSocketImpl;
 };
 
 nsresult
-WebSocketImpl::InitializeConnection()
+WebSocketImpl::InitializeConnection(nsIPrincipal* aPrincipal)
 {
   AssertIsOnMainThread();
   NS_ABORT_IF_FALSE(!mChannel, "mChannel should be null");
 
   nsCOMPtr<nsIWebSocketChannel> wsChannel;
   nsAutoCloseWS autoClose(this);
   nsresult rv;
 
@@ -1559,19 +1590,18 @@ WebSocketImpl::InitializeConnection()
   // was not set during channel creation.
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mOriginDocument);
 
   // mOriginDocument has to be release on main-thread because WeakReferences
   // are not thread-safe.
   mOriginDocument = nullptr;
 
   nsCOMPtr<nsILoadInfo> loadInfo =
-    new LoadInfo(doc ?
-                   doc->NodePrincipal() : mPrincipal.get(),
-                 mPrincipal,
+    new LoadInfo(doc ? doc->NodePrincipal() : aPrincipal,
+                 aPrincipal,
                  doc,
                  nsILoadInfo::SEC_NORMAL,
                  nsIContentPolicy::TYPE_WEBSOCKET);
   rv = wsChannel->SetLoadInfo(loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mRequestedProtocolList.IsEmpty()) {
     rv = wsChannel->SetProtocol(mRequestedProtocolList);