Bug 1531538 - Delay resolving the promise returned from requestStorageAccess when the automatic storage access grants are invoked; r=baku
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 04 Mar 2019 20:12:14 +0000
changeset 462267 8cbf86043273811dd463d6707945ca3346ade726
parent 462266 ce7738b3a35df45b1984a8fccec773cc3a429325
child 462268 dd200b211b4adbbf149096dcf7341576384c5129
push id35646
push useraciure@mozilla.com
push dateTue, 05 Mar 2019 04:19:19 +0000
treeherdermozilla-central@7c5b913dc2e3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1531538
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 1531538 - Delay resolving the promise returned from requestStorageAccess when the automatic storage access grants are invoked; r=baku Differential Revision: https://phabricator.services.mozilla.com/D21771
dom/base/StorageAccessPermissionRequest.cpp
dom/base/StorageAccessPermissionRequest.h
modules/libpref/init/StaticPrefList.h
toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
--- a/dom/base/StorageAccessPermissionRequest.cpp
+++ b/dom/base/StorageAccessPermissionRequest.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "StorageAccessPermissionRequest.h"
+#include "mozilla/StaticPrefs.h"
+#include <cstdlib>
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(StorageAccessPermissionRequest,
                                    ContentPermissionRequestBase)
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(StorageAccessPermissionRequest,
@@ -34,16 +36,17 @@ StorageAccessPermissionRequest::StorageA
 }
 
 StorageAccessPermissionRequest::~StorageAccessPermissionRequest() { Cancel(); }
 
 NS_IMETHODIMP
 StorageAccessPermissionRequest::Cancel() {
   if (!mCallbackCalled) {
     mCallbackCalled = true;
+    mTimer = nullptr;
     mCancelCallback();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 StorageAccessPermissionRequest::Allow(JS::HandleValue aChoices) {
   nsTArray<PermissionChoice> choices;
@@ -54,17 +57,30 @@ StorageAccessPermissionRequest::Allow(JS
 
   if (!mCallbackCalled) {
     mCallbackCalled = true;
     if (choices.Length() == 1 &&
         choices[0].choice().EqualsLiteral("allow-on-any-site")) {
       mAllowAnySiteCallback();
     } else if (choices.Length() == 1 &&
                choices[0].choice().EqualsLiteral("allow-auto-grant")) {
-      mAllowAutoGrantCallback();
+      unsigned simulatedDelay = CalculateSimulatedDelay();
+      if (simulatedDelay) {
+        MOZ_ASSERT(!mTimer);
+        RefPtr<StorageAccessPermissionRequest> self = this;
+        rv = NS_NewTimerWithFuncCallback(
+            getter_AddRefs(mTimer), CallAutoGrantCallback, this, simulatedDelay,
+            nsITimer::TYPE_ONE_SHOT, "DelayedAllowAutoGrantCallback");
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+        NS_ADDREF(this);
+      } else {
+        mAllowAutoGrantCallback();
+      }
     } else {
       mAllowCallback();
     }
   }
   return NS_OK;
 }
 
 already_AddRefed<StorageAccessPermissionRequest>
@@ -83,10 +99,34 @@ StorageAccessPermissionRequest::Create(
   RefPtr<StorageAccessPermissionRequest> request =
       new StorageAccessPermissionRequest(
           aWindow, win->GetPrincipal(), std::move(aAllowCallback),
           std::move(aAllowAutoGrantCallback), std::move(aAllowAnySiteCallback),
           std::move(aCancelCallback));
   return request.forget();
 }
 
+unsigned StorageAccessPermissionRequest::CalculateSimulatedDelay() {
+  if (!StaticPrefs::dom_storage_access_auto_grants_delayed()) {
+    return 0;
+  }
+
+  // Generate a random time value that is at least 5 seconds and at most 15
+  // minutes.
+  std::srand(static_cast<unsigned>(PR_Now()));
+
+  const unsigned kMin = 5000;
+  const unsigned kMax = 6000;
+  const unsigned random = std::abs(std::rand());
+
+  return kMin + random % (kMax - kMin);
+}
+
+void StorageAccessPermissionRequest::CallAutoGrantCallback(nsITimer* aTimer,
+                                                           void* aClosure) {
+  auto self = static_cast<StorageAccessPermissionRequest*>(aClosure);
+  self->mAllowAutoGrantCallback();
+  self->mTimer = nullptr;
+  NS_RELEASE(self);
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/StorageAccessPermissionRequest.h
+++ b/dom/base/StorageAccessPermissionRequest.h
@@ -42,20 +42,25 @@ class StorageAccessPermissionRequest fin
   StorageAccessPermissionRequest(
       nsPIDOMWindowInner* aWindow, nsIPrincipal* aNodePrincipal,
       AllowCallback&& aAllowCallback,
       AllowAutoGrantCallback&& aAllowAutoGrantCallback,
       AllowAnySiteCallback&& aAllowAnySiteCallback,
       CancelCallback&& aCancelCallback);
   ~StorageAccessPermissionRequest();
 
+  unsigned CalculateSimulatedDelay();
+
+  static void CallAutoGrantCallback(nsITimer* aTimer, void* aClosure);
+
   AllowCallback mAllowCallback;
   AllowAutoGrantCallback mAllowAutoGrantCallback;
   AllowAnySiteCallback mAllowAnySiteCallback;
   CancelCallback mCancelCallback;
+  nsCOMPtr<nsITimer> mTimer;
   nsTArray<PermissionRequest> mPermissionRequests;
   bool mCallbackCalled;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // StorageAccessPermissionRequest_h_
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -515,16 +515,22 @@ VARCACHE_PREF(
 
 // Storage-access API.
 VARCACHE_PREF(
   "dom.storage_access.enabled",
    dom_storage_access_enabled,
   bool, false
 )
 
+VARCACHE_PREF(
+  "dom.storage_access.auto_grants.delayed",
+   dom_storage_access_auto_grants_delayed,
+  bool, true
+)
+
 //---------------------------------------------------------------------------
 // Extension prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "extensions.allowPrivateBrowsingByDefault",
    extensions_allowPrivateBrowsingByDefault,
   bool, true
--- a/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
+++ b/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
@@ -17,16 +17,17 @@ async function testDoorHanger(choice, sh
   }
 
   await SpecialPowers.flushPrefEnv();
   await SpecialPowers.pushPrefEnv({"set": [
     ["browser.contentblocking.allowlist.annotations.enabled", true],
     ["browser.contentblocking.allowlist.storage.enabled", true],
     [ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS],
     ["dom.storage_access.auto_grants", true],
+    ["dom.storage_access.auto_grants.delayed", false],
     ["dom.storage_access.enabled", true],
     ["dom.storage_access.max_concurrent_auto_grants", maxConcurrent],
     ["dom.storage_access.prompt.testing", false],
     ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
     ["privacy.trackingprotection.enabled", false],
     ["privacy.trackingprotection.pbmode.enabled", false],
     ["privacy.trackingprotection.annotate_channels", true],
     ["privacy.restrict3rdpartystorage.userInteractionRequiredForHosts", "tracking.example.com,tracking.example.org"],