Bug 1467223 - Part 1: Move CrossProcessRedirect Message to PContent, r=valentin
authorNika Layzell <nika@thelayzells.com>
Wed, 23 Jan 2019 21:27:44 +0000
changeset 515201 b0b61b6a4014ee5d9b8257b660cde6a55df66522
parent 515200 a77e9c7eabb535d9d114ae4f1733f1d954132f14
child 515202 881438d34f0921971cd9d67c2ef2ab8d4383a49f
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1467223
milestone66.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 1467223 - Part 1: Move CrossProcessRedirect Message to PContent, r=valentin This is needed because early in a content process's lifecycle, NeckoParent may not have been created yet. This leads to issues when trying to redirect into a fresh process which hasn't performed network loads yet. By sending the message over PContent, we can be sure the APIs are available. Differential Revision: https://phabricator.services.mozilla.com/D15608
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
dom/ipc/moz.build
dom/xhr/XMLHttpRequestMainThread.h
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/http/HttpChannelParentListener.cpp
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpResponseHead.h
netwerk/test/browser/browser_cross_process_redirect.js
uriloader/prefetch/nsPrefetchService.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -85,16 +85,20 @@
 #include "mozilla/recordreplay/ParentIPC.h"
 #include "mozilla/widget/ScreenManager.h"
 #include "mozilla/widget/WidgetMessageUtils.h"
 #include "nsBaseDragService.h"
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/WebBrowserPersistDocumentChild.h"
 #include "mozilla/HangDetails.h"
+#include "mozilla/LoadInfo.h"
+#include "nsIChildProcessChannelListener.h"
+#include "mozilla/net/HttpChannelChild.h"
+#include "nsQueryObject.h"
 #include "imgLoader.h"
 #include "GMPServiceChild.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIStringBundle.h"
 #include "nsIWorkerDebuggerManager.h"
 #include "nsGeolocation.h"
 
 #if !defined(XP_WIN)
@@ -3429,16 +3433,76 @@ mozilla::ipc::IPCResult ContentChild::Re
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvSaveRecording(
     const FileDescriptor& aFile) {
   recordreplay::parent::SaveRecording(aFile);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
+    const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
+    const OptionalLoadInfoArgs& aLoadInfo, const uint64_t& aChannelId,
+    nsIURI* aOriginalURI, const uint64_t& aIdentifier) {
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  nsresult rv =
+      mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(loadInfo));
+  if (NS_FAILED(rv)) {
+    MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIChannel> newChannel;
+  rv = NS_NewChannelInternal(getter_AddRefs(newChannel), aURI, loadInfo,
+                             nullptr,  // PerformanceStorage
+                             nullptr,  // aLoadGroup
+                             nullptr,  // aCallbacks
+                             aNewLoadFlags);
+
+  // We are sure this is a HttpChannelChild because the parent
+  // is always a HTTP channel.
+  RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);
+  if (NS_FAILED(rv) || !httpChild) {
+    MOZ_DIAGNOSTIC_ASSERT(false, "NS_NewChannelInternal failed");
+    return IPC_OK();
+  }
+
+  // This is used to report any errors back to the parent by calling
+  // CrossProcessRedirectFinished.
+  auto scopeExit =
+      MakeScopeExit([&]() { httpChild->CrossProcessRedirectFinished(rv); });
+
+  rv = httpChild->SetChannelId(aChannelId);
+  if (NS_FAILED(rv)) {
+    return IPC_OK();
+  }
+
+  rv = httpChild->SetOriginalURI(aOriginalURI);
+  if (NS_FAILED(rv)) {
+    return IPC_OK();
+  }
+
+  // connect parent.
+  rv = httpChild->ConnectParent(aRegistrarId);  // creates parent channel
+  if (NS_FAILED(rv)) {
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIChildProcessChannelListener> processListener =
+      do_GetService("@mozilla.org/network/childProcessChannelListener;1");
+  // The listener will call completeRedirectSetup on the channel.
+  rv = processListener->OnChannelReady(httpChild, aIdentifier);
+  if (NS_FAILED(rv)) {
+    return IPC_OK();
+  }
+
+  // scopeExit will call CrossProcessRedirectFinished(rv) here
+  return IPC_OK();
+}
+
 already_AddRefed<nsIEventTarget> ContentChild::GetSpecificMessageEventTarget(
     const Message& aMsg) {
   switch (aMsg.type()) {
     // Javascript
     case PJavaScript::Msg_DropTemporaryStrongReferences__ID:
     case PJavaScript::Msg_DropObject__ID:
 
     // Navigation
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -690,16 +690,22 @@ class ContentChild final : public PConte
       const ClientOpenWindowArgs& aArgs) override;
 
   virtual bool DeallocPClientOpenWindowOpChild(
       PClientOpenWindowOpChild* aActor) override;
 
   mozilla::ipc::IPCResult RecvSaveRecording(
       const FileDescriptor& aFile) override;
 
+  virtual mozilla::ipc::IPCResult RecvCrossProcessRedirect(
+      const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
+      const OptionalLoadInfoArgs& aLoadInfoForwarder,
+      const uint64_t& aChannelId, nsIURI* aOriginalURI,
+      const uint64_t& aIdentifier) override;
+
 #ifdef NIGHTLY_BUILD
   // Fetch the current number of pending input events.
   //
   // NOTE: This method performs an atomic read, and is safe to call from all
   // threads.
   uint32_t GetPendingInputEvents() { return mPendingInputEvents; }
 #endif
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -56,16 +56,17 @@ include ProtocolTypes;
 include PBackgroundSharedTypes;
 include PContentPermission;
 include ServiceWorkerConfiguration;
 include GraphicsMessages;
 include MemoryReportTypes;
 include ClientIPCTypes;
 include HangTypes;
 include PrefsTypes;
+include NeckoChannelParams;
 
 // Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
 // are put into different UnifiedProtocolsXX.cpp files.
 // XXX Remove this once bug 1069073 is fixed
 include "mozilla/dom/PContentBridgeParent.h";
 
 using refcounted class nsIDOMGeoPosition from "nsGeoPositionIPCSerialiser.h";
 using refcounted class nsIAlertNotification from "mozilla/AlertNotificationIPCSerializer.h";
@@ -737,16 +738,28 @@ child:
      * open windows cross-process and receive notification when the operation
      * has completed.
      */
     async PClientOpenWindowOp(ClientOpenWindowArgs aArgs);
 
     /* Save the execution up to the current point in a recording process. */
     async SaveRecording(FileDescriptor file);
 
+    // This message is sent to content processes, and triggers the creation of a
+    // new HttpChannelChild that will be connected to the parent channel
+    // represented by registrarId.
+    // This is on PContent not PNecko, as PNecko may not be initialized yet.
+    async CrossProcessRedirect(uint32_t aRegistrarId,
+                               nsIURI aURI,
+                               uint32_t aNewLoadFlags,
+                               OptionalLoadInfoArgs aLoadInfo,
+                               uint64_t aChannelId,
+                               nsIURI aOriginalURI,
+                               uint64_t aIdentifier);
+
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
                             TabId openerTabId,
                             TabId tabId)
         returns (ContentParentId cpId, bool isForBrowser);
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -153,16 +153,17 @@ LOCAL_INCLUDES += [
     '/extensions/spellcheck/src',
     '/gfx/2d',
     '/hal/sandbox',
     '/js/xpconnect/loader',
     '/js/xpconnect/src',
     '/layout/base',
     '/media/webrtc',
     '/netwerk/base',
+    '/netwerk/protocol/http',
     '/toolkit/components/printingui/ipc',
     '/toolkit/crashreporter',
     '/toolkit/xre',
     '/uriloader/exthandler',
     '/widget',
     '/xpcom/base',
     '/xpcom/threads',
 ]
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -48,17 +48,19 @@
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/dom/XMLHttpRequestEventTarget.h"
 #include "mozilla/dom/XMLHttpRequestString.h"
 #include "mozilla/Encoding.h"
 
 #ifdef Status
 /* Xlib headers insist on this for some reason... Nuke it because
    it'll override our member name */
+typedef Status __StatusTmp;
 #  undef Status
+typedef __StatusTmp Status;
 #endif
 
 class nsIJARChannel;
 class nsILoadGroup;
 
 namespace mozilla {
 namespace dom {
 
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -333,76 +333,16 @@ PTransportProviderChild* NeckoChild::All
   return res.forget().take();
 }
 
 bool NeckoChild::DeallocPTransportProviderChild(
     PTransportProviderChild* aActor) {
   return true;
 }
 
-mozilla::ipc::IPCResult NeckoChild::RecvCrossProcessRedirect(
-    const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
-    const OptionalLoadInfoArgs& aLoadInfo, const uint64_t& aChannelId,
-    nsIURI* aOriginalURI, const uint64_t& aIdentifier) {
-  nsCOMPtr<nsILoadInfo> loadInfo;
-  nsresult rv =
-      ipc::LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(loadInfo));
-  if (NS_FAILED(rv)) {
-    MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
-    return IPC_OK();
-  }
-
-  nsCOMPtr<nsIChannel> newChannel;
-  rv = NS_NewChannelInternal(getter_AddRefs(newChannel), aURI, loadInfo,
-                             nullptr,  // PerformanceStorage
-                             nullptr,  // aLoadGroup
-                             nullptr,  // aCallbacks
-                             aNewLoadFlags);
-
-  // We are sure this is a HttpChannelChild because the parent
-  // is always a HTTP channel.
-  RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);
-  if (NS_FAILED(rv) || !httpChild) {
-    MOZ_DIAGNOSTIC_ASSERT(false, "NS_NewChannelInternal failed");
-    return IPC_OK();
-  }
-
-  // This is used to report any errors back to the parent by calling
-  // CrossProcessRedirectFinished.
-  auto scopeExit =
-      MakeScopeExit([&]() { httpChild->CrossProcessRedirectFinished(rv); });
-
-  rv = httpChild->SetChannelId(aChannelId);
-  if (NS_FAILED(rv)) {
-    return IPC_OK();
-  }
-
-  rv = httpChild->SetOriginalURI(aOriginalURI);
-  if (NS_FAILED(rv)) {
-    return IPC_OK();
-  }
-
-  // connect parent.
-  rv = httpChild->ConnectParent(aRegistrarId);  // creates parent channel
-  if (NS_FAILED(rv)) {
-    return IPC_OK();
-  }
-
-  nsCOMPtr<nsIChildProcessChannelListener> processListener =
-      do_GetClassObject("@mozilla.org/network/childProcessChannelListener");
-  // The listener will call completeRedirectSetup on the channel.
-  rv = processListener->OnChannelReady(httpChild, aIdentifier);
-  if (NS_FAILED(rv)) {
-    return IPC_OK();
-  }
-
-  // scopeExit will call CrossProcessRedirectFinished(rv) here
-  return IPC_OK();
-}
-
 mozilla::ipc::IPCResult NeckoChild::RecvAsyncAuthPromptForNestedFrame(
     const TabId& aNestedFrameId, const nsCString& aUri, const nsString& aRealm,
     const uint64_t& aCallbackId) {
   RefPtr<dom::TabChild> tabChild = dom::TabChild::FindTabChild(aNestedFrameId);
   if (!tabChild) {
     MOZ_CRASH();
     return IPC_FAIL_NO_REASON(this);
   }
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -100,22 +100,16 @@ class NeckoChild : public PNeckoChild {
       const URIParams& aURI) override;
   virtual mozilla::ipc::IPCResult RecvPredOnPredictDNS(
       const URIParams& aURI) override;
 
   virtual mozilla::ipc::IPCResult RecvSpeculativeConnectRequest() override;
   virtual mozilla::ipc::IPCResult RecvNetworkChangeNotification(
       nsCString const& type) override;
 
-  virtual mozilla::ipc::IPCResult RecvCrossProcessRedirect(
-      const uint32_t& aRegistrarId, nsIURI* aURI, const uint32_t& aNewLoadFlags,
-      const OptionalLoadInfoArgs& aLoadInfoForwarder,
-      const uint64_t& aChannelId, nsIURI* aOriginalURI,
-      const uint64_t& aIdentifier) override;
-
   virtual PTrackingDummyChannelChild* AllocPTrackingDummyChannelChild(
       nsIURI* aURI, nsIURI* aTopWindowURI, const nsresult& aTopWindowURIResult,
       const OptionalLoadInfoArgs& aLoadInfo) override;
 
   virtual bool DeallocPTrackingDummyChannelChild(
       PTrackingDummyChannelChild* aChannel) override;
 };
 
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -164,27 +164,16 @@ child:
   async SpeculativeConnectRequest();
 
   // Using high priority to deliver this notification possibly sooner than we
   // enter poll() on the child process with infinite timeout.
   prio(high) async NetworkChangeNotification(nsCString type);
 
   async PTransportProvider();
 
-  // This message is sent to PNecko and triggers the creation of a new
-  // HttpChannelChild that will be connected to the parent channel represented
-  // by registrarId.
-  async CrossProcessRedirect(uint32_t aRegistrarId,
-                             nsIURI aURI,
-                             uint32_t aNewLoadFlags,
-                             OptionalLoadInfoArgs aLoadInfo,
-                             uint64_t aChannelId,
-                             nsIURI aOriginalURI,
-                             uint64_t aIdentifier);
-
 both:
   // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
   // signatures on parent and child. So when constructing the parent side object, we just
   // leave host/port unused.
   async PTCPSocket(nsString host, uint16_t port);
 };
 
 
--- a/netwerk/protocol/http/HttpChannelParentListener.cpp
+++ b/netwerk/protocol/http/HttpChannelParentListener.cpp
@@ -193,25 +193,23 @@ nsresult HttpChannelParentListener::Trig
         nsCOMPtr<nsIURI> originalURI;
         channel->GetOriginalURI(getter_AddRefs(originalURI));
 
         uint64_t channelId;
         MOZ_ALWAYS_SUCCEEDS(httpChannel->GetChannelId(&channelId));
 
         dom::TabParent* tabParent = dom::TabParent::GetFrom(tp);
         ContentParent* cp = tabParent->Manager()->AsContentParent();
-        PNeckoParent* neckoParent =
-            SingleManagedOrNull(cp->ManagedPNeckoParent());
 
         RefPtr<HttpChannelParent> channelParent =
             do_QueryObject(self->mNextListener);
         MOZ_ASSERT(channelParent);
         channelParent->SetCrossProcessRedirect();
 
-        auto result = neckoParent->SendCrossProcessRedirect(
+        auto result = cp->SendCrossProcessRedirect(
             self->mRedirectChannelId, uri, newLoadFlags, loadInfoArgs,
             channelId, originalURI, aIdentifier);
 
         MOZ_ASSERT(result, "SendCrossProcessRedirect failed");
 
         return result ? NS_OK : NS_ERROR_UNEXPECTED;
       },
       [httpChannel](nsresult aStatus) {
--- a/netwerk/protocol/http/nsAHttpTransaction.h
+++ b/netwerk/protocol/http/nsAHttpTransaction.h
@@ -4,16 +4,24 @@
 
 #ifndef nsAHttpTransaction_h__
 #define nsAHttpTransaction_h__
 
 #include "nsISupports.h"
 #include "nsTArray.h"
 #include "nsWeakReference.h"
 
+#ifdef Status
+/* Xlib headers insist on this for some reason... Nuke it because
+   it'll override our member name */
+typedef Status __StatusTmp;
+#undef Status
+typedef __StatusTmp Status;
+#endif
+
 class nsIInterfaceRequestor;
 class nsITransport;
 class nsIRequestContext;
 
 namespace mozilla {
 namespace net {
 
 class nsAHttpConnection;
--- a/netwerk/protocol/http/nsHttpResponseHead.h
+++ b/netwerk/protocol/http/nsHttpResponseHead.h
@@ -6,16 +6,24 @@
 #ifndef nsHttpResponseHead_h__
 #define nsHttpResponseHead_h__
 
 #include "nsHttpHeaderArray.h"
 #include "nsHttp.h"
 #include "nsString.h"
 #include "mozilla/RecursiveMutex.h"
 
+#ifdef Status
+/* Xlib headers insist on this for some reason... Nuke it because
+   it'll override our member name */
+typedef Status __StatusTmp;
+#undef Status
+typedef __StatusTmp Status;
+#endif
+
 class nsIHttpHeaderVisitor;
 
 // This needs to be forward declared here so we can include only this header
 // without also including PHttpChannelParams.h
 namespace IPC {
 template <typename>
 struct ParamTraits;
 }  // namespace IPC
@@ -44,18 +52,16 @@ class nsHttpResponseHead {
 
   nsHttpResponseHead(const nsHttpResponseHead &aOther);
   nsHttpResponseHead &operator=(const nsHttpResponseHead &aOther);
 
   void Enter() { mRecursiveMutex.Lock(); }
   void Exit() { mRecursiveMutex.Unlock(); }
 
   HttpVersion Version();
-// X11's Xlib.h #defines 'Status' to 'int' on some systems!
-#undef Status
   uint16_t Status();
   void StatusText(nsACString &aStatusText);
   int64_t ContentLength();
   void ContentType(nsACString &aContentType);
   void ContentCharset(nsACString &aContentCharset);
   bool Private();
   bool NoStore();
   bool NoCache();
--- a/netwerk/test/browser/browser_cross_process_redirect.js
+++ b/netwerk/test/browser/browser_cross_process_redirect.js
@@ -176,17 +176,17 @@ add_task(async function() {
     // We register the listener in process no. 2
     return new Promise(resolve => {
       var childListener = new content.window.ChildListener(arg.URI, arg.originalURI, resolve);
       var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
       childListener.onComplete = () => {
         registrar.unregisterFactory(childListener.classID, childListener);
       }
       registrar.registerFactory(childListener.classID, "",
-                              "@mozilla.org/network/childProcessChannelListener",
+                              "@mozilla.org/network/childProcessChannelListener;1",
                               childListener);
     });
   });
 
   let browser1LoadHasStopped = BrowserTestUtils.browserStopped(browser1);
 
   await BrowserTestUtils.loadURI(browser1, kRoot1 + "redirect.sjs?" + kRoot2 + "dummy.html");
 
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -59,27 +59,16 @@ static LazyLogModule gPrefetchLog("nsPre
 #define LOG_ENABLED() MOZ_LOG_TEST(gPrefetchLog, mozilla::LogLevel::Debug)
 
 #define PREFETCH_PREF "network.prefetch-next"
 #define PRELOAD_PREF "network.preload"
 #define PARALLELISM_PREF "network.prefetch-next.parallelism"
 #define AGGRESSIVE_PREF "network.prefetch-next.aggressive"
 
 //-----------------------------------------------------------------------------
-// helpers
-//-----------------------------------------------------------------------------
-
-static inline uint32_t PRTimeToSeconds(PRTime t_usec) {
-  PRTime usec_per_sec = PR_USEC_PER_SEC;
-  return uint32_t(t_usec /= usec_per_sec);
-}
-
-#define NowInSeconds() PRTimeToSeconds(PR_Now())
-
-//-----------------------------------------------------------------------------
 // nsPrefetchNode <public>
 //-----------------------------------------------------------------------------
 
 nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService, nsIURI *aURI,
                                nsIURI *aReferrerURI, nsINode *aSource,
                                nsContentPolicyType aPolicyType, bool aPreload)
     : mURI(aURI),
       mReferrerURI(aReferrerURI),