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 11 matching lines...) Expand all Loading... |
22 * Boston, MA 02110-1301, USA. | 22 * Boston, MA 02110-1301, USA. |
23 */ | 23 */ |
24 | 24 |
25 #include "core/dom/ScriptLoader.h" | 25 #include "core/dom/ScriptLoader.h" |
26 | 26 |
27 #include "bindings/core/v8/ScriptController.h" | 27 #include "bindings/core/v8/ScriptController.h" |
28 #include "bindings/core/v8/ScriptSourceCode.h" | 28 #include "bindings/core/v8/ScriptSourceCode.h" |
29 #include "bindings/core/v8/V8Binding.h" | 29 #include "bindings/core/v8/V8Binding.h" |
30 #include "core/HTMLNames.h" | 30 #include "core/HTMLNames.h" |
31 #include "core/SVGNames.h" | 31 #include "core/SVGNames.h" |
| 32 #include "core/dom/ClassicPendingScript.h" |
32 #include "core/dom/ClassicScript.h" | 33 #include "core/dom/ClassicScript.h" |
33 #include "core/dom/Document.h" | 34 #include "core/dom/Document.h" |
34 #include "core/dom/DocumentParserTiming.h" | 35 #include "core/dom/DocumentParserTiming.h" |
35 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" | 36 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" |
| 37 #include "core/dom/Modulator.h" |
| 38 #include "core/dom/ModulePendingScript.h" |
36 #include "core/dom/Script.h" | 39 #include "core/dom/Script.h" |
37 #include "core/dom/ScriptElementBase.h" | 40 #include "core/dom/ScriptElementBase.h" |
38 #include "core/dom/ScriptRunner.h" | 41 #include "core/dom/ScriptRunner.h" |
39 #include "core/dom/ScriptableDocumentParser.h" | 42 #include "core/dom/ScriptableDocumentParser.h" |
40 #include "core/dom/Text.h" | 43 #include "core/dom/Text.h" |
41 #include "core/events/Event.h" | 44 #include "core/events/Event.h" |
42 #include "core/frame/LocalFrame.h" | 45 #include "core/frame/LocalFrame.h" |
43 #include "core/frame/SubresourceIntegrity.h" | 46 #include "core/frame/SubresourceIntegrity.h" |
44 #include "core/frame/csp/ContentSecurityPolicy.h" | 47 #include "core/frame/csp/ContentSecurityPolicy.h" |
45 #include "core/html/CrossOriginAttribute.h" | |
46 #include "core/html/imports/HTMLImport.h" | 48 #include "core/html/imports/HTMLImport.h" |
47 #include "core/html/parser/HTMLParserIdioms.h" | 49 #include "core/html/parser/HTMLParserIdioms.h" |
| 50 #include "core/loader/modulescript/ModuleScriptFetchRequest.h" |
| 51 #include "core/loader/resource/ScriptResource.h" |
48 #include "platform/WebFrameScheduler.h" | 52 #include "platform/WebFrameScheduler.h" |
49 #include "platform/loader/fetch/AccessControlStatus.h" | 53 #include "platform/loader/fetch/AccessControlStatus.h" |
50 #include "platform/loader/fetch/FetchParameters.h" | 54 #include "platform/loader/fetch/FetchParameters.h" |
51 #include "platform/loader/fetch/MemoryCache.h" | |
52 #include "platform/loader/fetch/ResourceFetcher.h" | 55 #include "platform/loader/fetch/ResourceFetcher.h" |
53 #include "platform/network/mime/MIMETypeRegistry.h" | 56 #include "platform/network/mime/MIMETypeRegistry.h" |
54 #include "platform/weborigin/SecurityOrigin.h" | 57 #include "platform/weborigin/SecurityOrigin.h" |
55 #include "platform/wtf/StdLibExtras.h" | 58 #include "platform/wtf/StdLibExtras.h" |
56 #include "platform/wtf/text/StringBuilder.h" | 59 #include "platform/wtf/text/StringBuilder.h" |
57 #include "platform/wtf/text/StringHash.h" | 60 #include "platform/wtf/text/StringHash.h" |
58 #include "public/platform/WebCachePolicy.h" | 61 #include "public/platform/WebCachePolicy.h" |
59 | 62 |
60 namespace blink { | 63 namespace blink { |
61 | 64 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 element_->GetDocument().GetScriptableDocumentParser()->LineNumber(); | 103 element_->GetDocument().GetScriptableDocumentParser()->LineNumber(); |
101 } | 104 } |
102 } | 105 } |
103 | 106 |
104 ScriptLoader::~ScriptLoader() {} | 107 ScriptLoader::~ScriptLoader() {} |
105 | 108 |
106 DEFINE_TRACE(ScriptLoader) { | 109 DEFINE_TRACE(ScriptLoader) { |
107 visitor->Trace(element_); | 110 visitor->Trace(element_); |
108 visitor->Trace(resource_); | 111 visitor->Trace(resource_); |
109 visitor->Trace(pending_script_); | 112 visitor->Trace(pending_script_); |
| 113 visitor->Trace(module_tree_client_); |
110 PendingScriptClient::Trace(visitor); | 114 PendingScriptClient::Trace(visitor); |
111 } | 115 } |
112 | 116 |
113 void ScriptLoader::SetFetchDocWrittenScriptDeferIdle() { | 117 void ScriptLoader::SetFetchDocWrittenScriptDeferIdle() { |
114 DCHECK(!created_during_document_write_); | 118 DCHECK(!created_during_document_write_); |
115 document_write_intervention_ = | 119 document_write_intervention_ = |
116 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle; | 120 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle; |
117 } | 121 } |
118 | 122 |
119 void ScriptLoader::DidNotifySubtreeInsertionsToDocument() { | 123 void ScriptLoader::DidNotifySubtreeInsertionsToDocument() { |
(...skipping 30 matching lines...) Expand all Loading... |
150 | 154 |
151 void ScriptLoader::DispatchErrorEvent() { | 155 void ScriptLoader::DispatchErrorEvent() { |
152 element_->DispatchErrorEvent(); | 156 element_->DispatchErrorEvent(); |
153 } | 157 } |
154 | 158 |
155 void ScriptLoader::DispatchLoadEvent() { | 159 void ScriptLoader::DispatchLoadEvent() { |
156 element_->DispatchLoadEvent(); | 160 element_->DispatchLoadEvent(); |
157 SetHaveFiredLoadEvent(true); | 161 SetHaveFiredLoadEvent(true); |
158 } | 162 } |
159 | 163 |
160 bool ScriptLoader::IsValidScriptTypeAndLanguage( | 164 namespace { |
| 165 |
| 166 bool IsValidClassicScriptTypeAndLanguage( |
161 const String& type, | 167 const String& type, |
162 const String& language, | 168 const String& language, |
163 LegacyTypeSupport support_legacy_types) { | 169 ScriptLoader::LegacyTypeSupport support_legacy_types) { |
164 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used | 170 // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used |
165 // here to maintain backwards compatibility with existing layout tests. The | 171 // here to maintain backwards compatibility with existing layout tests. The |
166 // specific violations are: | 172 // specific violations are: |
167 // - Allowing type=javascript. type= should only support MIME types, such as | 173 // - Allowing type=javascript. type= should only support MIME types, such as |
168 // text/javascript. | 174 // text/javascript. |
169 // - Allowing a different set of languages for language= and type=. language= | 175 // - Allowing a different set of languages for language= and type=. language= |
170 // supports Javascript 1.1 and 1.4-1.6, but type= does not. | 176 // supports Javascript 1.1 and 1.4-1.6, but type= does not. |
171 if (type.IsEmpty()) { | 177 if (type.IsEmpty()) { |
172 return language.IsEmpty() || // assume text/javascript. | 178 return language.IsEmpty() || // assume text/javascript. |
173 MIMETypeRegistry::IsSupportedJavaScriptMIMEType("text/" + | 179 MIMETypeRegistry::IsSupportedJavaScriptMIMEType("text/" + |
174 language) || | 180 language) || |
175 MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(language); | 181 MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(language); |
176 } else if (RuntimeEnabledFeatures::moduleScriptsEnabled() && | |
177 type == "module") { | |
178 return true; | |
179 } else if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType( | 182 } else if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType( |
180 type.StripWhiteSpace()) || | 183 type.StripWhiteSpace()) || |
181 (support_legacy_types == kAllowLegacyTypeInTypeAttribute && | 184 (support_legacy_types == |
| 185 ScriptLoader::kAllowLegacyTypeInTypeAttribute && |
182 MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(type))) { | 186 MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(type))) { |
183 return true; | 187 return true; |
184 } | 188 } |
185 | 189 |
186 return false; | 190 return false; |
187 } | 191 } |
188 | 192 |
189 bool ScriptLoader::IsScriptTypeSupported( | 193 } // namespace |
190 LegacyTypeSupport support_legacy_types) const { | 194 |
| 195 // Step 6 of https://html.spec.whatwg.org/#prepare-a-script |
| 196 bool ScriptLoader::IsValidScriptTypeAndLanguage( |
| 197 const String& type, |
| 198 const String& language, |
| 199 LegacyTypeSupport support_legacy_types, |
| 200 ScriptType& out_script_type) { |
| 201 if (IsValidClassicScriptTypeAndLanguage(type, language, |
| 202 support_legacy_types)) { |
| 203 // - "If the script block's type string is an ASCII case-insensitive match |
| 204 // for any JavaScript MIME type, the script's type is "classic"." |
| 205 // TODO(hiroshige): Annotate and/or cleanup this step. |
| 206 out_script_type = ScriptType::kClassic; |
| 207 return true; |
| 208 } |
| 209 |
| 210 if (RuntimeEnabledFeatures::moduleScriptsEnabled() && type == "module") { |
| 211 // - "If the script block's type string is an ASCII case-insensitive match |
| 212 // for the string "module", the script's type is "module"." |
| 213 out_script_type = ScriptType::kModule; |
| 214 return true; |
| 215 } |
| 216 |
| 217 // - "If neither of the above conditions are true, then abort these steps |
| 218 // at this point. No script is executed." |
| 219 return false; |
| 220 } |
| 221 |
| 222 bool ScriptLoader::IsScriptTypeSupported(LegacyTypeSupport support_legacy_types, |
| 223 ScriptType& out_script_type) const { |
191 return IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(), | 224 return IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(), |
192 element_->LanguageAttributeValue(), | 225 element_->LanguageAttributeValue(), |
193 support_legacy_types); | 226 support_legacy_types, out_script_type); |
194 } | 227 } |
195 | 228 |
196 // https://html.spec.whatwg.org/#prepare-a-script | 229 // https://html.spec.whatwg.org/#prepare-a-script |
197 bool ScriptLoader::PrepareScript(const TextPosition& script_start_position, | 230 bool ScriptLoader::PrepareScript(const TextPosition& script_start_position, |
198 LegacyTypeSupport support_legacy_types) { | 231 LegacyTypeSupport support_legacy_types) { |
199 // 1. "If the script element is marked as having "already started", then | 232 // 1. "If the script element is marked as having "already started", then |
200 // abort these steps at this point. The script is not executed." | 233 // abort these steps at this point. The script is not executed." |
201 if (already_started_) | 234 if (already_started_) |
202 return false; | 235 return false; |
203 | 236 |
(...skipping 20 matching lines...) Expand all Loading... |
224 // FIXME: HTML5 spec says we should check that all children are either | 257 // FIXME: HTML5 spec says we should check that all children are either |
225 // comments or empty text nodes. | 258 // comments or empty text nodes. |
226 if (!element_->HasSourceAttribute() && !element_->HasChildren()) | 259 if (!element_->HasSourceAttribute() && !element_->HasChildren()) |
227 return false; | 260 return false; |
228 | 261 |
229 // 5. "If the element is not connected, then abort these steps. | 262 // 5. "If the element is not connected, then abort these steps. |
230 // The script is not executed." | 263 // The script is not executed." |
231 if (!element_->IsConnected()) | 264 if (!element_->IsConnected()) |
232 return false; | 265 return false; |
233 | 266 |
234 // 6. | 267 // 6. "Determine the script's type as follows:" |
235 // TODO(hiroshige): Annotate and/or cleanup this step. | 268 // |script_type_| is set here. |
236 if (!IsScriptTypeSupported(support_legacy_types)) | 269 if (!IsScriptTypeSupported(support_legacy_types, script_type_)) |
237 return false; | 270 return false; |
238 | 271 |
239 // 7. "If was-parser-inserted is true, | 272 // 7. "If was-parser-inserted is true, |
240 // then flag the element as "parser-inserted" again, | 273 // then flag the element as "parser-inserted" again, |
241 // and set the element's "non-blocking" flag to false." | 274 // and set the element's "non-blocking" flag to false." |
242 if (was_parser_inserted) { | 275 if (was_parser_inserted) { |
243 parser_inserted_ = true; | 276 parser_inserted_ = true; |
244 non_blocking_ = false; | 277 non_blocking_ = false; |
245 } | 278 } |
246 | 279 |
(...skipping 10 matching lines...) Expand all Loading... |
257 if (!element_document.ExecutingFrame()) | 290 if (!element_document.ExecutingFrame()) |
258 return false; | 291 return false; |
259 if (!context_document || !context_document->ExecutingFrame()) | 292 if (!context_document || !context_document->ExecutingFrame()) |
260 return false; | 293 return false; |
261 | 294 |
262 // 10. "If scripting is disabled for the script element, then abort these | 295 // 10. "If scripting is disabled for the script element, then abort these |
263 // steps at this point. The script is not executed." | 296 // steps at this point. The script is not executed." |
264 if (!context_document->CanExecuteScripts(kAboutToExecuteScript)) | 297 if (!context_document->CanExecuteScripts(kAboutToExecuteScript)) |
265 return false; | 298 return false; |
266 | 299 |
| 300 // 11. "If the script element has a nomodule content attribute |
| 301 // and the script's type is "classic", then abort these steps. |
| 302 // The script is not executed." |
| 303 // TODO(japhet): Implement this step. |
| 304 |
267 // 13. | 305 // 13. |
268 if (!IsScriptForEventSupported()) | 306 if (!IsScriptForEventSupported()) |
269 return false; | 307 return false; |
270 | 308 |
271 // 14. "If the script element has a charset attribute, | 309 // 14. is handled below. |
272 // then let encoding be the result of | 310 |
273 // getting an encoding from the value of the charset attribute." | 311 // 15. "Let CORS setting be the current state of the element's |
274 // "If the script element does not have a charset attribute, | 312 // crossorigin content attribute." |
275 // or if getting an encoding failed, let encoding | 313 CrossOriginAttributeValue cross_origin = |
276 // be the same as the encoding of the script element's node document." | 314 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue()); |
277 // TODO(hiroshige): Should we handle failure in getting an encoding? | 315 |
278 String encoding; | 316 // 16. is handled below. |
279 if (!element_->CharsetAttributeValue().IsEmpty()) | 317 |
280 encoding = element_->CharsetAttributeValue(); | 318 // 17. "If the script element has a nonce attribute, |
281 else | 319 // then let cryptographic nonce be that attribute's value. |
282 encoding = element_document.characterSet(); | 320 // Otherwise, let cryptographic nonce be the empty string." |
283 | 321 String nonce; |
284 // Steps 15--20 are handled in fetchScript(). | 322 if (element_->IsNonceableElement()) |
| 323 nonce = element_->nonce(); |
| 324 |
| 325 // 18. is handled below. |
| 326 |
| 327 // 19. "Let parser state be "parser-inserted" |
| 328 // if the script element has been flagged as "parser-inserted", |
| 329 // and "not parser-inserted" otherwise." |
| 330 ParserDisposition parser_state = |
| 331 IsParserInserted() ? kParserInserted : kNotParserInserted; |
285 | 332 |
286 // 21. "If the element has a src content attribute, run these substeps:" | 333 // 21. "If the element has a src content attribute, run these substeps:" |
287 if (element_->HasSourceAttribute()) { | 334 if (element_->HasSourceAttribute()) { |
288 FetchParameters::DeferOption defer = FetchParameters::kNoDefer; | 335 // 21.1. Let src be the value of the element's src attribute. |
289 if (!parser_inserted_ || element_->AsyncAttributeValue() || | 336 String src = |
290 element_->DeferAttributeValue()) | 337 StripLeadingAndTrailingHTMLSpaces(element_->SourceAttributeValue()); |
291 defer = FetchParameters::kLazyLoad; | 338 |
292 if (document_write_intervention_ == | 339 // 21.2. "If src is the empty string, queue a task to |
293 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) | 340 // fire an event named error at the element, and abort these steps." |
294 defer = FetchParameters::kIdleLoad; | 341 if (src.IsEmpty()) { |
295 if (!FetchScript(element_->SourceAttributeValue(), encoding, defer)) | 342 // TODO(hiroshige): Make this asynchronous. Currently we fire the error |
| 343 // event synchronously to keep the existing behavior. |
| 344 DispatchErrorEvent(); |
296 return false; | 345 return false; |
| 346 } |
| 347 |
| 348 // 21.3. "Set the element's from an external file flag." |
| 349 is_external_script_ = true; |
| 350 |
| 351 // 21.4. "Parse src relative to the element's node document." |
| 352 KURL url = element_document.CompleteURL(src); |
| 353 |
| 354 // 21.5. "If the previous step failed, queue a task to |
| 355 // fire an event named error at the element, and abort these steps." |
| 356 if (!url.IsValid()) { |
| 357 // TODO(hiroshige): Make this asynchronous. Currently we fire the error |
| 358 // event synchronously to keep the existing behavior. |
| 359 DispatchErrorEvent(); |
| 360 return false; |
| 361 } |
| 362 |
| 363 DCHECK(!resource_); |
| 364 DCHECK(!module_tree_client_); |
| 365 |
| 366 // 21.6. "Switch on the script's type:" |
| 367 if (GetScriptType() == ScriptType::kClassic) { |
| 368 // - "classic": |
| 369 |
| 370 // 14. "If the script element has a charset attribute, |
| 371 // then let encoding be the result of |
| 372 // getting an encoding from the value of the charset attribute." |
| 373 // "If the script element does not have a charset attribute, |
| 374 // or if getting an encoding failed, let encoding |
| 375 // be the same as the encoding of the script element's node |
| 376 // document." |
| 377 // TODO(hiroshige): Should we handle failure in getting an encoding? |
| 378 String encoding; |
| 379 if (!element_->CharsetAttributeValue().IsEmpty()) |
| 380 encoding = element_->CharsetAttributeValue(); |
| 381 else |
| 382 encoding = element_document.characterSet(); |
| 383 |
| 384 // Step 16 is skipped because "module script credentials" is not used |
| 385 // for classic scripts. |
| 386 |
| 387 // 18. "If the script element has an integrity attribute, |
| 388 // then let integrity metadata be that attribute's value. |
| 389 // Otherwise, let integrity metadata be the empty string." |
| 390 String integrity_attr = element_->IntegrityAttributeValue(); |
| 391 IntegrityMetadataSet integrity_metadata; |
| 392 if (!integrity_attr.IsEmpty()) { |
| 393 SubresourceIntegrity::ParseIntegrityAttribute( |
| 394 integrity_attr, integrity_metadata, &element_document); |
| 395 } |
| 396 |
| 397 if (!FetchClassicScript(url, element_document.Fetcher(), nonce, |
| 398 integrity_metadata, parser_state, cross_origin, |
| 399 element_document.GetSecurityOrigin(), encoding)) { |
| 400 // TODO(hiroshige): Make this asynchronous. Currently we fire the error |
| 401 // event synchronously to keep the existing behavior. |
| 402 DispatchErrorEvent(); |
| 403 return false; |
| 404 } |
| 405 |
| 406 DCHECK(resource_); |
| 407 DCHECK(!module_tree_client_); |
| 408 } else { |
| 409 // - "module": |
| 410 |
| 411 // Steps 14 and 18 are skipped because they are not used in module |
| 412 // scripts. |
| 413 |
| 414 // 16. "Let module script credentials mode be determined by switching |
| 415 // on CORS setting:" |
| 416 WebURLRequest::FetchCredentialsMode credentials_mode = |
| 417 WebURLRequest::kFetchCredentialsModeOmit; |
| 418 switch (cross_origin) { |
| 419 case kCrossOriginAttributeNotSet: |
| 420 credentials_mode = WebURLRequest::kFetchCredentialsModeOmit; |
| 421 break; |
| 422 case kCrossOriginAttributeAnonymous: |
| 423 credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin; |
| 424 break; |
| 425 case kCrossOriginAttributeUseCredentials: |
| 426 credentials_mode = WebURLRequest::kFetchCredentialsModeInclude; |
| 427 break; |
| 428 } |
| 429 |
| 430 DCHECK(RuntimeEnabledFeatures::moduleScriptsEnabled()); |
| 431 Modulator* modulator = Modulator::From( |
| 432 ToScriptStateForMainWorld(element_document.GetFrame())); |
| 433 FetchModuleScriptTree(url, modulator, nonce, parser_state, |
| 434 credentials_mode); |
| 435 |
| 436 DCHECK(!resource_); |
| 437 DCHECK(module_tree_client_); |
| 438 } |
| 439 |
| 440 // "When the chosen algorithm asynchronously completes, set |
| 441 // the script's script to the result. At that time, the script is ready." |
| 442 // When the script is ready, PendingScriptClient::pendingScriptFinished() |
| 443 // is used as the notification, and the action to take when |
| 444 // the script is ready is specified later, in |
| 445 // - ScriptLoader::PrepareScript(), or |
| 446 // - HTMLParserScriptRunner, |
| 447 // depending on the conditions in Step 23 of "prepare a script". |
297 } | 448 } |
298 | 449 |
299 // 22. "If the element does not have a src content attribute, | 450 // 22. "If the element does not have a src content attribute, |
300 // run these substeps:" | 451 // run these substeps:" |
301 | 452 if (!element_->HasSourceAttribute()) { |
302 // 22.1. "Let source text be the value of the text IDL attribute." | 453 // 22.1. "Let source text be the value of the text IDL attribute." |
303 // This step is done later: | 454 // This step is done later: |
304 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), | 455 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), |
305 // as Element::textFromChildren() in ScriptLoader::scriptContent(), | 456 // as Element::textFromChildren() in ScriptLoader::scriptContent(), |
306 // - in HTMLParserScriptRunner::processScriptElementInternal() | 457 // - in HTMLParserScriptRunner::processScriptElementInternal() |
307 // (Duplicated code of Step 23, 6th Clause), | 458 // (Duplicated code of Step 23, 6th Clause), |
308 // as Element::textContent(), | 459 // as Element::textContent(), |
309 // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause), | 460 // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause), |
310 // as Element::textFromChildren() in ScriptLoader::scriptContent(), | 461 // as Element::textFromChildren() in ScriptLoader::scriptContent(), |
311 // - PendingScript::getSource() (Indirectly used via | 462 // - PendingScript::getSource() (Indirectly used via |
312 // HTMLParserScriptRunner::processScriptElementInternal(), | 463 // HTMLParserScriptRunner::processScriptElementInternal(), |
313 // Step 23, 5th Clause), | 464 // Step 23, 5th Clause), |
314 // as Element::textContent(). | 465 // as Element::textContent(). |
315 // TODO(hiroshige): Make them merged or consistent. | 466 // TODO(hiroshige): Make them merged or consistent. |
316 | 467 |
317 // 22.2. "Switch on the script's type:" | 468 // 22.2. "Switch on the script's type:" |
318 // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". | 469 switch (GetScriptType()) { |
319 // TODO(hiroshige): Implement Step 22.2 for "module". | 470 // - "classic": |
| 471 case ScriptType::kClassic: |
| 472 // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". |
| 473 break; |
| 474 |
| 475 // - "module": |
| 476 case ScriptType::kModule: |
| 477 // Inline module scripts are not yet supported. |
| 478 // FOXME: (how) should we handle this? Should we fail more gracefully? |
| 479 fprintf( |
| 480 stderr, |
| 481 "Inline module script is not yet supported (Document URL: %s)\n", |
| 482 element_document.Url().GetString().Utf8().Data()); |
| 483 CHECK(false); |
| 484 break; |
| 485 } |
| 486 } |
320 | 487 |
321 // [Intervention] | 488 // [Intervention] |
322 // Since the asynchronous, low priority fetch for doc.written blocked | 489 // Since the asynchronous, low priority fetch for doc.written blocked |
323 // script is not for execution, return early from here. Watch for its | 490 // script is not for execution, return early from here. Watch for its |
324 // completion to be able to remove it from the memory cache. | 491 // completion to be able to remove it from the memory cache. |
325 if (document_write_intervention_ == | 492 if (GetScriptType() == ScriptType::kClassic && |
326 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { | 493 document_write_intervention_ == |
| 494 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { |
327 pending_script_ = CreatePendingScript(); | 495 pending_script_ = CreatePendingScript(); |
328 pending_script_->WatchForLoad(this); | 496 pending_script_->WatchForLoad(this); |
329 return true; | 497 return true; |
330 } | 498 } |
331 | 499 |
332 // 23. "Then, follow the first of the following options that describes the | 500 // 23. "Then, follow the first of the following options that describes the |
333 // situation:" | 501 // situation:" |
334 | 502 |
335 // Three flags are used to instruct the caller of prepareScript() to execute | 503 // Three flags are used to instruct the caller of prepareScript() to execute |
336 // a part of Step 23, when |m_willBeParserExecuted| is true: | 504 // a part of Step 23, when |m_willBeParserExecuted| is true: |
337 // - |m_willBeParserExecuted| | 505 // - |m_willBeParserExecuted| |
338 // - |m_willExecuteWhenDocumentFinishedParsing| | 506 // - |m_willExecuteWhenDocumentFinishedParsing| |
339 // - |m_readyToBeParserExecuted| | 507 // - |m_readyToBeParserExecuted| |
340 // TODO(hiroshige): Clean up the dependency. | 508 // TODO(hiroshige): Clean up the dependency. |
341 | 509 |
342 // 1st Clause: | 510 // 1st Clause: |
343 // - "If the script's type is "classic", and | 511 // - "If the script's type is "classic", and |
344 // the element has a src attribute, and the element has a defer attribute, | 512 // the element has a src attribute, and the element has a defer attribute, |
345 // and the element has been flagged as "parser-inserted", | 513 // and the element has been flagged as "parser-inserted", |
346 // and the element does not have an async attribute" | 514 // and the element does not have an async attribute" |
347 // TODO(hiroshige): Check the script's type and implement "module" case. | 515 // - "If the script's type is "module", |
348 if (element_->HasSourceAttribute() && element_->DeferAttributeValue() && | 516 // and the element has been flagged as "parser-inserted", |
349 parser_inserted_ && !element_->AsyncAttributeValue()) { | 517 // and the element does not have an async attribute" |
| 518 if ((GetScriptType() == ScriptType::kClassic && |
| 519 element_->HasSourceAttribute() && element_->DeferAttributeValue() && |
| 520 parser_inserted_ && !element_->AsyncAttributeValue()) || |
| 521 (GetScriptType() == ScriptType::kModule && parser_inserted_ && |
| 522 !element_->AsyncAttributeValue())) { |
350 // This clause is implemented by the caller-side of prepareScript(): | 523 // This clause is implemented by the caller-side of prepareScript(): |
351 // - HTMLParserScriptRunner::requestDeferredScript(), and | 524 // - HTMLParserScriptRunner::requestDeferredScript(), and |
352 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 525 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
353 will_execute_when_document_finished_parsing_ = true; | 526 will_execute_when_document_finished_parsing_ = true; |
354 will_be_parser_executed_ = true; | 527 will_be_parser_executed_ = true; |
355 | 528 |
356 return true; | 529 return true; |
357 } | 530 } |
358 | 531 |
359 // 2nd Clause: | 532 // 2nd Clause: |
360 // - "If the script's type is "classic", | 533 // - "If the script's type is "classic", |
361 // and the element has a src attribute, | 534 // and the element has a src attribute, |
362 // and the element has been flagged as "parser-inserted", | 535 // and the element has been flagged as "parser-inserted", |
363 // and the element does not have an async attribute" | 536 // and the element does not have an async attribute" |
364 // TODO(hiroshige): Check the script's type. | 537 // TODO(hiroshige): Check the script's type. |
365 if (element_->HasSourceAttribute() && parser_inserted_ && | 538 if (GetScriptType() == ScriptType::kClassic && |
| 539 element_->HasSourceAttribute() && parser_inserted_ && |
366 !element_->AsyncAttributeValue()) { | 540 !element_->AsyncAttributeValue()) { |
367 // This clause is implemented by the caller-side of prepareScript(): | 541 // This clause is implemented by the caller-side of prepareScript(): |
368 // - HTMLParserScriptRunner::requestParsingBlockingScript() | 542 // - HTMLParserScriptRunner::requestParsingBlockingScript() |
369 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 543 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
370 will_be_parser_executed_ = true; | 544 will_be_parser_executed_ = true; |
371 | 545 |
372 return true; | 546 return true; |
373 } | 547 } |
374 | 548 |
375 // 5th Clause: | 549 // 5th Clause: |
376 // TODO(hiroshige): Reorder the clauses to match the spec. | 550 // TODO(hiroshige): Reorder the clauses to match the spec. |
377 // - "If the element does not have a src attribute, | 551 // - "If the element does not have a src attribute, |
378 // and the element has been flagged as "parser-inserted", | 552 // and the element has been flagged as "parser-inserted", |
379 // and either the parser that created the script is an XML parser | 553 // and either the parser that created the script is an XML parser |
380 // or it's an HTML parser whose script nesting level is not greater than | 554 // or it's an HTML parser whose script nesting level is not greater than |
381 // one, | 555 // one, |
382 // and the Document of the HTML parser or XML parser that created | 556 // and the Document of the HTML parser or XML parser that created |
383 // the script element has a style sheet that is blocking scripts" | 557 // the script element has a style sheet that is blocking scripts" |
384 // The last part "... has a style sheet that is blocking scripts" | 558 // The last part "... has a style sheet that is blocking scripts" |
385 // is implemented in Document::isScriptExecutionReady(). | 559 // is implemented in Document::isScriptExecutionReady(). |
386 // Part of the condition check is done in | 560 // Part of the condition check is done in |
387 // HTMLParserScriptRunner::processScriptElementInternal(). | 561 // HTMLParserScriptRunner::processScriptElementInternal(). |
388 // TODO(hiroshige): Clean up the split condition check. | 562 // TODO(hiroshige): Clean up the split condition check. |
389 if (!element_->HasSourceAttribute() && parser_inserted_ && | 563 // We check that the type is "classic" here, because according to the spec |
| 564 // a "module" script doesn't reach the 5th Clause because the 4th Clause |
| 565 // catches all "module" scripts. |
| 566 if (GetScriptType() == ScriptType::kClassic && |
| 567 !element_->HasSourceAttribute() && parser_inserted_ && |
390 !element_document.IsScriptExecutionReady()) { | 568 !element_document.IsScriptExecutionReady()) { |
391 // The former part of this clause is | 569 // The former part of this clause is |
392 // implemented by the caller-side of prepareScript(): | 570 // implemented by the caller-side of prepareScript(): |
393 // - HTMLParserScriptRunner::requestParsingBlockingScript() | 571 // - HTMLParserScriptRunner::requestParsingBlockingScript() |
394 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() | 572 // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() |
395 will_be_parser_executed_ = true; | 573 will_be_parser_executed_ = true; |
396 // "Set the element's "ready to be parser-executed" flag." | 574 // "Set the element's "ready to be parser-executed" flag." |
397 ready_to_be_parser_executed_ = true; | 575 ready_to_be_parser_executed_ = true; |
398 | 576 |
399 return true; | 577 return true; |
400 } | 578 } |
401 | 579 |
402 // 3rd Clause: | 580 // 3rd Clause: |
403 // - "If the script's type is "classic", | 581 // - "If the script's type is "classic", |
404 // and the element has a src attribute, | 582 // and the element has a src attribute, |
405 // and the element does not have an async attribute, | 583 // and the element does not have an async attribute, |
406 // and the element does not have the "non-blocking" flag set" | 584 // and the element does not have the "non-blocking" flag set" |
| 585 // - "If the script's type is "module", |
| 586 // and the element does not have an async attribute, |
| 587 // and the element does not have the "non-blocking" flag set" |
407 // TODO(hiroshige): Check the script's type and implement "module" case. | 588 // TODO(hiroshige): Check the script's type and implement "module" case. |
408 if (element_->HasSourceAttribute() && !element_->AsyncAttributeValue() && | 589 if ((GetScriptType() == ScriptType::kClassic && |
409 !non_blocking_) { | 590 element_->HasSourceAttribute() && !element_->AsyncAttributeValue() && |
| 591 !non_blocking_) || |
| 592 (GetScriptType() == ScriptType::kModule && |
| 593 !element_->AsyncAttributeValue() && !non_blocking_)) { |
410 // "Add the element to the end of the list of scripts that will execute | 594 // "Add the element to the end of the list of scripts that will execute |
411 // in order as soon as possible associated with the node document of the | 595 // in order as soon as possible associated with the node document of the |
412 // script element at the time the prepare a script algorithm started." | 596 // script element at the time the prepare a script algorithm started." |
413 pending_script_ = CreatePendingScript(); | 597 pending_script_ = CreatePendingScript(); |
414 async_exec_type_ = ScriptRunner::kInOrder; | 598 async_exec_type_ = ScriptRunner::kInOrder; |
415 // TODO(hiroshige): Here |contextDocument| is used as "node document" | 599 // TODO(hiroshige): Here |contextDocument| is used as "node document" |
416 // while Step 14 uses |elementDocument| as "node document". Fix this. | 600 // while Step 14 uses |elementDocument| as "node document". Fix this. |
417 context_document->GetScriptRunner()->QueueScriptForExecution( | 601 context_document->GetScriptRunner()->QueueScriptForExecution( |
418 this, async_exec_type_); | 602 this, async_exec_type_); |
419 // Note that watchForLoad can immediately call pendingScriptFinished. | 603 // Note that watchForLoad can immediately call pendingScriptFinished. |
420 pending_script_->WatchForLoad(this); | 604 pending_script_->WatchForLoad(this); |
421 // The part "When the script is ready..." is implemented in | 605 // The part "When the script is ready..." is implemented in |
422 // ScriptRunner::notifyScriptReady(). | 606 // ScriptRunner::notifyScriptReady(). |
423 // TODO(hiroshige): Annotate it. | 607 // TODO(hiroshige): Annotate it. |
424 | 608 |
425 return true; | 609 return true; |
426 } | 610 } |
427 | 611 |
428 // 4th Clause: | 612 // 4th Clause: |
429 // - "If the script's type is "classic", and the element has a src attribute" | 613 // - "If the script's type is "classic", and the element has a src attribute" |
430 // TODO(hiroshige): Check the script's type and implement "module" case. | 614 // - "If the script's type is "module"" |
431 if (element_->HasSourceAttribute()) { | 615 if ((GetScriptType() == ScriptType::kClassic && |
| 616 element_->HasSourceAttribute()) || |
| 617 GetScriptType() == ScriptType::kModule) { |
432 // "The element must be added to the set of scripts that will execute | 618 // "The element must be added to the set of scripts that will execute |
433 // as soon as possible of the node document of the script element at the | 619 // as soon as possible of the node document of the script element at the |
434 // time the prepare a script algorithm started." | 620 // time the prepare a script algorithm started." |
435 pending_script_ = CreatePendingScript(); | 621 pending_script_ = CreatePendingScript(); |
436 async_exec_type_ = ScriptRunner::kAsync; | 622 async_exec_type_ = ScriptRunner::kAsync; |
437 pending_script_->StartStreamingIfPossible(&element_->GetDocument(), | 623 pending_script_->StartStreamingIfPossible(&element_->GetDocument(), |
438 ScriptStreamer::kAsync); | 624 ScriptStreamer::kAsync); |
439 // TODO(hiroshige): Here |contextDocument| is used as "node document" | 625 // TODO(hiroshige): Here |contextDocument| is used as "node document" |
440 // while Step 14 uses |elementDocument| as "node document". Fix this. | 626 // while Step 14 uses |elementDocument| as "node document". Fix this. |
441 context_document->GetScriptRunner()->QueueScriptForExecution( | 627 context_document->GetScriptRunner()->QueueScriptForExecution( |
(...skipping 10 matching lines...) Expand all Loading... |
452 // 6th Clause: | 638 // 6th Clause: |
453 // - "Otherwise" | 639 // - "Otherwise" |
454 // "Immediately execute the script block, | 640 // "Immediately execute the script block, |
455 // even if other scripts are already executing." | 641 // even if other scripts are already executing." |
456 // Note: this block is also duplicated in | 642 // Note: this block is also duplicated in |
457 // HTMLParserScriptRunner::processScriptElementInternal(). | 643 // HTMLParserScriptRunner::processScriptElementInternal(). |
458 // TODO(hiroshige): Merge the duplicated code. | 644 // TODO(hiroshige): Merge the duplicated code. |
459 | 645 |
460 // This clause is executed only if the script's type is "classic" | 646 // This clause is executed only if the script's type is "classic" |
461 // and the element doesn't have a src attribute. | 647 // and the element doesn't have a src attribute. |
| 648 DCHECK_EQ(GetScriptType(), ScriptType::kClassic); |
| 649 DCHECK(!is_external_script_); |
462 | 650 |
463 // Reset line numbering for nested writes. | 651 // Reset line numbering for nested writes. |
464 TextPosition position = element_document.IsInDocumentWrite() | 652 TextPosition position = element_document.IsInDocumentWrite() |
465 ? TextPosition() | 653 ? TextPosition() |
466 : script_start_position; | 654 : script_start_position; |
467 KURL script_url = (!element_document.IsInDocumentWrite() && parser_inserted_) | 655 KURL script_url = (!element_document.IsInDocumentWrite() && parser_inserted_) |
468 ? element_document.Url() | 656 ? element_document.Url() |
469 : KURL(); | 657 : KURL(); |
470 | 658 |
471 if (!ExecuteScript(ClassicScript::Create( | 659 if (!ExecuteScript(ClassicScript::Create( |
472 ScriptSourceCode(ScriptContent(), script_url, position)))) { | 660 ScriptSourceCode(ScriptContent(), script_url, position)))) { |
473 DispatchErrorEvent(); | 661 DispatchErrorEvent(); |
474 return false; | 662 return false; |
475 } | 663 } |
476 | 664 |
477 return true; | 665 return true; |
478 } | 666 } |
479 | 667 |
480 // Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script | 668 bool ScriptLoader::FetchClassicScript( |
481 bool ScriptLoader::FetchScript(const String& source_url, | 669 const KURL& url, |
482 const String& encoding, | 670 ResourceFetcher* fetcher, |
483 FetchParameters::DeferOption defer) { | 671 const String& nonce, |
484 Document* element_document = &(element_->GetDocument()); | 672 const IntegrityMetadataSet& integrity_metadata, |
485 if (!element_->IsConnected() || element_->GetDocument() != element_document) | 673 ParserDisposition parser_state, |
486 return false; | 674 CrossOriginAttributeValue cross_origin, |
| 675 SecurityOrigin* security_origin, |
| 676 const String& encoding) { |
| 677 // https://html.spec.whatwg.org/#prepare-a-script |
| 678 // 21.6, "classic": |
| 679 // "Fetch a classic script given url, settings, ..." |
| 680 ResourceRequest resource_request(url); |
487 | 681 |
488 DCHECK(!resource_); | 682 // [Intervention] |
489 // 21. "If the element has a src content attribute, run these substeps:" | 683 if (document_write_intervention_ == |
490 if (!StripLeadingAndTrailingHTMLSpaces(source_url).IsEmpty()) { | 684 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { |
491 // 21.4. "Parse src relative to the element's node document." | 685 resource_request.SetHTTPHeaderField( |
492 ResourceRequest resource_request(element_document->CompleteURL(source_url)); | 686 "Intervention", |
493 | 687 "<https://www.chromestatus.com/feature/5718547946799104>"); |
494 // [Intervention] | |
495 if (document_write_intervention_ == | |
496 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { | |
497 resource_request.SetHTTPHeaderField( | |
498 "Intervention", | |
499 "<https://www.chromestatus.com/feature/5718547946799104>"); | |
500 } | |
501 | |
502 FetchParameters params(resource_request, element_->InitiatorName()); | |
503 | |
504 // 15. "Let CORS setting be the current state of the element's | |
505 // crossorigin content attribute." | |
506 CrossOriginAttributeValue cross_origin = | |
507 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue()); | |
508 | |
509 // 16. "Let module script credentials mode be determined by switching | |
510 // on CORS setting:" | |
511 // TODO(hiroshige): Implement this step for "module". | |
512 | |
513 // 21.6, "classic": "Fetch a classic script given ... CORS setting | |
514 // ... and encoding." | |
515 if (cross_origin != kCrossOriginAttributeNotSet) { | |
516 params.SetCrossOriginAccessControl(element_document->GetSecurityOrigin(), | |
517 cross_origin); | |
518 } | |
519 | |
520 params.SetCharset(encoding); | |
521 | |
522 // 17. "If the script element has a nonce attribute, | |
523 // then let cryptographic nonce be that attribute's value. | |
524 // Otherwise, let cryptographic nonce be the empty string." | |
525 if (element_->IsNonceableElement()) | |
526 params.SetContentSecurityPolicyNonce(element_->nonce()); | |
527 | |
528 // 19. "Let parser state be "parser-inserted" | |
529 // if the script element has been flagged as "parser-inserted", | |
530 // and "not parser-inserted" otherwise." | |
531 params.SetParserDisposition(IsParserInserted() ? kParserInserted | |
532 : kNotParserInserted); | |
533 | |
534 params.SetDefer(defer); | |
535 | |
536 // 18. "If the script element has an integrity attribute, | |
537 // then let integrity metadata be that attribute's value. | |
538 // Otherwise, let integrity metadata be the empty string." | |
539 String integrity_attr = element_->IntegrityAttributeValue(); | |
540 if (!integrity_attr.IsEmpty()) { | |
541 IntegrityMetadataSet metadata_set; | |
542 SubresourceIntegrity::ParseIntegrityAttribute( | |
543 integrity_attr, metadata_set, element_document); | |
544 params.SetIntegrityMetadata(metadata_set); | |
545 } | |
546 | |
547 // 21.6. "Switch on the script's type:" | |
548 | |
549 // - "classic": | |
550 // "Fetch a classic script given url, settings, cryptographic nonce, | |
551 // integrity metadata, parser state, CORS setting, and encoding." | |
552 resource_ = ScriptResource::Fetch(params, element_document->Fetcher()); | |
553 | |
554 // - "module": | |
555 // "Fetch a module script graph given url, settings, "script", | |
556 // cryptographic nonce, parser state, and | |
557 // module script credentials mode." | |
558 // TODO(kouhei, hiroshige): Implement this. | |
559 | |
560 // "When the chosen algorithm asynchronously completes, set | |
561 // the script's script to the result. At that time, the script is ready." | |
562 // When the script is ready, PendingScriptClient::pendingScriptFinished() | |
563 // is used as the notification, and the action to take when | |
564 // the script is ready is specified later, in | |
565 // - ScriptLoader::prepareScript(), or | |
566 // - HTMLParserScriptRunner, | |
567 // depending on the conditions in Step 23 of "prepare a script". | |
568 | |
569 // 21.3. "Set the element's from an external file flag." | |
570 is_external_script_ = true; | |
571 } | 688 } |
572 | 689 |
573 if (!resource_) { | 690 FetchParameters params(resource_request, element_->InitiatorName()); |
574 // 21.2. "If src is the empty string, queue a task to | 691 |
575 // fire an event named error at the element, and abort these steps." | 692 // "... cryptographic nonce, ..." |
576 // 21.5. "If the previous step failed, queue a task to | 693 params.SetContentSecurityPolicyNonce(nonce); |
577 // fire an event named error at the element, and abort these steps." | 694 |
578 // TODO(hiroshige): Make this asynchronous. | 695 // "... integrity metadata, ..." |
579 DispatchErrorEvent(); | 696 params.SetIntegrityMetadata(integrity_metadata); |
| 697 |
| 698 // "... parser state, ..." |
| 699 params.SetParserDisposition(parser_state); |
| 700 |
| 701 // "... CORS setting, ..." |
| 702 if (cross_origin != kCrossOriginAttributeNotSet) { |
| 703 params.SetCrossOriginAccessControl(security_origin, cross_origin); |
| 704 } |
| 705 |
| 706 // "... and encoding." |
| 707 params.SetCharset(encoding); |
| 708 |
| 709 // This DeferOption logic is only for classic scripts, as we always set |
| 710 // |kLazyLoad| for module scripts in ModuleScriptLoader. |
| 711 FetchParameters::DeferOption defer = FetchParameters::kNoDefer; |
| 712 if (!parser_inserted_ || element_->AsyncAttributeValue() || |
| 713 element_->DeferAttributeValue()) |
| 714 defer = FetchParameters::kLazyLoad; |
| 715 if (document_write_intervention_ == |
| 716 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) |
| 717 defer = FetchParameters::kIdleLoad; |
| 718 params.SetDefer(defer); |
| 719 |
| 720 resource_ = ScriptResource::Fetch(params, fetcher); |
| 721 |
| 722 if (!resource_) |
580 return false; | 723 return false; |
581 } | |
582 | 724 |
583 // [Intervention] | 725 // [Intervention] |
584 if (created_during_document_write_ && | 726 if (created_during_document_write_ && |
585 resource_->GetResourceRequest().GetCachePolicy() == | 727 resource_->GetResourceRequest().GetCachePolicy() == |
586 WebCachePolicy::kReturnCacheDataDontLoad) { | 728 WebCachePolicy::kReturnCacheDataDontLoad) { |
587 document_write_intervention_ = | 729 document_write_intervention_ = |
588 DocumentWriteIntervention::kDoNotFetchDocWrittenScript; | 730 DocumentWriteIntervention::kDoNotFetchDocWrittenScript; |
589 } | 731 } |
590 | 732 |
591 return true; | 733 return true; |
592 } | 734 } |
593 | 735 |
| 736 void ScriptLoader::FetchModuleScriptTree( |
| 737 const KURL& url, |
| 738 Modulator* modulator, |
| 739 const String& nonce, |
| 740 ParserDisposition parser_state, |
| 741 WebURLRequest::FetchCredentialsMode credentials_mode) { |
| 742 // https://html.spec.whatwg.org/#prepare-a-script |
| 743 // 21.6, "module": |
| 744 // "Fetch a module script graph given url, settings, "script", |
| 745 // cryptographic nonce, parser state, and |
| 746 // module script credentials mode." |
| 747 ModuleScriptFetchRequest module_request(url, nonce, parser_state, |
| 748 credentials_mode); |
| 749 |
| 750 module_tree_client_ = ModulePendingScriptTreeClient::Create(); |
| 751 |
| 752 modulator->FetchTree(module_request, module_tree_client_); |
| 753 } |
| 754 |
594 PendingScript* ScriptLoader::CreatePendingScript() { | 755 PendingScript* ScriptLoader::CreatePendingScript() { |
595 CHECK(resource_); | 756 switch (GetScriptType()) { |
596 return PendingScript::Create(element_, resource_); | 757 case ScriptType::kClassic: |
| 758 CHECK(resource_); |
| 759 return ClassicPendingScript::Create(element_, resource_); |
| 760 case ScriptType::kModule: |
| 761 CHECK(module_tree_client_); |
| 762 return ModulePendingScript::Create(element_, module_tree_client_); |
| 763 } |
| 764 NOTREACHED(); |
| 765 return nullptr; |
597 } | 766 } |
598 | 767 |
599 bool ScriptLoader::ExecuteScript(const Script* script) { | 768 bool ScriptLoader::ExecuteScript(const Script* script) { |
600 double script_exec_start_time = MonotonicallyIncreasingTime(); | 769 double script_exec_start_time = MonotonicallyIncreasingTime(); |
601 bool result = DoExecuteScript(script); | 770 bool result = DoExecuteScript(script); |
602 | 771 |
603 // NOTE: we do not check m_willBeParserExecuted here, since | 772 // NOTE: we do not check m_willBeParserExecuted here, since |
604 // m_willBeParserExecuted is false for inline scripts, and we want to | 773 // m_willBeParserExecuted is false for inline scripts, and we want to |
605 // include inline script execution time as part of parser blocked script | 774 // include inline script execution time as part of parser blocked script |
606 // execution time. | 775 // execution time. |
607 if (async_exec_type_ == ScriptRunner::kNone) | 776 if (async_exec_type_ == ScriptRunner::kNone) |
608 DocumentParserTiming::From(element_->GetDocument()) | 777 DocumentParserTiming::From(element_->GetDocument()) |
609 .RecordParserBlockedOnScriptExecutionDuration( | 778 .RecordParserBlockedOnScriptExecutionDuration( |
610 MonotonicallyIncreasingTime() - script_exec_start_time, | 779 MonotonicallyIncreasingTime() - script_exec_start_time, |
611 WasCreatedDuringDocumentWrite()); | 780 WasCreatedDuringDocumentWrite()); |
612 return result; | 781 return result; |
613 } | 782 } |
614 | 783 |
615 // https://html.spec.whatwg.org/#execute-the-script-block | 784 // https://html.spec.whatwg.org/#execute-the-script-block |
616 // with additional support for HTML imports. | 785 // with additional support for HTML imports. |
617 // Note that Steps 2 and 8 must be handled by the caller of doExecuteScript(), | 786 // Note that Steps 2 and 8 must be handled by the caller of doExecuteScript(), |
618 // i.e. load/error events are dispatched by the caller. | 787 // i.e. load/error events are dispatched by the caller. |
619 // Steps 3--7 are implemented here in doExecuteScript(). | 788 // Steps 3--7 are implemented here in doExecuteScript(). |
620 // TODO(hiroshige): Move event dispatching code to doExecuteScript(). | 789 // TODO(hiroshige): Move event dispatching code to doExecuteScript(). |
621 bool ScriptLoader::DoExecuteScript(const Script* script) { | 790 bool ScriptLoader::DoExecuteScript(const Script* script) { |
622 DCHECK(already_started_); | 791 DCHECK(already_started_); |
| 792 CHECK_EQ(script->GetScriptType(), GetScriptType()); |
623 | 793 |
624 if (script->IsEmpty()) | 794 if (script->IsEmpty()) |
625 return true; | 795 return true; |
626 | 796 |
627 Document* element_document = &(element_->GetDocument()); | 797 Document* element_document = &(element_->GetDocument()); |
628 Document* context_document = element_document->ContextDocument(); | 798 Document* context_document = element_document->ContextDocument(); |
629 if (!context_document) | 799 if (!context_document) |
630 return true; | 800 return true; |
631 | 801 |
632 LocalFrame* frame = context_document->GetFrame(); | 802 LocalFrame* frame = context_document->GetFrame(); |
(...skipping 22 matching lines...) Expand all Loading... |
655 context_document, element_->GetDocument().GetSecurityOrigin())) | 825 context_document, element_->GetDocument().GetSecurityOrigin())) |
656 return false; | 826 return false; |
657 } | 827 } |
658 | 828 |
659 const bool is_imported_script = context_document != element_document; | 829 const bool is_imported_script = context_document != element_document; |
660 | 830 |
661 // 3. "If the script is from an external file, | 831 // 3. "If the script is from an external file, |
662 // or the script's type is module", | 832 // or the script's type is module", |
663 // then increment the ignore-destructive-writes counter of the | 833 // then increment the ignore-destructive-writes counter of the |
664 // script element's node document. Let neutralized doc be that Document." | 834 // script element's node document. Let neutralized doc be that Document." |
665 // TODO(hiroshige): Implement "module" case. | |
666 IgnoreDestructiveWriteCountIncrementer | 835 IgnoreDestructiveWriteCountIncrementer |
667 ignore_destructive_write_count_incrementer( | 836 ignore_destructive_write_count_incrementer( |
668 is_external_script_ || is_imported_script ? context_document : 0); | 837 is_external_script_ || |
| 838 script->GetScriptType() == ScriptType::kModule || |
| 839 is_imported_script |
| 840 ? context_document |
| 841 : 0); |
669 | 842 |
670 // 4. "Let old script element be the value to which the script element's | 843 // 4. "Let old script element be the value to which the script element's |
671 // node document's currentScript object was most recently set." | 844 // node document's currentScript object was most recently set." |
672 // This is implemented as push/popCurrentScript(). | 845 // This is implemented as push/popCurrentScript(). |
673 | 846 |
674 // 5. "Switch on the script's type:" | 847 // 5. "Switch on the script's type:" |
675 // - "classic": | 848 // - "classic": |
676 // 1. "If the script element's root is not a shadow root, | 849 // 1. "If the script element's root is not a shadow root, |
677 // then set the script element's node document's currentScript | 850 // then set the script element's node document's currentScript |
678 // attribute to the script element. Otherwise, set it to null." | 851 // attribute to the script element. Otherwise, set it to null." |
679 context_document->PushCurrentScript(element_.Get()); | 852 // - "module": |
| 853 // 1. "Set the script element's node document's currentScript attribute |
| 854 // to null." |
| 855 ScriptElementBase* current_script = nullptr; |
| 856 if (script->GetScriptType() == ScriptType::kClassic) |
| 857 current_script = element_; |
| 858 context_document->PushCurrentScript(current_script); |
680 | 859 |
| 860 // - "classic": |
681 // 2. "Run the classic script given by the script's script." | 861 // 2. "Run the classic script given by the script's script." |
682 // Note: This is where the script is compiled and actually executed. | 862 // Note: This is where the script is compiled and actually executed. |
| 863 // - "module": |
| 864 // 2. "Run the module script given by the script's script." |
683 script->RunScript(frame, element_->GetDocument().GetSecurityOrigin()); | 865 script->RunScript(frame, element_->GetDocument().GetSecurityOrigin()); |
684 | 866 |
685 // - "module": | |
686 // TODO(hiroshige): Implement this. | |
687 | |
688 // 6. "Set the script element's node document's currentScript attribute | 867 // 6. "Set the script element's node document's currentScript attribute |
689 // to old script element." | 868 // to old script element." |
690 context_document->PopCurrentScript(element_.Get()); | 869 context_document->PopCurrentScript(current_script); |
691 | 870 |
692 return true; | 871 return true; |
693 | 872 |
694 // 7. "Decrement the ignore-destructive-writes counter of neutralized doc, | 873 // 7. "Decrement the ignore-destructive-writes counter of neutralized doc, |
695 // if it was incremented in the earlier step." | 874 // if it was incremented in the earlier step." |
696 // Implemented as the scope out of IgnoreDestructiveWriteCountIncrementer. | 875 // Implemented as the scope out of IgnoreDestructiveWriteCountIncrementer. |
697 } | 876 } |
698 | 877 |
699 void ScriptLoader::Execute() { | 878 void ScriptLoader::Execute() { |
700 DCHECK(!will_be_parser_executed_); | 879 DCHECK(!will_be_parser_executed_); |
701 DCHECK(async_exec_type_ != ScriptRunner::kNone); | 880 DCHECK(async_exec_type_ != ScriptRunner::kNone); |
702 DCHECK(pending_script_->GetResource()); | 881 DCHECK(pending_script_->IsExternal()); |
703 bool error_occurred = false; | 882 bool error_occurred = false; |
704 Script* script = pending_script_->GetSource(KURL(), error_occurred); | 883 Script* script = pending_script_->GetSource(KURL(), error_occurred); |
| 884 const bool wasCanceled = pending_script_->WasCanceled(); |
705 DetachPendingScript(); | 885 DetachPendingScript(); |
706 if (error_occurred) { | 886 if (error_occurred) { |
707 DispatchErrorEvent(); | 887 DispatchErrorEvent(); |
708 } else if (!resource_->WasCanceled()) { | 888 } else if (!wasCanceled) { |
709 if (ExecuteScript(script)) | 889 if (ExecuteScript(script)) |
710 DispatchLoadEvent(); | 890 DispatchLoadEvent(); |
711 else | 891 else |
712 DispatchErrorEvent(); | 892 DispatchErrorEvent(); |
713 } | 893 } |
714 resource_ = nullptr; | 894 resource_ = nullptr; |
| 895 module_tree_client_ = nullptr; |
715 } | 896 } |
716 | 897 |
717 void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) { | 898 void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) { |
718 DCHECK(!will_be_parser_executed_); | 899 DCHECK(!will_be_parser_executed_); |
719 DCHECK_EQ(pending_script_, pending_script); | 900 DCHECK_EQ(pending_script_, pending_script); |
720 DCHECK_EQ(pending_script->GetResource(), resource_); | 901 DCHECK_EQ(pending_script_->GetScriptType(), GetScriptType()); |
721 | 902 |
722 // We do not need this script in the memory cache. The primary goals of | 903 // We do not need this script in the memory cache. The primary goals of |
723 // sending this fetch request are to let the third party server know | 904 // sending this fetch request are to let the third party server know |
724 // about the document.write scripts intervention and populate the http | 905 // about the document.write scripts intervention and populate the http |
725 // cache for subsequent uses. | 906 // cache for subsequent uses. |
726 if (document_write_intervention_ == | 907 if (document_write_intervention_ == |
727 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { | 908 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { |
728 GetMemoryCache()->Remove(pending_script_->GetResource()); | 909 DCHECK_EQ(pending_script_->GetScriptType(), ScriptType::kClassic); |
| 910 pending_script_->RemoveFromMemoryCache(); |
729 pending_script_->StopWatchingForLoad(); | 911 pending_script_->StopWatchingForLoad(); |
730 return; | 912 return; |
731 } | 913 } |
732 | 914 |
733 DCHECK(async_exec_type_ != ScriptRunner::kNone); | 915 DCHECK(async_exec_type_ != ScriptRunner::kNone); |
734 | 916 |
735 Document* context_document = element_->GetDocument().ContextDocument(); | 917 Document* context_document = element_->GetDocument().ContextDocument(); |
736 if (!context_document) { | 918 if (!context_document) { |
737 DetachPendingScript(); | 919 DetachPendingScript(); |
738 return; | 920 return; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
781 // then abort these steps at this point. The script is not executed. | 963 // then abort these steps at this point. The script is not executed. |
782 return DeprecatedEqualIgnoringCase(event_attribute, "onload") || | 964 return DeprecatedEqualIgnoringCase(event_attribute, "onload") || |
783 DeprecatedEqualIgnoringCase(event_attribute, "onload()"); | 965 DeprecatedEqualIgnoringCase(event_attribute, "onload()"); |
784 } | 966 } |
785 | 967 |
786 String ScriptLoader::ScriptContent() const { | 968 String ScriptLoader::ScriptContent() const { |
787 return element_->TextFromChildren(); | 969 return element_->TextFromChildren(); |
788 } | 970 } |
789 | 971 |
790 } // namespace blink | 972 } // namespace blink |
OLD | NEW |