1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "PreloadHashKey.h"
6 
7 #include "mozilla/dom/Element.h"  // StringToCORSMode
8 #include "mozilla/css/SheetLoadData.h"
9 #include "mozilla/dom/ReferrerPolicyBinding.h"
10 #include "nsIPrincipal.h"
11 #include "nsIReferrerInfo.h"
12 
13 namespace mozilla {
14 
PreloadHashKey(const nsIURI * aKey,ResourceType aAs)15 PreloadHashKey::PreloadHashKey(const nsIURI* aKey, ResourceType aAs)
16     : nsURIHashKey(aKey), mAs(aAs) {}
17 
PreloadHashKey(const PreloadHashKey * aKey)18 PreloadHashKey::PreloadHashKey(const PreloadHashKey* aKey)
19     : nsURIHashKey(aKey->mKey) {
20   *this = *aKey;
21 }
22 
PreloadHashKey(PreloadHashKey && aToMove)23 PreloadHashKey::PreloadHashKey(PreloadHashKey&& aToMove)
24     : nsURIHashKey(std::move(aToMove)) {
25   mAs = std::move(aToMove.mAs);
26   mCORSMode = std::move(aToMove.mCORSMode);
27   mPrincipal = std::move(aToMove.mPrincipal);
28 
29   switch (mAs) {
30     case ResourceType::SCRIPT:
31       mScript = std::move(aToMove.mScript);
32       break;
33     case ResourceType::STYLE:
34       mStyle = std::move(aToMove.mStyle);
35       break;
36     case ResourceType::IMAGE:
37       break;
38     case ResourceType::FONT:
39       break;
40     case ResourceType::FETCH:
41       break;
42     case ResourceType::NONE:
43       break;
44   }
45 }
46 
operator =(const PreloadHashKey & aOther)47 PreloadHashKey& PreloadHashKey::operator=(const PreloadHashKey& aOther) {
48   MOZ_ASSERT(mAs == ResourceType::NONE || aOther.mAs == ResourceType::NONE,
49              "Assigning more than once, only reset is allowed");
50 
51   nsURIHashKey::operator=(aOther);
52 
53   mAs = aOther.mAs;
54   mCORSMode = aOther.mCORSMode;
55   mPrincipal = aOther.mPrincipal;
56 
57   switch (mAs) {
58     case ResourceType::SCRIPT:
59       mScript = aOther.mScript;
60       break;
61     case ResourceType::STYLE:
62       mStyle = aOther.mStyle;
63       break;
64     case ResourceType::IMAGE:
65       break;
66     case ResourceType::FONT:
67       break;
68     case ResourceType::FETCH:
69       break;
70     case ResourceType::NONE:
71       break;
72   }
73 
74   return *this;
75 }
76 
77 // static
CreateAsScript(nsIURI * aURI,CORSMode aCORSMode,dom::ScriptKind aScriptKind)78 PreloadHashKey PreloadHashKey::CreateAsScript(nsIURI* aURI, CORSMode aCORSMode,
79                                               dom::ScriptKind aScriptKind) {
80   PreloadHashKey key(aURI, ResourceType::SCRIPT);
81   key.mCORSMode = aCORSMode;
82 
83   key.mScript.mScriptKind = aScriptKind;
84 
85   return key;
86 }
87 
88 // static
CreateAsScript(nsIURI * aURI,const nsAString & aCrossOrigin,const nsAString & aType)89 PreloadHashKey PreloadHashKey::CreateAsScript(nsIURI* aURI,
90                                               const nsAString& aCrossOrigin,
91                                               const nsAString& aType) {
92   dom::ScriptKind scriptKind = dom::ScriptKind::eClassic;
93   if (aType.LowerCaseEqualsASCII("module")) {
94     scriptKind = dom::ScriptKind::eModule;
95   }
96   CORSMode crossOrigin = dom::Element::StringToCORSMode(aCrossOrigin);
97   return CreateAsScript(aURI, crossOrigin, scriptKind);
98 }
99 
100 // static
CreateAsStyle(nsIURI * aURI,nsIPrincipal * aPrincipal,CORSMode aCORSMode,css::SheetParsingMode aParsingMode)101 PreloadHashKey PreloadHashKey::CreateAsStyle(
102     nsIURI* aURI, nsIPrincipal* aPrincipal, CORSMode aCORSMode,
103     css::SheetParsingMode aParsingMode) {
104   PreloadHashKey key(aURI, ResourceType::STYLE);
105   key.mCORSMode = aCORSMode;
106   key.mPrincipal = aPrincipal;
107 
108   key.mStyle.mParsingMode = aParsingMode;
109 
110   return key;
111 }
112 
113 // static
CreateAsStyle(css::SheetLoadData & aSheetLoadData)114 PreloadHashKey PreloadHashKey::CreateAsStyle(
115     css::SheetLoadData& aSheetLoadData) {
116   return CreateAsStyle(aSheetLoadData.mURI, aSheetLoadData.mTriggeringPrincipal,
117                        aSheetLoadData.mSheet->GetCORSMode(),
118                        aSheetLoadData.mSheet->ParsingMode());
119 }
120 
121 // static
CreateAsImage(nsIURI * aURI,nsIPrincipal * aPrincipal,CORSMode aCORSMode)122 PreloadHashKey PreloadHashKey::CreateAsImage(nsIURI* aURI,
123                                              nsIPrincipal* aPrincipal,
124                                              CORSMode aCORSMode) {
125   PreloadHashKey key(aURI, ResourceType::IMAGE);
126   key.mCORSMode = aCORSMode;
127   key.mPrincipal = aPrincipal;
128 
129   return key;
130 }
131 
132 // static
CreateAsFetch(nsIURI * aURI,CORSMode aCORSMode)133 PreloadHashKey PreloadHashKey::CreateAsFetch(nsIURI* aURI, CORSMode aCORSMode) {
134   PreloadHashKey key(aURI, ResourceType::FETCH);
135   key.mCORSMode = aCORSMode;
136 
137   return key;
138 }
139 
140 // static
CreateAsFetch(nsIURI * aURI,const nsAString & aCrossOrigin)141 PreloadHashKey PreloadHashKey::CreateAsFetch(nsIURI* aURI,
142                                              const nsAString& aCrossOrigin) {
143   return CreateAsFetch(aURI, dom::Element::StringToCORSMode(aCrossOrigin));
144 }
145 
CreateAsFont(nsIURI * aURI,CORSMode aCORSMode)146 PreloadHashKey PreloadHashKey::CreateAsFont(nsIURI* aURI, CORSMode aCORSMode) {
147   PreloadHashKey key(aURI, ResourceType::FONT);
148   key.mCORSMode = aCORSMode;
149 
150   return key;
151 }
152 
KeyEquals(KeyTypePointer aOther) const153 bool PreloadHashKey::KeyEquals(KeyTypePointer aOther) const {
154   if (mAs != aOther->mAs || mCORSMode != aOther->mCORSMode) {
155     return false;
156   }
157 
158   if (!mPrincipal != !aOther->mPrincipal) {
159     // One or the other has a principal, but not both... not equal
160     return false;
161   }
162 
163   if (mPrincipal && !mPrincipal->Equals(aOther->mPrincipal)) {
164     return false;
165   }
166 
167   if (!nsURIHashKey::KeyEquals(
168           static_cast<const nsURIHashKey*>(aOther)->GetKey())) {
169     return false;
170   }
171 
172   switch (mAs) {
173     case ResourceType::SCRIPT:
174       if (mScript.mScriptKind != aOther->mScript.mScriptKind) {
175         return false;
176       }
177       break;
178     case ResourceType::STYLE: {
179       if (mStyle.mParsingMode != aOther->mStyle.mParsingMode) {
180         return false;
181       }
182       break;
183     }
184     case ResourceType::IMAGE:
185       // No more checks needed.  The image cache key consists of the document
186       // (which we are scoped into), origin attributes (which we compare as part
187       // of the principal check) and the URL.  imgLoader::ValidateEntry compares
188       // CORS, referrer info and principal, which we do by default.
189       break;
190     case ResourceType::FONT:
191       break;
192     case ResourceType::FETCH:
193       // No more checks needed.
194       break;
195     case ResourceType::NONE:
196       break;
197   }
198 
199   return true;
200 }
201 
202 // static
HashKey(KeyTypePointer aKey)203 PLDHashNumber PreloadHashKey::HashKey(KeyTypePointer aKey) {
204   PLDHashNumber hash = nsURIHashKey::HashKey(aKey->mKey);
205 
206   // Enough to use the common attributes
207   hash = AddToHash(hash, static_cast<uint32_t>(aKey->mAs));
208   hash = AddToHash(hash, static_cast<uint32_t>(aKey->mCORSMode));
209 
210   return hash;
211 }
212 
213 }  // namespace mozilla
214