summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp')
-rw-r--r--toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp596
1 files changed, 596 insertions, 0 deletions
diff --git a/toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp b/toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp
new file mode 100644
index 0000000000..e5d9ccfea9
--- /dev/null
+++ b/toolkit/components/antitracking/bouncetrackingprotection/BounceTrackingProtection.cpp
@@ -0,0 +1,596 @@
+/* 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 "BounceTrackingProtection.h"
+
+#include "BounceTrackingProtectionStorage.h"
+#include "BounceTrackingState.h"
+#include "BounceTrackingRecord.h"
+
+#include "BounceTrackingStateGlobal.h"
+#include "ErrorList.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPrefs_privacy.h"
+#include "mozilla/dom/Promise.h"
+#include "nsDebug.h"
+#include "nsHashPropertyBag.h"
+#include "nsIClearDataService.h"
+#include "nsIObserverService.h"
+#include "nsIPrincipal.h"
+#include "nsISupports.h"
+#include "nsServiceManagerUtils.h"
+#include "nscore.h"
+#include "prtime.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "xpcpublic.h"
+
+#define TEST_OBSERVER_MSG_RECORD_BOUNCES_FINISHED "test-record-bounces-finished"
+
+namespace mozilla {
+
+NS_IMPL_ISUPPORTS(BounceTrackingProtection, nsIBounceTrackingProtection);
+
+LazyLogModule gBounceTrackingProtectionLog("BounceTrackingProtection");
+
+static StaticRefPtr<BounceTrackingProtection> sBounceTrackingProtection;
+
+static constexpr uint32_t TRACKER_PURGE_FLAGS =
+ nsIClearDataService::CLEAR_ALL_CACHES | nsIClearDataService::CLEAR_COOKIES |
+ nsIClearDataService::CLEAR_DOM_STORAGES |
+ nsIClearDataService::CLEAR_CLIENT_AUTH_REMEMBER_SERVICE |
+ nsIClearDataService::CLEAR_EME | nsIClearDataService::CLEAR_MEDIA_DEVICES |
+ nsIClearDataService::CLEAR_STORAGE_ACCESS |
+ nsIClearDataService::CLEAR_AUTH_TOKENS |
+ nsIClearDataService::CLEAR_AUTH_CACHE;
+
+// static
+already_AddRefed<BounceTrackingProtection>
+BounceTrackingProtection::GetSingleton() {
+ MOZ_ASSERT(XRE_IsParentProcess());
+
+ if (!StaticPrefs::privacy_bounceTrackingProtection_enabled_AtStartup()) {
+ return nullptr;
+ }
+
+ if (!sBounceTrackingProtection) {
+ sBounceTrackingProtection = new BounceTrackingProtection();
+
+ RunOnShutdown([] { sBounceTrackingProtection = nullptr; });
+ }
+
+ return do_AddRef(sBounceTrackingProtection);
+}
+
+BounceTrackingProtection::BounceTrackingProtection() {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug, ("constructor"));
+
+ mStorage = new BounceTrackingProtectionStorage();
+
+ nsresult rv = mStorage->Init();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Error,
+ ("storage init failed"));
+ return;
+ }
+
+ // Schedule timer for tracker purging. The timer interval is determined by
+ // pref.
+ uint32_t purgeTimerPeriod = StaticPrefs::
+ privacy_bounceTrackingProtection_bounceTrackingPurgeTimerPeriodSec();
+
+ // The pref can be set to 0 to disable interval purging.
+ if (purgeTimerPeriod == 0) {
+ return;
+ }
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("Scheduling mBounceTrackingPurgeTimer. Interval: %d seconds.",
+ purgeTimerPeriod));
+
+ rv = NS_NewTimerWithCallback(
+ getter_AddRefs(mBounceTrackingPurgeTimer),
+ [](auto) {
+ if (!sBounceTrackingProtection) {
+ return;
+ }
+ sBounceTrackingProtection->PurgeBounceTrackers()->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ [] {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: PurgeBounceTrackers finished after timer call.",
+ __FUNCTION__));
+ },
+ [] { NS_WARNING("RunPurgeBounceTrackers failed"); });
+ },
+ purgeTimerPeriod * PR_MSEC_PER_SEC, nsITimer::TYPE_REPEATING_SLACK,
+ "mBounceTrackingPurgeTimer");
+
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Failed to schedule timer for RunPurgeBounceTrackers.");
+}
+
+nsresult BounceTrackingProtection::RecordStatefulBounces(
+ BounceTrackingState* aBounceTrackingState) {
+ NS_ENSURE_ARG_POINTER(aBounceTrackingState);
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: aBounceTrackingState: %s", __FUNCTION__,
+ aBounceTrackingState->Describe().get()));
+
+ // Assert: navigable’s bounce tracking record is not null.
+ BounceTrackingRecord* record =
+ aBounceTrackingState->GetBounceTrackingRecord();
+ NS_ENSURE_TRUE(record, NS_ERROR_FAILURE);
+
+ // Get the bounce tracker map and the user activation map.
+ RefPtr<BounceTrackingStateGlobal> globalState =
+ mStorage->GetOrCreateStateGlobal(aBounceTrackingState);
+ MOZ_ASSERT(globalState);
+
+ // For each host in navigable’s bounce tracking record's bounce set:
+ for (const nsACString& host : record->GetBounceHosts()) {
+ // If host equals navigable’s bounce tracking record's initial host,
+ // continue.
+ if (host == record->GetInitialHost()) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host == initialHost: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+ // If host equals navigable’s bounce tracking record's final host, continue.
+ if (host == record->GetFinalHost()) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host == finalHost: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+
+ // If user activation map contains host, continue.
+ if (globalState->HasUserActivation(host)) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host with recent user activation: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+
+ // If stateful bounce tracking map contains host, continue.
+ if (globalState->HasBounceTracker(host)) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip already existing host: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+
+ // If navigable’s bounce tracking record's storage access set does not
+ // contain host, continue.
+ if (StaticPrefs::
+ privacy_bounceTrackingProtection_requireStatefulBounces() &&
+ !record->GetStorageAccessHosts().Contains(host)) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host without storage access: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+
+ // Set stateful bounce tracking map[host] to topDocument’s relevant settings
+ // object's current wall time.
+ PRTime now = PR_Now();
+ MOZ_ASSERT(!globalState->HasBounceTracker(host));
+ nsresult rv = globalState->RecordBounceTracker(host, now);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ continue;
+ }
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
+ ("%s: Added candidate to mBounceTrackers: %s, Time: %" PRIu64,
+ __FUNCTION__, PromiseFlatCString(host).get(),
+ static_cast<uint64_t>(now)));
+ }
+
+ // Set navigable’s bounce tracking record to null.
+ aBounceTrackingState->ResetBounceTrackingRecord();
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Done, reset aBounceTrackingState: %s", __FUNCTION__,
+ aBounceTrackingState->Describe().get()));
+
+ // If running in test automation, dispatch an observer message indicating
+ // we're finished recording bounces.
+ if (StaticPrefs::privacy_bounceTrackingProtection_enableTestMode()) {
+ nsCOMPtr<nsIObserverService> obsSvc =
+ mozilla::services::GetObserverService();
+ NS_ENSURE_TRUE(obsSvc, NS_ERROR_FAILURE);
+
+ RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
+
+ nsresult rv = props->SetPropertyAsUint64(
+ u"browserId"_ns, aBounceTrackingState->GetBrowserId());
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = obsSvc->NotifyObservers(
+ ToSupports(props), TEST_OBSERVER_MSG_RECORD_BOUNCES_FINISHED, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult BounceTrackingProtection::RecordUserActivation(
+ nsIPrincipal* aPrincipal) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+
+ NS_ENSURE_ARG_POINTER(aPrincipal);
+ NS_ENSURE_TRUE(aPrincipal->GetIsContentPrincipal(), NS_ERROR_FAILURE);
+
+ nsAutoCString siteHost;
+ nsresult rv = aPrincipal->GetBaseDomain(siteHost);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
+ ("%s: siteHost: %s", __FUNCTION__, siteHost.get()));
+
+ RefPtr<BounceTrackingStateGlobal> globalState =
+ mStorage->GetOrCreateStateGlobal(aPrincipal);
+ MOZ_ASSERT(globalState);
+
+ return globalState->RecordUserActivation(siteHost, PR_Now());
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::TestGetBounceTrackerCandidateHosts(
+ JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
+ nsTArray<nsCString>& aCandidates) {
+ MOZ_ASSERT(aCx);
+
+ OriginAttributes oa;
+ if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ BounceTrackingStateGlobal* globalState = mStorage->GetOrCreateStateGlobal(oa);
+ MOZ_ASSERT(globalState);
+
+ for (const nsACString& host : globalState->BounceTrackersMapRef().Keys()) {
+ aCandidates.AppendElement(host);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::TestGetUserActivationHosts(
+ JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
+ nsTArray<nsCString>& aHosts) {
+ MOZ_ASSERT(aCx);
+
+ OriginAttributes oa;
+ if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ BounceTrackingStateGlobal* globalState = mStorage->GetOrCreateStateGlobal(oa);
+ MOZ_ASSERT(globalState);
+
+ for (const nsACString& host : globalState->UserActivationMapRef().Keys()) {
+ aHosts.AppendElement(host);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::ClearAll() {
+ BounceTrackingState::ResetAll();
+ return mStorage->Clear();
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::ClearBySiteHostAndOA(
+ const nsACString& aSiteHost, JS::Handle<JS::Value> aOriginAttributes,
+ JSContext* aCx) {
+ NS_ENSURE_ARG_POINTER(aCx);
+
+ OriginAttributes originAttributes;
+ if (!aOriginAttributes.isObject() ||
+ !originAttributes.Init(aCx, aOriginAttributes)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Reset per tab state for tabs matching the given OriginAttributes.
+ BounceTrackingState::ResetAllForOriginAttributes(originAttributes);
+
+ return mStorage->ClearBySiteHost(aSiteHost, &originAttributes);
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::ClearBySiteHost(const nsACString& aSiteHost) {
+ BounceTrackingState::ResetAll();
+
+ return mStorage->ClearBySiteHost(aSiteHost, nullptr);
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::ClearByTimeRange(PRTime aFrom, PRTime aTo) {
+ NS_ENSURE_TRUE(aFrom >= 0, NS_ERROR_INVALID_ARG);
+ NS_ENSURE_TRUE(aFrom < aTo, NS_ERROR_INVALID_ARG);
+
+ // Clear all BounceTrackingState, we don't keep track of time ranges.
+ BounceTrackingState::ResetAll();
+
+ return mStorage->ClearByTimeRange(aFrom, aTo);
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::ClearByOriginAttributesPattern(
+ const nsAString& aPattern) {
+ OriginAttributesPattern pattern;
+ if (!pattern.Init(aPattern)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Reset all per-tab state matching the given OriginAttributesPattern.
+ BounceTrackingState::ResetAllForOriginAttributesPattern(pattern);
+
+ return mStorage->ClearByOriginAttributesPattern(pattern);
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::TestRunPurgeBounceTrackers(
+ JSContext* aCx, mozilla::dom::Promise** aPromise) {
+ NS_ENSURE_ARG_POINTER(aCx);
+ NS_ENSURE_ARG_POINTER(aPromise);
+
+ nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
+ if (!globalObject) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ ErrorResult result;
+ RefPtr<dom::Promise> promise = dom::Promise::Create(globalObject, result);
+ if (result.Failed()) {
+ return result.StealNSResult();
+ }
+
+ // PurgeBounceTrackers returns a MozPromise, wrap it in a dom::Promise
+ // required for XPCOM.
+ PurgeBounceTrackers()->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ [promise](const PurgeBounceTrackersMozPromise::ResolveValueType&
+ purgedSiteHosts) {
+ promise->MaybeResolve(purgedSiteHosts);
+ },
+ [promise] { promise->MaybeRejectWithUndefined(); });
+
+ promise.forget(aPromise);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::TestAddBounceTrackerCandidate(
+ JS::Handle<JS::Value> aOriginAttributes, const nsACString& aHost,
+ const PRTime aBounceTime, JSContext* aCx) {
+ MOZ_ASSERT(aCx);
+
+ OriginAttributes oa;
+ if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ BounceTrackingStateGlobal* stateGlobal = mStorage->GetOrCreateStateGlobal(oa);
+ MOZ_ASSERT(stateGlobal);
+
+ // Ensure aHost is lowercase to match nsIURI and nsIPrincipal.
+ nsAutoCString host(aHost);
+ ToLowerCase(host);
+
+ // Can not have a host in both maps.
+ nsresult rv = stateGlobal->TestRemoveUserActivation(host);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return stateGlobal->RecordBounceTracker(host, aBounceTime);
+}
+
+NS_IMETHODIMP
+BounceTrackingProtection::TestAddUserActivation(
+ JS::Handle<JS::Value> aOriginAttributes, const nsACString& aHost,
+ const PRTime aActivationTime, JSContext* aCx) {
+ MOZ_ASSERT(aCx);
+
+ OriginAttributes oa;
+ if (!aOriginAttributes.isObject() || !oa.Init(aCx, aOriginAttributes)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ BounceTrackingStateGlobal* stateGlobal = mStorage->GetOrCreateStateGlobal(oa);
+ MOZ_ASSERT(stateGlobal);
+
+ // Ensure aHost is lowercase to match nsIURI and nsIPrincipal.
+ nsAutoCString host(aHost);
+ ToLowerCase(host);
+
+ return stateGlobal->RecordUserActivation(host, aActivationTime);
+}
+
+RefPtr<BounceTrackingProtection::PurgeBounceTrackersMozPromise>
+BounceTrackingProtection::PurgeBounceTrackers() {
+ // Run the purging algorithm for all global state objects.
+ for (const auto& entry : mStorage->StateGlobalMapRef()) {
+ const OriginAttributes& originAttributes = entry.GetKey();
+ BounceTrackingStateGlobal* stateGlobal = entry.GetData();
+ MOZ_ASSERT(stateGlobal);
+
+ if (MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
+ nsAutoCString oaSuffix;
+ originAttributes.CreateSuffix(oaSuffix);
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Running purge algorithm for OA: '%s'", __FUNCTION__,
+ oaSuffix.get()));
+ }
+
+ PurgeBounceTrackersForStateGlobal(stateGlobal, originAttributes);
+ }
+
+ // Wait for all data clearing operations to complete. mClearPromises contains
+ // one promise per host / clear task.
+ return ClearDataMozPromise::AllSettled(GetCurrentSerialEventTarget(),
+ mClearPromises)
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [&](ClearDataMozPromise::AllSettledPromiseType::ResolveOrRejectValue&&
+ aResults) {
+ MOZ_ASSERT(aResults.IsResolve(), "AllSettled never rejects");
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
+ ("%s: Done. Cleared %zu hosts.", __FUNCTION__,
+ aResults.ResolveValue().Length()));
+
+ nsTArray<nsCString> purgedSiteHosts;
+ // If any clear call failed reject.
+ for (auto& result : aResults.ResolveValue()) {
+ if (result.IsReject()) {
+ mClearPromises.Clear();
+ return PurgeBounceTrackersMozPromise::CreateAndReject(
+ NS_ERROR_FAILURE, __func__);
+ }
+ purgedSiteHosts.AppendElement(result.ResolveValue());
+ }
+
+ // No clearing errors, resolve.
+ mClearPromises.Clear();
+ return PurgeBounceTrackersMozPromise::CreateAndResolve(
+ std::move(purgedSiteHosts), __func__);
+ });
+}
+
+nsresult BounceTrackingProtection::PurgeBounceTrackersForStateGlobal(
+ BounceTrackingStateGlobal* aStateGlobal,
+ const OriginAttributes& aOriginAttributes) {
+ MOZ_ASSERT(aStateGlobal);
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: #mUserActivation: %d, #mBounceTrackers: %d", __FUNCTION__,
+ aStateGlobal->UserActivationMapRef().Count(),
+ aStateGlobal->BounceTrackersMapRef().Count()));
+
+ // Purge already in progress.
+ if (!mClearPromises.IsEmpty()) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip: Purge already in progress.", __FUNCTION__));
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ const PRTime now = PR_Now();
+ // Convert the user activation lifetime into microseconds for calculation with
+ // PRTime values. The pref is a 32-bit value. Cast into 64-bit before
+ // multiplying so we get the correct result.
+ int64_t activationLifetimeUsec =
+ static_cast<int64_t>(
+ StaticPrefs::
+ privacy_bounceTrackingProtection_bounceTrackingActivationLifetimeSec()) *
+ PR_USEC_PER_SEC;
+
+ // 1. Remove hosts from the user activation map whose user activation flag has
+ // expired.
+ nsresult rv =
+ aStateGlobal->ClearUserActivationBefore(now - activationLifetimeUsec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // 2. Go over bounce tracker candidate map and purge state.
+ rv = NS_OK;
+ nsCOMPtr<nsIClearDataService> clearDataService =
+ do_GetService("@mozilla.org/clear-data-service;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mClearPromises.Clear();
+ nsTArray<nsCString> purgedSiteHosts;
+
+ // Collect hosts to remove from the bounce trackers map. We can not remove
+ // them while iterating over the map.
+ nsTArray<nsCString> bounceTrackerCandidatesToRemove;
+
+ for (auto hostIter = aStateGlobal->BounceTrackersMapRef().ConstIter();
+ !hostIter.Done(); hostIter.Next()) {
+ const nsACString& host = hostIter.Key();
+ const PRTime& bounceTime = hostIter.Data();
+
+ // If bounceTime + bounce tracking grace period is after now, then continue.
+ // The host is still within the grace period and must not be purged.
+ if (bounceTime +
+ StaticPrefs::
+ privacy_bounceTrackingProtection_bounceTrackingGracePeriodSec() *
+ PR_USEC_PER_SEC >
+ now) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host within bounce tracking grace period %s",
+ __FUNCTION__, PromiseFlatCString(host).get()));
+
+ continue;
+ }
+
+ // If there is a top-level traversable whose active document's origin's
+ // site's host equals host, then continue.
+ // TODO: Bug 1842047: Implement a more accurate check that calls into the
+ // browser implementations to determine whether the site is currently open
+ // on the top level.
+ bool hostIsActive;
+ rv = BounceTrackingState::HasBounceTrackingStateForSite(host, hostIsActive);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ hostIsActive = false;
+ }
+ if (hostIsActive) {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Skip host which is active %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+ continue;
+ }
+
+ // No exception above applies, clear state for the given host.
+
+ RefPtr<ClearDataMozPromise::Private> clearPromise =
+ new ClearDataMozPromise::Private(__func__);
+ RefPtr<ClearDataCallback> cb = new ClearDataCallback(clearPromise, host);
+
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
+ ("%s: Purge state for host: %s", __FUNCTION__,
+ PromiseFlatCString(host).get()));
+
+ // TODO: Bug 1842067: Clear by site + OA.
+ rv = clearDataService->DeleteDataFromBaseDomain(host, false,
+ TRACKER_PURGE_FLAGS, cb);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ clearPromise->Reject(0, __func__);
+ }
+
+ mClearPromises.AppendElement(clearPromise);
+
+ // Remove it from the bounce trackers map, it's about to be purged. If the
+ // clear call fails still remove it. We want to avoid an ever growing list
+ // of hosts in case of repeated failures.
+ bounceTrackerCandidatesToRemove.AppendElement(host);
+ }
+
+ // Remove hosts from the bounce trackers map which we executed purge calls
+ // for.
+ return aStateGlobal->RemoveBounceTrackers(bounceTrackerCandidatesToRemove);
+}
+
+// ClearDataCallback
+
+NS_IMPL_ISUPPORTS(BounceTrackingProtection::ClearDataCallback,
+ nsIClearDataCallback);
+
+// nsIClearDataCallback implementation
+NS_IMETHODIMP BounceTrackingProtection::ClearDataCallback::OnDataDeleted(
+ uint32_t aFailedFlags) {
+ if (aFailedFlags) {
+ mPromise->Reject(aFailedFlags, __func__);
+ } else {
+ MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Info,
+ ("%s: Cleared %s", __FUNCTION__, mHost.get()));
+ mPromise->Resolve(std::move(mHost), __func__);
+ }
+ return NS_OK;
+}
+
+} // namespace mozilla