Bug 1551601 - When performing a cross process redirect update the loadInfo to have the correct browsingContext r=nika
authorValentin Gosu <valentin.gosu@gmail.com>
Sun, 30 Jun 2019 20:20:51 +0000
changeset 480731 1582b3ffe71226af68979a58b5852afa49ff939b
parent 480729 adc59d50adf815ad6764ff235f833a5ba74291b6
child 480732 199bcb54e5122b5e7ac2476c90288b2169db2013
push id36222
push useropoprus@mozilla.com
push dateMon, 01 Jul 2019 09:51:59 +0000
treeherdermozilla-central@501f50ccafdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1551601
milestone69.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 1551601 - When performing a cross process redirect update the loadInfo to have the correct browsingContext r=nika Differential Revision: https://phabricator.services.mozilla.com/D35839
docshell/base/nsDocShell.cpp
netwerk/base/LoadInfo.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8296,53 +8296,59 @@ nsresult nsDocShell::CreateContentViewer
 
     // Update the notification callbacks, so that progress and
     // status information are sent to the right docshell...
     aOpenedChannel->SetNotificationCallbacks(this);
   }
 
   if (DocGroup::TryToLoadIframesInBackground()) {
     if ((!mContentViewer || GetDocument()->IsInitialDocument()) && IsFrame()) {
-      // At this point, we know we just created a new iframe document based on the
-      // response from the server, and we check if it's a cross-domain iframe
+      // At this point, we know we just created a new iframe document based on
+      // the response from the server, and we check if it's a cross-domain
+      // iframe
 
       RefPtr<Document> newDoc = viewer->GetDocument();
 
       RefPtr<nsDocShell> parent = GetParentDocshell();
-      nsCOMPtr<nsIPrincipal> parentPrincipal = parent->GetDocument()->NodePrincipal();
+      nsCOMPtr<nsIPrincipal> parentPrincipal =
+          parent->GetDocument()->NodePrincipal();
       nsCOMPtr<nsIPrincipal> thisPrincipal = newDoc->NodePrincipal();
 
       SiteIdentifier parentSite;
       SiteIdentifier thisSite;
 
-      nsresult rv = BasePrincipal::Cast(parentPrincipal)->GetSiteIdentifier(parentSite);
+      nsresult rv =
+          BasePrincipal::Cast(parentPrincipal)->GetSiteIdentifier(parentSite);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = BasePrincipal::Cast(thisPrincipal)->GetSiteIdentifier(thisSite);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (!parentSite.Equals(thisSite)) {
 #ifdef MOZ_GECKO_PROFILER
         nsCOMPtr<nsIURI> prinURI;
         thisPrincipal->GetURI(getter_AddRefs(prinURI));
-        nsPrintfCString marker("Iframe loaded in background: %s", prinURI->GetSpecOrDefault().get());
+        nsPrintfCString marker("Iframe loaded in background: %s",
+                               prinURI->GetSpecOrDefault().get());
         TimeStamp now = TimeStamp::Now();
-        profiler_add_text_marker("Background Iframe", marker, JS::ProfilingCategoryPair::DOM, now, now, Nothing(), Nothing());
+        profiler_add_text_marker("Background Iframe", marker,
+                                 JS::ProfilingCategoryPair::DOM, now, now,
+                                 Nothing(), Nothing());
 #endif
         SetBackgroundLoadIframe();
       }
     }
   }
 
   NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE);
 
   if (TreatAsBackgroundLoad()) {
-    nsCOMPtr<nsIRunnable> triggerParentCheckDocShell = NewRunnableMethod(
-        "nsDocShell::TriggerParentCheckDocShellIsEmpty", this,
-        &nsDocShell::TriggerParentCheckDocShellIsEmpty);
+    nsCOMPtr<nsIRunnable> triggerParentCheckDocShell =
+        NewRunnableMethod("nsDocShell::TriggerParentCheckDocShellIsEmpty", this,
+                          &nsDocShell::TriggerParentCheckDocShellIsEmpty);
     nsresult rv = NS_DispatchToCurrentThread(triggerParentCheckDocShell);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mSavedRefreshURIList = nullptr;
   mSavingOldViewer = false;
   mEODForCurrentDocument = false;
 
@@ -10595,16 +10601,29 @@ nsresult nsDocShell::OpenInitializedChan
   auto cleanupInitialClient =
       MakeScopeExit([&] { mInitialClientSource.reset(); });
 
   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
   NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
 
   MaybeCreateInitialClientSource();
 
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+
+  LoadInfo* li = static_cast<LoadInfo*>(loadInfo.get());
+  if (loadInfo->GetExternalContentPolicyType() ==
+      nsIContentPolicy::TYPE_DOCUMENT) {
+    li->UpdateBrowsingContextID(mBrowsingContext->Id());
+  } else if (loadInfo->GetExternalContentPolicyType() ==
+             nsIContentPolicy::TYPE_SUBDOCUMENT) {
+    li->UpdateFrameBrowsingContextID(mBrowsingContext->Id());
+  }
+  // TODO: more attributes need to be updated on the LoadInfo (bug 1561706)
+
   // Since we are loading a document we need to make sure the proper reserved
   // and initial client data is stored on the nsILoadInfo.  The
   // ClientChannelHelper does this and ensures that it is propagated properly
   // on redirects.  We pass no reserved client here so that the helper will
   // create the reserved ClientSource if necessary.
   Maybe<ClientInfo> noReservedClient;
   rv = AddClientChannelHelper(aChannel, std::move(noReservedClient),
                               GetInitialClientInfo(),
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -169,16 +169,26 @@ class LoadInfo final : public nsILoadInf
   void ComputeIsThirdPartyContext(nsPIDOMWindowOuter* aOuterWindow);
 
   // This function is the *only* function which can change the securityflags
   // of a loadinfo. It only exists because of the XHR code. Don't call it
   // from anywhere else!
   void SetIncludeCookiesSecFlag();
   friend class mozilla::dom::XMLHttpRequestMainThread;
 
+  // nsDocShell::OpenInitializedChannel needs to update the loadInfo with
+  // the correct browsingContext.
+  friend class ::nsDocShell;
+  void UpdateBrowsingContextID(uint64_t aBrowsingContextID) {
+    mBrowsingContextID = aBrowsingContextID;
+  }
+  void UpdateFrameBrowsingContextID(uint64_t aFrameBrowsingContextID) {
+    mFrameBrowsingContextID = aFrameBrowsingContextID;
+  }
+
   // if you add a member, please also update the copy constructor and consider
   // if it should be merged from parent channel through
   // ParentLoadInfoForwarderArgs.
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
   nsCOMPtr<nsIPrincipal> mSandboxedLoadingPrincipal;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -4055,14 +4055,23 @@ void HttpChannelChild::MaybeCallSynthesi
   mSynthesizedCallback->BodyComplete(mStatus);
   mSynthesizedCallback = nullptr;
 }
 
 nsresult HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus) {
   if (!CanSend()) {
     return NS_BINDING_FAILED;
   }
-  Unused << SendCrossProcessRedirectDone(aStatus);
+
+  // The loadInfo is updated in nsDocShell::OpenInitializedChannel to have the
+  // correct attributes (such as browsingContextID).
+  // We need to send it to the parent channel so the two match, which is done
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  MOZ_ALWAYS_SUCCEEDS(GetLoadInfo(getter_AddRefs(loadInfo)));
+  Maybe<LoadInfoArgs> loadInfoArgs;
+  MOZ_ALWAYS_SUCCEEDS(
+      mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs));
+  Unused << SendCrossProcessRedirectDone(aStatus, loadInfoArgs);
   return NS_OK;
 }
 
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1244,29 +1244,43 @@ static void FinishCrossProcessRedirect(n
     // the same time cancels the old channel.
     parentListener->OnRedirectResult(status == NS_OK);
   }
 
   channel->OnRedirectVerifyCallback(status);
 }
 
 mozilla::ipc::IPCResult HttpChannelParent::RecvCrossProcessRedirectDone(
-    const nsresult& aResult) {
+    const nsresult& aResult,
+    const mozilla::Maybe<LoadInfoArgs>& aLoadInfoArgs) {
   RefPtr<nsHttpChannel> chan = do_QueryObject(mChannel);
+  nsresult rv = NS_OK;
+  auto sendReply =
+      MakeScopeExit([&]() { FinishCrossProcessRedirect(chan, rv); });
+
+  nsCOMPtr<nsILoadInfo> newLoadInfo;
+  rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(newLoadInfo));
+  if (NS_FAILED(rv)) {
+    return IPC_OK();
+  }
+
+  if (newLoadInfo) {
+    chan->SetLoadInfo(newLoadInfo);
+  }
+
   if (!mBgParent) {
+    sendReply.release();
     RefPtr<HttpChannelParent> self = this;
     WaitForBgParent()->Then(
         GetMainThreadSerialEventTarget(), __func__,
         [self, chan, aResult]() { FinishCrossProcessRedirect(chan, aResult); },
         [self, chan](const nsresult& aRejectionRv) {
           MOZ_ASSERT(NS_FAILED(aRejectionRv), "This should be an error code");
           FinishCrossProcessRedirect(chan, aRejectionRv);
         });
-  } else {
-    FinishCrossProcessRedirect(chan, aResult);
   }
 
   return IPC_OK();
 }
 
 void HttpChannelParent::ResponseSynthesized() {
   // Suspend now even though the FinishSynthesizeResponse runnable has
   // not executed.  We want to suspend after we get far enough to trigger
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -196,17 +196,18 @@ class HttpChannelParent final : public n
   virtual mozilla::ipc::IPCResult RecvMarkOfflineCacheEntryAsForeign() override;
   virtual mozilla::ipc::IPCResult RecvDivertOnDataAvailable(
       const nsCString& data, const uint64_t& offset,
       const uint32_t& count) override;
   virtual mozilla::ipc::IPCResult RecvDivertOnStopRequest(
       const nsresult& statusCode) override;
   virtual mozilla::ipc::IPCResult RecvDivertComplete() override;
   virtual mozilla::ipc::IPCResult RecvCrossProcessRedirectDone(
-      const nsresult& aResult) override;
+      const nsresult& aResult,
+      const mozilla::Maybe<LoadInfoArgs>& aLoadInfoArgs) override;
   virtual mozilla::ipc::IPCResult RecvRemoveCorsPreflightCacheEntry(
       const URIParams& uri,
       const mozilla::ipc::PrincipalInfo& requestingPrincipal) override;
   virtual mozilla::ipc::IPCResult RecvBytesRead(const int32_t& aCount) override;
   virtual mozilla::ipc::IPCResult RecvOpenOriginalCacheInputStream() override;
   virtual mozilla::ipc::IPCResult RecvOpenAltDataCacheInputStream(
       const nsCString& aType) override;
   virtual void ActorDestroy(ActorDestroyReason why) override;
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -47,17 +47,19 @@ parent:
                         ChildLoadInfoForwarderArgs loadInfoForwarder,
                         uint32_t loadFlags, nsIReferrerInfo referrerInfo,
                         URIParams? apiRedirectTo,
                         CorsPreflightArgs? corsPreflightArgs,
                         bool chooseAppcache);
 
   // Sent to the parent in order signal that the child side listeners have been
   // set up and the parent side of the channel can be opened.
-  async CrossProcessRedirectDone(nsresult result);
+  // The passed loadInfo needs to be set on the channel - since the channel
+  // moved to a new process it now has different properties.
+  async CrossProcessRedirectDone(nsresult result, LoadInfoArgs? loadInfo);
 
   // For document loads we keep this protocol open after child's
   // OnStopRequest, and send this msg (instead of __delete__) to allow
   // partial cleanup on parent.
   async DocumentChannelCleanup(bool clearCacheEntry);
 
   // This might have to be sync. If this fails we must fail the document load
   // to avoid endless loop.