| 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 |