/src/mozilla-central/image/ImageCacheKey.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
5 | | |
6 | | #include "ImageCacheKey.h" |
7 | | |
8 | | #include "mozilla/HashFunctions.h" |
9 | | #include "mozilla/Move.h" |
10 | | #include "nsContentUtils.h" |
11 | | #include "nsICookieService.h" |
12 | | #include "nsLayoutUtils.h" |
13 | | #include "nsString.h" |
14 | | #include "mozilla/AntiTrackingCommon.h" |
15 | | #include "mozilla/dom/BlobURLProtocolHandler.h" |
16 | | #include "mozilla/dom/File.h" |
17 | | #include "mozilla/dom/ServiceWorkerManager.h" |
18 | | #include "nsIDocument.h" |
19 | | #include "nsPrintfCString.h" |
20 | | |
21 | | namespace mozilla { |
22 | | |
23 | | using namespace dom; |
24 | | |
25 | | namespace image { |
26 | | |
27 | | static Maybe<uint64_t> |
28 | | BlobSerial(nsIURI* aURI) |
29 | 0 | { |
30 | 0 | nsAutoCString spec; |
31 | 0 | aURI->GetSpec(spec); |
32 | 0 |
|
33 | 0 | RefPtr<BlobImpl> blob; |
34 | 0 | if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec, getter_AddRefs(blob))) && |
35 | 0 | blob) { |
36 | 0 | return Some(blob->GetSerialNumber()); |
37 | 0 | } |
38 | 0 | |
39 | 0 | return Nothing(); |
40 | 0 | } |
41 | | |
42 | | ImageCacheKey::ImageCacheKey(nsIURI* aURI, |
43 | | const OriginAttributes& aAttrs, |
44 | | nsIDocument* aDocument, |
45 | | nsresult& aRv) |
46 | | : mURI(aURI) |
47 | | , mOriginAttributes(aAttrs) |
48 | | , mControlledDocument(GetSpecialCaseDocumentToken(aDocument, aURI)) |
49 | | , mHash(0) |
50 | | , mIsChrome(false) |
51 | 0 | { |
52 | 0 | if (SchemeIs("blob")) { |
53 | 0 | mBlobSerial = BlobSerial(mURI); |
54 | 0 | } else if (SchemeIs("chrome")) { |
55 | 0 | mIsChrome = true; |
56 | 0 | } |
57 | 0 |
|
58 | 0 | // Since we frequently call Hash() several times in a row on the same |
59 | 0 | // ImageCacheKey, as an optimization we compute our hash once and store it. |
60 | 0 |
|
61 | 0 | nsPrintfCString ptr("%p", mControlledDocument); |
62 | 0 | nsAutoCString suffix; |
63 | 0 | mOriginAttributes.CreateSuffix(suffix); |
64 | 0 |
|
65 | 0 | if (mBlobSerial) { |
66 | 0 | aRv = mURI->GetRef(mBlobRef); |
67 | 0 | NS_ENSURE_SUCCESS_VOID(aRv); |
68 | 0 | mHash = HashGeneric(*mBlobSerial, HashString(mBlobRef)); |
69 | 0 | } else { |
70 | 0 | nsAutoCString spec; |
71 | 0 | aRv = mURI->GetSpec(spec); |
72 | 0 | NS_ENSURE_SUCCESS_VOID(aRv); |
73 | 0 | mHash = HashString(spec); |
74 | 0 | } |
75 | 0 |
|
76 | 0 | mHash = AddToHash(mHash, HashString(suffix), HashString(ptr)); |
77 | 0 | } |
78 | | |
79 | | ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther) |
80 | | : mURI(aOther.mURI) |
81 | | , mBlobSerial(aOther.mBlobSerial) |
82 | | , mBlobRef(aOther.mBlobRef) |
83 | | , mOriginAttributes(aOther.mOriginAttributes) |
84 | | , mControlledDocument(aOther.mControlledDocument) |
85 | | , mHash(aOther.mHash) |
86 | | , mIsChrome(aOther.mIsChrome) |
87 | 0 | { } |
88 | | |
89 | | ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther) |
90 | | : mURI(std::move(aOther.mURI)) |
91 | | , mBlobSerial(std::move(aOther.mBlobSerial)) |
92 | | , mBlobRef(std::move(aOther.mBlobRef)) |
93 | | , mOriginAttributes(aOther.mOriginAttributes) |
94 | | , mControlledDocument(aOther.mControlledDocument) |
95 | | , mHash(aOther.mHash) |
96 | | , mIsChrome(aOther.mIsChrome) |
97 | 0 | { } |
98 | | |
99 | | bool |
100 | | ImageCacheKey::operator==(const ImageCacheKey& aOther) const |
101 | 0 | { |
102 | 0 | // Don't share the image cache between a controlled document and anything else. |
103 | 0 | if (mControlledDocument != aOther.mControlledDocument) { |
104 | 0 | return false; |
105 | 0 | } |
106 | 0 | // The origin attributes always have to match. |
107 | 0 | if (mOriginAttributes != aOther.mOriginAttributes) { |
108 | 0 | return false; |
109 | 0 | } |
110 | 0 | if (mBlobSerial || aOther.mBlobSerial) { |
111 | 0 | // If at least one of us has a blob serial, just compare the blob serial and |
112 | 0 | // the ref portion of the URIs. |
113 | 0 | return mBlobSerial == aOther.mBlobSerial && |
114 | 0 | mBlobRef == aOther.mBlobRef; |
115 | 0 | } |
116 | 0 |
|
117 | 0 | // For non-blob URIs, compare the URIs. |
118 | 0 | bool equals = false; |
119 | 0 | nsresult rv = mURI->Equals(aOther.mURI, &equals); |
120 | 0 | return NS_SUCCEEDED(rv) && equals; |
121 | 0 | } |
122 | | |
123 | | bool |
124 | | ImageCacheKey::SchemeIs(const char* aScheme) |
125 | 0 | { |
126 | 0 | bool matches = false; |
127 | 0 | return NS_SUCCEEDED(mURI->SchemeIs(aScheme, &matches)) && matches; |
128 | 0 | } |
129 | | |
130 | | /* static */ void* |
131 | | ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI) |
132 | 0 | { |
133 | 0 | // Cookie-averse documents can never have storage granted to them. Since they |
134 | 0 | // may not have inner windows, they would require special handling below, so |
135 | 0 | // just bail out early here. |
136 | 0 | if (!aDocument || aDocument->IsCookieAverse()) { |
137 | 0 | return nullptr; |
138 | 0 | } |
139 | 0 | |
140 | 0 | // For controlled documents, we cast the pointer into a void* to avoid |
141 | 0 | // dereferencing it (since we only use it for comparisons). |
142 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
143 | 0 | if (swm && aDocument->GetController().isSome()) { |
144 | 0 | return aDocument; |
145 | 0 | } |
146 | 0 | |
147 | 0 | // If the window is 3rd party resource, let's see if first-party storage |
148 | 0 | // access is granted for this image. |
149 | 0 | if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) { |
150 | 0 | return nsContentUtils::StorageDisabledByAntiTracking(aDocument, aURI) ? |
151 | 0 | aDocument : nullptr; |
152 | 0 | } |
153 | 0 |
|
154 | 0 | // Another scenario is if this image is a 3rd party resource loaded by a |
155 | 0 | // first party context. In this case, we should check if the nsIChannel has |
156 | 0 | // been marked as tracking resource, but we don't have the channel yet at |
157 | 0 | // this point. The best approach here is to be conservative: if we are sure |
158 | 0 | // that the permission is granted, let's return a nullptr. Otherwise, let's |
159 | 0 | // make a unique image cache. |
160 | 0 | if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(), |
161 | 0 | aURI)) { |
162 | 0 | return aDocument; |
163 | 0 | } |
164 | 0 | |
165 | 0 | return nullptr; |
166 | 0 | } |
167 | | |
168 | | } // namespace image |
169 | | } // namespace mozilla |