Bug 1533074 - Implement Fingerprinting and Cryptomining annotation features - Part 2 - Fingerprinting-annotation, r=dimi
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 14 Mar 2019 17:48:20 +0000
changeset 521916 83534ac4c0eb43b8cfa1c6f93431978fe11ba120
parent 521915 a0c8d47ee188ee72fb0896dd80b02076f9bcafb5
child 521917 61efe2bbaf454d63a4ca5130e0aaebe077b34009
push id10870
push usernbeleuzu@mozilla.com
push dateFri, 15 Mar 2019 20:00:07 +0000
treeherdermozilla-beta@c594aee5b7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdimi
bugs1533074
milestone67.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 1533074 - Implement Fingerprinting and Cryptomining annotation features - Part 2 - Fingerprinting-annotation, r=dimi Differential Revision: https://phabricator.services.mozilla.com/D22342
browser/app/profile/firefox.js
modules/libpref/init/StaticPrefList.h
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/nsIHttpChannel.idl
netwerk/url-classifier/UrlClassifierCommon.cpp
netwerk/url-classifier/UrlClassifierCommon.h
netwerk/url-classifier/UrlClassifierFeatureBase.cpp
netwerk/url-classifier/UrlClassifierFeatureBase.h
netwerk/url-classifier/UrlClassifierFeatureCryptominingProtection.cpp
netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.cpp
netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.h
netwerk/url-classifier/UrlClassifierFeatureFingerprintingProtection.cpp
netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
netwerk/url-classifier/moz.build
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1243,16 +1243,17 @@ pref("services.sync.prefs.sync.privacy.c
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
 pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
 pref("services.sync.prefs.sync.privacy.fuzzyfox.enabled", false);
 pref("services.sync.prefs.sync.privacy.fuzzyfox.clockgrainus", false);
 pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.cryptomining.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.enabled", true);
+pref("services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.annotate.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting", true);
 pref("services.sync.prefs.sync.privacy.reduceTimerPrecision", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.microseconds", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.jitter", true);
 pref("services.sync.prefs.sync.security.OCSP.enabled", true);
 pref("services.sync.prefs.sync.security.OCSP.require", true);
 pref("services.sync.prefs.sync.security.default_personal_cert", true);
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -2002,23 +2002,28 @@ VARCACHE_PREF(
 // Annotate channels based on the tracking protection list in all modes
 VARCACHE_PREF(
   "privacy.trackingprotection.annotate_channels",
    privacy_trackingprotection_annotate_channels,
   bool, true
 )
 
 // Block 3rd party fingerprinting resources.
-# define PREF_VALUE false
 VARCACHE_PREF(
   "privacy.trackingprotection.fingerprinting.enabled",
    privacy_trackingprotection_fingerprinting_enabled,
-  bool, PREF_VALUE
+  bool, false
 )
-#undef PREF_VALUE
+
+// Annotate fingerprinting resources.
+VARCACHE_PREF(
+  "privacy.trackingprotection.fingerprinting.annotate.enabled",
+   privacy_trackingprotection_fingerprinting_annotate_enabled,
+  bool, false
+)
 
 // Block 3rd party cryptomining resources.
 # define PREF_VALUE false
 VARCACHE_PREF(
   "privacy.trackingprotection.cryptomining.enabled",
    privacy_trackingprotection_cryptomining_enabled,
   bool, PREF_VALUE
 )
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -59,16 +59,17 @@
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "nsIURL.h"
 #include "nsIConsoleService.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/PartiallySeekableInputStream.h"
+#include "mozilla/net/UrlClassifierCommon.h"
 #include "mozilla/InputStreamLengthHelper.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIMIMEInputStream.h"
 #include "nsIXULRuntime.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIURIFixup.h"
 #include "nsHttpChannel.h"
@@ -1469,32 +1470,34 @@ NS_IMETHODIMP HttpBaseChannel::SetTopLev
   mContentWindowId = aWindowId;
   return NS_OK;
 }
 
 bool
 HttpBaseChannel::IsTrackingResource() const {
   MOZ_ASSERT(!mFirstPartyClassificationFlags ||
              !mThirdPartyClassificationFlags);
-  return
-      (mThirdPartyClassificationFlags & nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING) ||
-      (mFirstPartyClassificationFlags & nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING);
+  return UrlClassifierCommon::IsTrackingClassificationFlag(
+             mThirdPartyClassificationFlags) ||
+         UrlClassifierCommon::IsTrackingClassificationFlag(
+             mFirstPartyClassificationFlags);
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetIsTrackingResource(bool* aIsTrackingResource) {
   *aIsTrackingResource = IsTrackingResource();
   return NS_OK;
 }
 
 bool
 HttpBaseChannel::IsThirdPartyTrackingResource() const {
   MOZ_ASSERT(
       !(mFirstPartyClassificationFlags && mThirdPartyClassificationFlags));
-  return (mThirdPartyClassificationFlags & nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING);
+  return UrlClassifierCommon::IsTrackingClassificationFlag(
+      mThirdPartyClassificationFlags);
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetIsThirdPartyTrackingResource(bool* aIsTrackingResource) {
   *aIsTrackingResource = IsThirdPartyTrackingResource();
   return NS_OK;
 }
 
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -537,31 +537,33 @@ interface nsIHttpChannel : nsIChannel
        */
       CLASSIFIED_TRACKING = 0x04,
     };
 
     /**
      * Returns true if the channel has loaded a resource that is classified as
      * tracker.
      * This is a helper attribute which returns the same value of
-     * (classificationFlags & CLASSIFIED_TRACKING)
+     * (classificationFlags & CLASSIFIED_TRACKING) ||
+     *   (classificationFlags & CLASSIFIED_FINGERPRINTING)
      *
      * Note that top-level channels could be marked as tracking
      * resource. In order to identify third-party tracking resources
      * specifically, use isThirdPartyTrackingResource.
      */
     [infallible] readonly attribute boolean isTrackingResource;
 
     /**
      * Returns the classification flags if the channel has been processed by
      * URL-Classifier features and is considered third-party with the top
      * window URI.
      *
      * This is a helper attribute which returns the same value of
-     * (thirdPartyClassificationFlags & CLASSIFIED_TRACKING)
+     * (thirdPartyClassificationFlags & CLASSIFIED_TRACKING) ||
+     *   (thirdPartyClassificationFlags & CLASSIFIED_FINGERPRINTING)
      */
     [infallible] readonly attribute boolean isThirdPartyTrackingResource;
 
     /**
      * Returns the allowing status for flash plugin for this channel.
      */
     cenum FlashPluginState : 8 {
       FlashPluginUnknown = 0,
--- a/netwerk/url-classifier/UrlClassifierCommon.cpp
+++ b/netwerk/url-classifier/UrlClassifierCommon.cpp
@@ -3,30 +3,33 @@
 /* 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/. */
 
 #include "mozilla/net/UrlClassifierCommon.h"
 
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsContentUtils.h"
 #include "nsIChannel.h"
 #include "nsIClassifiedChannel.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocShell.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIParentChannel.h"
 #include "nsIScriptError.h"
 #include "nsIWebProgressListener.h"
 #include "nsNetUtil.h"
+#include "nsQueryObject.h"
+#include "TrackingDummyChannel.h"
 
 namespace mozilla {
 namespace net {
 
 const nsCString::size_type UrlClassifierCommon::sMaxSpecLength = 128;
 
 // MOZ_LOG=nsChannelClassifier:5
 LazyLogModule UrlClassifierCommon::sLog("nsChannelClassifier");
@@ -270,10 +273,193 @@ nsresult UrlClassifierCommon::CreatePair
   nsCOMPtr<nsIURI> whitelistURI;
   rv = NS_NewURI(getter_AddRefs(whitelistURI), whitelistEntry);
   NS_ENSURE_SUCCESS(rv, rv);
 
   whitelistURI.forget(aURI);
   return NS_OK;
 }
 
+namespace {
+
+void SetClassificationFlagsHelper(nsIChannel* aChannel,
+                                  uint32_t aClassificationFlags,
+                                  bool aIsThirdParty) {
+  MOZ_ASSERT(aChannel);
+
+  nsCOMPtr<nsIParentChannel> parentChannel;
+  NS_QueryNotificationCallbacks(aChannel, parentChannel);
+  if (parentChannel) {
+    // This channel is a parent-process proxy for a child process
+    // request. We should notify the child process as well.
+    parentChannel->NotifyClassificationFlags(aClassificationFlags,
+                                             aIsThirdParty);
+  }
+
+  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
+  if (httpChannel) {
+    httpChannel->AddClassificationFlags(aClassificationFlags, aIsThirdParty);
+  }
+
+  RefPtr<TrackingDummyChannel> dummyChannel = do_QueryObject(aChannel);
+  if (dummyChannel) {
+    dummyChannel->AddClassificationFlags(aClassificationFlags);
+  }
+}
+
+void LowerPriorityHelper(nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  bool isBlockingResource = false;
+
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
+  if (cos) {
+    if (nsContentUtils::IsTailingEnabled()) {
+      uint32_t cosFlags = 0;
+      cos->GetClassFlags(&cosFlags);
+      isBlockingResource =
+          cosFlags & (nsIClassOfService::UrgentStart |
+                      nsIClassOfService::Leader | nsIClassOfService::Unblocked);
+
+      // Requests not allowed to be tailed are usually those with higher
+      // prioritization.  That overweights being a tracker: don't throttle
+      // them when not in background.
+      if (!(cosFlags & nsIClassOfService::TailForbidden)) {
+        cos->AddClassFlags(nsIClassOfService::Throttleable);
+      }
+    } else {
+      // Yes, we even don't want to evaluate the isBlockingResource when tailing
+      // is off see bug 1395525.
+
+      cos->AddClassFlags(nsIClassOfService::Throttleable);
+    }
+  }
+
+  if (!isBlockingResource) {
+    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
+    if (p) {
+      if (UC_LOG_ENABLED()) {
+        nsCOMPtr<nsIURI> uri;
+        aChannel->GetURI(getter_AddRefs(uri));
+        nsAutoCString spec;
+        uri->GetAsciiSpec(spec);
+        spec.Truncate(
+            std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength));
+        UC_LOG(("Setting PRIORITY_LOWEST for channel[%p] (%s)", aChannel,
+                spec.get()));
+      }
+      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
+    }
+  }
+}
+
+}  // namespace
+
+// static
+void UrlClassifierCommon::AnnotateChannel(
+    nsIChannel* aChannel,
+    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose,
+    uint32_t aClassificationFlags, uint32_t aLoadingState) {
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
+             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
+             aPurpose == AntiTrackingCommon::eFingerprinting ||
+             aPurpose == AntiTrackingCommon::eCryptomining);
+
+  nsCOMPtr<nsIURI> chanURI;
+  nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    UC_LOG(
+        ("UrlClassifierCommon::AnnotateChannel nsIChannel::GetURI(%p) failed",
+         (void*)aChannel));
+    return;
+  }
+
+  bool isThirdPartyWithTopLevelWinURI =
+      nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, chanURI);
+
+  UC_LOG(("UrlClassifierCommon::AnnotateChannel, annotating channel[%p]",
+          aChannel));
+
+  SetClassificationFlagsHelper(aChannel, aClassificationFlags,
+                               isThirdPartyWithTopLevelWinURI);
+
+  if (isThirdPartyWithTopLevelWinURI || IsAllowListed(aChannel, aPurpose)) {
+    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
+        aChannel, aLoadingState);
+  }
+
+  if (isThirdPartyWithTopLevelWinURI &&
+      StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
+    LowerPriorityHelper(aChannel);
+  }
+}
+
+// static
+bool UrlClassifierCommon::IsAllowListed(
+    nsIChannel* aChannel,
+    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose) {
+  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
+             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
+             aPurpose == AntiTrackingCommon::eFingerprinting ||
+             aPurpose == AntiTrackingCommon::eCryptomining);
+
+  nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
+  if (!channel) {
+    UC_LOG(("nsChannelClassifier: Not an HTTP channel"));
+    return false;
+  }
+
+  nsCOMPtr<nsIURI> topWinURI;
+  nsresult rv = channel->GetTopWindowURI(getter_AddRefs(topWinURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  if (!topWinURI && StaticPrefs::channelclassifier_allowlist_example()) {
+    UC_LOG(("nsChannelClassifier: Allowlisting test domain"));
+    nsCOMPtr<nsIIOService> ios = services::GetIOService();
+    if (NS_WARN_IF(!ios)) {
+      return false;
+    }
+
+    rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
+                     nullptr, nullptr, getter_AddRefs(topWinURI));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+  }
+
+  bool isAllowListed = false;
+  rv = AntiTrackingCommon::IsOnContentBlockingAllowList(
+      topWinURI, NS_UsePrivateBrowsing(aChannel), aPurpose, isAllowListed);
+  if (NS_FAILED(rv)) {  // normal for some loads, no need to print a warning
+    return false;
+  }
+
+  if (isAllowListed) {
+    if (UC_LOG_ENABLED()) {
+      nsCOMPtr<nsIURI> chanURI;
+      nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return isAllowListed;
+      }
+
+      nsCString chanSpec = chanURI->GetSpecOrDefault();
+      chanSpec.Truncate(
+          std::min(chanSpec.Length(), UrlClassifierCommon::sMaxSpecLength));
+      UC_LOG(("nsChannelClassifier: User override on channel[%p] (%s)",
+              aChannel, chanSpec.get()));
+    }
+  }
+
+  return isAllowListed;
+}
+
+// static
+bool UrlClassifierCommon::IsTrackingClassificationFlag(uint32_t aFlag) {
+  return (aFlag & nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING) ||
+         (aFlag &
+          nsIHttpChannel::ClassificationFlags::CLASSIFIED_FINGERPRINTING);
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/url-classifier/UrlClassifierCommon.h
+++ b/netwerk/url-classifier/UrlClassifierCommon.h
@@ -37,16 +37,27 @@ class UrlClassifierCommon final {
                                     const nsACString& aProvider,
                                     const nsACString& aFullHash);
 
   // Use this function only when you are looking for a pairwise whitelist uri
   // with the format: http://toplevel.page/?resource=channel.uri.domain
   static nsresult CreatePairwiseWhiteListURI(nsIChannel* aChannel,
                                              nsIURI** aURI);
 
+  static void AnnotateChannel(
+      nsIChannel* aChannel,
+      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose,
+      uint32_t aClassificationFlags, uint32_t aLoadingState);
+
+  static bool IsAllowListed(
+      nsIChannel* aChannel,
+      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose);
+
+  static bool IsTrackingClassificationFlag(uint32_t aFlag);
+
  private:
   // aBlockedReason must be one of the nsIWebProgressListener state.
   static void NotifyChannelBlocked(nsIChannel* aChannel,
                                    nsIURI* aURIBeingLoaded,
                                    unsigned aBlockedReason);
 };
 
 }  // namespace net
--- a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp
@@ -159,70 +159,10 @@ UrlClassifierFeatureBase::HasHostInPrefe
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureBase::GetSkipHostList(nsACString& aList) {
   aList = mSkipHosts;
   return NS_OK;
 }
 
-bool UrlClassifierFeatureBase::IsAllowListed(
-    nsIChannel* aChannel,
-    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose) {
-  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
-             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
-             aPurpose == AntiTrackingCommon::eFingerprinting ||
-             aPurpose == AntiTrackingCommon::eCryptomining);
-
-  nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
-  if (!channel) {
-    UC_LOG(("nsChannelClassifier: Not an HTTP channel"));
-    return false;
-  }
-
-  nsCOMPtr<nsIURI> topWinURI;
-  nsresult rv = channel->GetTopWindowURI(getter_AddRefs(topWinURI));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  if (!topWinURI && StaticPrefs::channelclassifier_allowlist_example()) {
-    UC_LOG(("nsChannelClassifier: Allowlisting test domain"));
-    nsCOMPtr<nsIIOService> ios = services::GetIOService();
-    if (NS_WARN_IF(!ios)) {
-      return false;
-    }
-
-    rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
-                     nullptr, nullptr, getter_AddRefs(topWinURI));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-  }
-
-  bool isAllowListed = false;
-  rv = AntiTrackingCommon::IsOnContentBlockingAllowList(
-      topWinURI, NS_UsePrivateBrowsing(aChannel), aPurpose, isAllowListed);
-  if (NS_FAILED(rv)) {  // normal for some loads, no need to print a warning
-    return false;
-  }
-
-  if (isAllowListed) {
-    if (UC_LOG_ENABLED()) {
-      nsCOMPtr<nsIURI> chanURI;
-      nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return isAllowListed;
-      }
-
-      nsCString chanSpec = chanURI->GetSpecOrDefault();
-      chanSpec.Truncate(
-          std::min(chanSpec.Length(), UrlClassifierCommon::sMaxSpecLength));
-      UC_LOG(("nsChannelClassifier: User override on channel[%p] (%s)",
-              aChannel, chanSpec.get()));
-    }
-  }
-
-  return isAllowListed;
-}
-
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/url-classifier/UrlClassifierFeatureBase.h
+++ b/netwerk/url-classifier/UrlClassifierFeatureBase.h
@@ -53,20 +53,16 @@ class UrlClassifierFeatureBase : public 
                            const nsACString& aPrefWhitelistTableName,
                            const nsACString& aPrefSkipHosts);
 
   virtual ~UrlClassifierFeatureBase();
 
   void InitializePreferences();
   void ShutdownPreferences();
 
-  bool IsAllowListed(
-      nsIChannel* aChannel,
-      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose);
-
  private:
   nsCString mName;
 
   nsCString mPrefSkipHosts;
 
   // 2: blacklist and whitelist.
   nsCString mPrefTables[2];
   nsTArray<nsCString> mTables[2];
--- a/netwerk/url-classifier/UrlClassifierFeatureCryptominingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureCryptominingProtection.cpp
@@ -138,18 +138,18 @@ UrlClassifierFeatureCryptominingProtecti
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureCryptominingProtection::ProcessChannel(
     nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eCryptomining);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eCryptomining);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (isAllowListed) {
     // Even with cryptomining blocking disabled, we still want to show the user
     // that there are unblocked cryptominers on the site, so notify the UI that
     // we loaded cryptomining content.  UI code can treat this notification
--- a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 
 // List of Features
 #include "UrlClassifierFeatureCryptominingProtection.h"
+#include "UrlClassifierFeatureFingerprintingAnnotation.h"
 #include "UrlClassifierFeatureFingerprintingProtection.h"
 #include "UrlClassifierFeatureFlash.h"
 #include "UrlClassifierFeatureLoginReputation.h"
 #include "UrlClassifierFeaturePhishingProtection.h"
 #include "UrlClassifierFeatureTrackingProtection.h"
 #include "UrlClassifierFeatureTrackingAnnotation.h"
 #include "UrlClassifierFeatureCustomTables.h"
 
@@ -24,16 +25,17 @@ namespace net {
 /* static */
 void UrlClassifierFeatureFactory::Shutdown() {
   // We want to expose Features only in the parent process.
   if (!XRE_IsParentProcess()) {
     return;
   }
 
   UrlClassifierFeatureCryptominingProtection::MaybeShutdown();
+  UrlClassifierFeatureFingerprintingAnnotation::MaybeShutdown();
   UrlClassifierFeatureFingerprintingProtection::MaybeShutdown();
   UrlClassifierFeatureFlash::MaybeShutdown();
   UrlClassifierFeatureLoginReputation::MaybeShutdown();
   UrlClassifierFeaturePhishingProtection::MaybeShutdown();
   UrlClassifierFeatureTrackingAnnotation::MaybeShutdown();
   UrlClassifierFeatureTrackingProtection::MaybeShutdown();
 }
 
@@ -58,16 +60,22 @@ void UrlClassifierFeatureFactory::GetFea
   }
 
   // Fingerprinting Protection
   feature = UrlClassifierFeatureFingerprintingProtection::MaybeCreate(aChannel);
   if (feature) {
     aFeatures.AppendElement(feature);
   }
 
+  // Fingerprinting Annotation
+  feature = UrlClassifierFeatureFingerprintingAnnotation::MaybeCreate(aChannel);
+  if (feature) {
+    aFeatures.AppendElement(feature);
+  }
+
   // Tracking Protection
   feature = UrlClassifierFeatureTrackingProtection::MaybeCreate(aChannel);
   if (feature) {
     aFeatures.AppendElement(feature);
   }
 
   // Tracking Annotation
   feature = UrlClassifierFeatureTrackingAnnotation::MaybeCreate(aChannel);
@@ -103,16 +111,23 @@ UrlClassifierFeatureFactory::GetFeatureB
   nsCOMPtr<nsIUrlClassifierFeature> feature;
 
   // Cryptomining Protection
   feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(aName);
   if (feature) {
     return feature.forget();
   }
 
+  // Fingerprinting Annotation
+  feature =
+      UrlClassifierFeatureFingerprintingAnnotation::GetIfNameMatches(aName);
+  if (feature) {
+    return feature.forget();
+  }
+
   // Fingerprinting Protection
   feature =
       UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(aName);
   if (feature) {
     return feature.forget();
   }
 
   // Tracking Protection
@@ -156,16 +171,22 @@ void UrlClassifierFeatureFactory::GetFea
 
   // Cryptomining Protection
   nsAutoCString name;
   name.Assign(UrlClassifierFeatureCryptominingProtection::Name());
   if (!name.IsEmpty()) {
     aArray.AppendElement(name);
   }
 
+  // Fingerprinting Annotation
+  name.Assign(UrlClassifierFeatureFingerprintingAnnotation::Name());
+  if (!name.IsEmpty()) {
+    aArray.AppendElement(name);
+  }
+
   // Fingerprinting Protection
   name.Assign(UrlClassifierFeatureFingerprintingProtection::Name());
   if (!name.IsEmpty()) {
     aArray.AppendElement(name);
   }
 
   // Tracking Protection
   name.Assign(UrlClassifierFeatureTrackingProtection::Name());
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.cpp
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "UrlClassifierFeatureFingerprintingAnnotation.h"
+
+#include "mozilla/AntiTrackingCommon.h"
+#include "mozilla/net/UrlClassifierCommon.h"
+#include "mozilla/StaticPrefs.h"
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace net {
+
+namespace {
+
+#define FINGERPRINTING_ANNOTATION_FEATURE_NAME "fingerprinting-annotation"
+
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST \
+  "urlclassifier.features.fingerprinting.annotate.blacklistTables"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST_TEST_ENTRIES \
+  "urlclassifier.features.fingerprinting.annotate.blacklistHosts"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST \
+  "urlclassifier.features.fingerprinting.annotate.whitelistTables"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST_TEST_ENTRIES \
+  "urlclassifier.features.fingerprinting.annotate.whitelistHosts"
+#define TABLE_FINGERPRINTING_ANNOTATION_BLACKLIST_PREF \
+  "fingerprinting-annotate-blacklist-pref"
+#define TABLE_FINGERPRINTING_ANNOTATION_WHITELIST_PREF \
+  "fingerprinting-annotate-whitelist-pref"
+
+StaticRefPtr<UrlClassifierFeatureFingerprintingAnnotation>
+    gFeatureFingerprintingAnnotation;
+
+}  // namespace
+
+UrlClassifierFeatureFingerprintingAnnotation::
+    UrlClassifierFeatureFingerprintingAnnotation()
+    : UrlClassifierFeatureBase(
+          NS_LITERAL_CSTRING(FINGERPRINTING_ANNOTATION_FEATURE_NAME),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(TABLE_FINGERPRINTING_ANNOTATION_BLACKLIST_PREF),
+          NS_LITERAL_CSTRING(TABLE_FINGERPRINTING_ANNOTATION_WHITELIST_PREF),
+          EmptyCString()) {}
+
+/* static */ const char* UrlClassifierFeatureFingerprintingAnnotation::Name() {
+  return FINGERPRINTING_ANNOTATION_FEATURE_NAME;
+}
+
+/* static */
+void UrlClassifierFeatureFingerprintingAnnotation::MaybeInitialize() {
+  UC_LOG(("UrlClassifierFeatureFingerprintingAnnotation: MaybeInitialize"));
+
+  if (!gFeatureFingerprintingAnnotation) {
+    gFeatureFingerprintingAnnotation =
+        new UrlClassifierFeatureFingerprintingAnnotation();
+    gFeatureFingerprintingAnnotation->InitializePreferences();
+  }
+}
+
+/* static */
+void UrlClassifierFeatureFingerprintingAnnotation::MaybeShutdown() {
+  UC_LOG(("UrlClassifierFeatureFingerprintingAnnotation: MaybeShutdown"));
+
+  if (gFeatureFingerprintingAnnotation) {
+    gFeatureFingerprintingAnnotation->ShutdownPreferences();
+    gFeatureFingerprintingAnnotation = nullptr;
+  }
+}
+
+/* static */
+already_AddRefed<UrlClassifierFeatureFingerprintingAnnotation>
+UrlClassifierFeatureFingerprintingAnnotation::MaybeCreate(
+    nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingAnnotation: MaybeCreate for channel "
+       "%p",
+       aChannel));
+
+  if (!StaticPrefs::
+          privacy_trackingprotection_fingerprinting_annotate_enabled()) {
+    return nullptr;
+  }
+
+  if (!UrlClassifierCommon::ShouldEnableClassifier(aChannel)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureFingerprintingAnnotation);
+
+  RefPtr<UrlClassifierFeatureFingerprintingAnnotation> self =
+      gFeatureFingerprintingAnnotation;
+  return self.forget();
+}
+
+/* static */
+already_AddRefed<nsIUrlClassifierFeature>
+UrlClassifierFeatureFingerprintingAnnotation::GetIfNameMatches(
+    const nsACString& aName) {
+  if (!aName.EqualsLiteral(FINGERPRINTING_ANNOTATION_FEATURE_NAME)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureFingerprintingAnnotation);
+
+  RefPtr<UrlClassifierFeatureFingerprintingAnnotation> self =
+      gFeatureFingerprintingAnnotation;
+  return self.forget();
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureFingerprintingAnnotation::ProcessChannel(
+    nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aShouldContinue);
+
+  // This is not a blocking feature.
+  *aShouldContinue = true;
+
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingAnnotation::ProcessChannel, "
+       "annotating channel[%p]",
+       aChannel));
+
+  UrlClassifierCommon::AnnotateChannel(
+      aChannel, AntiTrackingCommon::eFingerprinting,
+      nsIHttpChannel::ClassificationFlags::CLASSIFIED_FINGERPRINTING,
+      nsIWebProgressListener::STATE_LOADED_FINGERPRINTING_CONTENT);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureFingerprintingAnnotation::GetURIByListType(
+    nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
+    nsIURI** aURI) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aURI);
+
+  if (aListType == nsIUrlClassifierFeature::blacklist) {
+    return aChannel->GetURI(aURI);
+  }
+
+  MOZ_ASSERT(aListType == nsIUrlClassifierFeature::whitelist);
+  return UrlClassifierCommon::CreatePairwiseWhiteListURI(aChannel, aURI);
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozilla_net_UrlClassifierFeatureFingerprintingAnnotation_h
+#define mozilla_net_UrlClassifierFeatureFingerprintingAnnotation_h
+
+#include "UrlClassifierFeatureBase.h"
+
+class nsIChannel;
+
+namespace mozilla {
+namespace net {
+
+class UrlClassifierFeatureFingerprintingAnnotation final
+    : public UrlClassifierFeatureBase {
+ public:
+  static const char* Name();
+
+  static void MaybeShutdown();
+
+  static already_AddRefed<UrlClassifierFeatureFingerprintingAnnotation>
+  MaybeCreate(nsIChannel* aChannel);
+
+  static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches(
+      const nsACString& aName);
+
+  NS_IMETHOD ProcessChannel(nsIChannel* aChannel, const nsACString& aList,
+                            bool* aShouldContinue) override;
+
+  NS_IMETHOD GetURIByListType(nsIChannel* aChannel,
+                              nsIUrlClassifierFeature::listType aListType,
+                              nsIURI** aURI) override;
+
+ private:
+  UrlClassifierFeatureFingerprintingAnnotation();
+
+  static void MaybeInitialize();
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_net_UrlClassifierFeatureFingerprintingAnnotation_h
--- a/netwerk/url-classifier/UrlClassifierFeatureFingerprintingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingProtection.cpp
@@ -12,17 +12,17 @@
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
-#define FINGERPRINTING_FEATURE_NAME "fingerprinting"
+#define FINGERPRINTING_FEATURE_NAME "fingerprinting-protection"
 
 #define URLCLASSIFIER_FINGERPRINTING_BLACKLIST \
   "urlclassifier.features.fingerprinting.blacklistTables"
 #define URLCLASSIFIER_FINGERPRINTING_BLACKLIST_TEST_ENTRIES \
   "urlclassifier.features.fingerprinting.blacklistHosts"
 #define URLCLASSIFIER_FINGERPRINTING_WHITELIST \
   "urlclassifier.features.fingerprinting.whitelistTables"
 #define URLCLASSIFIER_FINGERPRINTING_WHITELIST_TEST_ENTRIES \
@@ -142,48 +142,41 @@ UrlClassifierFeatureFingerprintingProtec
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureFingerprintingProtection::ProcessChannel(
     nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eFingerprinting);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eFingerprinting);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (isAllowListed) {
-    // Even with fingerprinting blocking disabled, we still want to show the
-    // user that there are unblocked trackers on the site, so notify the UI that
-    // we loaded tracking content.  UI code can treat this notification
-    // differently depending on whether fingerprinting blocking is enabled or
-    // not.
-    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
-        aChannel, nsIWebProgressListener::STATE_LOADED_FINGERPRINTING_CONTENT);
-  } else {
-    UrlClassifierCommon::SetBlockedContent(aChannel,
-                                           NS_ERROR_FINGERPRINTING_URI, aList,
-                                           EmptyCString(), EmptyCString());
+    return NS_OK;
+  }
+
+  UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_FINGERPRINTING_URI,
+                                         aList, EmptyCString(), EmptyCString());
 
-    UC_LOG(
-        ("UrlClassifierFeatureFingerprintingProtection::ProcessChannel, "
-         "cancelling "
-         "channel[%p]",
-         aChannel));
-    nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingProtection::ProcessChannel, "
+       "cancelling "
+       "channel[%p]",
+       aChannel));
+  nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
 
-    if (httpChannel) {
-      Unused << httpChannel->CancelByChannelClassifier(
-          NS_ERROR_FINGERPRINTING_URI);
-    } else {
-      Unused << aChannel->Cancel(NS_ERROR_FINGERPRINTING_URI);
-    }
+  if (httpChannel) {
+    Unused << httpChannel->CancelByChannelClassifier(
+        NS_ERROR_FINGERPRINTING_URI);
+  } else {
+    Unused << aChannel->Cancel(NS_ERROR_FINGERPRINTING_URI);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureFingerprintingProtection::GetURIByListType(
     nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
--- a/netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
@@ -3,23 +3,20 @@
 /* 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/. */
 
 #include "UrlClassifierFeatureTrackingAnnotation.h"
 
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Logging.h"
-#include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/net/UrlClassifierCommon.h"
 #include "nsContentUtils.h"
-#include "nsQueryObject.h"
-#include "TrackingDummyChannel.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
 #define TRACKING_ANNOTATION_FEATURE_NAME "tracking-annotation"
 
@@ -33,86 +30,16 @@ namespace {
   "urlclassifier.trackingAnnotationWhitelistTable.testEntries"
 #define URLCLASSIFIER_TRACKING_ANNOTATION_SKIP_URLS \
   "urlclassifier.trackingAnnotationSkipURLs"
 #define TABLE_ANNOTATION_BLACKLIST_PREF "annotation-blacklist-pref"
 #define TABLE_ANNOTATION_WHITELIST_PREF "annotation-whitelist-pref"
 
 StaticRefPtr<UrlClassifierFeatureTrackingAnnotation> gFeatureTrackingAnnotation;
 
-static void SetClassificationFlagsHelper(nsIChannel* aChannel,
-                                         bool aIsThirdParty) {
-  MOZ_ASSERT(aChannel);
-
-  nsCOMPtr<nsIParentChannel> parentChannel;
-  NS_QueryNotificationCallbacks(aChannel, parentChannel);
-  if (parentChannel) {
-    // This channel is a parent-process proxy for a child process
-    // request. We should notify the child process as well.
-    parentChannel->NotifyClassificationFlags(
-        nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING, aIsThirdParty);
-  }
-
-  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
-  if (httpChannel) {
-    httpChannel->AddClassificationFlags(nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING,
-                                        aIsThirdParty);
-  }
-
-  RefPtr<TrackingDummyChannel> dummyChannel = do_QueryObject(aChannel);
-  if (dummyChannel) {
-    dummyChannel->AddClassificationFlags(nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING);
-  }
-}
-
-static void LowerPriorityHelper(nsIChannel* aChannel) {
-  MOZ_ASSERT(aChannel);
-
-  bool isBlockingResource = false;
-
-  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
-  if (cos) {
-    if (nsContentUtils::IsTailingEnabled()) {
-      uint32_t cosFlags = 0;
-      cos->GetClassFlags(&cosFlags);
-      isBlockingResource =
-          cosFlags & (nsIClassOfService::UrgentStart |
-                      nsIClassOfService::Leader | nsIClassOfService::Unblocked);
-
-      // Requests not allowed to be tailed are usually those with higher
-      // prioritization.  That overweights being a tracker: don't throttle
-      // them when not in background.
-      if (!(cosFlags & nsIClassOfService::TailForbidden)) {
-        cos->AddClassFlags(nsIClassOfService::Throttleable);
-      }
-    } else {
-      // Yes, we even don't want to evaluate the isBlockingResource when tailing
-      // is off see bug 1395525.
-
-      cos->AddClassFlags(nsIClassOfService::Throttleable);
-    }
-  }
-
-  if (!isBlockingResource) {
-    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
-    if (p) {
-      if (UC_LOG_ENABLED()) {
-        nsCOMPtr<nsIURI> uri;
-        aChannel->GetURI(getter_AddRefs(uri));
-        nsAutoCString spec;
-        uri->GetAsciiSpec(spec);
-        spec.Truncate(
-            std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength));
-        UC_LOG(("Setting PRIORITY_LOWEST for channel[%p] (%s)", aChannel,
-                spec.get()));
-      }
-      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
-    }
-  }
-}
 
 }  // namespace
 
 UrlClassifierFeatureTrackingAnnotation::UrlClassifierFeatureTrackingAnnotation()
     : UrlClassifierFeatureBase(
           NS_LITERAL_CSTRING(TRACKING_ANNOTATION_FEATURE_NAME),
           NS_LITERAL_CSTRING(URLCLASSIFIER_ANNOTATION_BLACKLIST),
           NS_LITERAL_CSTRING(URLCLASSIFIER_ANNOTATION_WHITELIST),
@@ -192,52 +119,20 @@ UrlClassifierFeatureTrackingAnnotation::
                                                        const nsACString& aList,
                                                        bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
   // This is not a blocking feature.
   *aShouldContinue = true;
 
-  nsCOMPtr<nsIURI> chanURI;
-  nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    UC_LOG(
-        ("UrlClassifierFeatureTrackingAnnotation::ProcessChannel "
-         "nsIChannel::GetURI(%p) failed",
-         (void*)aChannel));
-    return NS_OK;
-  }
-
-  bool isThirdPartyWithTopLevelWinURI =
-      nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, chanURI);
-
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eTrackingAnnotations);
-
-  UC_LOG(
-      ("UrlClassifierFeatureTrackingAnnotation::ProcessChannel, annotating "
-       "channel[%p]",
-       aChannel));
-
-  SetClassificationFlagsHelper(aChannel, isThirdPartyWithTopLevelWinURI);
-
-  if (isThirdPartyWithTopLevelWinURI || isAllowListed) {
-    // Even with TP disabled, we still want to show the user that there
-    // are unblocked trackers on the site, so notify the UI that we loaded
-    // tracking content. UI code can treat this notification differently
-    // depending on whether TP is enabled or disabled.
-    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
-        aChannel, nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
-  }
-
-  if (isThirdPartyWithTopLevelWinURI &&
-      StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
-    LowerPriorityHelper(aChannel);
-  }
+  UrlClassifierCommon::AnnotateChannel(
+      aChannel, AntiTrackingCommon::eTrackingAnnotations,
+      nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING,
+      nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureTrackingAnnotation::GetURIByListType(
     nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
     nsIURI** aURI) {
--- a/netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
@@ -134,18 +134,18 @@ UrlClassifierFeatureTrackingProtection::
 
 NS_IMETHODIMP
 UrlClassifierFeatureTrackingProtection::ProcessChannel(nsIChannel* aChannel,
                                                        const nsACString& aList,
                                                        bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eTrackingProtection);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eTrackingProtection);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (!isAllowListed) {
     UrlClassifierCommon::SetBlockedContent(
         aChannel, NS_ERROR_TRACKING_URI, aList, EmptyCString(), EmptyCString());
 
--- a/netwerk/url-classifier/moz.build
+++ b/netwerk/url-classifier/moz.build
@@ -29,16 +29,17 @@ DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITI
 UNIFIED_SOURCES += [
     'AsyncUrlChannelClassifier.cpp',
     'nsChannelClassifier.cpp',
     'UrlClassifierCommon.cpp',
     'UrlClassifierFeatureBase.cpp',
     'UrlClassifierFeatureCryptominingProtection.cpp',
     'UrlClassifierFeatureCustomTables.cpp',
     'UrlClassifierFeatureFactory.cpp',
+    'UrlClassifierFeatureFingerprintingAnnotation.cpp',
     'UrlClassifierFeatureFingerprintingProtection.cpp',
     'UrlClassifierFeatureFlash.cpp',
     'UrlClassifierFeatureLoginReputation.cpp',
     'UrlClassifierFeaturePhishingProtection.cpp',
     'UrlClassifierFeatureResult.cpp',
     'UrlClassifierFeatureTrackingAnnotation.cpp',
     'UrlClassifierFeatureTrackingProtection.cpp',
 ]