OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "core/dom/PendingScript.h" | 26 #include "core/dom/PendingScript.h" |
27 | 27 |
28 #include "bindings/core/v8/ScriptSourceCode.h" | 28 #include "bindings/core/v8/ScriptSourceCode.h" |
29 #include "core/dom/Element.h" | 29 #include "core/dom/ScriptLoaderClient.h" |
30 #include "core/frame/SubresourceIntegrity.h" | 30 #include "core/frame/SubresourceIntegrity.h" |
31 #include "platform/SharedBuffer.h" | 31 #include "platform/SharedBuffer.h" |
32 #include "wtf/CurrentTime.h" | 32 #include "wtf/CurrentTime.h" |
33 | 33 |
34 namespace blink { | 34 namespace blink { |
35 | 35 |
36 PendingScript* PendingScript::create(Element* element, | 36 PendingScript* PendingScript::create(ScriptLoaderClient* scriptLoaderClient, |
37 ScriptResource* resource) { | 37 ScriptResource* resource) { |
38 return new PendingScript(element, resource, TextPosition()); | 38 return new PendingScript(scriptLoaderClient, resource, TextPosition()); |
39 } | 39 } |
40 | 40 |
41 PendingScript* PendingScript::create(Element* element, | 41 PendingScript* PendingScript::create(ScriptLoaderClient* scriptLoaderClient, |
42 const TextPosition& startingPosition) { | 42 const TextPosition& startingPosition) { |
43 return new PendingScript(element, nullptr, startingPosition); | 43 return new PendingScript(scriptLoaderClient, nullptr, startingPosition); |
44 } | 44 } |
45 | 45 |
46 PendingScript* PendingScript::createForTesting(ScriptResource* resource) { | 46 PendingScript* PendingScript::createForTesting(ScriptResource* resource) { |
47 return new PendingScript(nullptr, resource, TextPosition(), true); | 47 return new PendingScript(nullptr, resource, TextPosition(), true); |
48 } | 48 } |
49 | 49 |
50 PendingScript::PendingScript(Element* element, | 50 PendingScript::PendingScript(ScriptLoaderClient* scriptLoaderClient, |
51 ScriptResource* resource, | 51 ScriptResource* resource, |
52 const TextPosition& startingPosition, | 52 const TextPosition& startingPosition, |
53 bool isForTesting) | 53 bool isForTesting) |
54 : m_watchingForLoad(false), | 54 : m_watchingForLoad(false), |
55 m_element(element), | 55 m_scriptLoaderClient(scriptLoaderClient), |
56 m_startingPosition(startingPosition), | 56 m_startingPosition(startingPosition), |
57 m_integrityFailure(false), | 57 m_integrityFailure(false), |
58 m_parserBlockingLoadStartTime(0), | 58 m_parserBlockingLoadStartTime(0), |
59 m_client(nullptr), | 59 m_client(nullptr), |
60 m_isForTesting(isForTesting) { | 60 m_isForTesting(isForTesting) { |
61 checkState(); | 61 checkState(); |
62 setResource(resource); | 62 setResource(resource); |
63 MemoryCoordinator::instance().registerClient(this); | 63 MemoryCoordinator::instance().registerClient(this); |
64 } | 64 } |
65 | 65 |
66 PendingScript::~PendingScript() {} | 66 PendingScript::~PendingScript() {} |
67 | 67 |
68 NOINLINE void PendingScript::checkState() const { | 68 NOINLINE void PendingScript::checkState() const { |
69 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. | 69 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. |
70 CHECK(m_isForTesting || m_element); | 70 CHECK(m_isForTesting || m_scriptLoaderClient); |
71 CHECK(resource() || !m_streamer); | 71 CHECK(resource() || !m_streamer); |
72 CHECK(!m_streamer || m_streamer->resource() == resource()); | 72 CHECK(!m_streamer || m_streamer->resource() == resource()); |
73 } | 73 } |
74 | 74 |
75 void PendingScript::dispose() { | 75 void PendingScript::dispose() { |
76 stopWatchingForLoad(); | 76 stopWatchingForLoad(); |
77 DCHECK(!m_client); | 77 DCHECK(!m_client); |
78 DCHECK(!m_watchingForLoad); | 78 DCHECK(!m_watchingForLoad); |
79 | 79 |
80 setResource(nullptr); | 80 setResource(nullptr); |
81 m_startingPosition = TextPosition::belowRangePosition(); | 81 m_startingPosition = TextPosition::belowRangePosition(); |
82 m_integrityFailure = false; | 82 m_integrityFailure = false; |
83 m_parserBlockingLoadStartTime = 0; | 83 m_parserBlockingLoadStartTime = 0; |
84 if (m_streamer) | 84 if (m_streamer) |
85 m_streamer->cancel(); | 85 m_streamer->cancel(); |
86 m_streamer = nullptr; | 86 m_streamer = nullptr; |
87 m_element = nullptr; | 87 m_scriptLoaderClient = nullptr; |
88 } | 88 } |
89 | 89 |
90 void PendingScript::watchForLoad(PendingScriptClient* client) { | 90 void PendingScript::watchForLoad(PendingScriptClient* client) { |
91 checkState(); | 91 checkState(); |
92 | 92 |
93 DCHECK(!m_watchingForLoad); | 93 DCHECK(!m_watchingForLoad); |
94 // addClient() will call streamingFinished() if the load is complete. Callers | 94 // addClient() will call streamingFinished() if the load is complete. Callers |
95 // who do not expect to be re-entered from this call should not call | 95 // who do not expect to be re-entered from this call should not call |
96 // watchForLoad for a PendingScript which isReady. We also need to set | 96 // watchForLoad for a PendingScript which isReady. We also need to set |
97 // m_watchingForLoad early, since addClient() can result in calling | 97 // m_watchingForLoad early, since addClient() can result in calling |
98 // notifyFinished and further stopWatchingForLoad(). | 98 // notifyFinished and further stopWatchingForLoad(). |
99 m_watchingForLoad = true; | 99 m_watchingForLoad = true; |
100 m_client = client; | 100 m_client = client; |
101 if (isReady()) | 101 if (isReady()) |
102 m_client->pendingScriptFinished(this); | 102 m_client->pendingScriptFinished(this); |
103 } | 103 } |
104 | 104 |
105 void PendingScript::stopWatchingForLoad() { | 105 void PendingScript::stopWatchingForLoad() { |
106 if (!m_watchingForLoad) | 106 if (!m_watchingForLoad) |
107 return; | 107 return; |
108 checkState(); | 108 checkState(); |
109 DCHECK(resource()); | 109 DCHECK(resource()); |
110 m_client = nullptr; | 110 m_client = nullptr; |
111 m_watchingForLoad = false; | 111 m_watchingForLoad = false; |
112 } | 112 } |
113 | 113 |
114 Element* PendingScript::element() const { | 114 ScriptLoaderClient* PendingScript::scriptLoaderClient() const { |
115 // As mentioned in the comment at |m_element| declaration, |m_element| | 115 // As mentioned in the comment at |m_scriptLoaderClient| declaration, |
116 // must points to the corresponding ScriptLoader's element. | 116 // |m_scriptLoaderClient| must point to the corresponding ScriptLoader's |
117 CHECK(m_element); | 117 // client. |
118 return m_element.get(); | 118 CHECK(m_scriptLoaderClient); |
| 119 return m_scriptLoaderClient.get(); |
119 } | 120 } |
120 | 121 |
121 void PendingScript::streamingFinished() { | 122 void PendingScript::streamingFinished() { |
122 checkState(); | 123 checkState(); |
123 DCHECK(resource()); | 124 DCHECK(resource()); |
124 if (m_client) | 125 if (m_client) |
125 m_client->pendingScriptFinished(this); | 126 m_client->pendingScriptFinished(this); |
126 } | 127 } |
127 | 128 |
128 void PendingScript::markParserBlockingLoadStartTime() { | 129 void PendingScript::markParserBlockingLoadStartTime() { |
129 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); | 130 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); |
130 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); | 131 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); |
131 } | 132 } |
132 | 133 |
133 // Returns true if SRI check passed. | 134 // Returns true if SRI check passed. |
134 static bool checkScriptResourceIntegrity(Resource* resource, Element* element) { | 135 static bool checkScriptResourceIntegrity( |
| 136 Resource* resource, |
| 137 ScriptLoaderClient* scriptLoaderClient) { |
135 DCHECK_EQ(resource->getType(), Resource::Script); | 138 DCHECK_EQ(resource->getType(), Resource::Script); |
136 ScriptResource* scriptResource = toScriptResource(resource); | 139 ScriptResource* scriptResource = toScriptResource(resource); |
137 String integrityAttr = element->fastGetAttribute(HTMLNames::integrityAttr); | 140 String integrityAttr = scriptLoaderClient->integrityAttributeValue(); |
138 | 141 |
139 // It is possible to get back a script resource with integrity metadata | 142 // It is possible to get back a script resource with integrity metadata |
140 // for a request with an empty integrity attribute. In that case, the | 143 // for a request with an empty integrity attribute. In that case, the |
141 // integrity check should be skipped, so this check ensures that the | 144 // integrity check should be skipped, so this check ensures that the |
142 // integrity attribute isn't empty in addition to checking if the | 145 // integrity attribute isn't empty in addition to checking if the |
143 // resource has empty integrity metadata. | 146 // resource has empty integrity metadata. |
144 if (integrityAttr.isEmpty() || scriptResource->integrityMetadata().isEmpty()) | 147 if (integrityAttr.isEmpty() || scriptResource->integrityMetadata().isEmpty()) |
145 return true; | 148 return true; |
146 | 149 |
147 switch (scriptResource->integrityDisposition()) { | 150 switch (scriptResource->integrityDisposition()) { |
148 case ResourceIntegrityDisposition::Passed: | 151 case ResourceIntegrityDisposition::Passed: |
149 return true; | 152 return true; |
150 | 153 |
151 case ResourceIntegrityDisposition::Failed: | 154 case ResourceIntegrityDisposition::Failed: |
152 // TODO(jww): This should probably also generate a console | 155 // TODO(jww): This should probably also generate a console |
153 // message identical to the one produced by | 156 // message identical to the one produced by |
154 // CheckSubresourceIntegrity below. See https://crbug.com/585267. | 157 // CheckSubresourceIntegrity below. See https://crbug.com/585267. |
155 return false; | 158 return false; |
156 | 159 |
157 case ResourceIntegrityDisposition::NotChecked: { | 160 case ResourceIntegrityDisposition::NotChecked: { |
158 if (!resource->resourceBuffer()) | 161 if (!resource->resourceBuffer()) |
159 return true; | 162 return true; |
160 | 163 |
161 bool passed = SubresourceIntegrity::CheckSubresourceIntegrity( | 164 bool passed = SubresourceIntegrity::CheckSubresourceIntegrity( |
162 scriptResource->integrityMetadata(), *element, | 165 scriptResource->integrityMetadata(), scriptLoaderClient->document(), |
163 resource->resourceBuffer()->data(), | 166 resource->resourceBuffer()->data(), |
164 resource->resourceBuffer()->size(), resource->url(), *resource); | 167 resource->resourceBuffer()->size(), resource->url(), *resource); |
165 scriptResource->setIntegrityDisposition( | 168 scriptResource->setIntegrityDisposition( |
166 passed ? ResourceIntegrityDisposition::Passed | 169 passed ? ResourceIntegrityDisposition::Passed |
167 : ResourceIntegrityDisposition::Failed); | 170 : ResourceIntegrityDisposition::Failed); |
168 return passed; | 171 return passed; |
169 } | 172 } |
170 } | 173 } |
171 | 174 |
172 NOTREACHED(); | 175 NOTREACHED(); |
(...skipping 17 matching lines...) Expand all Loading... |
190 // In order to simulate the correct behavior, Blink explicitly does the SRI | 193 // In order to simulate the correct behavior, Blink explicitly does the SRI |
191 // checks here, when a PendingScript tied to a particular request is | 194 // checks here, when a PendingScript tied to a particular request is |
192 // finished (and in the case of a StyleSheet, at the point of execution), | 195 // finished (and in the case of a StyleSheet, at the point of execution), |
193 // while having proper Fetch checks in the fetch module for use in the | 196 // while having proper Fetch checks in the fetch module for use in the |
194 // fetch JavaScript API. In a future world where the ResourceFetcher uses | 197 // fetch JavaScript API. In a future world where the ResourceFetcher uses |
195 // the Fetch algorithm, this should be fixed by having separate Response | 198 // the Fetch algorithm, this should be fixed by having separate Response |
196 // objects (perhaps attached to identical Resource objects) per request. | 199 // objects (perhaps attached to identical Resource objects) per request. |
197 // | 200 // |
198 // See https://crbug.com/500701 for more information. | 201 // See https://crbug.com/500701 for more information. |
199 checkState(); | 202 checkState(); |
200 if (m_element) | 203 if (m_scriptLoaderClient) { |
201 m_integrityFailure = !checkScriptResourceIntegrity(resource, m_element); | 204 m_integrityFailure = |
| 205 !checkScriptResourceIntegrity(resource, m_scriptLoaderClient); |
| 206 } |
202 | 207 |
203 // If script streaming is in use, the client will be notified in | 208 // If script streaming is in use, the client will be notified in |
204 // streamingFinished. | 209 // streamingFinished. |
205 if (m_streamer) | 210 if (m_streamer) |
206 m_streamer->notifyFinished(resource); | 211 m_streamer->notifyFinished(resource); |
207 else if (m_client) | 212 else if (m_client) |
208 m_client->pendingScriptFinished(this); | 213 m_client->pendingScriptFinished(this); |
209 } | 214 } |
210 | 215 |
211 void PendingScript::notifyAppendData(ScriptResource* resource) { | 216 void PendingScript::notifyAppendData(ScriptResource* resource) { |
212 if (m_streamer) | 217 if (m_streamer) |
213 m_streamer->notifyAppendData(resource); | 218 m_streamer->notifyAppendData(resource); |
214 } | 219 } |
215 | 220 |
216 DEFINE_TRACE(PendingScript) { | 221 DEFINE_TRACE(PendingScript) { |
217 visitor->trace(m_element); | 222 visitor->trace(m_scriptLoaderClient); |
218 visitor->trace(m_streamer); | 223 visitor->trace(m_streamer); |
219 visitor->trace(m_client); | 224 visitor->trace(m_client); |
220 ResourceOwner<ScriptResource>::trace(visitor); | 225 ResourceOwner<ScriptResource>::trace(visitor); |
221 MemoryCoordinatorClient::trace(visitor); | 226 MemoryCoordinatorClient::trace(visitor); |
222 } | 227 } |
223 | 228 |
224 ScriptSourceCode PendingScript::getSource(const KURL& documentURL, | 229 ScriptSourceCode PendingScript::getSource(const KURL& documentURL, |
225 bool& errorOccurred) const { | 230 bool& errorOccurred) const { |
226 checkState(); | 231 checkState(); |
227 | 232 |
228 errorOccurred = this->errorOccurred(); | 233 errorOccurred = this->errorOccurred(); |
229 if (resource()) { | 234 if (resource()) { |
230 DCHECK(resource()->isLoaded()); | 235 DCHECK(resource()->isLoaded()); |
231 if (m_streamer && !m_streamer->streamingSuppressed()) | 236 if (m_streamer && !m_streamer->streamingSuppressed()) |
232 return ScriptSourceCode(m_streamer, resource()); | 237 return ScriptSourceCode(m_streamer, resource()); |
233 return ScriptSourceCode(resource()); | 238 return ScriptSourceCode(resource()); |
234 } | 239 } |
235 | 240 |
236 return ScriptSourceCode(m_element->textContent(), documentURL, | 241 return ScriptSourceCode(m_scriptLoaderClient->textContent(), documentURL, |
237 startingPosition()); | 242 startingPosition()); |
238 } | 243 } |
239 | 244 |
240 void PendingScript::setStreamer(ScriptStreamer* streamer) { | 245 void PendingScript::setStreamer(ScriptStreamer* streamer) { |
241 DCHECK(!m_streamer); | 246 DCHECK(!m_streamer); |
242 DCHECK(!m_watchingForLoad); | 247 DCHECK(!m_watchingForLoad); |
243 m_streamer = streamer; | 248 m_streamer = streamer; |
244 checkState(); | 249 checkState(); |
245 } | 250 } |
246 | 251 |
(...skipping 16 matching lines...) Expand all Loading... |
263 | 268 |
264 void PendingScript::onPurgeMemory() { | 269 void PendingScript::onPurgeMemory() { |
265 checkState(); | 270 checkState(); |
266 if (!m_streamer) | 271 if (!m_streamer) |
267 return; | 272 return; |
268 m_streamer->cancel(); | 273 m_streamer->cancel(); |
269 m_streamer = nullptr; | 274 m_streamer = nullptr; |
270 } | 275 } |
271 | 276 |
272 } // namespace blink | 277 } // namespace blink |
OLD | NEW |