Bug 1639247 - Isolate DNS cache per first-party when privacy.partition.network_state is set to true - part 3 - implementation, r=valentin,necko-reviewers
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 20 May 2020 17:27:43 +0000
changeset 531316 ab42c2dd3b435e2f8fe4d367963cbb90c6b21e95
parent 531315 174d7d969298918c23f6d7f25f07145bddd9e5c5
child 531317 84e6e0fcbd3575c29cf238050d61a59b34c7673c
push id37437
push usernerli@mozilla.com
push dateThu, 21 May 2020 02:34:41 +0000
treeherdermozilla-central@3d91ba9e1d25 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin, necko-reviewers
bugs1639247
milestone78.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 1639247 - Isolate DNS cache per first-party when privacy.partition.network_state is set to true - part 3 - implementation, r=valentin,necko-reviewers Differential Revision: https://phabricator.services.mozilla.com/D75985
dom/base/nsContentSink.cpp
dom/html/nsHTMLDNSPrefetch.cpp
dom/html/nsHTMLDNSPrefetch.h
netwerk/protocol/http/nsHttpChannel.cpp
toolkit/components/antitracking/StoragePrincipalHelper.cpp
toolkit/components/antitracking/StoragePrincipalHelper.h
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/Components.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/StaticPrefs_browser.h"
 #include "mozilla/StaticPrefs_content.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/MutationObservers.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/SRILogHelper.h"
+#include "mozilla/StoragePrincipalHelper.h"
 #include "nsStyleLinkElement.h"
 #include "nsIDocShell.h"
 #include "nsILoadContext.h"
 #include "nsIPrefetchService.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIMIMEHeaderParam.h"
 #include "nsIProtocolHandler.h"
@@ -848,19 +849,21 @@ void nsContentSink::PrefetchDNS(const ns
       nsAutoCString host;
       uri->GetHost(host);
       CopyUTF8toUTF16(host, hostname);
     }
     isHttps = uri->SchemeIs("https");
   }
 
   if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
-    nsHTMLDNSPrefetch::PrefetchLow(
-        hostname, isHttps, mDocument->NodePrincipal()->OriginAttributesRef(),
-        mDocument->GetChannel()->GetTRRMode());
+    OriginAttributes oa;
+    StoragePrincipalHelper::GetOriginAttributesForNetworkState(mDocument, oa);
+
+    nsHTMLDNSPrefetch::PrefetchLow(hostname, isHttps, oa,
+                                   mDocument->GetChannel()->GetTRRMode());
   }
 }
 
 void nsContentSink::Preconnect(const nsAString& aHref,
                                const nsAString& aCrossOrigin) {
   // construct URI using document charset
   auto encoding = mDocument->GetDocumentCharacterSet();
   nsCOMPtr<nsIURI> uri;
--- a/dom/html/nsHTMLDNSPrefetch.cpp
+++ b/dom/html/nsHTMLDNSPrefetch.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHTMLDNSPrefetch.h"
 
 #include "base/basictypes.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/NeckoChild.h"
+#include "mozilla/StoragePrincipalHelper.h"
 #include "nsURLHelper.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsIProtocolHandler.h"
@@ -128,78 +129,84 @@ nsresult nsHTMLDNSPrefetch::PrefetchLow(
 nsresult nsHTMLDNSPrefetch::PrefetchMedium(Link* aElement) {
   return Prefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
 }
 
 nsresult nsHTMLDNSPrefetch::PrefetchHigh(Link* aElement) {
   return Prefetch(aElement, 0);
 }
 
-nsresult nsHTMLDNSPrefetch::Prefetch(const nsAString& hostname, bool isHttps,
-                                     const OriginAttributes& aOriginAttributes,
-                                     uint32_t flags) {
+nsresult nsHTMLDNSPrefetch::Prefetch(
+    const nsAString& hostname, bool isHttps,
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    uint32_t flags) {
   if (IsNeckoChild()) {
     // We need to check IsEmpty() because net_IsValidHostName()
     // considers empty strings to be valid hostnames
     if (!hostname.IsEmpty() &&
         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
       // during shutdown gNeckoChild might be null
       if (gNeckoChild) {
         gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname), isHttps,
-                                         aOriginAttributes, flags);
+                                         aPartitionedPrincipalOriginAttributes,
+                                         flags);
       }
     }
     return NS_OK;
   }
 
   if (!(sInitialized && sPrefetches && sDNSListener) || !EnsureDNSService())
     return NS_ERROR_NOT_AVAILABLE;
 
   nsCOMPtr<nsICancelable> tmpOutstanding;
   nsresult rv = sDNSService->AsyncResolveNative(
       NS_ConvertUTF16toUTF8(hostname), flags | nsIDNSService::RESOLVE_SPECULATE,
-      sDNSListener, nullptr, aOriginAttributes, getter_AddRefs(tmpOutstanding));
+      sDNSListener, nullptr, aPartitionedPrincipalOriginAttributes,
+      getter_AddRefs(tmpOutstanding));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Fetch ESNI keys if needed.
   if (isHttps && sEsniEnabled) {
     nsAutoCString esniHost;
     esniHost.Append("_esni.");
     esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
     Unused << sDNSService->AsyncResolveByTypeNative(
         esniHost, nsIDNSService::RESOLVE_TYPE_TXT,
         flags | nsIDNSService::RESOLVE_SPECULATE, sDNSListener, nullptr,
-        aOriginAttributes, getter_AddRefs(tmpOutstanding));
+        aPartitionedPrincipalOriginAttributes, getter_AddRefs(tmpOutstanding));
   }
 
   return NS_OK;
 }
 
 nsresult nsHTMLDNSPrefetch::PrefetchLow(
     const nsAString& hostname, bool isHttps,
-    const OriginAttributes& aOriginAttributes, nsIRequest::TRRMode aMode) {
-  return Prefetch(hostname, isHttps, aOriginAttributes,
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    nsIRequest::TRRMode aMode) {
+  return Prefetch(hostname, isHttps, aPartitionedPrincipalOriginAttributes,
                   nsIDNSService::GetFlagsFromTRRMode(aMode) |
                       nsIDNSService::RESOLVE_PRIORITY_LOW);
 }
 
 nsresult nsHTMLDNSPrefetch::PrefetchMedium(
     const nsAString& hostname, bool isHttps,
-    const OriginAttributes& aOriginAttributes, nsIRequest::TRRMode aMode) {
-  return Prefetch(hostname, isHttps, aOriginAttributes,
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    nsIRequest::TRRMode aMode) {
+  return Prefetch(hostname, isHttps, aPartitionedPrincipalOriginAttributes,
                   nsIDNSService::GetFlagsFromTRRMode(aMode) |
                       nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
 }
 
 nsresult nsHTMLDNSPrefetch::PrefetchHigh(
     const nsAString& hostname, bool isHttps,
-    const OriginAttributes& aOriginAttributes, nsIRequest::TRRMode aMode) {
-  return Prefetch(hostname, isHttps, aOriginAttributes,
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    nsIRequest::TRRMode aMode) {
+  return Prefetch(hostname, isHttps, aPartitionedPrincipalOriginAttributes,
                   nsIDNSService::GetFlagsFromTRRMode(aMode));
 }
 
 nsresult nsHTMLDNSPrefetch::CancelPrefetch(Link* aElement, uint32_t flags,
                                            nsresult aReason) {
   if (!(sInitialized && sPrefetches && sDNSListener) || !EnsureDNSService())
     return NS_ERROR_NOT_AVAILABLE;
 
@@ -210,73 +217,78 @@ nsresult nsHTMLDNSPrefetch::CancelPrefet
   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
   nsAutoString protocol;
   aElement->GetProtocol(protocol);
   bool isHttps = false;
   if (protocol.EqualsLiteral("https:")) {
     isHttps = true;
   }
-  return CancelPrefetch(hostname, isHttps,
-                        element->NodePrincipal()->OriginAttributesRef(), flags,
-                        aReason);
+
+  OriginAttributes oa;
+  StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+      element->OwnerDoc(), oa);
+
+  return CancelPrefetch(hostname, isHttps, oa, flags, aReason);
 }
 
 nsresult nsHTMLDNSPrefetch::CancelPrefetch(
     const nsAString& hostname, bool isHttps,
-    const OriginAttributes& aOriginAttributes, uint32_t flags,
-    nsresult aReason) {
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    uint32_t flags, nsresult aReason) {
   // Forward this request to Necko Parent if we're a child process
   if (IsNeckoChild()) {
     // We need to check IsEmpty() because net_IsValidHostName()
     // considers empty strings to be valid hostnames
     if (!hostname.IsEmpty() &&
         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
       // during shutdown gNeckoChild might be null
       if (gNeckoChild) {
         gNeckoChild->SendCancelHTMLDNSPrefetch(
-            nsString(hostname), isHttps, aOriginAttributes, flags, aReason);
+            nsString(hostname), isHttps, aPartitionedPrincipalOriginAttributes,
+            flags, aReason);
       }
     }
     return NS_OK;
   }
 
   if (!(sInitialized && sPrefetches && sDNSListener) || !EnsureDNSService())
     return NS_ERROR_NOT_AVAILABLE;
 
   // Forward cancellation to DNS service
   nsresult rv = sDNSService->CancelAsyncResolveNative(
       NS_ConvertUTF16toUTF8(hostname), flags | nsIDNSService::RESOLVE_SPECULATE,
-      sDNSListener, aReason, aOriginAttributes);
+      sDNSListener, aReason, aPartitionedPrincipalOriginAttributes);
   // Cancel fetching ESNI keys if needed.
   if (sEsniEnabled && isHttps) {
     nsAutoCString esniHost;
     esniHost.Append("_esni.");
     esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
     sDNSService->CancelAsyncResolveByTypeNative(
         esniHost, nsIDNSService::RESOLVE_TYPE_TXT,
         flags | nsIDNSService::RESOLVE_SPECULATE, sDNSListener, aReason,
-        aOriginAttributes);
+        aPartitionedPrincipalOriginAttributes);
   }
   return rv;
 }
 
 nsresult nsHTMLDNSPrefetch::CancelPrefetchLow(Link* aElement,
                                               nsresult aReason) {
   return CancelPrefetch(
       aElement,
       GetDNSFlagsFromLink(aElement) | nsIDNSService::RESOLVE_PRIORITY_LOW,
       aReason);
 }
 
 nsresult nsHTMLDNSPrefetch::CancelPrefetchLow(
     const nsAString& hostname, bool isHttps,
-    const OriginAttributes& aOriginAttributes, nsIRequest::TRRMode aTRRMode,
-    nsresult aReason) {
-  return CancelPrefetch(hostname, isHttps, aOriginAttributes,
+    const OriginAttributes& aPartitionedPrincipalOriginAttributes,
+    nsIRequest::TRRMode aTRRMode, nsresult aReason) {
+  return CancelPrefetch(hostname, isHttps,
+                        aPartitionedPrincipalOriginAttributes,
                         nsIDNSService::GetFlagsFromTRRMode(aTRRMode) |
                             nsIDNSService::RESOLVE_PRIORITY_LOW,
                         aReason);
 }
 
 void nsHTMLDNSPrefetch::LinkDestroyed(Link* aLink) {
   MOZ_ASSERT(aLink->IsInDNSPrefetch());
   if (sPrefetches) {
@@ -373,46 +385,45 @@ void nsHTMLDNSPrefetch::nsDeferrals::Sub
         if (hrefURI) {
           hrefURI->GetAsciiHost(hostName);
           rv = NS_URIChainHasFlags(hrefURI,
                                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
                                    &isLocalResource);
           isHttps = hrefURI->SchemeIs("https");
         }
 
+        OriginAttributes oa;
+        StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+            element->OwnerDoc(), oa);
+
         if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource &&
             element) {
           if (IsNeckoChild()) {
             // during shutdown gNeckoChild might be null
             if (gNeckoChild) {
-              gNeckoChild->SendHTMLDNSPrefetch(
-                  NS_ConvertUTF8toUTF16(hostName), isHttps,
-                  element->NodePrincipal()->OriginAttributesRef(),
-                  mEntries[mTail].mFlags);
+              gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
+                                               isHttps, oa,
+                                               mEntries[mTail].mFlags);
             }
           } else {
             nsCOMPtr<nsICancelable> tmpOutstanding;
 
             rv = sDNSService->AsyncResolveNative(
                 hostName,
                 mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE,
-                sDNSListener, nullptr,
-                element->NodePrincipal()->OriginAttributesRef(),
-                getter_AddRefs(tmpOutstanding));
+                sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
             // Fetch ESNI keys if needed.
             if (NS_SUCCEEDED(rv) && sEsniEnabled && isHttps) {
               nsAutoCString esniHost;
               esniHost.Append("_esni.");
               esniHost.Append(hostName);
               sDNSService->AsyncResolveByTypeNative(
                   esniHost, nsIDNSService::RESOLVE_TYPE_TXT,
                   mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE,
-                  sDNSListener, nullptr,
-                  element->NodePrincipal()->OriginAttributesRef(),
-                  getter_AddRefs(tmpOutstanding));
+                  sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
             }
             // Tell link that deferred prefetch was requested
             if (NS_SUCCEEDED(rv)) link->OnDNSPrefetchRequested();
           }
         }
       }
     }
 
--- a/dom/html/nsHTMLDNSPrefetch.h
+++ b/dom/html/nsHTMLDNSPrefetch.h
@@ -42,50 +42,55 @@ class nsHTMLDNSPrefetch {
 
   // Call one of the Prefetch* methods to start the lookup.
   //
   // The URI versions will defer DNS lookup until pageload is
   // complete, while the string versions submit the lookup to
   // the DNS system immediately. The URI version is somewhat lighter
   // weight, but its request is also more likely to be dropped due to a
   // full queue and it may only be used from the main thread.
+  //
+  // If you are planning to use the methods with the OriginAttributes param, be
+  // sure that you pass a partitioned one. See StoragePrincipalHelper.h to know
+  // more.
 
   static nsresult PrefetchHigh(mozilla::dom::Link* aElement);
   static nsresult PrefetchMedium(mozilla::dom::Link* aElement);
   static nsresult PrefetchLow(mozilla::dom::Link* aElement);
-  static nsresult PrefetchHigh(
+  static nsresult PrefetchLow(
       const nsAString& host, bool isHttps,
-      const mozilla::OriginAttributes& aOriginAttributes,
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
       nsIRequest::TRRMode aTRRMode);
   static nsresult PrefetchMedium(
       const nsAString& host, bool isHttps,
-      const mozilla::OriginAttributes& aOriginAttributes,
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
       nsIRequest::TRRMode aTRRMode);
-  static nsresult PrefetchLow(
+  static nsresult PrefetchHigh(
       const nsAString& host, bool isHttps,
-      const mozilla::OriginAttributes& aOriginAttributes,
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
       nsIRequest::TRRMode aTRRMode);
   static nsresult CancelPrefetchLow(
       const nsAString& host, bool isHttps,
-      const mozilla::OriginAttributes& aOriginAttributes,
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
       nsIRequest::TRRMode aTRRMode, nsresult aReason);
   static nsresult CancelPrefetchLow(mozilla::dom::Link* aElement,
                                     nsresult aReason);
 
   static void LinkDestroyed(mozilla::dom::Link* aLink);
 
  private:
-  static nsresult Prefetch(const nsAString& host, bool isHttps,
-                           const mozilla::OriginAttributes& aOriginAttributes,
-                           uint32_t flags);
+  static nsresult Prefetch(
+      const nsAString& host, bool isHttps,
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
+      uint32_t flags);
   static nsresult Prefetch(mozilla::dom::Link* aElement, uint32_t flags);
   static nsresult CancelPrefetch(
       const nsAString& hostname, bool isHttps,
-      const mozilla::OriginAttributes& aOriginAttributes, uint32_t flags,
-      nsresult aReason);
+      const mozilla::OriginAttributes& aPartitionedPrincipalOriginAttributes,
+      uint32_t flags, nsresult aReason);
   static nsresult CancelPrefetch(mozilla::dom::Link* aElement, uint32_t flags,
                                  nsresult aReason);
 
  public:
   class nsListener final : public nsIDNSListener {
     // This class exists to give a safe callback no-op DNSListener
    public:
     NS_DECL_THREADSAFE_ISUPPORTS
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6987,18 +6987,18 @@ nsresult nsHttpChannel::MaybeStartDNSPre
   LOG(
       ("nsHttpChannel::MaybeStartDNSPrefetch [this=%p, strategy=%u] "
        "prefetching%s\n",
        this, dnsStrategy,
        mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : ""));
 
   if (dnsStrategy & DNS_PREFETCH_ORIGIN) {
     OriginAttributes originAttributes;
-    StoragePrincipalHelper::GetOriginAttributes(
-        this, originAttributes, StoragePrincipalHelper::eRegularPrincipal);
+    StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+        this, originAttributes);
 
     mDNSPrefetch = new nsDNSPrefetch(
         mURI, originAttributes, nsIRequest::GetTRRMode(), this, mTimingEnabled);
     nsresult rv = mDNSPrefetch->PrefetchHigh(mCaps & NS_HTTP_REFRESH_DNS);
 
     if (dnsStrategy & DNS_BLOCK_ON_ORIGIN_RESOLVE) {
       LOG(("  blocking on prefetching origin"));
 
--- a/toolkit/components/antitracking/StoragePrincipalHelper.cpp
+++ b/toolkit/components/antitracking/StoragePrincipalHelper.cpp
@@ -260,9 +260,29 @@ bool StoragePrincipalHelper::GetRegularP
   if (!loadContext) {
     return false;
   }
 
   loadContext->GetOriginAttributes(aAttributes);
   return true;
 }
 
+// static
+bool StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+    nsIChannel* aChannel, OriginAttributes& aAttributes) {
+  return StoragePrincipalHelper::GetOriginAttributes(
+      aChannel, aAttributes,
+      StaticPrefs::privacy_partition_network_state() ? ePartitionedPrincipal
+                                                     : eRegularPrincipal);
+}
+
+// static
+void StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+    Document* aDocument, OriginAttributes& aAttributes) {
+  if (!StaticPrefs::privacy_partition_network_state()) {
+    aAttributes = aDocument->NodePrincipal()->OriginAttributesRef();
+    return;
+  }
+
+  aAttributes = aDocument->IntrinsicStoragePrincipal()->OriginAttributesRef();
+}
+
 }  // namespace mozilla
--- a/toolkit/components/antitracking/StoragePrincipalHelper.h
+++ b/toolkit/components/antitracking/StoragePrincipalHelper.h
@@ -245,13 +245,20 @@ class StoragePrincipalHelper final {
                                   OriginAttributes& aAttributes,
                                   PrincipalType aPrincipalType);
 
   static bool GetRegularPrincipalOriginAttributes(
       dom::Document* aDocument, OriginAttributes& aAttributes);
 
   static bool GetRegularPrincipalOriginAttributes(
       nsILoadGroup* aLoadGroup, OriginAttributes& aAttributes);
+
+  // These methods return the correct originAttributes to be used for network
+  // state components (HSTS, network cache, image-cache, and so on).
+  static bool GetOriginAttributesForNetworkState(nsIChannel* aChanel,
+                                                 OriginAttributes& aAttributes);
+  static void GetOriginAttributesForNetworkState(dom::Document* aDocument,
+                                                 OriginAttributes& aAttributes);
 };
 
 }  // namespace mozilla
 
 #endif  // mozilla_StoragePrincipalHelper_h