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 |