Bug 1507055 - Implement Anti-tracking heuristic for redirects, r=Ehsan

Differential Revision: https://phabricator.services.mozilla.com/D56191

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2020-01-20 14:43:03 +00:00
Родитель ae842f31a4
Коммит 1aa9918367
9 изменённых файлов: 308 добавлений и 18 удалений

Просмотреть файл

@ -575,8 +575,9 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
aLoadInfo->GetIsPreflight(), aLoadInfo->GetLoadTriggeredFromExternal(),
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetDocumentHasLoaded(), cspNonce,
aLoadInfo->GetSkipContentSniffing(),
aLoadInfo->GetDocumentHasLoaded(),
aLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain(),
cspNonce, aLoadInfo->GetSkipContentSniffing(),
aLoadInfo->GetIsFromProcessingFrameAttributes(), cookieSettingsArgs,
aLoadInfo->GetRequestBlockingReason(), maybeCspToInheritInfo));
@ -764,9 +765,10 @@ nsresult LoadInfoArgsToLoadInfo(
loadInfoArgs.loadTriggeredFromExternal(),
loadInfoArgs.serviceWorkerTaintingSynthesized(),
loadInfoArgs.documentHasUserInteracted(),
loadInfoArgs.documentHasLoaded(), loadInfoArgs.cspNonce(),
loadInfoArgs.skipContentSniffing(), loadInfoArgs.requestBlockingReason(),
aLoadingContext);
loadInfoArgs.documentHasLoaded(),
loadInfoArgs.allowListFutureDocumentsCreatedFromThisRedirectChain(),
loadInfoArgs.cspNonce(), loadInfoArgs.skipContentSniffing(),
loadInfoArgs.requestBlockingReason(), aLoadingContext);
if (loadInfoArgs.isFromProcessingFrameAttributes()) {
loadInfo->SetIsFromProcessingFrameAttributes();
@ -785,6 +787,7 @@ void LoadInfoToParentLoadInfoForwarder(
false, // serviceWorkerTaintingSynthesized
false, // documentHasUserInteracted
false, // documentHasLoaded
false, // allowListFutureDocumentsCreatedFromThisRedirectChain
Maybe<CookieSettingsArgs>(),
nsILoadInfo::BLOCKING_REASON_NONE); // requestBlockingReason
return;
@ -816,8 +819,9 @@ void LoadInfoToParentLoadInfoForwarder(
aLoadInfo->GetSkipContentSniffing(),
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetDocumentHasLoaded(), cookieSettingsArgs,
aLoadInfo->GetRequestBlockingReason());
aLoadInfo->GetDocumentHasLoaded(),
aLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain(),
cookieSettingsArgs, aLoadInfo->GetRequestBlockingReason());
}
nsresult MergeParentLoadInfoForwarder(
@ -855,6 +859,10 @@ nsresult MergeParentLoadInfoForwarder(
aForwarderArgs.documentHasUserInteracted()));
MOZ_ALWAYS_SUCCEEDS(
aLoadInfo->SetDocumentHasLoaded(aForwarderArgs.documentHasLoaded()));
MOZ_ALWAYS_SUCCEEDS(
aLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(
aForwarderArgs
.allowListFutureDocumentsCreatedFromThisRedirectChain()));
MOZ_ALWAYS_SUCCEEDS(aLoadInfo->SetRequestBlockingReason(
aForwarderArgs.requestBlockingReason()));

Просмотреть файл

@ -7538,6 +7538,18 @@
value: true
mirror: always
# Enable the heuristic to allow storage access for windows opened using window.open()
- name: privacy.restrict3rdpartystorage.heuristic.redirect
type: bool
value: true
mirror: always
# Anti-tracking permission expiration.
- name: privacy.restrict3rdpartystorage.expiration_redirect
type: uint32_t
value: 900 # 15 minutes
mirror: always
# Anti-tracking user-interaction expiration.
- name: privacy.userInteraction.expiration
type: uint32_t

Просмотреть файл

@ -100,6 +100,7 @@ LoadInfo::LoadInfo(
mServiceWorkerTaintingSynthesized(false),
mDocumentHasUserInteracted(false),
mDocumentHasLoaded(false),
mAllowListFutureDocumentsCreatedFromThisRedirectChain(false),
mSkipContentSniffing(false),
mIsFromProcessingFrameAttributes(false) {
MOZ_ASSERT(mLoadingPrincipal);
@ -362,6 +363,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
mServiceWorkerTaintingSynthesized(false),
mDocumentHasUserInteracted(false),
mDocumentHasLoaded(false),
mAllowListFutureDocumentsCreatedFromThisRedirectChain(false),
mSkipContentSniffing(false),
mIsFromProcessingFrameAttributes(false) {
// Top-level loads are never third-party
@ -481,6 +483,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
mServiceWorkerTaintingSynthesized(false),
mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted),
mDocumentHasLoaded(rhs.mDocumentHasLoaded),
mAllowListFutureDocumentsCreatedFromThisRedirectChain(
rhs.mAllowListFutureDocumentsCreatedFromThisRedirectChain),
mCspNonce(rhs.mCspNonce),
mSkipContentSniffing(rhs.mSkipContentSniffing),
mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes) {}
@ -516,9 +520,10 @@ LoadInfo::LoadInfo(
const nsTArray<nsCString>& aCorsUnsafeHeaders, bool aForcePreflight,
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted,
bool aDocumentHasLoaded, const nsAString& aCspNonce,
bool aSkipContentSniffing, uint32_t aRequestBlockingReason,
nsINode* aLoadingContext)
bool aDocumentHasLoaded,
bool aAllowListFutureDocumentsCreatedFromThisRedirectChain,
const nsAString& aCspNonce, bool aSkipContentSniffing,
uint32_t aRequestBlockingReason, nsINode* aLoadingContext)
: mLoadingPrincipal(aLoadingPrincipal),
mTriggeringPrincipal(aTriggeringPrincipal),
mPrincipalToInherit(aPrincipalToInherit),
@ -571,6 +576,8 @@ LoadInfo::LoadInfo(
mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized),
mDocumentHasUserInteracted(aDocumentHasUserInteracted),
mDocumentHasLoaded(aDocumentHasLoaded),
mAllowListFutureDocumentsCreatedFromThisRedirectChain(
aAllowListFutureDocumentsCreatedFromThisRedirectChain),
mCspNonce(aCspNonce),
mSkipContentSniffing(aSkipContentSniffing),
mIsFromProcessingFrameAttributes(false) {
@ -1334,6 +1341,20 @@ LoadInfo::SetDocumentHasLoaded(bool aDocumentHasLoaded) {
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::GetAllowListFutureDocumentsCreatedFromThisRedirectChain(
bool* aValue) {
MOZ_ASSERT(aValue);
*aValue = mAllowListFutureDocumentsCreatedFromThisRedirectChain;
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::SetAllowListFutureDocumentsCreatedFromThisRedirectChain(bool aValue) {
mAllowListFutureDocumentsCreatedFromThisRedirectChain = aValue;
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::GetCspNonce(nsAString& aCspNonce) {
aCspNonce = mCspNonce;

Просмотреть файл

@ -157,6 +157,7 @@ class LoadInfo final : public nsILoadInfo {
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized,
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded,
bool aAllowListFutureDocumentsCreatedFromThisRedirectChain,
const nsAString& aCspNonce, bool aSkipContentSniffing,
uint32_t aRequestBlockingReason, nsINode* aLoadingContext);
LoadInfo(const LoadInfo& rhs);
@ -252,6 +253,7 @@ class LoadInfo final : public nsILoadInfo {
bool mServiceWorkerTaintingSynthesized;
bool mDocumentHasUserInteracted;
bool mDocumentHasLoaded;
bool mAllowListFutureDocumentsCreatedFromThisRedirectChain;
nsString mCspNonce;
bool mSkipContentSniffing;

Просмотреть файл

@ -1132,6 +1132,16 @@ interface nsILoadInfo : nsISupports
*/
[infallible] attribute boolean documentHasLoaded;
/**
* During a top-level document channel redirect from tracking to
* non-tracking resources, our anti-tracking heuristic, grants the storage
* access permission for a short amount of seconds (See
* privacy.restrict3rdpartystorage.expiration_redirect pref).
* We use this flag to remember this decision even if this channel is part
* of a chain of redirects.
*/
[infallible] attribute boolean allowListFutureDocumentsCreatedFromThisRedirectChain;
/**
* A snapshot of the nonce at load start time which is used for CSP
* checks and only set for:

Просмотреть файл

@ -142,6 +142,7 @@ struct LoadInfoArgs
bool serviceWorkerTaintingSynthesized;
bool documentHasUserInteracted;
bool documentHasLoaded;
bool allowListFutureDocumentsCreatedFromThisRedirectChain;
nsString cspNonce;
bool skipContentSniffing;
bool isFromProcessingFrameAttributes;
@ -189,6 +190,7 @@ struct ParentLoadInfoForwarderArgs
bool documentHasUserInteracted;
bool documentHasLoaded;
bool allowListFutureDocumentsCreatedFromThisRedirectChain;
CookieSettingsArgs? cookieSettings;

Просмотреть файл

@ -63,6 +63,7 @@
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/LazyIdleThread.h"
@ -823,6 +824,18 @@ void nsHttpHandler::NotifyObservers(nsIChannel* chan, const char* event) {
nsresult nsHttpHandler::AsyncOnChannelRedirect(
nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
nsIEventTarget* mainThreadEventTarget) {
MOZ_ASSERT(NS_IsMainThread() && (oldChan && newChan));
nsCOMPtr<nsIURI> oldURI;
oldChan->GetURI(getter_AddRefs(oldURI));
MOZ_ASSERT(oldURI);
nsCOMPtr<nsIURI> newURI;
newChan->GetURI(getter_AddRefs(newURI));
MOZ_ASSERT(newURI);
AntiTrackingCommon::RedirectHeuristic(oldChan, oldURI, newChan, newURI);
// TODO E10S This helper has to be initialized on the other process
RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
new nsAsyncRedirectVerifyHelper();

Просмотреть файл

@ -30,6 +30,7 @@
#include "nsIPermission.h"
#include "nsPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIRedirectHistoryEntry.h"
#include "nsIScriptError.h"
#include "nsIURI.h"
#include "nsIURIFixup.h"
@ -42,6 +43,7 @@
#include "prtime.h"
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
#define ANTITRACKING_CONSOLE_CATEGORY NS_LITERAL_CSTRING("Content Blocking")
using namespace mozilla;
using mozilla::dom::BrowsingContext;
@ -67,6 +69,25 @@ static const uint32_t kMaxConsoleOutputDelayMs = 100;
} \
PR_END_MACRO
#define LOG_SPEC2(format, uri1, uri2) \
PR_BEGIN_MACRO \
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug)) { \
nsAutoCString _specStr1(NS_LITERAL_CSTRING("(null)")); \
_specStr1.Truncate(std::min(_specStr1.Length(), sMaxSpecLength)); \
if (uri1) { \
_specStr1 = uri1->GetSpecOrDefault(); \
} \
const char* _spec1 = _specStr1.get(); \
nsAutoCString _specStr2(NS_LITERAL_CSTRING("(null)")); \
_specStr2.Truncate(std::min(_specStr2.Length(), sMaxSpecLength)); \
if (uri2) { \
_specStr2 = uri2->GetSpecOrDefault(); \
} \
const char* _spec2 = _specStr2.get(); \
LOG(format); \
} \
PR_END_MACRO
namespace {
UniquePtr<nsTArray<AntiTrackingCommon::AntiTrackingSettingsChangedCallback>>
@ -491,9 +512,9 @@ void ReportUnblockingToConsole(
}
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Content Blocking"),
doc, nsContentUtils::eNECKO_PROPERTIES, messageWithSameOrigin,
params, nullptr, sourceLine, lineNumber, columnNumber);
nsIScriptError::warningFlag, ANTITRACKING_CONSOLE_CATEGORY, doc,
nsContentUtils::eNECKO_PROPERTIES, messageWithSameOrigin, params,
nullptr, sourceLine, lineNumber, columnNumber);
});
RunConsoleReportingRunnable(runnable.forget());
@ -1097,7 +1118,6 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
if (XRE_IsParentProcess()) {
LOG(("Saving the permission: trackingOrigin=%s", trackingOrigin.get()));
return SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
topLevelStoragePrincipal, trackingPrincipal, trackingOrigin,
aAllowMode)
@ -1158,7 +1178,8 @@ AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
RefPtr<mozilla::AntiTrackingCommon::FirstPartyStorageAccessGrantPromise>
AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
nsIPrincipal* aParentPrincipal, nsIPrincipal* aTrackingPrincipal,
const nsCString& aTrackingOrigin, int aAllowMode) {
const nsCString& aTrackingOrigin, int aAllowMode,
uint64_t aExpirationTime) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aAllowMode == eAllow || aAllowMode == eAllowAutoGrant);
@ -1191,8 +1212,7 @@ AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
// Remember that this pref is stored in seconds!
uint32_t expirationType = nsIPermissionManager::EXPIRE_TIME;
uint32_t expirationTime =
StaticPrefs::privacy_restrict3rdpartystorage_expiration() * 1000;
uint32_t expirationTime = aExpirationTime * 1000;
int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + expirationTime;
uint32_t privateBrowsingId = 0;
@ -2266,3 +2286,199 @@ void AntiTrackingCommon::NotifyContentBlockingEvent(
aBlocked, aURI, trackingFullHashes,
aReason);
}
/* static */
void AntiTrackingCommon::RedirectHeuristic(nsIChannel* aOldChannel,
nsIURI* aOldURI,
nsIChannel* aNewChannel,
nsIURI* aNewURI) {
MOZ_ASSERT(aOldChannel);
MOZ_ASSERT(aOldURI);
MOZ_ASSERT(aNewChannel);
MOZ_ASSERT(aNewURI);
nsresult rv;
if (!StaticPrefs::privacy_restrict3rdpartystorage_heuristic_redirect()) {
return;
}
nsCOMPtr<nsIHttpChannel> newChannel = do_QueryInterface(aNewChannel);
if (!newChannel) {
return;
}
LOG_SPEC(("Checking redirect-heuristic for %s", _spec), aOldURI);
nsCOMPtr<nsILoadInfo> oldLoadInfo = aOldChannel->LoadInfo();
MOZ_ASSERT(oldLoadInfo);
nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->LoadInfo();
MOZ_ASSERT(newLoadInfo);
nsContentPolicyType contentType = oldLoadInfo->GetExternalContentPolicyType();
if (contentType != nsIContentPolicy::TYPE_DOCUMENT ||
!aOldChannel->IsDocument()) {
LOG_SPEC(("Ignoring redirect for %s because it's not a document", _spec),
aOldURI);
// We care about document redirects only.
return;
}
nsCOMPtr<nsIClassifiedChannel> classifiedOldChannel =
do_QueryInterface(aOldChannel);
nsCOMPtr<nsIClassifiedChannel> classifiedNewChannel =
do_QueryInterface(aNewChannel);
if (!classifiedOldChannel || !classifiedNewChannel) {
LOG_SPEC2(("Ignoring redirect for %s to %s because there is not "
"nsIClassifiedChannel interface",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
bool allowedByPreviousRedirect =
oldLoadInfo->GetAllowListFutureDocumentsCreatedFromThisRedirectChain();
if (classifiedNewChannel->IsTrackingResource()) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(("Redirect for %s to %s because it's not tracking to "
"non-tracking. Part of a chain of granted redirects: %d",
_spec1, _spec2, allowedByPreviousRedirect),
aOldURI, aNewURI);
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(
allowedByPreviousRedirect);
return;
}
if (!classifiedOldChannel->IsTrackingResource() &&
!allowedByPreviousRedirect) {
// This is not a tracking -> non-tracking redirect.
LOG_SPEC2(
("Redirect for %s to %s because it's not tracking to non-tracking.",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsIScriptSecurityManager* ssm =
nsScriptSecurityManager::GetScriptSecurityManager();
MOZ_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> trackingPrincipal;
nsCOMPtr<nsIURI> trackingURI;
if (allowedByPreviousRedirect) {
const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>& chain =
oldLoadInfo->RedirectChain();
MOZ_ASSERT(chain.Length() > 0);
rv = chain[0]->GetPrincipal(getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirect chain"));
return;
}
rv = trackingPrincipal->GetURI(getter_AddRefs(trackingURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the uri from the redirect chain"));
return;
}
} else {
trackingURI = aOldURI;
rv = ssm->GetChannelResultPrincipal(aOldChannel,
getter_AddRefs(trackingPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the tracking"));
return;
}
}
MOZ_ASSERT(trackingURI);
nsCOMPtr<nsIPrincipal> redirectedPrincipal;
rv = ssm->GetChannelResultPrincipal(aNewChannel,
getter_AddRefs(redirectedPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't obtain the principal from the redirected"));
return;
}
if (!AntiTrackingCommon::HasUserInteraction(trackingPrincipal)) {
LOG_SPEC2(("Ignoring redirect for %s to %s because no user-interaction on "
"tracker",
_spec1, _spec2),
aOldURI, aNewURI);
return;
}
nsAutoCString trackingOrigin;
rv = nsContentUtils::GetASCIIOrigin(trackingURI, trackingOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return;
}
nsAutoCString redirectedOrigin;
rv = nsContentUtils::GetASCIIOrigin(aNewURI, redirectedOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the origin from the URI"));
return;
}
LOG(("Adding a first-party storage exception for %s...",
PromiseFlatCString(redirectedOrigin).get()));
nsCOMPtr<nsICookieSettings> cookieSettings;
rv = oldLoadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Can't get the cookieSettings"));
return;
}
int32_t behavior = cookieSettings->GetCookieBehavior();
if (!cookieSettings->GetRejectThirdPartyTrackers()) {
LOG(
("Disabled by network.cookie.cookieBehavior pref (%d), bailing out "
"early",
behavior));
return;
}
MOZ_ASSERT(
behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
behavior ==
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
if (CheckContentBlockingAllowList(newChannel)) {
return;
}
LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
trackingOrigin.get(), redirectedOrigin.get()));
// Any new redirect from this loadInfo must be considered as granted.
newLoadInfo->SetAllowListFutureDocumentsCreatedFromThisRedirectChain(true);
uint64_t innerWindowID;
Unused << newChannel->GetTopLevelContentWindowId(&innerWindowID);
nsAutoString errorText;
AutoTArray<nsString, 2> params = {NS_ConvertUTF8toUTF16(redirectedOrigin),
NS_ConvertUTF8toUTF16(trackingOrigin)};
rv = nsContentUtils::FormatLocalizedString(
nsContentUtils::eNECKO_PROPERTIES, "CookieAllowedForTrackerByHeuristic",
params, errorText);
if (NS_SUCCEEDED(rv)) {
nsContentUtils::ReportToConsoleByWindowID(
errorText, nsIScriptError::warningFlag, ANTITRACKING_CONSOLE_CATEGORY,
innerWindowID);
}
// We don't care about this promise because the operation is actually sync.
RefPtr<FirstPartyStorageAccessGrantPromise> promise =
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
redirectedPrincipal, trackingPrincipal, trackingOrigin,
StorageAccessPromptChoices::eAllow,
StaticPrefs::privacy_restrict3rdpartystorage_expiration_redirect());
Unused << promise;
}

Просмотреть файл

@ -10,6 +10,7 @@
#include "nsString.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_privacy.h"
#define USER_INTERACTION_PERM NS_LITERAL_CSTRING("storageAccessAPI")
@ -131,7 +132,9 @@ class AntiTrackingCommon final {
static RefPtr<FirstPartyStorageAccessGrantPromise>
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(
nsIPrincipal* aPrincipal, nsIPrincipal* aTrackingPrinciapl,
const nsCString& aTrackingOrigin, int aAllowMode);
const nsCString& aTrackingOrigin, int aAllowMode,
uint64_t aExpirationTime =
StaticPrefs::privacy_restrict3rdpartystorage_expiration());
// Check whether a top window principal is on the content blocking allow list.
static nsresult IsOnContentBlockingAllowList(nsIPrincipal* aTopWinPrincipal,
@ -183,6 +186,9 @@ class AntiTrackingCommon final {
nsIChannel* aTrackingChannel, bool aBlocked, uint32_t aRejectedReason,
nsIURI* aURI,
const Maybe<StorageAccessGrantedReason>& aReason = Nothing());
static void RedirectHeuristic(nsIChannel* aOldChannel, nsIURI* aOldURI,
nsIChannel* aNewChannel, nsIURI* aNewURI);
};
} // namespace mozilla