Bug 1231211 P12 Allow the ClientInfo and ServiceWorkerDescriptor to be passed to NS_NewChannel() for principal based loads. r=valentin
authorBen Kelly <ben@wanderview.com>
Tue, 23 Jan 2018 10:38:54 -0500
changeset 453016 60a29396c52fcd556f9f0ebf52f11811cf7f912d
parent 453015 af8c5b7bf7961f4324412b5aeafef68e018328cc
child 453017 8fc3f67ba98e4dd0ec5be63349a6c0ab6df996d8
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1231211
milestone60.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 1231211 P12 Allow the ClientInfo and ServiceWorkerDescriptor to be passed to NS_NewChannel() for principal based loads. r=valentin
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsIIOService.idl
netwerk/base/nsIOService.cpp
netwerk/base/nsIOService.h
netwerk/base/nsNetUtil.cpp
netwerk/base/nsNetUtil.h
uriloader/prefetch/nsPrefetchService.cpp
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -41,22 +41,26 @@ FindTopOuterWindowID(nsPIDOMWindowOuter*
   }
   return outer->WindowID();
 }
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsINode* aLoadingContext,
                    nsSecurityFlags aSecurityFlags,
-                   nsContentPolicyType aContentPolicyType)
+                   nsContentPolicyType aContentPolicyType,
+                   const Maybe<mozilla::dom::ClientInfo>& aLoadingClientInfo,
+                   const Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController)
   : mLoadingPrincipal(aLoadingContext ?
                         aLoadingContext->NodePrincipal() : aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal ?
                            aTriggeringPrincipal : mLoadingPrincipal.get())
   , mPrincipalToInherit(nullptr)
+  , mClientInfo(aLoadingClientInfo)
+  , mController(aController)
   , mLoadingContext(do_GetWeakReference(aLoadingContext))
   , mContextForTopLevelLoad(nullptr)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
   , mEnforceSRI(false)
@@ -88,16 +92,21 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
 #endif
 
   // This constructor shouldn't be used for TYPE_DOCUMENT loads that don't
   // have a loadingPrincipal
   MOZ_ASSERT(skipContentTypeCheck ||
              mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT);
 
+  // We should only get an explicit controller for subresource requests.
+  MOZ_DIAGNOSTIC_ASSERT(
+    aController.isNothing() ||
+    !nsContentUtils::IsNonSubresourceInternalPolicyType(mInternalContentPolicyType));
+
   // TODO(bug 1259873): Above, we initialize mIsThirdPartyContext to false meaning
   // that consumers of LoadInfo that don't pass a context or pass a context from
   // which we can't find a window will default to assuming that they're 1st
   // party. It would be nice if we could default "safe" and assume that we are
   // 3rd party until proven otherwise.
 
   // if consumers pass both, aLoadingContext and aLoadingPrincipal
   // then the loadingPrincipal must be the same as the node's principal
@@ -108,26 +117,28 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
     mForceInheritPrincipalDropped =
       (mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL);
     mSecurityFlags &= ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
   if (aLoadingContext) {
     // Ensure that all network requests for a window client have the ClientInfo
-    // properly set.
-    // TODO: The ClientInfo is not set properly for worker initiated requests yet.
-    mClientInfo = aLoadingContext->OwnerDoc()->GetClientInfo();
+    // properly set.  Workers must currently pass the loading ClientInfo explicitly.
+    // We allow main thread requests to explicitly pass the value as well.
+    if (mClientInfo.isNothing()) {
+      mClientInfo = aLoadingContext->OwnerDoc()->GetClientInfo();
+    }
 
     // For subresource loads set the service worker based on the calling
-    // context's controller.
-    // TODO: The controller is not set properly for all requests initiated from a
-    //       worker context.  Some workers will not have an nsINode loading context
-    //       here.
-    if (!nsContentUtils::IsNonSubresourceInternalPolicyType(mInternalContentPolicyType)) {
+    // context's controller.  Workers must currently pass the controller in
+    // explicitly.  We allow main thread requests to explicitly pass the value
+    // as well, but otherwise extract from the loading context here.
+    if (mController.isNothing() &&
+        !nsContentUtils::IsNonSubresourceInternalPolicyType(mInternalContentPolicyType)) {
       mController = aLoadingContext->OwnerDoc()->GetController();
     }
 
     nsCOMPtr<nsPIDOMWindowOuter> contextOuter = aLoadingContext->OwnerDoc()->GetWindow();
     if (contextOuter) {
       ComputeIsThirdPartyContext(contextOuter);
       mOuterWindowID = contextOuter->WindowID();
       nsCOMPtr<nsPIDOMWindowOuter> parent = contextOuter->GetScriptableParent();
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -51,17 +51,21 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSILOADINFO
 
   // aLoadingPrincipal MUST NOT BE NULL.
   LoadInfo(nsIPrincipal* aLoadingPrincipal,
            nsIPrincipal* aTriggeringPrincipal,
            nsINode* aLoadingContext,
            nsSecurityFlags aSecurityFlags,
-           nsContentPolicyType aContentPolicyType);
+           nsContentPolicyType aContentPolicyType,
+           const Maybe<mozilla::dom::ClientInfo>& aLoadingClientInfo
+              = Maybe<mozilla::dom::ClientInfo>(),
+           const Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController
+              = Maybe<mozilla::dom::ServiceWorkerDescriptor>());
 
   // Constructor used for TYPE_DOCUMENT loads which have a different
   // loadingContext than other loads. This ContextForTopLevelLoad is
   // only used for content policy checks.
   LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
            nsIPrincipal* aTriggeringPrincipal,
            nsISupports* aContextForTopLevelLoad,
            nsSecurityFlags aSecurityFlags);
--- a/netwerk/base/nsIIOService.idl
+++ b/netwerk/base/nsIIOService.idl
@@ -8,16 +8,30 @@
 interface nsIProtocolHandler;
 interface nsIChannel;
 interface nsIURI;
 interface nsIFile;
 interface nsIDOMNode;
 interface nsIPrincipal;
 interface nsILoadInfo;
 
+%{C++
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+namespace dom {
+class ClientInfo;
+class ServiceWorkerDescriptor;
+} // namespace dom
+} // namespace mozilla
+%}
+
+[ref] native const_MaybeClientInfoRef(const mozilla::Maybe<mozilla::dom::ClientInfo>);
+[ref] native const_MaybeServiceWorkerDescriptorRef(const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>);
+
 /**
  * nsIIOService provides a set of network utility functions.  This interface
  * duplicates many of the nsIProtocolHandler methods in a protocol handler
  * independent way (e.g., NewURI inspects the scheme in order to delegate
  * creation of the new URI to the appropriate protocol handler).  nsIIOService
  * also provides a set of URL parsing utility functions.  These are provided
  * as a convenience to the programmer and in some cases to improve performance
  * by eliminating intermediate data structures and interfaces.
@@ -88,16 +102,27 @@ interface nsIIOService : nsISupports
      */
     nsIChannel newChannelFromURI2(in nsIURI aURI,
                                   in nsIDOMNode aLoadingNode,
                                   in nsIPrincipal aLoadingPrincipal,
                                   in nsIPrincipal aTriggeringPrincipal,
                                   in unsigned long aSecurityFlags,
                                   in unsigned long aContentPolicyType);
 
+    [noscript, nostdcall, notxpcom]
+    nsresult NewChannelFromURIWithClientAndController(in nsIURI aURI,
+                                                      in nsIDOMNode aLoadingNode,
+                                                      in nsIPrincipal aLoadingPrincipal,
+                                                      in nsIPrincipal aTriggeringPrincipal,
+                                                      in const_MaybeClientInfoRef aLoadingClientInfo,
+                                                      in const_MaybeServiceWorkerDescriptorRef aController,
+                                                      in unsigned long aSecurityFlags,
+                                                      in unsigned long aContentPolicyType,
+                                                      out nsIChannel aResult);
+
     /**
      * Equivalent to newChannelFromURI2(aURI, aLoadingNode, ...)
      */
     nsIChannel newChannelFromURIWithLoadInfo(in nsIURI aURI,
                                              in nsILoadInfo aLoadInfo);
 
     /**
      * Equivalent to newChannelFromURI2(newURI(...))
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -47,27 +47,33 @@
 #include "nsThreadUtils.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/net/DNS.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChild.h"
+#include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/Unused.h"
 #include "ReferrerPolicy.h"
 #include "nsContentSecurityManager.h"
 #include "nsContentUtils.h"
 #include "xpcpublic.h"
 
 namespace mozilla {
 namespace net {
 
+using mozilla::Maybe;
+using mozilla::dom::ClientInfo;
+using mozilla::dom::ServiceWorkerDescriptor;
+
 #define PORT_PREF_PREFIX           "network.security.ports."
 #define PORT_PREF(x)               PORT_PREF_PREFIX x
 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
 #define OFFLINE_MIRRORS_CONNECTIVITY "network.offline-mirrors-connectivity"
 
 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
 // "network.segment.count" and "network.segment.size" would be better names,
 // but the old names are still used to preserve backward compatibility.
@@ -729,16 +735,39 @@ nsIOService::NewChannelFromURI2(nsIURI* 
                                             0,       // aProxyFlags
                                             aLoadingNode,
                                             aLoadingPrincipal,
                                             aTriggeringPrincipal,
                                             aSecurityFlags,
                                             aContentPolicyType,
                                             result);
 }
+nsresult
+nsIOService::NewChannelFromURIWithClientAndController(nsIURI* aURI,
+                                                      nsIDOMNode* aLoadingNode,
+                                                      nsIPrincipal* aLoadingPrincipal,
+                                                      nsIPrincipal* aTriggeringPrincipal,
+                                                      const Maybe<ClientInfo>& aLoadingClientInfo,
+                                                      const Maybe<ServiceWorkerDescriptor>& aController,
+                                                      uint32_t aSecurityFlags,
+                                                      uint32_t aContentPolicyType,
+                                                      nsIChannel** aResult)
+{
+    return NewChannelFromURIWithProxyFlagsInternal(aURI,
+                                                   nullptr, // aProxyURI
+                                                   0,       // aProxyFlags
+                                                   aLoadingNode,
+                                                   aLoadingPrincipal,
+                                                   aTriggeringPrincipal,
+                                                   aLoadingClientInfo,
+                                                   aController,
+                                                   aSecurityFlags,
+                                                   aContentPolicyType,
+                                                   aResult);
+}
 
 /*  ***** DEPRECATED *****
  * please use NewChannelFromURI2 providing the right arguments for:
  *        * aLoadingNode
  *        * aLoadingPrincipal
  *        * aTriggeringPrincipal
  *        * aSecurityFlags
  *        * aContentPolicyType
@@ -777,16 +806,62 @@ nsIOService::NewChannelFromURIWithLoadIn
 {
   return NewChannelFromURIWithProxyFlagsInternal(aURI,
                                                  nullptr, // aProxyURI
                                                  0,       // aProxyFlags
                                                  aLoadInfo,
                                                  result);
 }
 
+
+nsresult
+nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
+                                                     nsIURI* aProxyURI,
+                                                     uint32_t aProxyFlags,
+                                                     nsIDOMNode* aLoadingNode,
+                                                     nsIPrincipal* aLoadingPrincipal,
+                                                     nsIPrincipal* aTriggeringPrincipal,
+                                                     const Maybe<ClientInfo>& aLoadingClientInfo,
+                                                     const Maybe<ServiceWorkerDescriptor>& aController,
+                                                     uint32_t aSecurityFlags,
+                                                     uint32_t aContentPolicyType,
+                                                     nsIChannel** result)
+{
+    // Ideally all callers of NewChannelFromURIWithProxyFlagsInternal provide
+    // the necessary arguments to create a loadinfo.
+    //
+    // Note, historically this could be called with nullptr aLoadingNode,
+    // aLoadingPrincipal, and aTriggeringPrincipal from addons using
+    // newChannelFromURIWithProxyFlags().  This code tried to accomodate
+    // by not creating a LoadInfo in such cases.  Now that both the legacy
+    // addons and that API are gone we could possibly require always creating a
+    // LoadInfo here.  See bug 1432205.
+    nsCOMPtr<nsILoadInfo> loadInfo;
+
+    // TYPE_DOCUMENT loads don't require a loadingNode or principal, but other
+    // types do.
+    if (aLoadingNode || aLoadingPrincipal ||
+        aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
+      nsCOMPtr<nsINode> loadingNode(do_QueryInterface(aLoadingNode));
+      loadInfo = new LoadInfo(aLoadingPrincipal,
+                              aTriggeringPrincipal,
+                              loadingNode,
+                              aSecurityFlags,
+                              aContentPolicyType,
+                              aLoadingClientInfo,
+                              aController);
+    }
+    NS_ASSERTION(loadInfo, "Please pass security info when creating a channel");
+    return NewChannelFromURIWithProxyFlagsInternal(aURI,
+                                                   aProxyURI,
+                                                   aProxyFlags,
+                                                   loadInfo,
+                                                   result);
+}
+
 nsresult
 nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
                                                      nsIURI* aProxyURI,
                                                      uint32_t aProxyFlags,
                                                      nsILoadInfo* aLoadInfo,
                                                      nsIChannel** result)
 {
     nsresult rv;
@@ -902,46 +977,26 @@ nsIOService::NewChannelFromURIWithProxyF
                                               uint32_t aProxyFlags,
                                               nsIDOMNode* aLoadingNode,
                                               nsIPrincipal* aLoadingPrincipal,
                                               nsIPrincipal* aTriggeringPrincipal,
                                               uint32_t aSecurityFlags,
                                               uint32_t aContentPolicyType,
                                               nsIChannel** result)
 {
-    // Ideally all callers of NewChannelFromURIWithProxyFlags2 provide the
-    // necessary arguments to create a loadinfo. Keep in mind that addons
-    // might still call NewChannelFromURIWithProxyFlags() which forwards
-    // its calls to NewChannelFromURIWithProxyFlags2 using *null* values
-    // as the arguments for aLoadingNode, aLoadingPrincipal, and also
-    // aTriggeringPrincipal.
-    // We do not want to break those addons, hence we only create a Loadinfo
-    // if 'aLoadingNode' or 'aLoadingPrincipal' are provided. Note, that
-    // either aLoadingNode or aLoadingPrincipal is required to succesfully
-    // create a LoadInfo object.
-    // Except in the case of top level TYPE_DOCUMENT loads, where the
-    // loadingNode and loadingPrincipal are allowed to have null values.
-    nsCOMPtr<nsILoadInfo> loadInfo;
-
-    // TYPE_DOCUMENT loads don't require a loadingNode or principal, but other
-    // types do.
-    if (aLoadingNode || aLoadingPrincipal ||
-        aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
-      nsCOMPtr<nsINode> loadingNode(do_QueryInterface(aLoadingNode));
-      loadInfo = new LoadInfo(aLoadingPrincipal,
-                              aTriggeringPrincipal,
-                              loadingNode,
-                              aSecurityFlags,
-                              aContentPolicyType);
-    }
-    NS_ASSERTION(loadInfo, "Please pass security info when creating a channel");
     return NewChannelFromURIWithProxyFlagsInternal(aURI,
                                                    aProxyURI,
                                                    aProxyFlags,
-                                                   loadInfo,
+                                                   aLoadingNode,
+                                                   aLoadingPrincipal,
+                                                   aTriggeringPrincipal,
+                                                   Maybe<ClientInfo>(),
+                                                   Maybe<ServiceWorkerDescriptor>(),
+                                                   aSecurityFlags,
+                                                   aContentPolicyType,
                                                    result);
 }
 
 NS_IMETHODIMP
 nsIOService::NewChannel2(const nsACString& aSpec,
                          const char* aCharset,
                          nsIURI* aBaseURI,
                          nsIDOMNode* aLoadingNode,
--- a/netwerk/base/nsIOService.h
+++ b/netwerk/base/nsIOService.h
@@ -136,16 +136,28 @@ private:
     nsresult InitializeNetworkLinkService();
     nsresult InitializeProtocolProxyService();
 
     // consolidated helper function
     void LookupProxyInfo(nsIURI *aURI, nsIURI *aProxyURI, uint32_t aProxyFlags,
                          nsCString *aScheme, nsIProxyInfo **outPI);
 
     nsresult NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
+                                                    nsIURI* aProxyURI,
+                                                    uint32_t aProxyFlags,
+                                                    nsIDOMNode* aLoadingNode,
+                                                    nsIPrincipal* aLoadingPrincipal,
+                                                    nsIPrincipal* aTriggeringPrincipal,
+                                                    const mozilla::Maybe<mozilla::dom::ClientInfo>& aLoadingClientInfo,
+                                                    const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
+                                                    uint32_t aSecurityFlags,
+                                                    uint32_t aContentPolicyType,
+                                                    nsIChannel** result);
+
+    nsresult NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
                                                      nsIURI* aProxyURI,
                                                      uint32_t aProxyFlags,
                                                      nsILoadInfo* aLoadInfo,
                                                      nsIChannel** result);
 
     nsresult SpeculativeConnectInternal(nsIURI *aURI,
                                         nsIPrincipal *aPrincipal,
                                         nsIInterfaceRequestor *aCallbacks,
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -77,16 +77,18 @@
 #include "nsIRedirectHistoryEntry.h"
 #include "nsICertBlocklist.h"
 #include "nsICertOverrideService.h"
 
 #include <limits>
 
 using namespace mozilla;
 using namespace mozilla::net;
+using mozilla::dom::ClientInfo;
+using mozilla::dom::ServiceWorkerDescriptor;
 
 #define DEFAULT_RP 3
 #define DEFAULT_PRIVATE_RP 2
 
 static uint32_t sDefaultRp = DEFAULT_RP;
 static uint32_t defaultPrivateRp = DEFAULT_PRIVATE_RP;
 
 already_AddRefed<nsIIOService>
@@ -206,66 +208,157 @@ NS_NewChannelInternal(nsIChannel        
     rv = channel->SetLoadFlags(aLoadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   channel.forget(outChannel);
   return NS_OK;
 }
 
+namespace {
+
+void
+AssertLoadingPrincipalAndClientInfoMatch(nsIPrincipal* aLoadingPrincipal,
+                                         const ClientInfo& aLoadingClientInfo,
+                                         nsContentPolicyType aType)
+{
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+  // Verify that the provided loading ClientInfo matches the loading
+  // principal.  Unfortunately we can't just use nsIPrincipal::Equals() here
+  // because of some corner cases:
+  //
+  //  1. Worker debugger scripts want to use a system loading principal for
+  //     worker scripts with a content principal.  We exempt these from this
+  //     check.
+  //  2. Null principals currently require exact object identity for
+  //     nsIPrincipal::Equals() to return true.  This doesn't work here because
+  //     ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
+  //     a new object.  To work around this we compare the principal origin
+  //     string itself.  If bug 1431771 is fixed then we could switch to
+  //     Equals().
+
+  // Allow worker debugger to load with a system principal.
+  if (aLoadingPrincipal->GetIsSystemPrincipal() &&
+      (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
+       aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
+       aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
+       aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS)) {
+    return;
+  }
+
+  // Perform a fast comparison for most principal checks.
+  nsCOMPtr<nsIPrincipal> clientPrincipal(aLoadingClientInfo.GetPrincipal());
+  if (aLoadingPrincipal->Equals(clientPrincipal)) {
+    return;
+  }
+
+  // Fall back to a slower origin equality test to support null principals.
+  nsAutoCString loadingOrigin;
+  MOZ_ALWAYS_SUCCEEDS(aLoadingPrincipal->GetOrigin(loadingOrigin));
+
+  nsAutoCString clientOrigin;
+  MOZ_ALWAYS_SUCCEEDS(clientPrincipal->GetOrigin(clientOrigin));
+
+  MOZ_DIAGNOSTIC_ASSERT(loadingOrigin == clientOrigin);
+#endif
+}
+
+}
+
 nsresult
 NS_NewChannel(nsIChannel           **outChannel,
               nsIURI                *aUri,
               nsIPrincipal          *aLoadingPrincipal,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
               nsILoadGroup          *aLoadGroup /* = nullptr */,
               nsIInterfaceRequestor *aCallbacks /* = nullptr */,
               nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
               nsIIOService          *aIoService /* = nullptr */)
 {
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                nullptr, // aLoadingNode,
                                aLoadingPrincipal,
                                nullptr, // aTriggeringPrincipal
+                               Maybe<ClientInfo>(),
+                               Maybe<ServiceWorkerDescriptor>(),
+                               aSecurityFlags,
+                               aContentPolicyType,
+                               aLoadGroup,
+                               aCallbacks,
+                               aLoadFlags,
+                               aIoService);
+}
+
+nsresult
+NS_NewChannel(nsIChannel           **outChannel,
+              nsIURI                *aUri,
+              nsIPrincipal          *aLoadingPrincipal,
+              const ClientInfo      &aLoadingClientInfo,
+              const Maybe<ServiceWorkerDescriptor>& aController,
+              nsSecurityFlags        aSecurityFlags,
+              nsContentPolicyType    aContentPolicyType,
+              nsILoadGroup          *aLoadGroup /* = nullptr */,
+              nsIInterfaceRequestor *aCallbacks /* = nullptr */,
+              nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
+              nsIIOService          *aIoService /* = nullptr */)
+{
+  AssertLoadingPrincipalAndClientInfoMatch(aLoadingPrincipal,
+                                           aLoadingClientInfo,
+                                           aContentPolicyType);
+
+  Maybe<ClientInfo> loadingClientInfo;
+  loadingClientInfo.emplace(aLoadingClientInfo);
+
+  return NS_NewChannelInternal(outChannel,
+                               aUri,
+                               nullptr, // aLoadingNode,
+                               aLoadingPrincipal,
+                               nullptr, // aTriggeringPrincipal
+                               loadingClientInfo,
+                               aController,
                                aSecurityFlags,
                                aContentPolicyType,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
                                aIoService);
 }
 
 nsresult
 NS_NewChannelInternal(nsIChannel           **outChannel,
                       nsIURI                *aUri,
                       nsINode               *aLoadingNode,
                       nsIPrincipal          *aLoadingPrincipal,
                       nsIPrincipal          *aTriggeringPrincipal,
+                      const Maybe<ClientInfo>& aLoadingClientInfo,
+                      const Maybe<ServiceWorkerDescriptor>& aController,
                       nsSecurityFlags        aSecurityFlags,
                       nsContentPolicyType    aContentPolicyType,
                       nsILoadGroup          *aLoadGroup /* = nullptr */,
                       nsIInterfaceRequestor *aCallbacks /* = nullptr */,
                       nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
                       nsIIOService          *aIoService /* = nullptr */)
 {
   NS_ENSURE_ARG_POINTER(outChannel);
 
   nsCOMPtr<nsIIOService> grip;
   nsresult rv = net_EnsureIOService(&aIoService, grip);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
-  rv = aIoService->NewChannelFromURI2(
+  rv = aIoService->NewChannelFromURIWithClientAndController(
          aUri,
          aLoadingNode ?
            aLoadingNode->AsDOMNode() : nullptr,
          aLoadingPrincipal,
          aTriggeringPrincipal,
+         aLoadingClientInfo,
+         aController,
          aSecurityFlags,
          aContentPolicyType,
          getter_AddRefs(channel));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (aLoadGroup) {
@@ -310,26 +403,28 @@ NS_NewChannelWithTriggeringPrincipal(nsI
 {
   MOZ_ASSERT(aLoadingNode);
   NS_ASSERTION(aTriggeringPrincipal, "Can not create channel without a triggering Principal!");
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                aLoadingNode,
                                aLoadingNode->NodePrincipal(),
                                aTriggeringPrincipal,
+                               Maybe<ClientInfo>(),
+                               Maybe<ServiceWorkerDescriptor>(),
                                aSecurityFlags,
                                aContentPolicyType,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
                                aIoService);
 }
 
 // See NS_NewChannelInternal for usage and argument description
-nsresult /*NS_NewChannelWithPrincipalAndTriggeringPrincipal */
+nsresult
 NS_NewChannelWithTriggeringPrincipal(nsIChannel           **outChannel,
                                      nsIURI                *aUri,
                                      nsIPrincipal          *aLoadingPrincipal,
                                      nsIPrincipal          *aTriggeringPrincipal,
                                      nsSecurityFlags        aSecurityFlags,
                                      nsContentPolicyType    aContentPolicyType,
                                      nsILoadGroup          *aLoadGroup /* = nullptr */,
                                      nsIInterfaceRequestor *aCallbacks /* = nullptr */,
@@ -337,41 +432,82 @@ NS_NewChannelWithTriggeringPrincipal(nsI
                                      nsIIOService          *aIoService /* = nullptr */)
 {
   NS_ASSERTION(aLoadingPrincipal, "Can not create channel without a loading Principal!");
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                nullptr, // aLoadingNode
                                aLoadingPrincipal,
                                aTriggeringPrincipal,
+                               Maybe<ClientInfo>(),
+                               Maybe<ServiceWorkerDescriptor>(),
                                aSecurityFlags,
                                aContentPolicyType,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
                                aIoService);
 }
 
-nsresult /* NS_NewChannelNode */
+// See NS_NewChannelInternal for usage and argument description
+nsresult
+NS_NewChannelWithTriggeringPrincipal(nsIChannel           **outChannel,
+                                     nsIURI                *aUri,
+                                     nsIPrincipal          *aLoadingPrincipal,
+                                     nsIPrincipal          *aTriggeringPrincipal,
+                                     const ClientInfo      &aLoadingClientInfo,
+                                     const Maybe<ServiceWorkerDescriptor>& aController,
+                                     nsSecurityFlags        aSecurityFlags,
+                                     nsContentPolicyType    aContentPolicyType,
+                                     nsILoadGroup          *aLoadGroup /* = nullptr */,
+                                     nsIInterfaceRequestor *aCallbacks /* = nullptr */,
+                                     nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
+                                     nsIIOService          *aIoService /* = nullptr */)
+{
+  AssertLoadingPrincipalAndClientInfoMatch(aLoadingPrincipal,
+                                           aLoadingClientInfo,
+                                           aContentPolicyType);
+
+  Maybe<ClientInfo> loadingClientInfo;
+  loadingClientInfo.emplace(aLoadingClientInfo);
+
+  return NS_NewChannelInternal(outChannel,
+                               aUri,
+                               nullptr, // aLoadingNode
+                               aLoadingPrincipal,
+                               aTriggeringPrincipal,
+                               loadingClientInfo,
+                               aController,
+                               aSecurityFlags,
+                               aContentPolicyType,
+                               aLoadGroup,
+                               aCallbacks,
+                               aLoadFlags,
+                               aIoService);
+}
+
+nsresult
 NS_NewChannel(nsIChannel           **outChannel,
               nsIURI                *aUri,
               nsINode               *aLoadingNode,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
               nsILoadGroup          *aLoadGroup /* = nullptr */,
               nsIInterfaceRequestor *aCallbacks /* = nullptr */,
               nsLoadFlags            aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
               nsIIOService          *aIoService /* = nullptr */)
 {
   NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
   return NS_NewChannelInternal(outChannel,
                                aUri,
                                aLoadingNode,
                                aLoadingNode->NodePrincipal(),
                                nullptr, // aTriggeringPrincipal
+                               Maybe<ClientInfo>(),
+                               Maybe<ServiceWorkerDescriptor>(),
                                aSecurityFlags,
                                aContentPolicyType,
                                aLoadGroup,
                                aCallbacks,
                                aLoadFlags,
                                aIoService);
 }
 
@@ -891,16 +1027,18 @@ NS_NewStreamLoaderInternal(nsIStreamLoad
                            nsIURI                  *aReferrer /* = nullptr */)
 {
    nsCOMPtr<nsIChannel> channel;
    nsresult rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                        aUri,
                                        aLoadingNode,
                                        aLoadingPrincipal,
                                        nullptr, // aTriggeringPrincipal
+                                       Maybe<ClientInfo>(),
+                                       Maybe<ServiceWorkerDescriptor>(),
                                        aSecurityFlags,
                                        aContentPolicyType,
                                        aLoadGroup,
                                        aCallbacks,
                                        aLoadFlags);
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
@@ -909,17 +1047,17 @@ NS_NewStreamLoaderInternal(nsIStreamLoad
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
   rv = NS_NewStreamLoader(outStream, aObserver);
   NS_ENSURE_SUCCESS(rv, rv);
   return channel->AsyncOpen2(*outStream);
 }
 
 
-nsresult /* NS_NewStreamLoaderNode */
+nsresult
 NS_NewStreamLoader(nsIStreamLoader        **outStream,
                    nsIURI                  *aUri,
                    nsIStreamLoaderObserver *aObserver,
                    nsINode                 *aLoadingNode,
                    nsSecurityFlags          aSecurityFlags,
                    nsContentPolicyType      aContentPolicyType,
                    nsILoadGroup            *aLoadGroup /* = nullptr */,
                    nsIInterfaceRequestor   *aCallbacks /* = nullptr */,
@@ -935,17 +1073,17 @@ NS_NewStreamLoader(nsIStreamLoader      
                                     aSecurityFlags,
                                     aContentPolicyType,
                                     aLoadGroup,
                                     aCallbacks,
                                     aLoadFlags,
                                     aReferrer);
 }
 
-nsresult /* NS_NewStreamLoaderPrincipal */
+nsresult
 NS_NewStreamLoader(nsIStreamLoader        **outStream,
                    nsIURI                  *aUri,
                    nsIStreamLoaderObserver *aObserver,
                    nsIPrincipal            *aLoadingPrincipal,
                    nsSecurityFlags          aSecurityFlags,
                    nsContentPolicyType      aContentPolicyType,
                    nsILoadGroup            *aLoadGroup /* = nullptr */,
                    nsIInterfaceRequestor   *aCallbacks /* = nullptr */,
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -2,16 +2,17 @@
 /* vim:set ts=4 sw=4 sts=4 et cin: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsNetUtil_h__
 #define nsNetUtil_h__
 
+#include "mozilla/Maybe.h"
 #include "nsCOMPtr.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadGroup.h"
 #include "nsINetUtil.h"
 #include "nsIRequest.h"
 #include "nsILoadInfo.h"
 #include "nsIIOService.h"
@@ -50,17 +51,21 @@ class nsIStreamLoaderObserver;
 class nsIIncrementalStreamLoader;
 class nsIIncrementalStreamLoaderObserver;
 class nsIUnicharStreamLoader;
 class nsIUnicharStreamLoaderObserver;
 
 namespace mozilla {
 class Encoding;
 class OriginAttributes;
-}
+namespace dom {
+class ClientInfo;
+class ServiceWorkerDescriptor;
+} // namespace dom
+} // namespace mozilla
 
 template <class> class nsCOMPtr;
 template <typename> struct already_AddRefed;
 
 already_AddRefed<nsIIOService> do_GetIOService(nsresult *error = 0);
 
 already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult *error = 0);
 
@@ -108,18 +113,20 @@ nsresult NS_GetSanitizedURIStringFromURI
 * NS_NewChannelWithTriggeringPrincipal,
 * NS_NewInputStreamChannel, NS_NewChannelInternal
 * and it's variations:
 *
 * What specific API function to use:
 * * The NS_NewChannelInternal functions should almost never be directly
 *   called outside of necko code.
 * * If possible, use NS_NewChannel() providing a loading *nsINode*
-* * If no loading *nsINode* is avaialable, call NS_NewChannel() providing
-*   a loading *nsIPrincipal*.
+* * If no loading *nsINode* is available, try calling NS_NewChannel() providing
+*   a loading *ClientInfo*.
+* * If no loading *nsINode* or *ClientInfo* are available, call NS_NewChannel()
+*   providing a loading *nsIPrincipal*.
 * * Call NS_NewChannelWithTriggeringPrincipal if the triggeringPrincipal
 *   is different from the loadingPrincipal.
 * * Call NS_NewChannelInternal() providing aLoadInfo object in cases where
 *   you already have loadInfo object, e.g in case of a channel redirect.
 *
 * @param aURI
 *        nsIURI from which to make a channel
 * @param aLoadingNode
@@ -129,24 +136,32 @@ nsresult NS_GetSanitizedURIStringFromURI
 * @param aContentPolicyType
 *        These will be used as values for the nsILoadInfo object on the
 *        created channel. For details, see nsILoadInfo in nsILoadInfo.idl
 *
 * Please note, if you provide both a loadingNode and a loadingPrincipal,
 * then loadingPrincipal must be equal to loadingNode->NodePrincipal().
 * But less error prone is to just supply a loadingNode.
 *
+* Note, if you provide a loading ClientInfo its principal must match the
+* loading principal.  Currently you must pass both as the loading principal
+* may have additional mutable values like CSP on it.  In the future these
+* will be removed from nsIPrincipal and the API can be changed to take just
+* the loading ClientInfo.
+*
 * Keep in mind that URIs coming from a webpage should *never* use the
 * systemPrincipal as the loadingPrincipal.
 */
 nsresult NS_NewChannelInternal(nsIChannel           **outChannel,
                                nsIURI                *aUri,
                                nsINode               *aLoadingNode,
                                nsIPrincipal          *aLoadingPrincipal,
                                nsIPrincipal          *aTriggeringPrincipal,
+                               const mozilla::Maybe<mozilla::dom::ClientInfo>& aLoadingClientInfo,
+                               const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
                                nsSecurityFlags        aSecurityFlags,
                                nsContentPolicyType    aContentPolicyType,
                                nsILoadGroup          *aLoadGroup = nullptr,
                                nsIInterfaceRequestor *aCallbacks = nullptr,
                                nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
                                nsIIOService          *aIoService = nullptr);
 
 // See NS_NewChannelInternal for usage and argument description
@@ -166,54 +181,83 @@ NS_NewChannelWithTriggeringPrincipal(nsI
                                      nsIPrincipal          *aTriggeringPrincipal,
                                      nsSecurityFlags        aSecurityFlags,
                                      nsContentPolicyType    aContentPolicyType,
                                      nsILoadGroup          *aLoadGroup = nullptr,
                                      nsIInterfaceRequestor *aCallbacks = nullptr,
                                      nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
                                      nsIIOService          *aIoService = nullptr);
 
-
 // See NS_NewChannelInternal for usage and argument description
-nsresult /*NS_NewChannelWithPrincipalAndTriggeringPrincipal */
+nsresult
 NS_NewChannelWithTriggeringPrincipal(nsIChannel           **outChannel,
                                      nsIURI                *aUri,
                                      nsIPrincipal          *aLoadingPrincipal,
                                      nsIPrincipal          *aTriggeringPrincipal,
                                      nsSecurityFlags        aSecurityFlags,
                                      nsContentPolicyType    aContentPolicyType,
                                      nsILoadGroup          *aLoadGroup = nullptr,
                                      nsIInterfaceRequestor *aCallbacks = nullptr,
                                      nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
                                      nsIIOService          *aIoService = nullptr);
 
 // See NS_NewChannelInternal for usage and argument description
-nsresult /* NS_NewChannelNode */
+nsresult
+NS_NewChannelWithTriggeringPrincipal(nsIChannel           **outChannel,
+                                     nsIURI                *aUri,
+                                     nsIPrincipal          *aLoadingPrincipal,
+                                     nsIPrincipal          *aTriggeringPrincipal,
+                                     const mozilla::dom::ClientInfo& aLoadingClientInfo,
+                                     const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
+                                     nsSecurityFlags        aSecurityFlags,
+                                     nsContentPolicyType    aContentPolicyType,
+                                     nsILoadGroup          *aLoadGroup = nullptr,
+                                     nsIInterfaceRequestor *aCallbacks = nullptr,
+                                     nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
+                                     nsIIOService          *aIoService = nullptr);
+
+
+// See NS_NewChannelInternal for usage and argument description
+nsresult
 NS_NewChannel(nsIChannel           **outChannel,
               nsIURI                *aUri,
               nsINode               *aLoadingNode,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
               nsILoadGroup          *aLoadGroup = nullptr,
               nsIInterfaceRequestor *aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
               nsIIOService          *aIoService = nullptr);
 
 // See NS_NewChannelInternal for usage and argument description
-nsresult /* NS_NewChannelPrincipal */
+nsresult
 NS_NewChannel(nsIChannel           **outChannel,
               nsIURI                *aUri,
               nsIPrincipal          *aLoadingPrincipal,
               nsSecurityFlags        aSecurityFlags,
               nsContentPolicyType    aContentPolicyType,
               nsILoadGroup          *aLoadGroup = nullptr,
               nsIInterfaceRequestor *aCallbacks = nullptr,
               nsLoadFlags            aLoadFlags = nsIRequest::LOAD_NORMAL,
               nsIIOService          *aIoService = nullptr);
 
+// See NS_NewChannelInternal for usage and argument description
+nsresult
+NS_NewChannel(nsIChannel** outChannel,
+              nsIURI* aUri,
+              nsIPrincipal* aLoadingPrincipal,
+              const mozilla::dom::ClientInfo& aLoadingClientInfo,
+              const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
+              nsSecurityFlags aSecurityFlags,
+              nsContentPolicyType aContentPolicyType,
+              nsILoadGroup* aLoadGroup = nullptr,
+              nsIInterfaceRequestor* aCallbacks = nullptr,
+              nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL,
+              nsIIOService* aIoService = nullptr);
+
 nsresult NS_GetIsDocumentChannel(nsIChannel * aChannel, bool *aIsDocument);
 
 nsresult NS_MakeAbsoluteURI(nsACString       &result,
                             const nsACString &spec,
                             nsIURI           *baseURI);
 
 nsresult NS_MakeAbsoluteURI(char        **result,
                             const char   *spec,
@@ -344,29 +388,29 @@ nsresult NS_NewStreamLoaderInternal(nsIS
                                     nsIPrincipal            *aLoadingPrincipal,
                                     nsSecurityFlags          aSecurityFlags,
                                     nsContentPolicyType      aContentPolicyType,
                                     nsILoadGroup            *aLoadGroup = nullptr,
                                     nsIInterfaceRequestor   *aCallbacks = nullptr,
                                     nsLoadFlags              aLoadFlags = nsIRequest::LOAD_NORMAL,
                                     nsIURI                  *aReferrer = nullptr);
 
-nsresult /* NS_NewStreamLoaderNode */
+nsresult
 NS_NewStreamLoader(nsIStreamLoader        **outStream,
                    nsIURI                  *aUri,
                    nsIStreamLoaderObserver *aObserver,
                    nsINode                 *aLoadingNode,
                    nsSecurityFlags          aSecurityFlags,
                    nsContentPolicyType      aContentPolicyType,
                    nsILoadGroup            *aLoadGroup = nullptr,
                    nsIInterfaceRequestor   *aCallbacks = nullptr,
                    nsLoadFlags              aLoadFlags = nsIRequest::LOAD_NORMAL,
                    nsIURI                  *aReferrer = nullptr);
 
-nsresult /* NS_NewStreamLoaderPrincipal */
+nsresult
 NS_NewStreamLoader(nsIStreamLoader        **outStream,
                    nsIURI                  *aUri,
                    nsIStreamLoaderObserver *aObserver,
                    nsIPrincipal            *aLoadingPrincipal,
                    nsSecurityFlags          aSecurityFlags,
                    nsContentPolicyType      aContentPolicyType,
                    nsILoadGroup            *aLoadGroup = nullptr,
                    nsIInterfaceRequestor   *aCallbacks = nullptr,
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -3,17 +3,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrefetchService.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
+#include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/HTMLLinkElement.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/Preferences.h"
 
 #include "nsICacheEntry.h"
 #include "nsIServiceManager.h"
 #include "nsICategoryManager.h"
 #include "nsIObserverService.h"
 #include "nsIWebProgress.h"
 #include "nsCURILoader.h"
@@ -141,16 +143,18 @@ nsPrefetchNode::OpenChannel()
         securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
       }
     }
     nsresult rv = NS_NewChannelInternal(getter_AddRefs(mChannel),
                                         mURI,
                                         source,
                                         source->NodePrincipal(),
                                         nullptr,   //aTriggeringPrincipal
+                                        Maybe<ClientInfo>(),
+                                        Maybe<ServiceWorkerDescriptor>(),
                                         securityFlags,
                                         mPolicyType,
                                         loadGroup, // aLoadGroup
                                         this,      // aCallbacks
                                         nsIRequest::LOAD_BACKGROUND |
                                         nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
 
     NS_ENSURE_SUCCESS(rv, rv);