OLD | NEW |
1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 // Use of this source code is governed by a BSD-style license that can be |
3 * | 3 // found in the LICENSE file. |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
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. | |
24 */ | |
25 | 4 |
26 #include "core/dom/PendingScript.h" | 5 #include "core/dom/ClassicPendingScript.h" |
27 | 6 |
28 #include "bindings/core/v8/ScriptSourceCode.h" | 7 #include "bindings/core/v8/ScriptSourceCode.h" |
29 #include "bindings/core/v8/ScriptState.h" | 8 #include "bindings/core/v8/ScriptState.h" |
30 #include "bindings/core/v8/V8Binding.h" | 9 #include "bindings/core/v8/V8Binding.h" |
31 #include "core/dom/ClassicScript.h" | |
32 #include "core/dom/Document.h" | 10 #include "core/dom/Document.h" |
33 #include "core/dom/ScriptElementBase.h" | |
34 #include "core/dom/TaskRunnerHelper.h" | 11 #include "core/dom/TaskRunnerHelper.h" |
35 #include "core/frame/LocalFrame.h" | 12 #include "core/frame/LocalFrame.h" |
36 #include "core/frame/SubresourceIntegrity.h" | 13 #include "core/frame/SubresourceIntegrity.h" |
37 #include "platform/SharedBuffer.h" | |
38 #include "wtf/CurrentTime.h" | |
39 | 14 |
40 namespace blink { | 15 namespace blink { |
41 | 16 |
42 PendingScript* PendingScript::create(ScriptElementBase* element, | 17 ClassicPendingScript* ClassicPendingScript::create(ScriptElementBase* element, |
43 ScriptResource* resource) { | 18 ScriptResource* resource) { |
44 return new PendingScript(element, resource, TextPosition()); | 19 return new ClassicPendingScript(element, resource, TextPosition()); |
45 } | 20 } |
46 | 21 |
47 PendingScript* PendingScript::create(ScriptElementBase* element, | 22 ClassicPendingScript* ClassicPendingScript::create( |
48 const TextPosition& startingPosition) { | 23 ScriptElementBase* element, |
49 return new PendingScript(element, nullptr, startingPosition); | 24 const TextPosition& startingPosition) { |
| 25 return new ClassicPendingScript(element, nullptr, startingPosition); |
50 } | 26 } |
51 | 27 |
52 PendingScript* PendingScript::createForTesting(ScriptResource* resource) { | 28 ClassicPendingScript* ClassicPendingScript::createForTesting( |
53 return new PendingScript(nullptr, resource, TextPosition(), true); | 29 ScriptResource* resource) { |
| 30 return new ClassicPendingScript(nullptr, resource, TextPosition(), true); |
54 } | 31 } |
55 | 32 |
56 PendingScript::PendingScript(ScriptElementBase* element, | 33 ClassicPendingScript::ClassicPendingScript(ScriptElementBase* element, |
57 ScriptResource* resource, | 34 ScriptResource* resource, |
58 const TextPosition& startingPosition, | 35 const TextPosition& startingPosition, |
59 bool isForTesting) | 36 bool isForTesting) |
60 : m_watchingForLoad(false), | 37 : PendingScript(element, startingPosition), |
61 m_element(element), | |
62 m_startingPosition(startingPosition), | |
63 m_integrityFailure(false), | 38 m_integrityFailure(false), |
64 m_parserBlockingLoadStartTime(0), | |
65 m_client(nullptr), | |
66 m_isForTesting(isForTesting) { | 39 m_isForTesting(isForTesting) { |
67 checkState(); | 40 checkState(); |
68 setResource(resource); | 41 setResource(resource); |
69 MemoryCoordinator::instance().registerClient(this); | 42 MemoryCoordinator::instance().registerClient(this); |
70 } | 43 } |
71 | 44 |
72 PendingScript::~PendingScript() {} | 45 ClassicPendingScript::~ClassicPendingScript() {} |
73 | 46 |
74 NOINLINE void PendingScript::checkState() const { | 47 NOINLINE void ClassicPendingScript::checkState() const { |
75 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. | 48 // TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta. |
76 CHECK(m_isForTesting || m_element); | 49 CHECK(m_isForTesting || element()); |
77 CHECK(resource() || !m_streamer); | 50 CHECK(resource() || !m_streamer); |
78 CHECK(!m_streamer || m_streamer->resource() == resource()); | 51 CHECK(!m_streamer || m_streamer->resource() == resource()); |
79 } | 52 } |
80 | 53 |
81 void PendingScript::dispose() { | 54 void ClassicPendingScript::disposeInternal() { |
82 stopWatchingForLoad(); | |
83 DCHECK(!m_client); | |
84 DCHECK(!m_watchingForLoad); | |
85 | |
86 MemoryCoordinator::instance().unregisterClient(this); | 55 MemoryCoordinator::instance().unregisterClient(this); |
87 setResource(nullptr); | 56 setResource(nullptr); |
88 m_startingPosition = TextPosition::belowRangePosition(); | |
89 m_integrityFailure = false; | 57 m_integrityFailure = false; |
90 m_parserBlockingLoadStartTime = 0; | |
91 if (m_streamer) | 58 if (m_streamer) |
92 m_streamer->cancel(); | 59 m_streamer->cancel(); |
93 m_streamer = nullptr; | 60 m_streamer = nullptr; |
94 m_element = nullptr; | |
95 } | 61 } |
96 | 62 |
97 void PendingScript::watchForLoad(PendingScriptClient* client) { | 63 void ClassicPendingScript::streamingFinished() { |
98 checkState(); | |
99 | |
100 DCHECK(!m_watchingForLoad); | |
101 // addClient() will call streamingFinished() if the load is complete. Callers | |
102 // who do not expect to be re-entered from this call should not call | |
103 // watchForLoad for a PendingScript which isReady. We also need to set | |
104 // m_watchingForLoad early, since addClient() can result in calling | |
105 // notifyFinished and further stopWatchingForLoad(). | |
106 m_watchingForLoad = true; | |
107 m_client = client; | |
108 if (isReady()) | |
109 m_client->pendingScriptFinished(this); | |
110 } | |
111 | |
112 void PendingScript::stopWatchingForLoad() { | |
113 if (!m_watchingForLoad) | |
114 return; | |
115 checkState(); | 64 checkState(); |
116 DCHECK(resource()); | 65 DCHECK(resource()); |
117 m_client = nullptr; | 66 if (client()) |
118 m_watchingForLoad = false; | 67 client()->pendingScriptFinished(this); |
119 } | |
120 | |
121 ScriptElementBase* PendingScript::element() const { | |
122 // As mentioned in the comment at |m_element| declaration, | |
123 // |m_element| must point to the corresponding ScriptLoader's | |
124 // client. | |
125 CHECK(m_element); | |
126 return m_element.get(); | |
127 } | |
128 | |
129 void PendingScript::streamingFinished() { | |
130 checkState(); | |
131 DCHECK(resource()); | |
132 if (m_client) | |
133 m_client->pendingScriptFinished(this); | |
134 } | |
135 | |
136 void PendingScript::markParserBlockingLoadStartTime() { | |
137 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); | |
138 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); | |
139 } | 68 } |
140 | 69 |
141 // Returns true if SRI check passed. | 70 // Returns true if SRI check passed. |
142 static bool checkScriptResourceIntegrity(Resource* resource, | 71 static bool checkScriptResourceIntegrity(Resource* resource, |
143 ScriptElementBase* element) { | 72 ScriptElementBase* element) { |
144 DCHECK_EQ(resource->getType(), Resource::Script); | 73 DCHECK_EQ(resource->getType(), Resource::Script); |
145 ScriptResource* scriptResource = toScriptResource(resource); | 74 ScriptResource* scriptResource = toScriptResource(resource); |
146 String integrityAttr = element->integrityAttributeValue(); | 75 String integrityAttr = element->integrityAttributeValue(); |
147 | 76 |
148 // It is possible to get back a script resource with integrity metadata | 77 // It is possible to get back a script resource with integrity metadata |
(...skipping 26 matching lines...) Expand all Loading... |
175 passed ? ResourceIntegrityDisposition::Passed | 104 passed ? ResourceIntegrityDisposition::Passed |
176 : ResourceIntegrityDisposition::Failed); | 105 : ResourceIntegrityDisposition::Failed); |
177 return passed; | 106 return passed; |
178 } | 107 } |
179 } | 108 } |
180 | 109 |
181 NOTREACHED(); | 110 NOTREACHED(); |
182 return true; | 111 return true; |
183 } | 112 } |
184 | 113 |
185 void PendingScript::notifyFinished(Resource* resource) { | 114 void ClassicPendingScript::notifyFinished(Resource* resource) { |
186 // The following SRI checks need to be here because, unfortunately, fetches | 115 // The following SRI checks need to be here because, unfortunately, fetches |
187 // are not done purely according to the Fetch spec. In particular, | 116 // are not done purely according to the Fetch spec. In particular, |
188 // different requests for the same resource do not have different | 117 // different requests for the same resource do not have different |
189 // responses; the memory cache can (and will) return the exact same | 118 // responses; the memory cache can (and will) return the exact same |
190 // Resource object. | 119 // Resource object. |
191 // | 120 // |
192 // For different requests, the same Resource object will be returned and | 121 // For different requests, the same Resource object will be returned and |
193 // will not be associated with the particular request. Therefore, when the | 122 // will not be associated with the particular request. Therefore, when the |
194 // body of the response comes in, there's no way to validate the integrity | 123 // body of the response comes in, there's no way to validate the integrity |
195 // of the Resource object against a particular request (since there may be | 124 // of the Resource object against a particular request (since there may be |
196 // several pending requests all tied to the identical object, and the | 125 // several pending requests all tied to the identical object, and the |
197 // actual requests are not stored). | 126 // actual requests are not stored). |
198 // | 127 // |
199 // In order to simulate the correct behavior, Blink explicitly does the SRI | 128 // In order to simulate the correct behavior, Blink explicitly does the SRI |
200 // checks here, when a PendingScript tied to a particular request is | 129 // checks here, when a PendingScript tied to a particular request is |
201 // finished (and in the case of a StyleSheet, at the point of execution), | 130 // finished (and in the case of a StyleSheet, at the point of execution), |
202 // while having proper Fetch checks in the fetch module for use in the | 131 // while having proper Fetch checks in the fetch module for use in the |
203 // fetch JavaScript API. In a future world where the ResourceFetcher uses | 132 // fetch JavaScript API. In a future world where the ResourceFetcher uses |
204 // the Fetch algorithm, this should be fixed by having separate Response | 133 // the Fetch algorithm, this should be fixed by having separate Response |
205 // objects (perhaps attached to identical Resource objects) per request. | 134 // objects (perhaps attached to identical Resource objects) per request. |
206 // | 135 // |
207 // See https://crbug.com/500701 for more information. | 136 // See https://crbug.com/500701 for more information. |
208 checkState(); | 137 checkState(); |
209 if (m_element) { | 138 if (!m_isForTesting && element()) { |
210 m_integrityFailure = !checkScriptResourceIntegrity(resource, m_element); | 139 m_integrityFailure = !checkScriptResourceIntegrity(resource, element()); |
211 } | 140 } |
212 | 141 |
213 // If script streaming is in use, the client will be notified in | 142 // If script streaming is in use, the client will be notified in |
214 // streamingFinished. | 143 // streamingFinished. |
215 if (m_streamer) | 144 if (m_streamer) |
216 m_streamer->notifyFinished(resource); | 145 m_streamer->notifyFinished(resource); |
217 else if (m_client) | 146 else if (client()) |
218 m_client->pendingScriptFinished(this); | 147 client()->pendingScriptFinished(this); |
219 } | 148 } |
220 | 149 |
221 void PendingScript::notifyAppendData(ScriptResource* resource) { | 150 void ClassicPendingScript::notifyAppendData(ScriptResource* resource) { |
222 if (m_streamer) | 151 if (m_streamer) |
223 m_streamer->notifyAppendData(resource); | 152 m_streamer->notifyAppendData(resource); |
224 } | 153 } |
225 | 154 |
226 DEFINE_TRACE(PendingScript) { | 155 DEFINE_TRACE(ClassicPendingScript) { |
227 visitor->trace(m_element); | |
228 visitor->trace(m_streamer); | 156 visitor->trace(m_streamer); |
229 visitor->trace(m_client); | |
230 ResourceOwner<ScriptResource>::trace(visitor); | 157 ResourceOwner<ScriptResource>::trace(visitor); |
231 MemoryCoordinatorClient::trace(visitor); | 158 MemoryCoordinatorClient::trace(visitor); |
| 159 PendingScript::trace(visitor); |
232 } | 160 } |
233 | 161 |
234 ClassicScript* PendingScript::getSource(const KURL& documentURL, | 162 ClassicScript* ClassicPendingScript::getSource(const KURL& documentURL, |
235 bool& errorOccurred) const { | 163 bool& errorOccurred) const { |
236 checkState(); | 164 checkState(); |
237 | 165 |
238 errorOccurred = this->errorOccurred(); | 166 errorOccurred = this->errorOccurred(); |
239 if (resource()) { | 167 if (resource()) { |
240 DCHECK(resource()->isLoaded()); | 168 DCHECK(resource()->isLoaded()); |
241 if (m_streamer && !m_streamer->streamingSuppressed()) | 169 if (m_streamer && !m_streamer->streamingSuppressed()) |
242 return ClassicScript::create(ScriptSourceCode(m_streamer, resource())); | 170 return ClassicScript::create(ScriptSourceCode(m_streamer, resource())); |
243 return ClassicScript::create(ScriptSourceCode(resource())); | 171 return ClassicScript::create(ScriptSourceCode(resource())); |
244 } | 172 } |
245 | 173 |
246 return ClassicScript::create(ScriptSourceCode( | 174 return ClassicScript::create(ScriptSourceCode( |
247 m_element->textContent(), documentURL, startingPosition())); | 175 element()->textContent(), documentURL, startingPosition())); |
248 } | 176 } |
249 | 177 |
250 void PendingScript::setStreamer(ScriptStreamer* streamer) { | 178 void ClassicPendingScript::setStreamer(ScriptStreamer* streamer) { |
251 DCHECK(!m_streamer); | 179 DCHECK(!m_streamer); |
252 DCHECK(!m_watchingForLoad); | 180 DCHECK(!isWatchingForLoad()); |
253 m_streamer = streamer; | 181 m_streamer = streamer; |
254 checkState(); | 182 checkState(); |
255 } | 183 } |
256 | 184 |
257 bool PendingScript::isReady() const { | 185 bool ClassicPendingScript::isReady() const { |
258 checkState(); | 186 checkState(); |
259 if (resource()) { | 187 if (resource()) { |
260 return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished()); | 188 return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished()); |
261 } | 189 } |
262 | 190 |
263 return true; | 191 return true; |
264 } | 192 } |
265 | 193 |
266 bool PendingScript::errorOccurred() const { | 194 bool ClassicPendingScript::errorOccurred() const { |
267 checkState(); | 195 checkState(); |
268 if (resource()) | 196 if (resource()) |
269 return resource()->errorOccurred() || m_integrityFailure; | 197 return resource()->errorOccurred() || m_integrityFailure; |
270 | 198 |
271 return false; | 199 return false; |
272 } | 200 } |
273 | 201 |
274 void PendingScript::onPurgeMemory() { | 202 void ClassicPendingScript::onPurgeMemory() { |
275 checkState(); | 203 checkState(); |
276 if (!m_streamer) | 204 if (!m_streamer) |
277 return; | 205 return; |
278 m_streamer->cancel(); | 206 m_streamer->cancel(); |
279 m_streamer = nullptr; | 207 m_streamer = nullptr; |
280 } | 208 } |
281 | 209 |
282 void PendingScript::startStreamingIfPossible( | 210 void ClassicPendingScript::startStreamingIfPossible( |
283 Document* document, | 211 Document* document, |
284 ScriptStreamer::Type streamerType) { | 212 ScriptStreamer::Type streamerType) { |
285 if (!document->frame()) | 213 if (!document->frame()) |
286 return; | 214 return; |
287 | 215 |
288 ScriptState* scriptState = toScriptStateForMainWorld(document->frame()); | 216 ScriptState* scriptState = toScriptStateForMainWorld(document->frame()); |
289 if (!scriptState) | 217 if (!scriptState) |
290 return; | 218 return; |
291 | 219 |
292 ScriptStreamer::startStreaming( | 220 ScriptStreamer::startStreaming( |
293 this, streamerType, document->frame()->settings(), scriptState, | 221 this, streamerType, document->frame()->settings(), scriptState, |
294 TaskRunnerHelper::get(TaskType::Networking, document)); | 222 TaskRunnerHelper::get(TaskType::Networking, document)); |
295 } | 223 } |
296 | 224 |
| 225 bool ClassicPendingScript::wasCanceled() const { |
| 226 return resource()->wasCanceled(); |
| 227 } |
| 228 |
| 229 KURL ClassicPendingScript::url() const { |
| 230 return resource()->url(); |
| 231 } |
| 232 |
297 } // namespace blink | 233 } // namespace blink |
OLD | NEW |