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/ScriptController.h" |
28 #include "bindings/core/v8/ScriptSourceCode.h" | 29 #include "bindings/core/v8/ScriptSourceCode.h" |
29 #include "core/dom/Element.h" | 30 #include "core/dom/Element.h" |
| 31 #include "core/dom/ScriptLoader.h" |
| 32 #include "core/dom/TaskRunnerHelper.h" |
| 33 #include "core/frame/LocalFrame.h" |
30 #include "core/frame/SubresourceIntegrity.h" | 34 #include "core/frame/SubresourceIntegrity.h" |
31 #include "platform/SharedBuffer.h" | 35 #include "platform/SharedBuffer.h" |
| 36 #include "platform/instrumentation/tracing/TraceEvent.h" |
32 #include "wtf/CurrentTime.h" | 37 #include "wtf/CurrentTime.h" |
33 | 38 |
34 namespace blink { | 39 namespace blink { |
35 | 40 |
36 PendingScript* PendingScript::create(Element* element, | 41 PendingScript* PendingScript::create(Element* element, |
37 ScriptResource* resource) { | 42 ScriptResource* resource) { |
38 return new PendingScript(element, resource, TextPosition()); | 43 return new PendingScript(element, resource, TextPosition()); |
39 } | 44 } |
40 | 45 |
41 PendingScript* PendingScript::create(Element* element, | 46 PendingScript* PendingScript::create(Element* element, |
42 const TextPosition& startingPosition) { | 47 const TextPosition& startingPosition) { |
43 return new PendingScript(element, nullptr, startingPosition); | 48 return new PendingScript(element, nullptr, startingPosition); |
44 } | 49 } |
45 | 50 |
46 PendingScript* PendingScript::createForTesting(ScriptResource* resource) { | 51 PendingScript* PendingScript::createForTesting(ScriptResource* resource) { |
47 return new PendingScript(nullptr, resource, TextPosition(), true); | 52 return new PendingScript(nullptr, resource, TextPosition(), true); |
48 } | 53 } |
49 | 54 |
50 PendingScript::PendingScript(Element* element, | 55 PendingScript::PendingScript(Element* element, |
51 ScriptResource* resource, | 56 ScriptResource* resource, |
52 const TextPosition& startingPosition, | 57 const TextPosition& startingPosition, |
53 bool isForTesting) | 58 bool isForTesting) |
54 : m_watchingForLoad(false), | 59 : m_watchingForLoad(false), |
| 60 m_readyState(resource ? kWaitingForResource : kReady), |
55 m_element(element), | 61 m_element(element), |
56 m_startingPosition(startingPosition), | 62 m_startingPosition(startingPosition), |
57 m_integrityFailure(false), | 63 m_integrityFailure(false), |
58 m_parserBlockingLoadStartTime(0), | 64 m_parserBlockingLoadStartTime(0), |
59 m_client(nullptr), | 65 m_client(nullptr), |
60 m_isForTesting(isForTesting) { | 66 m_isForTesting(isForTesting) { |
61 checkState(); | 67 checkState(); |
62 setResource(resource); | 68 setResource(resource); |
63 MemoryCoordinator::instance().registerClient(this); | 69 MemoryCoordinator::instance().registerClient(this); |
64 } | 70 } |
(...skipping 27 matching lines...) Expand all Loading... |
92 | 98 |
93 DCHECK(!m_watchingForLoad); | 99 DCHECK(!m_watchingForLoad); |
94 // addClient() will call streamingFinished() if the load is complete. Callers | 100 // 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 | 101 // 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 | 102 // watchForLoad for a PendingScript which isReady. We also need to set |
97 // m_watchingForLoad early, since addClient() can result in calling | 103 // m_watchingForLoad early, since addClient() can result in calling |
98 // notifyFinished and further stopWatchingForLoad(). | 104 // notifyFinished and further stopWatchingForLoad(). |
99 m_watchingForLoad = true; | 105 m_watchingForLoad = true; |
100 m_client = client; | 106 m_client = client; |
101 if (isReady()) | 107 if (isReady()) |
102 m_client->pendingScriptFinished(this); | 108 client->pendingScriptFinished(this); |
103 } | 109 } |
104 | 110 |
105 void PendingScript::stopWatchingForLoad() { | 111 void PendingScript::stopWatchingForLoad() { |
106 if (!m_watchingForLoad) | 112 if (!m_watchingForLoad) |
107 return; | 113 return; |
108 checkState(); | 114 checkState(); |
109 DCHECK(resource()); | 115 DCHECK(resource()); |
110 m_client = nullptr; | 116 m_client = nullptr; |
111 m_watchingForLoad = false; | 117 m_watchingForLoad = false; |
112 } | 118 } |
113 | 119 |
114 Element* PendingScript::element() const { | 120 Element* PendingScript::element() const { |
115 // As mentioned in the comment at |m_element| declaration, |m_element| | 121 // As mentioned in the comment at |m_element| declaration, |m_element| |
116 // must points to the corresponding ScriptLoader's element. | 122 // must points to the corresponding ScriptLoader's element. |
117 CHECK(m_element); | 123 CHECK(m_element); |
118 return m_element.get(); | 124 return m_element.get(); |
119 } | 125 } |
120 | 126 |
121 void PendingScript::streamingFinished() { | 127 void PendingScript::streamingFinished() { |
122 checkState(); | 128 checkState(); |
123 DCHECK(resource()); | 129 DCHECK(resource()); |
| 130 fetchFinished(); |
| 131 } |
| 132 |
| 133 void PendingScript::fetchFinished() { |
| 134 advanceReadyState(kWaitingForCompile); |
| 135 |
| 136 TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this, |
| 137 TRACE_EVENT_FLAG_FLOW_OUT); |
| 138 LocalFrame* frame = m_element ? m_element->document().frame() : nullptr; |
| 139 if (!frame) { |
| 140 // TODO(jbroman): A way of telling the client that it failed, without making |
| 141 // the client try again, would be great. |
| 142 compileFinished(); |
| 143 return; |
| 144 } |
| 145 |
| 146 ScriptState::Scope scope(ScriptState::forMainWorld(frame)); |
| 147 bool errorOccurred; |
| 148 ScriptSourceCode sourceCode = getSource(KURL(), errorOccurred); |
| 149 |
| 150 if (errorOccurred) { |
| 151 // TODO(jbroman): A way of telling the client that it failed, without making |
| 152 // the client try again, would be great. |
| 153 compileFinished(); |
| 154 return; |
| 155 } |
| 156 |
| 157 const bool isExternalScript = true; |
| 158 AccessControlStatus accessControlStatus = |
| 159 ScriptLoader::accessControlStatusForScript( |
| 160 isExternalScript, resource(), |
| 161 m_element->document().getSecurityOrigin()); |
| 162 m_compiledScript = |
| 163 frame->script().compileScriptInMainWorld(sourceCode, accessControlStatus); |
| 164 // TODO(jbroman): can this fail? |
| 165 CHECK(m_compiledScript) << "no compiled script? :'("; |
| 166 TaskRunnerHelper::get(TaskType::Networking, frame) |
| 167 ->postTask(FROM_HERE, WTF::bind(&PendingScript::compileFinished, |
| 168 wrapPersistent(this))); |
| 169 } |
| 170 |
| 171 void PendingScript::compileFinished() { |
| 172 TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this, |
| 173 TRACE_EVENT_FLAG_FLOW_IN); |
| 174 advanceReadyState(kReady); |
124 if (m_client) | 175 if (m_client) |
125 m_client->pendingScriptFinished(this); | 176 m_client->pendingScriptFinished(this); |
126 } | 177 } |
127 | 178 |
128 void PendingScript::markParserBlockingLoadStartTime() { | 179 void PendingScript::markParserBlockingLoadStartTime() { |
129 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); | 180 DCHECK_EQ(m_parserBlockingLoadStartTime, 0.0); |
130 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); | 181 m_parserBlockingLoadStartTime = monotonicallyIncreasingTime(); |
131 } | 182 } |
132 | 183 |
133 // Returns true if SRI check passed. | 184 // Returns true if SRI check passed. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 // the Fetch algorithm, this should be fixed by having separate Response | 246 // the Fetch algorithm, this should be fixed by having separate Response |
196 // objects (perhaps attached to identical Resource objects) per request. | 247 // objects (perhaps attached to identical Resource objects) per request. |
197 // | 248 // |
198 // See https://crbug.com/500701 for more information. | 249 // See https://crbug.com/500701 for more information. |
199 checkState(); | 250 checkState(); |
200 if (m_element) | 251 if (m_element) |
201 m_integrityFailure = !checkScriptResourceIntegrity(resource, m_element); | 252 m_integrityFailure = !checkScriptResourceIntegrity(resource, m_element); |
202 | 253 |
203 // If script streaming is in use, the client will be notified in | 254 // If script streaming is in use, the client will be notified in |
204 // streamingFinished. | 255 // streamingFinished. |
205 if (m_streamer) | 256 if (m_streamer) { |
| 257 advanceReadyState(kWaitingForStreaming); |
206 m_streamer->notifyFinished(resource); | 258 m_streamer->notifyFinished(resource); |
207 else if (m_client) | 259 } else { |
208 m_client->pendingScriptFinished(this); | 260 fetchFinished(); |
| 261 } |
209 } | 262 } |
210 | 263 |
211 void PendingScript::notifyAppendData(ScriptResource* resource) { | 264 void PendingScript::notifyAppendData(ScriptResource* resource) { |
212 if (m_streamer) | 265 if (m_streamer) |
213 m_streamer->notifyAppendData(resource); | 266 m_streamer->notifyAppendData(resource); |
214 } | 267 } |
215 | 268 |
216 DEFINE_TRACE(PendingScript) { | 269 DEFINE_TRACE(PendingScript) { |
217 visitor->trace(m_element); | 270 visitor->trace(m_element); |
218 visitor->trace(m_streamer); | 271 visitor->trace(m_streamer); |
219 visitor->trace(m_client); | 272 visitor->trace(m_client); |
| 273 visitor->trace(m_compiledScript); |
220 ResourceOwner<ScriptResource>::trace(visitor); | 274 ResourceOwner<ScriptResource>::trace(visitor); |
221 MemoryCoordinatorClient::trace(visitor); | 275 MemoryCoordinatorClient::trace(visitor); |
222 } | 276 } |
223 | 277 |
224 ScriptSourceCode PendingScript::getSource(const KURL& documentURL, | 278 ScriptSourceCode PendingScript::getSource(const KURL& documentURL, |
225 bool& errorOccurred) const { | 279 bool& errorOccurred) const { |
226 checkState(); | 280 checkState(); |
227 | 281 |
228 errorOccurred = this->errorOccurred(); | 282 errorOccurred = this->errorOccurred(); |
229 if (resource()) { | 283 if (resource()) { |
230 DCHECK(resource()->isLoaded()); | 284 DCHECK(resource()->isLoaded()); |
231 if (m_streamer && !m_streamer->streamingSuppressed()) | 285 if (m_streamer && !m_streamer->streamingSuppressed()) |
232 return ScriptSourceCode(m_streamer, resource()); | 286 return ScriptSourceCode(m_streamer, resource()); |
233 return ScriptSourceCode(resource()); | 287 return ScriptSourceCode(resource()); |
234 } | 288 } |
235 | 289 |
236 return ScriptSourceCode(m_element->textContent(), documentURL, | 290 return ScriptSourceCode(m_element->textContent(), documentURL, |
237 startingPosition()); | 291 startingPosition()); |
238 } | 292 } |
239 | 293 |
240 void PendingScript::setStreamer(ScriptStreamer* streamer) { | 294 void PendingScript::setStreamer(ScriptStreamer* streamer) { |
241 DCHECK(!m_streamer); | 295 DCHECK(!m_streamer); |
242 DCHECK(!m_watchingForLoad); | 296 DCHECK(!m_watchingForLoad); |
| 297 DCHECK(!streamer->isFinished()); |
| 298 DCHECK_LT(m_readyState, kWaitingForStreaming); |
243 m_streamer = streamer; | 299 m_streamer = streamer; |
244 checkState(); | 300 checkState(); |
245 } | 301 } |
246 | 302 |
247 bool PendingScript::isReady() const { | 303 bool PendingScript::isReady() const { |
248 checkState(); | 304 checkState(); |
249 if (resource()) { | 305 return m_readyState == kReady; |
250 return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished()); | |
251 } | |
252 | |
253 return true; | |
254 } | 306 } |
255 | 307 |
256 bool PendingScript::errorOccurred() const { | 308 bool PendingScript::errorOccurred() const { |
257 checkState(); | 309 checkState(); |
258 if (resource()) | 310 if (resource()) |
259 return resource()->errorOccurred() || m_integrityFailure; | 311 return resource()->errorOccurred() || m_integrityFailure; |
260 | 312 |
261 return false; | 313 return false; |
262 } | 314 } |
263 | 315 |
264 void PendingScript::onPurgeMemory() { | 316 void PendingScript::onPurgeMemory() { |
265 checkState(); | 317 checkState(); |
266 if (!m_streamer) | 318 if (!m_streamer) |
267 return; | 319 return; |
268 m_streamer->cancel(); | 320 m_streamer->cancel(); |
269 m_streamer = nullptr; | 321 m_streamer = nullptr; |
270 } | 322 } |
271 | 323 |
272 } // namespace blink | 324 } // namespace blink |
OLD | NEW |