Bug 1164567 - Get rid of mPrincipal from WebSocket. r=smaug, a=sledru
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 14 May 2015 15:43:06 -0700
changeset 267495 34ad06cb05a030e64f3b9fc0845a973fbaee3ed1
parent 267494 f191235f22eff986fba9878b5ebc91980508bf7e
child 267496 2d0b4ea8ae1bc2c4825deebfbe7d61227fe3e844
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, sledru
bugs1164567
milestone39.0
Bug 1164567 - Get rid of mPrincipal from WebSocket. r=smaug, a=sledru
dom/base/WebSocket.cpp
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -111,20 +111,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();
@@ -180,18 +180,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;
@@ -980,34 +979,24 @@ public:
   {
     JS_ClearPendingException(mCx);
   }
 
 private:
   JSContext* mCx;
 };
 
-class InitRunnable final : public WorkerMainThreadRunnable
+class WebSocketMainThreadRunnable : 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)
+  WebSocketMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
   {
-    MOZ_ASSERT(mWorkerPrivate);
-    mWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool MainThreadRun() override
   {
     AssertIsOnMainThread();
 
     // Walk up to our containing page
     WorkerPrivate* wp = mWorkerPrivate;
@@ -1015,21 +1004,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 final : public WebSocketMainThreadRunnable
+{
+public:
+  InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
+               nsTArray<nsString>& aProtocolArray,
+               const nsACString& aScriptFile, uint32_t aScriptLine,
+               ErrorResult& aRv, bool* aConnectionFailed)
+    : WebSocketMainThreadRunnable(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) override
   {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(aWindow))) {
       mRv.Throw(NS_ERROR_FAILURE);
       return true;
     }
 
     ClearException ce(jsapi.cx());
@@ -1046,59 +1061,77 @@ private:
       return true;
     }
 
     mImpl->Init(jsapi.cx(), principal, mURL, mProtocolArray, mScriptFile,
                 mScriptLine, mRv, mConnectionFailed);
     return true;
   }
 
-  bool InitWindowless()
+  virtual bool InitWindowless(WorkerPrivate* aTopLevelWorkerPrivate) 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 final : public WorkerMainThreadRunnable
+class AsyncOpenRunnable final : public WebSocketMainThreadRunnable
 {
 public:
   AsyncOpenRunnable(WebSocketImpl* aImpl, ErrorResult& aRv)
-    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
+    : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate)
     , mImpl(aImpl)
     , mRv(aRv)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  bool MainThreadRun() override
+protected:
+  virtual bool InitWithWindow(nsPIDOMWindow* aWindow) 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) override
+  {
+    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;
@@ -1248,17 +1281,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;
@@ -1301,25 +1335,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)
@@ -1356,18 +1388,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)
@@ -1484,17 +1514,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;
@@ -1504,30 +1534,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)
 {
   MOZ_ASSERT(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);
@@ -1556,17 +1586,17 @@ public:
       mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR);
     }
   }
 private:
   nsRefPtr<WebSocketImpl> mWebSocketImpl;
 };
 
 nsresult
-WebSocketImpl::InitializeConnection()
+WebSocketImpl::InitializeConnection(nsIPrincipal* aPrincipal)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!mChannel, "mChannel should be null");
 
   nsCOMPtr<nsIWebSocketChannel> wsChannel;
   nsAutoCloseWS autoClose(this);
   nsresult rv;
 
@@ -1596,18 +1626,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;
 
   wsChannel->InitLoadInfo(doc ? doc->AsDOMNode() : nullptr,
-                          doc ? doc->NodePrincipal() : mPrincipal.get(),
-                          mPrincipal,
+                          doc ? doc->NodePrincipal() : aPrincipal,
+                          aPrincipal,
                           nsILoadInfo::SEC_NORMAL,
                           nsIContentPolicy::TYPE_WEBSOCKET);
 
   if (!mRequestedProtocolList.IsEmpty()) {
     rv = wsChannel->SetProtocol(mRequestedProtocolList);
     NS_ENSURE_SUCCESS(rv, rv);
   }