Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights | 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights |
| 6 * reserved. | 6 * reserved. |
| 7 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> | 7 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> |
| 8 * | 8 * |
| 9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 #include "core/dom/ScriptLoaderClient.h" | 34 #include "core/dom/ScriptLoaderClient.h" |
| 35 #include "core/dom/ScriptRunner.h" | 35 #include "core/dom/ScriptRunner.h" |
| 36 #include "core/dom/ScriptableDocumentParser.h" | 36 #include "core/dom/ScriptableDocumentParser.h" |
| 37 #include "core/dom/Text.h" | 37 #include "core/dom/Text.h" |
| 38 #include "core/events/Event.h" | 38 #include "core/events/Event.h" |
| 39 #include "core/frame/LocalFrame.h" | 39 #include "core/frame/LocalFrame.h" |
| 40 #include "core/frame/SubresourceIntegrity.h" | 40 #include "core/frame/SubresourceIntegrity.h" |
| 41 #include "core/frame/UseCounter.h" | 41 #include "core/frame/UseCounter.h" |
| 42 #include "core/frame/csp/ContentSecurityPolicy.h" | 42 #include "core/frame/csp/ContentSecurityPolicy.h" |
| 43 #include "core/html/CrossOriginAttribute.h" | 43 #include "core/html/CrossOriginAttribute.h" |
| 44 #include "core/html/HTMLScriptElement.h" | |
| 45 #include "core/html/imports/HTMLImport.h" | 44 #include "core/html/imports/HTMLImport.h" |
| 46 #include "core/html/parser/HTMLParserIdioms.h" | 45 #include "core/html/parser/HTMLParserIdioms.h" |
| 47 #include "core/inspector/ConsoleMessage.h" | 46 #include "core/inspector/ConsoleMessage.h" |
| 48 #include "core/svg/SVGScriptElement.h" | |
| 49 #include "platform/WebFrameScheduler.h" | 47 #include "platform/WebFrameScheduler.h" |
| 50 #include "platform/loader/fetch/AccessControlStatus.h" | 48 #include "platform/loader/fetch/AccessControlStatus.h" |
| 51 #include "platform/loader/fetch/FetchRequest.h" | 49 #include "platform/loader/fetch/FetchRequest.h" |
| 52 #include "platform/loader/fetch/MemoryCache.h" | 50 #include "platform/loader/fetch/MemoryCache.h" |
| 53 #include "platform/loader/fetch/ResourceFetcher.h" | 51 #include "platform/loader/fetch/ResourceFetcher.h" |
| 54 #include "platform/network/mime/MIMETypeRegistry.h" | 52 #include "platform/network/mime/MIMETypeRegistry.h" |
| 55 #include "platform/weborigin/SecurityOrigin.h" | 53 #include "platform/weborigin/SecurityOrigin.h" |
| 56 #include "public/platform/WebCachePolicy.h" | 54 #include "public/platform/WebCachePolicy.h" |
| 57 #include "wtf/StdLibExtras.h" | 55 #include "wtf/StdLibExtras.h" |
| 58 #include "wtf/text/StringBuilder.h" | 56 #include "wtf/text/StringBuilder.h" |
| 59 #include "wtf/text/StringHash.h" | 57 #include "wtf/text/StringHash.h" |
| 60 | 58 |
| 61 namespace blink { | 59 namespace blink { |
| 62 | 60 |
| 63 ScriptLoader::ScriptLoader(Element* element, | 61 ScriptLoader::ScriptLoader(ScriptLoaderClient* client, |
| 64 bool parserInserted, | 62 bool parserInserted, |
| 65 bool alreadyStarted, | 63 bool alreadyStarted, |
| 66 bool createdDuringDocumentWrite) | 64 bool createdDuringDocumentWrite) |
| 67 : m_element(element), | 65 : m_client(client), |
| 68 m_startLineNumber(WTF::OrdinalNumber::beforeFirst()), | 66 m_startLineNumber(WTF::OrdinalNumber::beforeFirst()), |
| 69 m_haveFiredLoad(false), | 67 m_haveFiredLoad(false), |
| 70 m_willBeParserExecuted(false), | 68 m_willBeParserExecuted(false), |
| 71 m_willExecuteWhenDocumentFinishedParsing(false), | 69 m_willExecuteWhenDocumentFinishedParsing(false), |
| 72 m_createdDuringDocumentWrite(createdDuringDocumentWrite), | 70 m_createdDuringDocumentWrite(createdDuringDocumentWrite), |
| 73 m_asyncExecType(ScriptRunner::None), | 71 m_asyncExecType(ScriptRunner::None), |
| 74 m_documentWriteIntervention( | 72 m_documentWriteIntervention( |
| 75 DocumentWriteIntervention::DocumentWriteInterventionNone) { | 73 DocumentWriteIntervention::DocumentWriteInterventionNone) { |
| 76 DCHECK(m_element); | 74 DCHECK(m_client); |
| 77 | 75 |
| 78 // https://html.spec.whatwg.org/#already-started | 76 // https://html.spec.whatwg.org/#already-started |
| 79 // "The cloning steps for script elements must set the "already started" | 77 // "The cloning steps for script elements must set the "already started" |
| 80 // flag on the copy if it is set on the element being cloned." | 78 // flag on the copy if it is set on the element being cloned." |
| 81 // TODO(hiroshige): Cloning is implemented together with | 79 // TODO(hiroshige): Cloning is implemented together with |
| 82 // {HTML,SVG}ScriptElement::cloneElementWithoutAttributesAndChildren(). | 80 // {HTML,SVG}ScriptElement::cloneElementWithoutAttributesAndChildren(). |
| 83 // Clean up these later. | 81 // Clean up these later. |
| 84 if (alreadyStarted) | 82 if (alreadyStarted) |
| 85 m_alreadyStarted = true; | 83 m_alreadyStarted = true; |
| 86 | 84 |
| 87 if (parserInserted) { | 85 if (parserInserted) { |
| 88 // https://html.spec.whatwg.org/#parser-inserted | 86 // https://html.spec.whatwg.org/#parser-inserted |
| 89 // "It is set by the HTML parser and the XML parser | 87 // "It is set by the HTML parser and the XML parser |
| 90 // on script elements they insert" | 88 // on script elements they insert" |
| 91 m_parserInserted = true; | 89 m_parserInserted = true; |
| 92 | 90 |
| 93 // https://html.spec.whatwg.org/#non-blocking | 91 // https://html.spec.whatwg.org/#non-blocking |
| 94 // "It is unset by the HTML parser and the XML parser | 92 // "It is unset by the HTML parser and the XML parser |
| 95 // on script elements they insert." | 93 // on script elements they insert." |
| 96 m_nonBlocking = false; | 94 m_nonBlocking = false; |
| 97 } | 95 } |
| 98 | 96 |
| 99 if (parserInserted && element->document().scriptableDocumentParser() && | 97 if (parserInserted && m_client->document().scriptableDocumentParser() && |
| 100 !element->document().isInDocumentWrite()) | 98 !m_client->document().isInDocumentWrite()) { |
| 101 m_startLineNumber = | 99 m_startLineNumber = |
| 102 element->document().scriptableDocumentParser()->lineNumber(); | 100 m_client->document().scriptableDocumentParser()->lineNumber(); |
| 101 } | |
| 103 } | 102 } |
| 104 | 103 |
| 105 ScriptLoader::~ScriptLoader() {} | 104 ScriptLoader::~ScriptLoader() {} |
| 106 | 105 |
| 107 DEFINE_TRACE(ScriptLoader) { | 106 DEFINE_TRACE(ScriptLoader) { |
| 108 visitor->trace(m_element); | 107 visitor->trace(m_client); |
| 109 visitor->trace(m_resource); | 108 visitor->trace(m_resource); |
| 110 visitor->trace(m_pendingScript); | 109 visitor->trace(m_pendingScript); |
| 111 PendingScriptClient::trace(visitor); | 110 PendingScriptClient::trace(visitor); |
| 112 } | 111 } |
| 113 | 112 |
| 114 void ScriptLoader::setFetchDocWrittenScriptDeferIdle() { | 113 void ScriptLoader::setFetchDocWrittenScriptDeferIdle() { |
| 115 DCHECK(!m_createdDuringDocumentWrite); | 114 DCHECK(!m_createdDuringDocumentWrite); |
| 116 m_documentWriteIntervention = | 115 m_documentWriteIntervention = |
| 117 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle; | 116 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle; |
| 118 } | 117 } |
| 119 | 118 |
| 120 void ScriptLoader::didNotifySubtreeInsertionsToDocument() { | 119 void ScriptLoader::didNotifySubtreeInsertionsToDocument() { |
| 121 if (!m_parserInserted) | 120 if (!m_parserInserted) |
| 122 prepareScript(); // FIXME: Provide a real starting line number here. | 121 prepareScript(); // FIXME: Provide a real starting line number here. |
| 123 } | 122 } |
| 124 | 123 |
| 125 void ScriptLoader::childrenChanged() { | 124 void ScriptLoader::childrenChanged() { |
| 126 if (!m_parserInserted && m_element->isConnected()) | 125 if (!m_parserInserted && m_client->isConnected()) |
| 127 prepareScript(); // FIXME: Provide a real starting line number here. | 126 prepareScript(); // FIXME: Provide a real starting line number here. |
| 128 } | 127 } |
| 129 | 128 |
| 130 void ScriptLoader::handleSourceAttribute(const String& sourceUrl) { | 129 void ScriptLoader::handleSourceAttribute(const String& sourceUrl) { |
| 131 if (ignoresLoadRequest() || sourceUrl.isEmpty()) | 130 if (ignoresLoadRequest() || sourceUrl.isEmpty()) |
| 132 return; | 131 return; |
| 133 | 132 |
| 134 prepareScript(); // FIXME: Provide a real starting line number here. | 133 prepareScript(); // FIXME: Provide a real starting line number here. |
| 135 } | 134 } |
| 136 | 135 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 equalIgnoringASCIICase(language, "javascript1.4") || | 167 equalIgnoringASCIICase(language, "javascript1.4") || |
| 169 equalIgnoringASCIICase(language, "javascript1.5") || | 168 equalIgnoringASCIICase(language, "javascript1.5") || |
| 170 equalIgnoringASCIICase(language, "javascript1.6") || | 169 equalIgnoringASCIICase(language, "javascript1.6") || |
| 171 equalIgnoringASCIICase(language, "javascript1.7") || | 170 equalIgnoringASCIICase(language, "javascript1.7") || |
| 172 equalIgnoringASCIICase(language, "livescript") || | 171 equalIgnoringASCIICase(language, "livescript") || |
| 173 equalIgnoringASCIICase(language, "ecmascript") || | 172 equalIgnoringASCIICase(language, "ecmascript") || |
| 174 equalIgnoringASCIICase(language, "jscript"); | 173 equalIgnoringASCIICase(language, "jscript"); |
| 175 } | 174 } |
| 176 | 175 |
| 177 void ScriptLoader::dispatchErrorEvent() { | 176 void ScriptLoader::dispatchErrorEvent() { |
| 178 m_element->dispatchEvent(Event::create(EventTypeNames::error)); | 177 m_client->dispatchErrorEvent(); |
| 179 } | 178 } |
| 180 | 179 |
| 181 void ScriptLoader::dispatchLoadEvent() { | 180 void ScriptLoader::dispatchLoadEvent() { |
| 182 if (ScriptLoaderClient* client = this->client()) | 181 m_client->dispatchLoadEvent(); |
|
hiroshige
2017/03/01 00:58:14
So client() was always non-null and this if condit
Nate Chapin
2017/03/01 21:34:59
I believe so. I guess if buggy code had constructo
| |
| 183 client->dispatchLoadEvent(); | |
| 184 setHaveFiredLoadEvent(true); | 182 setHaveFiredLoadEvent(true); |
| 185 } | 183 } |
| 186 | 184 |
| 187 bool ScriptLoader::isValidScriptTypeAndLanguage( | 185 bool ScriptLoader::isValidScriptTypeAndLanguage( |
| 188 const String& type, | 186 const String& type, |
| 189 const String& language, | 187 const String& language, |
| 190 LegacyTypeSupport supportLegacyTypes) { | 188 LegacyTypeSupport supportLegacyTypes) { |
| 191 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used | 189 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used |
| 192 // here to maintain backwards compatibility with existing layout tests. The | 190 // here to maintain backwards compatibility with existing layout tests. The |
| 193 // specific violations are: | 191 // specific violations are: |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 208 (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && | 206 (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && |
| 209 isLegacySupportedJavaScriptLanguage(type))) { | 207 isLegacySupportedJavaScriptLanguage(type))) { |
| 210 return true; | 208 return true; |
| 211 } | 209 } |
| 212 | 210 |
| 213 return false; | 211 return false; |
| 214 } | 212 } |
| 215 | 213 |
| 216 bool ScriptLoader::isScriptTypeSupported( | 214 bool ScriptLoader::isScriptTypeSupported( |
| 217 LegacyTypeSupport supportLegacyTypes) const { | 215 LegacyTypeSupport supportLegacyTypes) const { |
| 218 return isValidScriptTypeAndLanguage(client()->typeAttributeValue(), | 216 return isValidScriptTypeAndLanguage(m_client->typeAttributeValue(), |
| 219 client()->languageAttributeValue(), | 217 m_client->languageAttributeValue(), |
| 220 supportLegacyTypes); | 218 supportLegacyTypes); |
| 221 } | 219 } |
| 222 | 220 |
| 223 // https://html.spec.whatwg.org/#prepare-a-script | 221 // https://html.spec.whatwg.org/#prepare-a-script |
| 224 bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, | 222 bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, |
| 225 LegacyTypeSupport supportLegacyTypes) { | 223 LegacyTypeSupport supportLegacyTypes) { |
| 226 // 1. "If the script element is marked as having "already started", then | 224 // 1. "If the script element is marked as having "already started", then |
| 227 // abort these steps at this point. The script is not executed." | 225 // abort these steps at this point. The script is not executed." |
| 228 if (m_alreadyStarted) | 226 if (m_alreadyStarted) |
| 229 return false; | 227 return false; |
| 230 | 228 |
| 231 ScriptLoaderClient* client = this->client(); | |
| 232 | |
| 233 // 2. "If the element has its "parser-inserted" flag set, then | 229 // 2. "If the element has its "parser-inserted" flag set, then |
| 234 // set was-parser-inserted to true and unset the element's | 230 // set was-parser-inserted to true and unset the element's |
| 235 // "parser-inserted" flag. | 231 // "parser-inserted" flag. |
| 236 // Otherwise, set was-parser-inserted to false." | 232 // Otherwise, set was-parser-inserted to false." |
| 237 bool wasParserInserted; | 233 bool wasParserInserted; |
| 238 if (m_parserInserted) { | 234 if (m_parserInserted) { |
| 239 wasParserInserted = true; | 235 wasParserInserted = true; |
| 240 m_parserInserted = false; | 236 m_parserInserted = false; |
| 241 } else { | 237 } else { |
| 242 wasParserInserted = false; | 238 wasParserInserted = false; |
| 243 } | 239 } |
| 244 | 240 |
| 245 // 3. "If was-parser-inserted is true and the element does not have an | 241 // 3. "If was-parser-inserted is true and the element does not have an |
| 246 // async attribute, then set the element's "non-blocking" flag to true." | 242 // async attribute, then set the element's "non-blocking" flag to true." |
| 247 if (wasParserInserted && !client->asyncAttributeValue()) | 243 if (wasParserInserted && !m_client->asyncAttributeValue()) |
| 248 m_nonBlocking = true; | 244 m_nonBlocking = true; |
| 249 | 245 |
| 250 // 4. "If the element has no src attribute, and its child nodes, if any, | 246 // 4. "If the element has no src attribute, and its child nodes, if any, |
| 251 // consist only of comment nodes and empty Text nodes, | 247 // consist only of comment nodes and empty Text nodes, |
| 252 // then abort these steps at this point. The script is not executed." | 248 // then abort these steps at this point. The script is not executed." |
| 253 // FIXME: HTML5 spec says we should check that all children are either | 249 // FIXME: HTML5 spec says we should check that all children are either |
| 254 // comments or empty text nodes. | 250 // comments or empty text nodes. |
| 255 if (!client->hasSourceAttribute() && !m_element->hasChildren()) | 251 if (!m_client->hasSourceAttribute() && !m_client->hasChildren()) |
| 256 return false; | 252 return false; |
| 257 | 253 |
| 258 // 5. "If the element is not connected, then abort these steps. | 254 // 5. "If the element is not connected, then abort these steps. |
| 259 // The script is not executed." | 255 // The script is not executed." |
| 260 if (!m_element->isConnected()) | 256 if (!m_client->isConnected()) |
| 261 return false; | 257 return false; |
| 262 | 258 |
| 263 // 6. | 259 // 6. |
| 264 // TODO(hiroshige): Annotate and/or cleanup this step. | 260 // TODO(hiroshige): Annotate and/or cleanup this step. |
| 265 if (!isScriptTypeSupported(supportLegacyTypes)) | 261 if (!isScriptTypeSupported(supportLegacyTypes)) |
| 266 return false; | 262 return false; |
| 267 | 263 |
| 268 // 7. "If was-parser-inserted is true, | 264 // 7. "If was-parser-inserted is true, |
| 269 // then flag the element as "parser-inserted" again, | 265 // then flag the element as "parser-inserted" again, |
| 270 // and set the element's "non-blocking" flag to false." | 266 // and set the element's "non-blocking" flag to false." |
| 271 if (wasParserInserted) { | 267 if (wasParserInserted) { |
| 272 m_parserInserted = true; | 268 m_parserInserted = true; |
| 273 m_nonBlocking = false; | 269 m_nonBlocking = false; |
| 274 } | 270 } |
| 275 | 271 |
| 276 // 8. "Set the element's "already started" flag." | 272 // 8. "Set the element's "already started" flag." |
| 277 m_alreadyStarted = true; | 273 m_alreadyStarted = true; |
| 278 | 274 |
| 279 // 9. "If the element is flagged as "parser-inserted", but the element's | 275 // 9. "If the element is flagged as "parser-inserted", but the element's |
| 280 // node document is not the Document of the parser that created the element, | 276 // node document is not the Document of the parser that created the element, |
| 281 // then abort these steps." | 277 // then abort these steps." |
| 282 // FIXME: If script is parser inserted, verify it's still in the original | 278 // FIXME: If script is parser inserted, verify it's still in the original |
| 283 // document. | 279 // document. |
| 284 Document& elementDocument = m_element->document(); | 280 Document& elementDocument = m_client->document(); |
| 285 Document* contextDocument = elementDocument.contextDocument(); | 281 Document* contextDocument = elementDocument.contextDocument(); |
| 286 if (!contextDocument) | 282 if (!contextDocument) |
| 287 return false; | 283 return false; |
| 288 | 284 |
| 289 // 10. "If scripting is disabled for the script element, then abort these | 285 // 10. "If scripting is disabled for the script element, then abort these |
| 290 // steps at this point. The script is not executed." | 286 // steps at this point. The script is not executed." |
| 291 if (!contextDocument->allowExecutingScripts(m_element)) | 287 if (!contextDocument->allowExecutingScripts(&elementDocument)) |
| 292 return false; | 288 return false; |
| 293 | 289 |
| 294 // 13. | 290 // 13. |
| 295 if (!isScriptForEventSupported()) | 291 if (!isScriptForEventSupported()) |
| 296 return false; | 292 return false; |
| 297 | 293 |
| 298 // 14. "If the script element has a charset attribute, | 294 // 14. "If the script element has a charset attribute, |
| 299 // then let encoding be the result of | 295 // then let encoding be the result of |
| 300 // getting an encoding from the value of the charset attribute." | 296 // getting an encoding from the value of the charset attribute." |
| 301 // "If the script element does not have a charset attribute, | 297 // "If the script element does not have a charset attribute, |
| 302 // or if getting an encoding failed, let encoding | 298 // or if getting an encoding failed, let encoding |
| 303 // be the same as the encoding of the script element's node document." | 299 // be the same as the encoding of the script element's node document." |
| 304 // TODO(hiroshige): Should we handle failure in getting an encoding? | 300 // TODO(hiroshige): Should we handle failure in getting an encoding? |
| 305 String encoding; | 301 String encoding; |
| 306 if (!client->charsetAttributeValue().isEmpty()) | 302 if (!m_client->charsetAttributeValue().isEmpty()) |
| 307 encoding = client->charsetAttributeValue(); | 303 encoding = m_client->charsetAttributeValue(); |
| 308 else | 304 else |
| 309 encoding = elementDocument.characterSet(); | 305 encoding = elementDocument.characterSet(); |
| 310 | 306 |
| 311 // Steps 15--20 are handled in fetchScript(). | 307 // Steps 15--20 are handled in fetchScript(). |
| 312 | 308 |
| 313 // 21. "If the element has a src content attribute, run these substeps:" | 309 // 21. "If the element has a src content attribute, run these substeps:" |
| 314 if (client->hasSourceAttribute()) { | 310 if (m_client->hasSourceAttribute()) { |
| 315 FetchRequest::DeferOption defer = FetchRequest::NoDefer; | 311 FetchRequest::DeferOption defer = FetchRequest::NoDefer; |
| 316 if (!m_parserInserted || client->asyncAttributeValue() || | 312 if (!m_parserInserted || m_client->asyncAttributeValue() || |
| 317 client->deferAttributeValue()) | 313 m_client->deferAttributeValue()) |
| 318 defer = FetchRequest::LazyLoad; | 314 defer = FetchRequest::LazyLoad; |
| 319 if (m_documentWriteIntervention == | 315 if (m_documentWriteIntervention == |
| 320 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) | 316 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) |
| 321 defer = FetchRequest::IdleLoad; | 317 defer = FetchRequest::IdleLoad; |
| 322 if (!fetchScript(client->sourceAttributeValue(), encoding, defer)) | 318 if (!fetchScript(m_client->sourceAttributeValue(), encoding, defer)) |
| 323 return false; | 319 return false; |
| 324 } | 320 } |
| 325 | 321 |
| 326 // 22. "If the element does not have a src content attribute, | 322 // 22. "If the element does not have a src content attribute, |
| 327 // run these substeps:" | 323 // run these substeps:" |
| 328 | 324 |
| 329 // 22.1. "Let source text be the value of the text IDL attribute." | 325 // 22.1. "Let source text be the value of the text IDL attribute." |
| 330 // This step is done later: | 326 // This step is done later: |
| 331 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), | 327 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), |
| 332 // as Element::textFromChildren() in ScriptLoader::scriptContent(), | 328 // as Element::textFromChildren() in ScriptLoader::scriptContent(), |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 344 // 22.2. "Switch on the script's type:" | 340 // 22.2. "Switch on the script's type:" |
| 345 // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". | 341 // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". |
| 346 // TODO(hiroshige): Implement Step 22.2 for "module". | 342 // TODO(hiroshige): Implement Step 22.2 for "module". |
| 347 | 343 |
| 348 // [Intervention] | 344 // [Intervention] |
| 349 // Since the asynchronous, low priority fetch for doc.written blocked | 345 // Since the asynchronous, low priority fetch for doc.written blocked |
| 350 // script is not for execution, return early from here. Watch for its | 346 // script is not for execution, return early from here. Watch for its |
| 351 // completion to be able to remove it from the memory cache. | 347 // completion to be able to remove it from the memory cache. |
| 352 if (m_documentWriteIntervention == | 348 if (m_documentWriteIntervention == |
| 353 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { | 349 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { |
| 354 m_pendingScript = PendingScript::create(m_element, m_resource.get()); | 350 m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
| 355 m_pendingScript->watchForLoad(this); | 351 m_pendingScript->watchForLoad(this); |
| 356 return true; | 352 return true; |
| 357 } | 353 } |
| 358 | 354 |
| 359 // 23. "Then, follow the first of the following options that describes the | 355 // 23. "Then, follow the first of the following options that describes the |
| 360 // situation:" | 356 // situation:" |
| 361 | 357 |
| 362 // Three flags are used to instruct the caller of prepareScript() to execute | 358 // Three flags are used to instruct the caller of prepareScript() to execute |
| 363 // a part of Step 23, when |m_willBeParserExecuted| is true: | 359 // a part of Step 23, when |m_willBeParserExecuted| is true: |
| 364 // - |m_willBeParserExecuted| | 360 // - |m_willBeParserExecuted| |
| 365 // - |m_willExecuteWhenDocumentFinishedParsing| | 361 // - |m_willExecuteWhenDocumentFinishedParsing| |
| 366 // - |m_readyToBeParserExecuted| | 362 // - |m_readyToBeParserExecuted| |
| 367 // TODO(hiroshige): Clean up the dependency. | 363 // TODO(hiroshige): Clean up the dependency. |
| 368 | 364 |
| 369 // 1st Clause: | 365 // 1st Clause: |
| 370 // - "If the script's type is "classic", and | 366 // - "If the script's type is "classic", and |
| 371 // the element has a src attribute, and the element has a defer attribute, | 367 // the element has a src attribute, and the element has a defer attribute, |
| 372 // and the element has been flagged as "parser-inserted", | 368 // and the element has been flagged as "parser-inserted", |
| 373 // and the element does not have an async attribute" | 369 // and the element does not have an async attribute" |
| 374 // TODO(hiroshige): Check the script's type and implement "module" case. | 370 // TODO(hiroshige): Check the script's type and implement "module" case. |
| 375 if (client->hasSourceAttribute() && client->deferAttributeValue() && | 371 if (m_client->hasSourceAttribute() && m_client->deferAttributeValue() && |
| 376 m_parserInserted && !client->asyncAttributeValue()) { | 372 m_parserInserted && !m_client->asyncAttributeValue()) { |
| 377 // This clause is implemented by the caller-side of prepareScript(): | 373 // This clause is implemented by the caller-side of prepareScript(): |
| 378 // - HTMLParserScriptRunner::requestDeferredScript(), and | 374 // - HTMLParserScriptRunner::requestDeferredScript(), and |
| 379 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 375 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
| 380 m_willExecuteWhenDocumentFinishedParsing = true; | 376 m_willExecuteWhenDocumentFinishedParsing = true; |
| 381 m_willBeParserExecuted = true; | 377 m_willBeParserExecuted = true; |
| 382 | 378 |
| 383 return true; | 379 return true; |
| 384 } | 380 } |
| 385 | 381 |
| 386 // 2nd Clause: | 382 // 2nd Clause: |
| 387 // - "If the script's type is "classic", | 383 // - "If the script's type is "classic", |
| 388 // and the element has a src attribute, | 384 // and the element has a src attribute, |
| 389 // and the element has been flagged as "parser-inserted", | 385 // and the element has been flagged as "parser-inserted", |
| 390 // and the element does not have an async attribute" | 386 // and the element does not have an async attribute" |
| 391 // TODO(hiroshige): Check the script's type. | 387 // TODO(hiroshige): Check the script's type. |
| 392 if (client->hasSourceAttribute() && m_parserInserted && | 388 if (m_client->hasSourceAttribute() && m_parserInserted && |
| 393 !client->asyncAttributeValue()) { | 389 !m_client->asyncAttributeValue()) { |
| 394 // This clause is implemented by the caller-side of prepareScript(): | 390 // This clause is implemented by the caller-side of prepareScript(): |
| 395 // - HTMLParserScriptRunner::requestParsingBlockingScript() | 391 // - HTMLParserScriptRunner::requestParsingBlockingScript() |
| 396 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 392 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
| 397 m_willBeParserExecuted = true; | 393 m_willBeParserExecuted = true; |
| 398 | 394 |
| 399 return true; | 395 return true; |
| 400 } | 396 } |
| 401 | 397 |
| 402 // 5th Clause: | 398 // 5th Clause: |
| 403 // TODO(hiroshige): Reorder the clauses to match the spec. | 399 // TODO(hiroshige): Reorder the clauses to match the spec. |
| 404 // - "If the element does not have a src attribute, | 400 // - "If the element does not have a src attribute, |
| 405 // and the element has been flagged as "parser-inserted", | 401 // and the element has been flagged as "parser-inserted", |
| 406 // and either the parser that created the script is an XML parser | 402 // and either the parser that created the script is an XML parser |
| 407 // or it's an HTML parser whose script nesting level is not greater than | 403 // or it's an HTML parser whose script nesting level is not greater than |
| 408 // one, | 404 // one, |
| 409 // and the Document of the HTML parser or XML parser that created | 405 // and the Document of the HTML parser or XML parser that created |
| 410 // the script element has a style sheet that is blocking scripts" | 406 // the script element has a style sheet that is blocking scripts" |
| 411 // The last part "... has a style sheet that is blocking scripts" | 407 // The last part "... has a style sheet that is blocking scripts" |
| 412 // is implemented in Document::isScriptExecutionReady(). | 408 // is implemented in Document::isScriptExecutionReady(). |
| 413 // Part of the condition check is done in | 409 // Part of the condition check is done in |
| 414 // HTMLParserScriptRunner::processScriptElementInternal(). | 410 // HTMLParserScriptRunner::processScriptElementInternal(). |
| 415 // TODO(hiroshige): Clean up the split condition check. | 411 // TODO(hiroshige): Clean up the split condition check. |
| 416 if (!client->hasSourceAttribute() && m_parserInserted && | 412 if (!m_client->hasSourceAttribute() && m_parserInserted && |
| 417 !elementDocument.isScriptExecutionReady()) { | 413 !elementDocument.isScriptExecutionReady()) { |
| 418 // The former part of this clause is | 414 // The former part of this clause is |
| 419 // implemented by the caller-side of prepareScript(): | 415 // implemented by the caller-side of prepareScript(): |
| 420 // - HTMLParserScriptRunner::requestParsingBlockingScript() | 416 // - HTMLParserScriptRunner::requestParsingBlockingScript() |
| 421 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 417 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
| 422 m_willBeParserExecuted = true; | 418 m_willBeParserExecuted = true; |
| 423 // "Set the element's "ready to be parser-executed" flag." | 419 // "Set the element's "ready to be parser-executed" flag." |
| 424 m_readyToBeParserExecuted = true; | 420 m_readyToBeParserExecuted = true; |
| 425 | 421 |
| 426 return true; | 422 return true; |
| 427 } | 423 } |
| 428 | 424 |
| 429 // 3rd Clause: | 425 // 3rd Clause: |
| 430 // - "If the script's type is "classic", | 426 // - "If the script's type is "classic", |
| 431 // and the element has a src attribute, | 427 // and the element has a src attribute, |
| 432 // and the element does not have an async attribute, | 428 // and the element does not have an async attribute, |
| 433 // and the element does not have the "non-blocking" flag set" | 429 // and the element does not have the "non-blocking" flag set" |
| 434 // TODO(hiroshige): Check the script's type and implement "module" case. | 430 // TODO(hiroshige): Check the script's type and implement "module" case. |
| 435 if (client->hasSourceAttribute() && !client->asyncAttributeValue() && | 431 if (m_client->hasSourceAttribute() && !m_client->asyncAttributeValue() && |
| 436 !m_nonBlocking) { | 432 !m_nonBlocking) { |
| 437 // "Add the element to the end of the list of scripts that will execute | 433 // "Add the element to the end of the list of scripts that will execute |
| 438 // in order as soon as possible associated with the node document of the | 434 // in order as soon as possible associated with the node document of the |
| 439 // script element at the time the prepare a script algorithm started." | 435 // script element at the time the prepare a script algorithm started." |
| 440 m_pendingScript = PendingScript::create(m_element, m_resource.get()); | 436 m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
| 441 m_asyncExecType = ScriptRunner::InOrder; | 437 m_asyncExecType = ScriptRunner::InOrder; |
| 442 // TODO(hiroshige): Here |contextDocument| is used as "node document" | 438 // TODO(hiroshige): Here |contextDocument| is used as "node document" |
| 443 // while Step 14 uses |elementDocument| as "node document". Fix this. | 439 // while Step 14 uses |elementDocument| as "node document". Fix this. |
| 444 contextDocument->scriptRunner()->queueScriptForExecution(this, | 440 contextDocument->scriptRunner()->queueScriptForExecution(this, |
| 445 m_asyncExecType); | 441 m_asyncExecType); |
| 446 // Note that watchForLoad can immediately call pendingScriptFinished. | 442 // Note that watchForLoad can immediately call pendingScriptFinished. |
| 447 m_pendingScript->watchForLoad(this); | 443 m_pendingScript->watchForLoad(this); |
| 448 // The part "When the script is ready..." is implemented in | 444 // The part "When the script is ready..." is implemented in |
| 449 // ScriptRunner::notifyScriptReady(). | 445 // ScriptRunner::notifyScriptReady(). |
| 450 // TODO(hiroshige): Annotate it. | 446 // TODO(hiroshige): Annotate it. |
| 451 | 447 |
| 452 return true; | 448 return true; |
| 453 } | 449 } |
| 454 | 450 |
| 455 // 4th Clause: | 451 // 4th Clause: |
| 456 // - "If the script's type is "classic", and the element has a src attribute" | 452 // - "If the script's type is "classic", and the element has a src attribute" |
| 457 // TODO(hiroshige): Check the script's type and implement "module" case. | 453 // TODO(hiroshige): Check the script's type and implement "module" case. |
| 458 if (client->hasSourceAttribute()) { | 454 if (m_client->hasSourceAttribute()) { |
| 459 // "The element must be added to the set of scripts that will execute | 455 // "The element must be added to the set of scripts that will execute |
| 460 // as soon as possible of the node document of the script element at the | 456 // as soon as possible of the node document of the script element at the |
| 461 // time the prepare a script algorithm started." | 457 // time the prepare a script algorithm started." |
| 462 m_pendingScript = PendingScript::create(m_element, m_resource.get()); | 458 m_pendingScript = PendingScript::create(m_client.get(), m_resource.get()); |
| 463 m_asyncExecType = ScriptRunner::Async; | 459 m_asyncExecType = ScriptRunner::Async; |
| 464 LocalFrame* frame = m_element->document().frame(); | 460 LocalFrame* frame = m_client->document().frame(); |
| 465 if (frame) { | 461 if (frame) { |
| 466 ScriptState* scriptState = ScriptState::forMainWorld(frame); | 462 ScriptState* scriptState = ScriptState::forMainWorld(frame); |
| 467 if (scriptState) | 463 if (scriptState) |
| 468 ScriptStreamer::startStreaming( | 464 ScriptStreamer::startStreaming( |
| 469 m_pendingScript.get(), ScriptStreamer::Async, frame->settings(), | 465 m_pendingScript.get(), ScriptStreamer::Async, frame->settings(), |
| 470 scriptState, frame->frameScheduler()->loadingTaskRunner()); | 466 scriptState, frame->frameScheduler()->loadingTaskRunner()); |
| 471 } | 467 } |
| 472 // TODO(hiroshige): Here |contextDocument| is used as "node document" | 468 // TODO(hiroshige): Here |contextDocument| is used as "node document" |
| 473 // while Step 14 uses |elementDocument| as "node document". Fix this. | 469 // while Step 14 uses |elementDocument| as "node document". Fix this. |
| 474 contextDocument->scriptRunner()->queueScriptForExecution(this, | 470 contextDocument->scriptRunner()->queueScriptForExecution(this, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 return false; | 502 return false; |
| 507 } | 503 } |
| 508 | 504 |
| 509 return true; | 505 return true; |
| 510 } | 506 } |
| 511 | 507 |
| 512 // Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script | 508 // Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script |
| 513 bool ScriptLoader::fetchScript(const String& sourceUrl, | 509 bool ScriptLoader::fetchScript(const String& sourceUrl, |
| 514 const String& encoding, | 510 const String& encoding, |
| 515 FetchRequest::DeferOption defer) { | 511 FetchRequest::DeferOption defer) { |
| 516 DCHECK(m_element); | 512 Document* elementDocument = &(m_client->document()); |
| 517 | 513 if (!m_client->isConnected() || m_client->document() != elementDocument) |
| 518 Document* elementDocument = &(m_element->document()); | |
| 519 if (!m_element->isConnected() || m_element->document() != elementDocument) | |
| 520 return false; | 514 return false; |
| 521 | 515 |
| 522 DCHECK(!m_resource); | 516 DCHECK(!m_resource); |
| 523 // 21. "If the element has a src content attribute, run these substeps:" | 517 // 21. "If the element has a src content attribute, run these substeps:" |
| 524 if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { | 518 if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { |
| 525 // 21.4. "Parse src relative to the element's node document." | 519 // 21.4. "Parse src relative to the element's node document." |
| 526 FetchRequest request( | 520 FetchRequest request( |
| 527 ResourceRequest(elementDocument->completeURL(sourceUrl)), | 521 ResourceRequest(elementDocument->completeURL(sourceUrl)), |
| 528 m_element->localName()); | 522 m_client->initiatorName()); |
| 529 | 523 |
| 530 // 15. "Let CORS setting be the current state of the element's | 524 // 15. "Let CORS setting be the current state of the element's |
| 531 // crossorigin content attribute." | 525 // crossorigin content attribute." |
| 532 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue( | 526 CrossOriginAttributeValue crossOrigin = |
| 533 m_element->fastGetAttribute(HTMLNames::crossoriginAttr)); | 527 crossOriginAttributeValue(m_client->crossOriginAttributeValue()); |
| 534 | 528 |
| 535 // 16. "Let module script credentials mode be determined by switching | 529 // 16. "Let module script credentials mode be determined by switching |
| 536 // on CORS setting:" | 530 // on CORS setting:" |
| 537 // TODO(hiroshige): Implement this step for "module". | 531 // TODO(hiroshige): Implement this step for "module". |
| 538 | 532 |
| 539 // 21.6, "classic": "Fetch a classic script given ... CORS setting | 533 // 21.6, "classic": "Fetch a classic script given ... CORS setting |
| 540 // ... and encoding." | 534 // ... and encoding." |
| 541 if (crossOrigin != CrossOriginAttributeNotSet) | 535 if (crossOrigin != CrossOriginAttributeNotSet) |
| 542 request.setCrossOriginAccessControl(elementDocument->getSecurityOrigin(), | 536 request.setCrossOriginAccessControl(elementDocument->getSecurityOrigin(), |
| 543 crossOrigin); | 537 crossOrigin); |
| 544 | 538 |
| 545 request.setCharset(encoding); | 539 request.setCharset(encoding); |
| 546 | 540 |
| 547 // 17. "If the script element has a nonce attribute, | 541 // 17. "If the script element has a nonce attribute, |
| 548 // then let cryptographic nonce be that attribute's value. | 542 // then let cryptographic nonce be that attribute's value. |
| 549 // Otherwise, let cryptographic nonce be the empty string." | 543 // Otherwise, let cryptographic nonce be the empty string." |
| 550 if (ContentSecurityPolicy::isNonceableElement(m_element.get())) | 544 if (m_client->isNonceableElement()) |
| 551 request.setContentSecurityPolicyNonce(client()->nonce()); | 545 request.setContentSecurityPolicyNonce(m_client->nonce()); |
| 552 | 546 |
| 553 // 19. "Let parser state be "parser-inserted" | 547 // 19. "Let parser state be "parser-inserted" |
| 554 // if the script element has been flagged as "parser-inserted", | 548 // if the script element has been flagged as "parser-inserted", |
| 555 // and "not parser-inserted" otherwise." | 549 // and "not parser-inserted" otherwise." |
| 556 request.setParserDisposition(isParserInserted() ? ParserInserted | 550 request.setParserDisposition(isParserInserted() ? ParserInserted |
| 557 : NotParserInserted); | 551 : NotParserInserted); |
| 558 | 552 |
| 559 request.setDefer(defer); | 553 request.setDefer(defer); |
| 560 | 554 |
| 561 // 18. "If the script element has an integrity attribute, | 555 // 18. "If the script element has an integrity attribute, |
| 562 // then let integrity metadata be that attribute's value. | 556 // then let integrity metadata be that attribute's value. |
| 563 // Otherwise, let integrity metadata be the empty string." | 557 // Otherwise, let integrity metadata be the empty string." |
| 564 String integrityAttr = | 558 String integrityAttr = m_client->integrityAttributeValue(); |
| 565 m_element->fastGetAttribute(HTMLNames::integrityAttr); | |
| 566 if (!integrityAttr.isEmpty()) { | 559 if (!integrityAttr.isEmpty()) { |
| 567 IntegrityMetadataSet metadataSet; | 560 IntegrityMetadataSet metadataSet; |
| 568 SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet, | 561 SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet, |
| 569 elementDocument); | 562 elementDocument); |
| 570 request.setIntegrityMetadata(metadataSet); | 563 request.setIntegrityMetadata(metadataSet); |
| 571 } | 564 } |
| 572 | 565 |
| 573 // [Intervention] | 566 // [Intervention] |
| 574 if (m_documentWriteIntervention == | 567 if (m_documentWriteIntervention == |
| 575 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { | 568 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 618 if (m_createdDuringDocumentWrite && | 611 if (m_createdDuringDocumentWrite && |
| 619 m_resource->resourceRequest().getCachePolicy() == | 612 m_resource->resourceRequest().getCachePolicy() == |
| 620 WebCachePolicy::ReturnCacheDataDontLoad) { | 613 WebCachePolicy::ReturnCacheDataDontLoad) { |
| 621 m_documentWriteIntervention = | 614 m_documentWriteIntervention = |
| 622 DocumentWriteIntervention::DoNotFetchDocWrittenScript; | 615 DocumentWriteIntervention::DoNotFetchDocWrittenScript; |
| 623 } | 616 } |
| 624 | 617 |
| 625 return true; | 618 return true; |
| 626 } | 619 } |
| 627 | 620 |
| 628 bool isHTMLScriptLoader(Element* element) { | |
| 629 DCHECK(element); | |
| 630 return isHTMLScriptElement(*element); | |
| 631 } | |
| 632 | |
| 633 bool isSVGScriptLoader(Element* element) { | |
| 634 DCHECK(element); | |
| 635 return isSVGScriptElement(*element); | |
| 636 } | |
| 637 | |
| 638 void ScriptLoader::logScriptMIMEType(LocalFrame* frame, | 621 void ScriptLoader::logScriptMIMEType(LocalFrame* frame, |
| 639 ScriptResource* resource, | 622 ScriptResource* resource, |
| 640 const String& mimeType) { | 623 const String& mimeType) { |
| 641 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)) | 624 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)) |
| 642 return; | 625 return; |
| 643 bool isText = mimeType.startsWith("text/", TextCaseASCIIInsensitive); | 626 bool isText = mimeType.startsWith("text/", TextCaseASCIIInsensitive); |
| 644 if (isText && isLegacySupportedJavaScriptLanguage(mimeType.substring(5))) | 627 if (isText && isLegacySupportedJavaScriptLanguage(mimeType.substring(5))) |
| 645 return; | 628 return; |
| 646 bool isSameOrigin = | 629 bool isSameOrigin = |
| 647 m_element->document().getSecurityOrigin()->canRequest(resource->url()); | 630 m_client->document().getSecurityOrigin()->canRequest(resource->url()); |
| 648 bool isApplication = | 631 bool isApplication = |
| 649 !isText && mimeType.startsWith("application/", TextCaseASCIIInsensitive); | 632 !isText && mimeType.startsWith("application/", TextCaseASCIIInsensitive); |
| 650 | 633 |
| 651 UseCounter::Feature feature = | 634 UseCounter::Feature feature = |
| 652 isSameOrigin | 635 isSameOrigin |
| 653 ? (isText ? UseCounter::SameOriginTextScript | 636 ? (isText ? UseCounter::SameOriginTextScript |
| 654 : isApplication ? UseCounter::SameOriginApplicationScript | 637 : isApplication ? UseCounter::SameOriginApplicationScript |
| 655 : UseCounter::SameOriginOtherScript) | 638 : UseCounter::SameOriginOtherScript) |
| 656 : (isText ? UseCounter::CrossOriginTextScript | 639 : (isText ? UseCounter::CrossOriginTextScript |
| 657 : isApplication ? UseCounter::CrossOriginApplicationScript | 640 : isApplication ? UseCounter::CrossOriginApplicationScript |
| 658 : UseCounter::CrossOriginOtherScript); | 641 : UseCounter::CrossOriginOtherScript); |
| 659 | 642 |
| 660 UseCounter::count(frame, feature); | 643 UseCounter::count(frame, feature); |
| 661 } | 644 } |
| 662 | 645 |
| 663 bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) { | 646 bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) { |
| 664 double scriptExecStartTime = monotonicallyIncreasingTime(); | 647 double scriptExecStartTime = monotonicallyIncreasingTime(); |
| 665 bool result = doExecuteScript(sourceCode); | 648 bool result = doExecuteScript(sourceCode); |
| 666 | 649 |
| 667 // NOTE: we do not check m_willBeParserExecuted here, since | 650 // NOTE: we do not check m_willBeParserExecuted here, since |
| 668 // m_willBeParserExecuted is false for inline scripts, and we want to | 651 // m_willBeParserExecuted is false for inline scripts, and we want to |
| 669 // include inline script execution time as part of parser blocked script | 652 // include inline script execution time as part of parser blocked script |
| 670 // execution time. | 653 // execution time. |
| 671 if (m_asyncExecType == ScriptRunner::None) | 654 if (m_asyncExecType == ScriptRunner::None) |
| 672 DocumentParserTiming::from(m_element->document()) | 655 DocumentParserTiming::from(m_client->document()) |
| 673 .recordParserBlockedOnScriptExecutionDuration( | 656 .recordParserBlockedOnScriptExecutionDuration( |
| 674 monotonicallyIncreasingTime() - scriptExecStartTime, | 657 monotonicallyIncreasingTime() - scriptExecStartTime, |
| 675 wasCreatedDuringDocumentWrite()); | 658 wasCreatedDuringDocumentWrite()); |
| 676 return result; | 659 return result; |
| 677 } | 660 } |
| 678 | 661 |
| 679 // https://html.spec.whatwg.org/#execute-the-script-block | 662 // https://html.spec.whatwg.org/#execute-the-script-block |
| 680 // with additional support for HTML imports. | 663 // with additional support for HTML imports. |
| 681 // Note that Steps 2 and 8 must be handled by the caller of doExecuteScript(), | 664 // Note that Steps 2 and 8 must be handled by the caller of doExecuteScript(), |
| 682 // i.e. load/error events are dispatched by the caller. | 665 // i.e. load/error events are dispatched by the caller. |
| 683 // Steps 3--7 are implemented here in doExecuteScript(). | 666 // Steps 3--7 are implemented here in doExecuteScript(). |
| 684 // TODO(hiroshige): Move event dispatching code to doExecuteScript(). | 667 // TODO(hiroshige): Move event dispatching code to doExecuteScript(). |
| 685 bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { | 668 bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) { |
| 686 DCHECK(m_alreadyStarted); | 669 DCHECK(m_alreadyStarted); |
| 687 | 670 |
| 688 if (sourceCode.isEmpty()) | 671 if (sourceCode.isEmpty()) |
| 689 return true; | 672 return true; |
| 690 | 673 |
| 691 Document* elementDocument = &(m_element->document()); | 674 Document* elementDocument = &(m_client->document()); |
| 692 Document* contextDocument = elementDocument->contextDocument(); | 675 Document* contextDocument = elementDocument->contextDocument(); |
| 693 if (!contextDocument) | 676 if (!contextDocument) |
| 694 return true; | 677 return true; |
| 695 | 678 |
| 696 LocalFrame* frame = contextDocument->frame(); | 679 LocalFrame* frame = contextDocument->frame(); |
| 697 if (!frame) | 680 if (!frame) |
| 698 return true; | 681 return true; |
| 699 | 682 |
| 700 const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy(); | 683 const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy(); |
| 701 bool shouldBypassMainWorldCSP = | 684 bool shouldBypassMainWorldCSP = |
| 702 (frame->script().shouldBypassMainWorldCSP()) || | 685 (frame->script().shouldBypassMainWorldCSP()) || |
| 703 csp->allowScriptWithHash(sourceCode.source(), | 686 csp->allowScriptWithHash(sourceCode.source(), |
| 704 ContentSecurityPolicy::InlineType::Block); | 687 ContentSecurityPolicy::InlineType::Block); |
| 705 | 688 |
| 706 AtomicString nonce = | 689 AtomicString nonce = |
| 707 ContentSecurityPolicy::isNonceableElement(m_element.get()) | 690 m_client->isNonceableElement() ? m_client->nonce() : nullAtom; |
| 708 ? client()->nonce() | 691 if (!m_isExternalScript && !shouldBypassMainWorldCSP && |
| 709 : nullAtom; | 692 !m_client->allowInlineScriptForCSP(nonce, m_startLineNumber, |
| 710 if (!m_isExternalScript && | 693 sourceCode.source())) { |
| 711 (!shouldBypassMainWorldCSP && | |
| 712 !csp->allowInlineScript(m_element, elementDocument->url(), nonce, | |
| 713 m_startLineNumber, sourceCode.source()))) { | |
| 714 return false; | 694 return false; |
| 715 } | 695 } |
| 716 | 696 |
| 717 if (m_isExternalScript) { | 697 if (m_isExternalScript) { |
| 718 ScriptResource* resource = | 698 ScriptResource* resource = |
| 719 m_resource ? m_resource.get() : sourceCode.resource(); | 699 m_resource ? m_resource.get() : sourceCode.resource(); |
| 720 if (resource) { | 700 if (resource) { |
| 721 if (!ScriptResource::mimeTypeAllowedByNosniff(resource->response())) { | 701 if (!ScriptResource::mimeTypeAllowedByNosniff(resource->response())) { |
| 722 contextDocument->addConsoleMessage(ConsoleMessage::create( | 702 contextDocument->addConsoleMessage(ConsoleMessage::create( |
| 723 SecurityMessageSource, ErrorMessageLevel, | 703 SecurityMessageSource, ErrorMessageLevel, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 if (!m_isExternalScript) { | 736 if (!m_isExternalScript) { |
| 757 accessControlStatus = SharableCrossOrigin; | 737 accessControlStatus = SharableCrossOrigin; |
| 758 } else if (sourceCode.resource()) { | 738 } else if (sourceCode.resource()) { |
| 759 if (sourceCode.resource()->response().wasFetchedViaServiceWorker()) { | 739 if (sourceCode.resource()->response().wasFetchedViaServiceWorker()) { |
| 760 if (sourceCode.resource()->response().serviceWorkerResponseType() == | 740 if (sourceCode.resource()->response().serviceWorkerResponseType() == |
| 761 WebServiceWorkerResponseTypeOpaque) | 741 WebServiceWorkerResponseTypeOpaque) |
| 762 accessControlStatus = OpaqueResource; | 742 accessControlStatus = OpaqueResource; |
| 763 else | 743 else |
| 764 accessControlStatus = SharableCrossOrigin; | 744 accessControlStatus = SharableCrossOrigin; |
| 765 } else if (sourceCode.resource()->passesAccessControlCheck( | 745 } else if (sourceCode.resource()->passesAccessControlCheck( |
| 766 m_element->document().getSecurityOrigin())) { | 746 m_client->document().getSecurityOrigin())) { |
| 767 accessControlStatus = SharableCrossOrigin; | 747 accessControlStatus = SharableCrossOrigin; |
| 768 } | 748 } |
| 769 } | 749 } |
| 770 | 750 |
| 771 const bool isImportedScript = contextDocument != elementDocument; | 751 const bool isImportedScript = contextDocument != elementDocument; |
| 772 | 752 |
| 773 // 3. "If the script is from an external file, | 753 // 3. "If the script is from an external file, |
| 774 // or the script's type is module", | 754 // or the script's type is module", |
| 775 // then increment the ignore-destructive-writes counter of the | 755 // then increment the ignore-destructive-writes counter of the |
| 776 // script element's node document. Let neutralized doc be that Document." | 756 // script element's node document. Let neutralized doc be that Document." |
| 777 // TODO(hiroshige): Implement "module" case. | 757 // TODO(hiroshige): Implement "module" case. |
| 778 IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer( | 758 IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer( |
| 779 m_isExternalScript || isImportedScript ? contextDocument : 0); | 759 m_isExternalScript || isImportedScript ? contextDocument : 0); |
| 780 | 760 |
| 781 // 4. "Let old script element be the value to which the script element's | 761 // 4. "Let old script element be the value to which the script element's |
| 782 // node document's currentScript object was most recently set." | 762 // node document's currentScript object was most recently set." |
| 783 // This is implemented as push/popCurrentScript(). | 763 // This is implemented as push/popCurrentScript(). |
| 784 | 764 |
| 785 // 5. "Switch on the script's type:" | 765 // 5. "Switch on the script's type:" |
| 786 // - "classic": | 766 // - "classic": |
| 787 // 1. "If the script element's root is not a shadow root, | 767 // 1. "If the script element's root is not a shadow root, |
| 788 // then set the script element's node document's currentScript | 768 // then set the script element's node document's currentScript |
| 789 // attribute to the script element. Otherwise, set it to null." | 769 // attribute to the script element. Otherwise, set it to null." |
| 790 if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) | 770 contextDocument->pushCurrentScript(m_client.get()); |
| 791 contextDocument->pushCurrentScript(m_element); | |
| 792 | 771 |
| 793 // 2. "Run the classic script given by the script's script." | 772 // 2. "Run the classic script given by the script's script." |
| 794 // Note: This is where the script is compiled and actually executed. | 773 // Note: This is where the script is compiled and actually executed. |
| 795 frame->script().executeScriptInMainWorld(sourceCode, accessControlStatus); | 774 frame->script().executeScriptInMainWorld(sourceCode, accessControlStatus); |
| 796 | 775 |
| 797 // - "module": | 776 // - "module": |
| 798 // TODO(hiroshige): Implement this. | 777 // TODO(hiroshige): Implement this. |
| 799 | 778 |
| 800 // 6. "Set the script element's node document's currentScript attribute | 779 // 6. "Set the script element's node document's currentScript attribute |
| 801 // to old script element." | 780 // to old script element." |
| 802 if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) { | 781 contextDocument->popCurrentScript(m_client.get()); |
| 803 DCHECK(contextDocument->currentScript() == m_element); | |
| 804 contextDocument->popCurrentScript(); | |
| 805 } | |
| 806 | 782 |
| 807 return true; | 783 return true; |
| 808 | 784 |
| 809 // 7. "Decrement the ignore-destructive-writes counter of neutralized doc, | 785 // 7. "Decrement the ignore-destructive-writes counter of neutralized doc, |
| 810 // if it was incremented in the earlier step." | 786 // if it was incremented in the earlier step." |
| 811 // Implemented as the scope out of IgnoreDestructiveWriteCountIncrementer. | 787 // Implemented as the scope out of IgnoreDestructiveWriteCountIncrementer. |
| 812 } | 788 } |
| 813 | 789 |
| 814 void ScriptLoader::execute() { | 790 void ScriptLoader::execute() { |
| 815 DCHECK(!m_willBeParserExecuted); | 791 DCHECK(!m_willBeParserExecuted); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 840 // cache for subsequent uses. | 816 // cache for subsequent uses. |
| 841 if (m_documentWriteIntervention == | 817 if (m_documentWriteIntervention == |
| 842 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { | 818 DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) { |
| 843 memoryCache()->remove(m_pendingScript->resource()); | 819 memoryCache()->remove(m_pendingScript->resource()); |
| 844 m_pendingScript->stopWatchingForLoad(); | 820 m_pendingScript->stopWatchingForLoad(); |
| 845 return; | 821 return; |
| 846 } | 822 } |
| 847 | 823 |
| 848 DCHECK(m_asyncExecType != ScriptRunner::None); | 824 DCHECK(m_asyncExecType != ScriptRunner::None); |
| 849 | 825 |
| 850 Document* contextDocument = m_element->document().contextDocument(); | 826 Document* contextDocument = m_client->document().contextDocument(); |
| 851 if (!contextDocument) { | 827 if (!contextDocument) { |
| 852 detachPendingScript(); | 828 detachPendingScript(); |
| 853 return; | 829 return; |
| 854 } | 830 } |
| 855 | 831 |
| 856 if (errorOccurred()) { | 832 if (errorOccurred()) { |
| 857 contextDocument->scriptRunner()->notifyScriptLoadError(this, | 833 contextDocument->scriptRunner()->notifyScriptLoadError(this, |
| 858 m_asyncExecType); | 834 m_asyncExecType); |
| 859 detachPendingScript(); | 835 detachPendingScript(); |
| 860 dispatchErrorEvent(); | 836 dispatchErrorEvent(); |
| 861 return; | 837 return; |
| 862 } | 838 } |
| 863 contextDocument->scriptRunner()->notifyScriptReady(this, m_asyncExecType); | 839 contextDocument->scriptRunner()->notifyScriptReady(this, m_asyncExecType); |
| 864 m_pendingScript->stopWatchingForLoad(); | 840 m_pendingScript->stopWatchingForLoad(); |
| 865 } | 841 } |
| 866 | 842 |
| 867 bool ScriptLoader::ignoresLoadRequest() const { | 843 bool ScriptLoader::ignoresLoadRequest() const { |
| 868 return m_alreadyStarted || m_isExternalScript || m_parserInserted || | 844 return m_alreadyStarted || m_isExternalScript || m_parserInserted || |
| 869 !element() || !element()->isConnected(); | 845 !m_client->isConnected(); |
| 870 } | 846 } |
| 871 | 847 |
| 872 // Step 13 of https://html.spec.whatwg.org/#prepare-a-script | 848 // Step 13 of https://html.spec.whatwg.org/#prepare-a-script |
| 873 bool ScriptLoader::isScriptForEventSupported() const { | 849 bool ScriptLoader::isScriptForEventSupported() const { |
| 874 // 1. "Let for be the value of the for attribute." | 850 // 1. "Let for be the value of the for attribute." |
| 875 String eventAttribute = client()->eventAttributeValue(); | 851 String eventAttribute = m_client->eventAttributeValue(); |
| 876 // 2. "Let event be the value of the event attribute." | 852 // 2. "Let event be the value of the event attribute." |
| 877 String forAttribute = client()->forAttributeValue(); | 853 String forAttribute = m_client->forAttributeValue(); |
| 878 | 854 |
| 879 // "If the script element has an event attribute and a for attribute, and | 855 // "If the script element has an event attribute and a for attribute, and |
| 880 // the script's type is "classic", then run these substeps:" | 856 // the script's type is "classic", then run these substeps:" |
| 881 // TODO(hiroshige): Check the script's type. | 857 // TODO(hiroshige): Check the script's type. |
| 882 if (eventAttribute.isNull() || forAttribute.isNull()) | 858 if (eventAttribute.isNull() || forAttribute.isNull()) |
| 883 return true; | 859 return true; |
| 884 | 860 |
| 885 // 3. "Strip leading and trailing ASCII whitespace from event and for." | 861 // 3. "Strip leading and trailing ASCII whitespace from event and for." |
| 886 forAttribute = forAttribute.stripWhiteSpace(); | 862 forAttribute = forAttribute.stripWhiteSpace(); |
| 887 // 4. "If for is not an ASCII case-insensitive match for the string | 863 // 4. "If for is not an ASCII case-insensitive match for the string |
| 888 // "window", | 864 // "window", |
| 889 // then abort these steps at this point. The script is not executed." | 865 // then abort these steps at this point. The script is not executed." |
| 890 if (!equalIgnoringCase(forAttribute, "window")) | 866 if (!equalIgnoringCase(forAttribute, "window")) |
| 891 return false; | 867 return false; |
| 892 eventAttribute = eventAttribute.stripWhiteSpace(); | 868 eventAttribute = eventAttribute.stripWhiteSpace(); |
| 893 // 5. "If event is not an ASCII case-insensitive match for either the | 869 // 5. "If event is not an ASCII case-insensitive match for either the |
| 894 // string "onload" or the string "onload()", | 870 // string "onload" or the string "onload()", |
| 895 // then abort these steps at this point. The script is not executed. | 871 // then abort these steps at this point. The script is not executed. |
| 896 return equalIgnoringCase(eventAttribute, "onload") || | 872 return equalIgnoringCase(eventAttribute, "onload") || |
| 897 equalIgnoringCase(eventAttribute, "onload()"); | 873 equalIgnoringCase(eventAttribute, "onload()"); |
| 898 } | 874 } |
| 899 | 875 |
| 900 String ScriptLoader::scriptContent() const { | 876 String ScriptLoader::scriptContent() const { |
| 901 return m_element->textFromChildren(); | 877 return m_client->textFromChildren(); |
| 902 } | |
| 903 | |
| 904 ScriptLoaderClient* ScriptLoader::client() const { | |
| 905 if (isHTMLScriptLoader(m_element)) | |
| 906 return toHTMLScriptElement(m_element); | |
| 907 | |
| 908 if (isSVGScriptLoader(m_element)) | |
| 909 return toSVGScriptElement(m_element); | |
| 910 | |
| 911 NOTREACHED(); | |
| 912 return 0; | |
| 913 } | |
| 914 | |
| 915 ScriptLoader* toScriptLoaderIfPossible(Element* element) { | |
| 916 if (isHTMLScriptLoader(element)) | |
| 917 return toHTMLScriptElement(element)->loader(); | |
| 918 | |
| 919 if (isSVGScriptLoader(element)) | |
| 920 return toSVGScriptElement(element)->loader(); | |
| 921 | |
| 922 return 0; | |
| 923 } | 878 } |
| 924 | 879 |
| 925 } // namespace blink | 880 } // namespace blink |
| OLD | NEW |