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