forked from mirrors/gecko-dev
Bug 1848406 - Detect stateful bounces for window associated storages. r=bvandersloot,asuth
Differential Revision: https://phabricator.services.mozilla.com/D203607
This commit is contained in:
parent
68be9069f7
commit
ba487d8c6e
10 changed files with 167 additions and 19 deletions
|
|
@ -170,7 +170,10 @@ void BrowsingContextWebProgress::ContextReplaced(
|
|||
already_AddRefed<BounceTrackingState>
|
||||
BrowsingContextWebProgress::GetBounceTrackingState() {
|
||||
if (!mBounceTrackingState) {
|
||||
mBounceTrackingState = BounceTrackingState::GetOrCreate(this);
|
||||
nsresult rv = NS_OK;
|
||||
mBounceTrackingState = BounceTrackingState::GetOrCreate(this, rv);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to get BounceTrackingState.");
|
||||
}
|
||||
return do_AddRef(mBounceTrackingState);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/BounceTrackingStorageObserver.h"
|
||||
#include "mozilla/CallState.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
|
|
@ -4648,6 +4649,19 @@ already_AddRefed<nsICSSDeclaration> nsGlobalWindowInner::GetComputedStyleHelper(
|
|||
aError, nullptr);
|
||||
}
|
||||
|
||||
void nsGlobalWindowInner::MaybeNotifyStorageKeyUsed() {
|
||||
// Only notify once per window lifetime.
|
||||
if (hasNotifiedStorageKeyUsed) {
|
||||
return;
|
||||
}
|
||||
nsresult rv =
|
||||
BounceTrackingStorageObserver::OnInitialStorageAccess(GetWindowContext());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
hasNotifiedStorageKeyUsed = true;
|
||||
}
|
||||
|
||||
Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) {
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
nsIPrincipal* storagePrincipal;
|
||||
|
|
@ -4770,6 +4784,8 @@ Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) {
|
|||
}
|
||||
}
|
||||
|
||||
MaybeNotifyStorageKeyUsed();
|
||||
|
||||
MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
|
||||
("nsGlobalWindowInner %p returns %p sessionStorage", this,
|
||||
mSessionStorage.get()));
|
||||
|
|
@ -4938,6 +4954,8 @@ Storage* nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) {
|
|||
new PartitionedLocalStorage(this, principal, storagePrincipal, cache);
|
||||
}
|
||||
|
||||
MaybeNotifyStorageKeyUsed();
|
||||
|
||||
MOZ_ASSERT(mLocalStorage);
|
||||
MOZ_ASSERT(
|
||||
mLocalStorage->Type() ==
|
||||
|
|
@ -4957,6 +4975,8 @@ IDBFactory* nsGlobalWindowInner::GetIndexedDB(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
MaybeNotifyStorageKeyUsed();
|
||||
|
||||
return mIndexedDB;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -728,6 +728,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
mozilla::ErrorResult& aError);
|
||||
void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
void MaybeNotifyStorageKeyUsed();
|
||||
|
||||
mozilla::dom::Storage* GetSessionStorage(mozilla::ErrorResult& aError);
|
||||
mozilla::dom::Storage* GetLocalStorage(mozilla::ErrorResult& aError);
|
||||
mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
|
||||
|
|
@ -1389,6 +1392,11 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
mozilla::Maybe<mozilla::StorageAccess> mStorageAllowedCache;
|
||||
uint32_t mStorageAllowedReasonCache;
|
||||
|
||||
// When window associated storage is accessed we need to notify the parent
|
||||
// process. This flag is used to ensure we only do it once per window
|
||||
// lifetime.
|
||||
bool hasNotifiedStorageKeyUsed{false};
|
||||
|
||||
RefPtr<mozilla::dom::DebuggerNotificationManager>
|
||||
mDebuggerNotificationManager;
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,10 @@ parent:
|
|||
bool fromHttp,
|
||||
CookieStruct[] cookies);
|
||||
|
||||
// Notify parent of storage access in the content process. This only happens
|
||||
// once per window lifetime to avoid redundant IPC.
|
||||
async OnInitialStorageAccess();
|
||||
|
||||
child:
|
||||
async NotifyPermissionChange(nsCString type, uint32_t permission);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/BounceTrackingStorageObserver.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ContentBlockingAllowList.h"
|
||||
#include "mozilla/dom/InProcessParent.h"
|
||||
|
|
@ -1705,6 +1706,13 @@ IPCResult WindowGlobalParent::RecvSetCookies(
|
|||
aCookies, GetBrowsingContext());
|
||||
}
|
||||
|
||||
IPCResult WindowGlobalParent::RecvOnInitialStorageAccess() {
|
||||
DebugOnly<nsresult> rv =
|
||||
BounceTrackingStorageObserver::OnInitialStorageAccess(this);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to notify storage access");
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowGlobalParent, WindowContext,
|
||||
mPageUseCountersWindow)
|
||||
|
||||
|
|
|
|||
|
|
@ -329,6 +329,8 @@ class WindowGlobalParent final : public WindowContext,
|
|||
const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
|
||||
nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies);
|
||||
|
||||
mozilla::ipc::IPCResult RecvOnInitialStorageAccess();
|
||||
|
||||
private:
|
||||
WindowGlobalParent(CanonicalBrowsingContext* aBrowsingContext,
|
||||
uint64_t aInnerWindowId, uint64_t aOuterWindowId,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
@ -54,8 +55,13 @@ BounceTrackingState::~BounceTrackingState() {
|
|||
|
||||
// static
|
||||
already_AddRefed<BounceTrackingState> BounceTrackingState::GetOrCreate(
|
||||
dom::BrowsingContextWebProgress* aWebProgress) {
|
||||
MOZ_ASSERT(aWebProgress);
|
||||
dom::BrowsingContextWebProgress* aWebProgress, nsresult& aRv) {
|
||||
aRv = NS_OK;
|
||||
|
||||
if (!aWebProgress) {
|
||||
aRv = NS_ERROR_INVALID_ARG;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ShouldCreateBounceTrackingStateForWebProgress(aWebProgress)) {
|
||||
return nullptr;
|
||||
|
|
@ -73,8 +79,8 @@ already_AddRefed<BounceTrackingState> BounceTrackingState::GetOrCreate(
|
|||
sStorageObserver = new BounceTrackingStorageObserver();
|
||||
ClearOnShutdown(&sStorageObserver);
|
||||
|
||||
DebugOnly<nsresult> rv = sStorageObserver->Init();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to init storage observer");
|
||||
aRv = sStorageObserver->Init();
|
||||
NS_ENSURE_SUCCESS(aRv, nullptr);
|
||||
}
|
||||
|
||||
dom::BrowsingContext* browsingContext = aWebProgress->GetBrowsingContext();
|
||||
|
|
@ -90,10 +96,8 @@ already_AddRefed<BounceTrackingState> BounceTrackingState::GetOrCreate(
|
|||
}));
|
||||
|
||||
if (createdNew) {
|
||||
nsresult rv = bounceTrackingState->Init(aWebProgress);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
aRv = bounceTrackingState->Init(aWebProgress);
|
||||
NS_ENSURE_SUCCESS(aRv, nullptr);
|
||||
}
|
||||
|
||||
return bounceTrackingState.forget();
|
||||
|
|
@ -614,4 +618,35 @@ nsresult BounceTrackingState::OnCookieWrite(const nsACString& aSiteHost) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult BounceTrackingState::OnStorageAccess(nsIPrincipal* aPrincipal) {
|
||||
NS_ENSURE_ARG_POINTER(aPrincipal);
|
||||
NS_ENSURE_TRUE(aPrincipal->GetIsContentPrincipal(), NS_ERROR_FAILURE);
|
||||
|
||||
if (MOZ_LOG_TEST(gBounceTrackingProtectionLog, LogLevel::Debug)) {
|
||||
nsAutoCString origin;
|
||||
nsresult rv = aPrincipal->GetOrigin(origin);
|
||||
if (NS_FAILED(rv)) {
|
||||
origin = "err";
|
||||
}
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Debug,
|
||||
("%s: origin: %s, mBounceTrackingRecord: %s", __FUNCTION__,
|
||||
origin.get(),
|
||||
mBounceTrackingRecord ? mBounceTrackingRecord->Describe().get()
|
||||
: "null"));
|
||||
}
|
||||
|
||||
if (!mBounceTrackingRecord) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString siteHost;
|
||||
nsresult rv = aPrincipal->GetBaseDomain(siteHost);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(!siteHost.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
mBounceTrackingRecord->AddStorageAccessHost(siteHost);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class BounceTrackingState : public nsIWebProgressListener,
|
|||
// return nullptr if the given web progress / browsing context is not suitable
|
||||
// (see ShouldCreateBounceTrackingStateForWebProgress).
|
||||
static already_AddRefed<BounceTrackingState> GetOrCreate(
|
||||
dom::BrowsingContextWebProgress* aWebProgress);
|
||||
dom::BrowsingContextWebProgress* aWebProgress, nsresult& aRv);
|
||||
|
||||
// Reset state for all BounceTrackingState instances this includes resetting
|
||||
// BounceTrackingRecords and cancelling any running timers.
|
||||
|
|
@ -99,6 +99,10 @@ class BounceTrackingState : public nsIWebProgressListener,
|
|||
// Create a string that describes this object. Used for logging.
|
||||
nsCString Describe();
|
||||
|
||||
// Record sites which have accessed storage in the current extended
|
||||
// navigation.
|
||||
nsresult OnStorageAccess(nsIPrincipal* aPrincipal);
|
||||
|
||||
private:
|
||||
explicit BounceTrackingState();
|
||||
virtual ~BounceTrackingState();
|
||||
|
|
@ -140,12 +144,6 @@ class BounceTrackingState : public nsIWebProgressListener,
|
|||
// final host.
|
||||
nsresult OnDocumentLoaded(nsIPrincipal* aDocumentPrincipal);
|
||||
|
||||
// TODO: Bug 1839918: Detection of stateful bounces.
|
||||
|
||||
// Record sites which have accessed storage in the current extended
|
||||
// navigation.
|
||||
nsresult OnStorageAccess();
|
||||
|
||||
// Record sites which have activated service workers in the current
|
||||
// extended navigation.
|
||||
nsresult OnServiceWorkerActivation();
|
||||
|
|
|
|||
|
|
@ -6,14 +6,15 @@
|
|||
|
||||
#include "BounceTrackingState.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICookieNotification.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "nsICookie.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
@ -104,4 +105,66 @@ BounceTrackingStorageObserver::Observe(nsISupports* aSubject,
|
|||
return bounceTrackingState->OnCookieWrite(baseDomain);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult BounceTrackingStorageObserver::OnInitialStorageAccess(
|
||||
dom::WindowContext* aWindowContext) {
|
||||
NS_ENSURE_ARG_POINTER(aWindowContext);
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
// Skip partitioned storage access. Checking this in the content process
|
||||
// potentially saves us an IPC message to the parent.
|
||||
nsIPrincipal* storagePrincipal =
|
||||
aWindowContext->GetInnerWindow()->GetEffectiveStoragePrincipal();
|
||||
if (storagePrincipal &&
|
||||
!storagePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty()) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Verbose,
|
||||
("Skipping partitioned storage access (content process)."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
dom::WindowGlobalChild* windowGlobalChild =
|
||||
aWindowContext->GetWindowGlobalChild();
|
||||
NS_ENSURE_TRUE(windowGlobalChild, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(windowGlobalChild->SendOnInitialStorageAccess(),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
aWindowContext->Canonical()->DocumentStoragePrincipal();
|
||||
NS_ENSURE_TRUE(storagePrincipal, NS_ERROR_FAILURE);
|
||||
|
||||
if (!storagePrincipal->GetIsContentPrincipal()) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Verbose,
|
||||
("Skipping non-content principal."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!storagePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty()) {
|
||||
MOZ_LOG(gBounceTrackingProtectionLog, LogLevel::Verbose,
|
||||
("Skipping partitioned storage access."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
dom::BrowsingContext* browsingContext = aWindowContext->GetBrowsingContext();
|
||||
NS_ENSURE_TRUE(browsingContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
RefPtr<BounceTrackingState> bounceTrackingState =
|
||||
BounceTrackingState::GetOrCreate(
|
||||
browsingContext->Top()->Canonical()->GetWebProgress(), rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We may not always get a BounceTrackingState, e.g. if the feature is
|
||||
// disabled or we don't keep track of bounce tracking for the given
|
||||
// BrowsingContext.
|
||||
if (!bounceTrackingState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return bounceTrackingState->OnStorageAccess(storagePrincipal);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class WindowContext;
|
||||
}
|
||||
|
||||
extern LazyLogModule gBounceTrackingProtectionLog;
|
||||
|
||||
class BounceTrackingStorageObserver final : public nsIObserver {
|
||||
|
|
@ -19,6 +23,9 @@ class BounceTrackingStorageObserver final : public nsIObserver {
|
|||
BounceTrackingStorageObserver() = default;
|
||||
nsresult Init();
|
||||
|
||||
[[nodiscard]] static nsresult OnInitialStorageAccess(
|
||||
dom::WindowContext* aWindowContext);
|
||||
|
||||
private:
|
||||
~BounceTrackingStorageObserver() = default;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue