Bug 1834493: part 1) Rename `PopoverState` to `PopoverAttributeState`. r=emilio
[gecko.git] / image / ImageCacheKey.cpp
blob141985bf05e57c9f452dbeecaa77923745f9a074
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ImageCacheKey.h"
8 #include <utility>
10 #include "mozilla/AntiTrackingUtils.h"
11 #include "mozilla/HashFunctions.h"
12 #include "mozilla/StorageAccess.h"
13 #include "mozilla/StoragePrincipalHelper.h"
14 #include "mozilla/Unused.h"
15 #include "mozilla/dom/Document.h"
16 #include "mozilla/dom/File.h"
17 #include "mozilla/dom/ServiceWorkerManager.h"
18 #include "mozilla/StaticPrefs_privacy.h"
19 #include "mozilla/StorageAccess.h"
20 #include "nsContentUtils.h"
21 #include "nsHashKeys.h"
22 #include "nsLayoutUtils.h"
23 #include "nsPrintfCString.h"
24 #include "nsString.h"
26 namespace mozilla {
28 using namespace dom;
30 namespace image {
32 ImageCacheKey::ImageCacheKey(nsIURI* aURI, const OriginAttributes& aAttrs,
33 Document* aDocument)
34 : mURI(aURI),
35 mOriginAttributes(aAttrs),
36 mControlledDocument(GetSpecialCaseDocumentToken(aDocument)),
37 mIsolationKey(GetIsolationKey(aDocument, aURI)) {}
39 ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
40 : mURI(aOther.mURI),
41 mOriginAttributes(aOther.mOriginAttributes),
42 mControlledDocument(aOther.mControlledDocument),
43 mIsolationKey(aOther.mIsolationKey),
44 mHash(aOther.mHash) {}
46 ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
47 : mURI(std::move(aOther.mURI)),
48 mOriginAttributes(aOther.mOriginAttributes),
49 mControlledDocument(aOther.mControlledDocument),
50 mIsolationKey(aOther.mIsolationKey),
51 mHash(aOther.mHash) {}
53 bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const {
54 // Don't share the image cache between a controlled document and anything
55 // else.
56 if (mControlledDocument != aOther.mControlledDocument) {
57 return false;
59 // Don't share the image cache between two top-level documents of different
60 // base domains.
61 if (!mIsolationKey.Equals(aOther.mIsolationKey,
62 nsCaseInsensitiveCStringComparator)) {
63 return false;
65 // The origin attributes always have to match.
66 if (mOriginAttributes != aOther.mOriginAttributes) {
67 return false;
70 // For non-blob URIs, compare the URIs.
71 bool equals = false;
72 nsresult rv = mURI->Equals(aOther.mURI, &equals);
73 return NS_SUCCEEDED(rv) && equals;
76 void ImageCacheKey::EnsureHash() const {
77 MOZ_ASSERT(mHash.isNothing());
78 PLDHashNumber hash = 0;
80 // Since we frequently call Hash() several times in a row on the same
81 // ImageCacheKey, as an optimization we compute our hash once and store it.
83 nsPrintfCString ptr("%p", mControlledDocument);
84 nsAutoCString suffix;
85 mOriginAttributes.CreateSuffix(suffix);
87 nsAutoCString spec;
88 Unused << mURI->GetSpec(spec);
89 hash = HashString(spec);
91 hash = AddToHash(hash, HashString(suffix), HashString(mIsolationKey),
92 HashString(ptr));
93 mHash.emplace(hash);
96 /* static */
97 void* ImageCacheKey::GetSpecialCaseDocumentToken(Document* aDocument) {
98 // Cookie-averse documents can never have storage granted to them. Since they
99 // may not have inner windows, they would require special handling below, so
100 // just bail out early here.
101 if (!aDocument || aDocument->IsCookieAverse()) {
102 return nullptr;
105 // For controlled documents, we cast the pointer into a void* to avoid
106 // dereferencing it (since we only use it for comparisons).
107 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
108 if (swm && aDocument->GetController().isSome()) {
109 return aDocument;
112 return nullptr;
115 /* static */
116 nsCString ImageCacheKey::GetIsolationKey(Document* aDocument, nsIURI* aURI) {
117 if (!aDocument || !aDocument->GetInnerWindow()) {
118 return ""_ns;
121 // Network-state isolation
122 if (StaticPrefs::privacy_partition_network_state()) {
123 OriginAttributes oa;
124 StoragePrincipalHelper::GetOriginAttributesForNetworkState(aDocument, oa);
126 nsAutoCString suffix;
127 oa.CreateSuffix(suffix);
129 return std::move(suffix);
132 // If the window is 3rd party resource, let's see if first-party storage
133 // access is granted for this image.
134 if (AntiTrackingUtils::IsThirdPartyWindow(aDocument->GetInnerWindow(),
135 nullptr)) {
136 uint32_t rejectedReason = 0;
137 Unused << rejectedReason;
138 return StorageDisabledByAntiTracking(aDocument, aURI, rejectedReason)
139 ? aDocument->GetBaseDomain()
140 : ""_ns;
143 // Another scenario is if this image is a 3rd party resource loaded by a
144 // first party context. In this case, we should check if the nsIChannel has
145 // been marked as tracking resource, but we don't have the channel yet at
146 // this point. The best approach here is to be conservative: if we are sure
147 // that the permission is granted, let's return 0. Otherwise, let's make a
148 // unique image cache per the top-level document eTLD+1.
149 if (!ApproximateAllowAccessForWithoutChannel(aDocument->GetInnerWindow(),
150 aURI)) {
151 // If we are here, the image is a 3rd-party resource loaded by a first-party
152 // context. We can just use the document's base domain as the key because it
153 // should be the same as the top-level document's base domain.
154 return aDocument
155 ->GetBaseDomain(); // because we don't have anything better!
158 return ""_ns;
161 } // namespace image
162 } // namespace mozilla