Bug 1441932 P3 Forward reserved client, initial client, and controller on Redirect2Verify message back to parent. r=mayhemer
authorBen Kelly <ben@wanderview.com>
Mon, 04 Jun 2018 09:26:51 -0700
changeset 421208 de52f4e67dacff658acb548d3072ce3c80edbdc8
parent 421207 503612a3376769c17b107cbecc9641cf11772c66
child 421209 55a9e16be96084570c64e50229c88aca43c12c52
push id34090
push userbtara@mozilla.com
push dateTue, 05 Jun 2018 09:30:51 +0000
treeherdermozilla-central@a358755643e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1441932
milestone62.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 1441932 P3 Forward reserved client, initial client, and controller on Redirect2Verify message back to parent. r=mayhemer
ipc/glue/BackgroundUtils.cpp
ipc/glue/BackgroundUtils.h
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -625,10 +625,96 @@ MergeParentLoadInfoForwarder(ParentLoadI
   if (controller.type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     aLoadInfo->SetController(
       ServiceWorkerDescriptor(controller.get_IPCServiceWorkerDescriptor()));
   }
 
   return NS_OK;
 }
 
+void
+LoadInfoToChildLoadInfoForwarder(nsILoadInfo* aLoadInfo,
+                                 ChildLoadInfoForwarderArgs* aForwarderArgsOut)
+{
+  if (!aLoadInfo) {
+    *aForwarderArgsOut = ChildLoadInfoForwarderArgs(void_t(), void_t(),
+                                                    void_t());
+    return;
+  }
+
+  OptionalIPCClientInfo ipcReserved = void_t();
+  Maybe<ClientInfo> reserved(aLoadInfo->GetReservedClientInfo());
+  if (reserved.isSome()) {
+    ipcReserved = reserved.ref().ToIPC();
+  }
+
+  OptionalIPCClientInfo ipcInitial = void_t();
+  Maybe<ClientInfo> initial(aLoadInfo->GetInitialClientInfo());
+  if (initial.isSome()) {
+    ipcInitial = initial.ref().ToIPC();
+  }
+
+  OptionalIPCServiceWorkerDescriptor ipcController = void_t();
+  Maybe<ServiceWorkerDescriptor> controller(aLoadInfo->GetController());
+  if (controller.isSome()) {
+    ipcController = controller.ref().ToIPC();
+  }
+
+  *aForwarderArgsOut = ChildLoadInfoForwarderArgs(
+    ipcReserved,
+    ipcInitial,
+    ipcController
+  );
+}
+
+nsresult
+MergeChildLoadInfoForwarder(const ChildLoadInfoForwarderArgs& aForwarderArgs,
+                            nsILoadInfo* aLoadInfo)
+{
+  if (!aLoadInfo) {
+    return NS_OK;
+  }
+
+  Maybe<ClientInfo> reservedClientInfo;
+  auto& ipcReserved = aForwarderArgs.reservedClientInfo();
+  if (ipcReserved.type() != OptionalIPCClientInfo::Tvoid_t) {
+    reservedClientInfo.emplace(ClientInfo(ipcReserved.get_IPCClientInfo()));
+  }
+
+  Maybe<ClientInfo> initialClientInfo;
+  auto& ipcInitial = aForwarderArgs.initialClientInfo();
+  if (ipcInitial.type() != OptionalIPCClientInfo::Tvoid_t) {
+    initialClientInfo.emplace(ClientInfo(ipcInitial.get_IPCClientInfo()));
+  }
+
+  // There should only be at most one reserved or initial ClientInfo.
+  if (NS_WARN_IF(reservedClientInfo.isSome() && initialClientInfo.isSome())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // If we received no reserved or initial ClientInfo, then we must not
+  // already have one set.  There are no use cases where this should
+  // happen and we don't have a way to clear the current value.
+  if (NS_WARN_IF(reservedClientInfo.isNothing() &&
+                 initialClientInfo.isNothing() &&
+                 (aLoadInfo->GetReservedClientInfo().isSome() ||
+                  aLoadInfo->GetInitialClientInfo().isSome()))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (reservedClientInfo.isSome()) {
+    aLoadInfo->SetReservedClientInfo(reservedClientInfo.ref());
+  } else if (initialClientInfo.isSome()) {
+    aLoadInfo->SetInitialClientInfo(initialClientInfo.ref());
+  }
+
+  aLoadInfo->ClearController();
+  auto& controller = aForwarderArgs.controller();
+  if (controller.type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
+    aLoadInfo->SetController(
+      ServiceWorkerDescriptor(controller.get_IPCServiceWorkerDescriptor()));
+  }
+
+  return NS_OK;
+}
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/BackgroundUtils.h
+++ b/ipc/glue/BackgroundUtils.h
@@ -44,16 +44,17 @@ struct OriginAttributesParamTraits
 template<>
 struct ParamTraits<mozilla::OriginAttributes>
   : public detail::OriginAttributesParamTraits<mozilla::OriginAttributes> {};
 
 } // namespace IPC
 
 namespace mozilla {
 namespace net {
+class ChildLoadInfoForwarderArgs;
 class OptionalLoadInfoArgs;
 class ParentLoadInfoForwarderArgs;
 class RedirectHistoryEntryInfo;
 } // namespace net
 
 namespace ipc {
 
 class PrincipalInfo;
@@ -122,12 +123,28 @@ LoadInfoToParentLoadInfoForwarder(nsILoa
 /**
  * Merges (replaces) properties of an existing LoadInfo on a child process
  * with properties carried down through ParentLoadInfoForwarderArgs.
  */
 nsresult
 MergeParentLoadInfoForwarder(mozilla::net::ParentLoadInfoForwarderArgs const& aForwarderArgs,
                              nsILoadInfo *aLoadInfo);
 
+/**
+ * Fills ChildLoadInfoForwarderArgs with properties we want to carry to the
+ * parent process after the initial channel creation.
+ */
+void
+LoadInfoToChildLoadInfoForwarder(nsILoadInfo* aLoadInfo,
+                                 mozilla::net::ChildLoadInfoForwarderArgs* aForwarderArgsOut);
+
+/**
+ * Merges (replaces) properties of an existing LoadInfo on the parent process
+ * with properties contained in a ChildLoadInfoForwarderArgs.
+ */
+nsresult
+MergeChildLoadInfoForwarder(const mozilla::net::ChildLoadInfoForwarderArgs& aForwardArgs,
+                            nsILoadInfo* aLoadInfo);
+
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_backgroundutils_h__
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -132,16 +132,35 @@ struct ParentLoadInfoForwarderArgs
   // interception occurs.
   OptionalIPCServiceWorkerDescriptor controller;
 
   // IMPORTANT: when you add new properites here you must also update
   // LoadInfoToParentLoadInfoForwarder and MergeParentLoadInfoForwarder
   // in BackgroundUtils.cpp/.h!
 };
 
+/**
+ * This structure is used to carry selected properties of a LoadInfo
+ * object to the parent process that might have changed in the child
+ * during a redirect.  We don't want to use LoadInfoArgs for that since
+ * it's too huge and we only care about small subpart of properties
+ * anyway.
+ */
+struct ChildLoadInfoForwarderArgs
+{
+  // The reserved and initial ClientInfo values may change during a
+  // redirect if the new channel is cross-origin to the old channel.
+  OptionalIPCClientInfo reservedClientInfo;
+  OptionalIPCClientInfo initialClientInfo;
+
+  // The ServiceWorker controller may be cleared in the child during
+  // a redirect.
+  OptionalIPCServiceWorkerDescriptor controller;
+};
+
 //-----------------------------------------------------------------------------
 // HTTP IPDL structs
 //-----------------------------------------------------------------------------
 
 union OptionalHttpResponseHead
 {
   void_t;
   nsHttpResponseHead;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2310,20 +2310,29 @@ HttpChannelChild::OnRedirectVerifyCallba
 
   bool chooseAppcache = false;
   nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
     do_QueryInterface(newHttpChannel);
   if (appCacheChannel) {
     appCacheChannel->GetChooseApplicationCache(&chooseAppcache);
   }
 
+  nsCOMPtr<nsILoadInfo> newChannelLoadInfo;
+  nsCOMPtr<nsIChannel> newChannel = do_QueryInterface(mRedirectChannelChild);
+  if (newChannel) {
+    Unused << newChannel->GetLoadInfo(getter_AddRefs(newChannelLoadInfo));
+  }
+
+  ChildLoadInfoForwarderArgs loadInfoForwarder;
+  LoadInfoToChildLoadInfoForwarder(newChannelLoadInfo, &loadInfoForwarder);
+
   if (mIPCOpen)
-    SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
-                        referrerURI, redirectURI, corsPreflightArgs,
-                        chooseAppcache);
+    SendRedirect2Verify(result, *headerTuples, loadInfoForwarder, loadFlags,
+                        referrerPolicy, referrerURI, redirectURI,
+                        corsPreflightArgs, chooseAppcache);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIRequest
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -874,28 +874,36 @@ HttpChannelParent::RecvUpdateAssociatedC
   if (mAssociatedContentSecurity) {
     mAssociatedContentSecurity->SetCountSubRequestsBrokenSecurity(broken);
     mAssociatedContentSecurity->SetCountSubRequestsNoSecurity(no);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
+HttpChannelParent::RecvRedirect2Verify(const nsresult& aResult,
                                        const RequestHeaderTuples& changedHeaders,
+                                       const ChildLoadInfoForwarderArgs& aLoadInfoForwarder,
                                        const uint32_t& loadFlags,
                                        const uint32_t& referrerPolicy,
                                        const OptionalURIParams& aReferrerURI,
                                        const OptionalURIParams& aAPIRedirectURI,
                                        const OptionalCorsPreflightArgs& aCorsPreflightArgs,
                                        const bool& aChooseAppcache)
 {
   LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
-       this, static_cast<uint32_t>(result)));
+       this, static_cast<uint32_t>(aResult)));
+
+  // Result from the child.  If something fails here, we might overwrite a
+  // success with a further failure.
+  nsresult result = aResult;
+
+  // Local results.
   nsresult rv;
+
   if (NS_SUCCEEDED(result)) {
     nsCOMPtr<nsIHttpChannel> newHttpChannel =
         do_QueryInterface(mRedirectChannel);
 
     if (newHttpChannel) {
       nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
 
       if (apiRedirectUri) {
@@ -932,16 +940,23 @@ HttpChannelParent::RecvRedirect2Verify(c
       rv = newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
 
       nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
         do_QueryInterface(newHttpChannel);
       if (appCacheChannel) {
         appCacheChannel->SetChooseApplicationCache(aChooseAppcache);
       }
+
+      nsCOMPtr<nsILoadInfo> newLoadInfo;
+      Unused << newHttpChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
+      rv = MergeChildLoadInfoForwarder(aLoadInfoForwarder, newLoadInfo);
+      if (NS_FAILED(rv) && NS_SUCCEEDED(result)) {
+        result = rv;
+      }
     }
   }
 
   // Continue the verification procedure if child has veto the redirection.
   if (NS_FAILED(result)) {
     ContinueRedirect2Verify(result);
     return IPC_OK();
   }
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -184,16 +184,17 @@ protected:
   virtual mozilla::ipc::IPCResult RecvSetPriority(const int16_t& priority) override;
   virtual mozilla::ipc::IPCResult RecvSetClassOfService(const uint32_t& cos) override;
   virtual mozilla::ipc::IPCResult RecvSetCacheTokenCachedCharset(const nsCString& charset) override;
   virtual mozilla::ipc::IPCResult RecvSuspend() override;
   virtual mozilla::ipc::IPCResult RecvResume() override;
   virtual mozilla::ipc::IPCResult RecvCancel(const nsresult& status) override;
   virtual mozilla::ipc::IPCResult RecvRedirect2Verify(const nsresult& result,
                                                       const RequestHeaderTuples& changedHeaders,
+                                                      const ChildLoadInfoForwarderArgs& aLoadInfoForwarder,
                                                       const uint32_t& loadFlags,
                                                       const uint32_t& referrerPolicy,
                                                       const OptionalURIParams& aReferrerURI,
                                                       const OptionalURIParams& apiRedirectUri,
                                                       const OptionalCorsPreflightArgs& aCorsPreflightArgs,
                                                       const bool& aChooseAppcache) override;
   virtual mozilla::ipc::IPCResult RecvUpdateAssociatedContentSecurity(const int32_t& broken,
                                                    const int32_t& no) override;
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -39,16 +39,17 @@ parent:
                                         int32_t no);
   async Suspend();
   async Resume();
 
   async Cancel(nsresult status);
 
   // Reports approval/veto of redirect by child process redirect observers
   async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders,
+                        ChildLoadInfoForwarderArgs loadInfoForwarder,
                         uint32_t loadFlags, uint32_t referrerPolicy,
                         OptionalURIParams referrerUri,
                         OptionalURIParams apiRedirectTo,
                         OptionalCorsPreflightArgs corsPreflightArgs,
                         bool chooseAppcache);
 
   // For document loads we keep this protocol open after child's
   // OnStopRequest, and send this msg (instead of __delete__) to allow