| 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? Yes, it can. |
| 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 // Avoid consuming the streamed source code more than once. |
| 286 // TODO(jbroman): Update this if we don't always do the precompile step. |
| 287 if (m_streamer && !m_streamer->streamingSuppressed() && |
| 288 m_readyState < ReadyState::kReady) { |
| 232 return ScriptSourceCode(m_streamer, resource()); | 289 return ScriptSourceCode(m_streamer, resource()); |
| 290 } |
| 233 return ScriptSourceCode(resource()); | 291 return ScriptSourceCode(resource()); |
| 234 } | 292 } |
| 235 | 293 |
| 236 return ScriptSourceCode(m_element->textContent(), documentURL, | 294 return ScriptSourceCode(m_element->textContent(), documentURL, |
| 237 startingPosition()); | 295 startingPosition()); |
| 238 } | 296 } |
| 239 | 297 |
| 240 void PendingScript::setStreamer(ScriptStreamer* streamer) { | 298 void PendingScript::setStreamer(ScriptStreamer* streamer) { |
| 241 DCHECK(!m_streamer); | 299 DCHECK(!m_streamer); |
| 242 DCHECK(!m_watchingForLoad); | 300 DCHECK(!m_watchingForLoad); |
| 301 DCHECK(!streamer->isFinished()); |
| 302 DCHECK_LT(m_readyState, kWaitingForStreaming); |
| 243 m_streamer = streamer; | 303 m_streamer = streamer; |
| 244 checkState(); | 304 checkState(); |
| 245 } | 305 } |
| 246 | 306 |
| 247 bool PendingScript::isReady() const { | 307 bool PendingScript::isReady() const { |
| 248 checkState(); | 308 checkState(); |
| 249 if (resource()) { | 309 return m_readyState == kReady; |
| 250 return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished()); | |
| 251 } | |
| 252 | |
| 253 return true; | |
| 254 } | 310 } |
| 255 | 311 |
| 256 bool PendingScript::errorOccurred() const { | 312 bool PendingScript::errorOccurred() const { |
| 257 checkState(); | 313 checkState(); |
| 258 if (resource()) | 314 if (resource()) |
| 259 return resource()->errorOccurred() || m_integrityFailure; | 315 return resource()->errorOccurred() || m_integrityFailure; |
| 260 | 316 |
| 261 return false; | 317 return false; |
| 262 } | 318 } |
| 263 | 319 |
| 264 void PendingScript::onPurgeMemory() { | 320 void PendingScript::onPurgeMemory() { |
| 265 checkState(); | 321 checkState(); |
| 266 if (!m_streamer) | 322 if (!m_streamer) |
| 267 return; | 323 return; |
| 268 m_streamer->cancel(); | 324 m_streamer->cancel(); |
| 269 m_streamer = nullptr; | 325 m_streamer = nullptr; |
| 270 } | 326 } |
| 271 | 327 |
| 272 } // namespace blink | 328 } // namespace blink |
| OLD | NEW |