Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(726)

Side by Side Diff: third_party/WebKit/Source/core/dom/ScriptLoader.cpp

Issue 2821553002: Refactor code around ScriptLoader::FetchScript() according to the spec (Closed)
Patch Set: refine Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/ScriptLoader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 24 matching lines...) Expand all
35 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" 35 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h"
36 #include "core/dom/Script.h" 36 #include "core/dom/Script.h"
37 #include "core/dom/ScriptElementBase.h" 37 #include "core/dom/ScriptElementBase.h"
38 #include "core/dom/ScriptRunner.h" 38 #include "core/dom/ScriptRunner.h"
39 #include "core/dom/ScriptableDocumentParser.h" 39 #include "core/dom/ScriptableDocumentParser.h"
40 #include "core/dom/Text.h" 40 #include "core/dom/Text.h"
41 #include "core/events/Event.h" 41 #include "core/events/Event.h"
42 #include "core/frame/LocalFrame.h" 42 #include "core/frame/LocalFrame.h"
43 #include "core/frame/SubresourceIntegrity.h" 43 #include "core/frame/SubresourceIntegrity.h"
44 #include "core/frame/csp/ContentSecurityPolicy.h" 44 #include "core/frame/csp/ContentSecurityPolicy.h"
45 #include "core/html/CrossOriginAttribute.h"
46 #include "core/html/imports/HTMLImport.h" 45 #include "core/html/imports/HTMLImport.h"
47 #include "core/html/parser/HTMLParserIdioms.h" 46 #include "core/html/parser/HTMLParserIdioms.h"
47 #include "core/loader/resource/ScriptResource.h"
48 #include "platform/WebFrameScheduler.h" 48 #include "platform/WebFrameScheduler.h"
49 #include "platform/loader/fetch/AccessControlStatus.h" 49 #include "platform/loader/fetch/AccessControlStatus.h"
50 #include "platform/loader/fetch/FetchParameters.h" 50 #include "platform/loader/fetch/FetchParameters.h"
51 #include "platform/loader/fetch/ResourceFetcher.h" 51 #include "platform/loader/fetch/ResourceFetcher.h"
52 #include "platform/network/mime/MIMETypeRegistry.h" 52 #include "platform/network/mime/MIMETypeRegistry.h"
53 #include "platform/weborigin/SecurityOrigin.h" 53 #include "platform/weborigin/SecurityOrigin.h"
54 #include "platform/wtf/StdLibExtras.h" 54 #include "platform/wtf/StdLibExtras.h"
55 #include "platform/wtf/text/StringBuilder.h" 55 #include "platform/wtf/text/StringBuilder.h"
56 #include "platform/wtf/text/StringHash.h" 56 #include "platform/wtf/text/StringHash.h"
57 #include "public/platform/WebCachePolicy.h" 57 #include "public/platform/WebCachePolicy.h"
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 260
261 // 10. "If scripting is disabled for the script element, then abort these 261 // 10. "If scripting is disabled for the script element, then abort these
262 // steps at this point. The script is not executed." 262 // steps at this point. The script is not executed."
263 if (!context_document->CanExecuteScripts(kAboutToExecuteScript)) 263 if (!context_document->CanExecuteScripts(kAboutToExecuteScript))
264 return false; 264 return false;
265 265
266 // 13. 266 // 13.
267 if (!IsScriptForEventSupported()) 267 if (!IsScriptForEventSupported())
268 return false; 268 return false;
269 269
270 // 14. "If the script element has a charset attribute, 270 // 14. is handled below.
hiroshige 2017/04/14 00:13:29 Step 14 is moved below.
271 // then let encoding be the result of
272 // getting an encoding from the value of the charset attribute."
273 // "If the script element does not have a charset attribute,
274 // or if getting an encoding failed, let encoding
275 // be the same as the encoding of the script element's node document."
276 // TODO(hiroshige): Should we handle failure in getting an encoding?
277 String encoding;
278 if (!element_->CharsetAttributeValue().IsEmpty())
279 encoding = element_->CharsetAttributeValue();
280 else
281 encoding = element_document.characterSet();
282 271
283 // Steps 15--20 are handled in fetchScript(). 272 // 15. "Let CORS setting be the current state of the element's
hiroshige 2017/04/14 00:13:29 Step 15 is moved from FetchScript().
273 // crossorigin content attribute."
274 CrossOriginAttributeValue cross_origin =
275 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
276
277 // 16. will be handled below once module script support is implemented.
278
279 // 17. "If the script element has a nonce attribute,
hiroshige 2017/04/14 00:13:29 Step 17 is moved from FetchScript().
280 // then let cryptographic nonce be that attribute's value.
281 // Otherwise, let cryptographic nonce be the empty string."
282 String nonce;
283 if (element_->IsNonceableElement())
284 nonce = element_->nonce();
285
286 // 18. is handled below.
287
288 // 19. "Let parser state be "parser-inserted"
hiroshige 2017/04/14 00:13:29 Step 19 is moved from FetchScript().
289 // if the script element has been flagged as "parser-inserted",
290 // and "not parser-inserted" otherwise."
291 ParserDisposition parser_state =
292 IsParserInserted() ? kParserInserted : kNotParserInserted;
284 293
285 // 21. "If the element has a src content attribute, run these substeps:" 294 // 21. "If the element has a src content attribute, run these substeps:"
286 if (element_->HasSourceAttribute()) { 295 if (element_->HasSourceAttribute()) {
287 FetchParameters::DeferOption defer = FetchParameters::kNoDefer; 296 // 21.1. Let src be the value of the element's src attribute.
288 if (!parser_inserted_ || element_->AsyncAttributeValue() || 297 String src =
289 element_->DeferAttributeValue()) 298 StripLeadingAndTrailingHTMLSpaces(element_->SourceAttributeValue());
hiroshige 2017/04/14 00:13:29 Moved from Line 489.
290 defer = FetchParameters::kLazyLoad; 299
291 if (document_write_intervention_ == 300 // 21.2. "If src is the empty string, queue a task to
hiroshige 2017/04/14 00:13:29 Moved from Line 579.
292 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) 301 // fire an event named error at the element, and abort these steps."
293 defer = FetchParameters::kIdleLoad; 302 if (src.IsEmpty()) {
294 if (!FetchScript(element_->SourceAttributeValue(), encoding, defer)) 303 // TODO(hiroshige): Make this asynchronous. Currently we fire the error
304 // event synchronously to keep the existing behavior.
305 DispatchErrorEvent();
295 return false; 306 return false;
307 }
308
309 // 21.3. "Set the element's from an external file flag."
hiroshige 2017/04/14 00:13:29 21.3 is moved from FetchScript(). Actually in this
310 is_external_script_ = true;
311
312 // 21.4. "Parse src relative to the element's node document."
313 KURL url = element_document.CompleteURL(src);
hiroshige 2017/04/14 00:13:29 This might cause slight behavior change: previousl
314
315 // 21.5. "If the previous step failed, queue a task to
hiroshige 2017/04/14 00:13:29 Moved from Line 579.
316 // fire an event named error at the element, and abort these steps."
317 if (!url.IsValid()) {
318 // TODO(hiroshige): Make this asynchronous. Currently we fire the error
319 // event synchronously to keep the existing behavior.
320 DispatchErrorEvent();
321 return false;
322 }
323
324 DCHECK(!resource_);
325
326 // 21.6. "Switch on the script's type:"
327 // - "classic":
328
329 // 14. "If the script element has a charset attribute,
hiroshige 2017/04/14 00:13:29 Step 14 is moved from above.
330 // then let encoding be the result of
331 // getting an encoding from the value of the charset attribute."
332 // "If the script element does not have a charset attribute,
333 // or if getting an encoding failed, let encoding
334 // be the same as the encoding of the script element's node
335 // document."
336 // TODO(hiroshige): Should we handle failure in getting an encoding?
337 String encoding;
338 if (!element_->CharsetAttributeValue().IsEmpty())
339 encoding = element_->CharsetAttributeValue();
340 else
341 encoding = element_document.characterSet();
342
343 // Step 16 is skipped because "module script credentials" is not used
344 // for classic scripts.
345
346 // 18. "If the script element has an integrity attribute,
hiroshige 2017/04/14 00:13:29 Step 18 is moved from FetchScript().
347 // then let integrity metadata be that attribute's value.
348 // Otherwise, let integrity metadata be the empty string."
349 String integrity_attr = element_->IntegrityAttributeValue();
350 IntegrityMetadataSet integrity_metadata;
351 if (!integrity_attr.IsEmpty()) {
352 SubresourceIntegrity::ParseIntegrityAttribute(
353 integrity_attr, integrity_metadata, &element_document);
354 }
355
356 if (!FetchClassicScript(url, element_document.Fetcher(), nonce,
357 integrity_metadata, parser_state, cross_origin,
358 element_document.GetSecurityOrigin(), encoding))
359 return false;
hiroshige 2017/04/14 00:13:29 Moved from Line 579. Oh, I should call DispatchErr
360
361 // - "module":
362 // TODO(hiroshige): Implement this.
363
364 // "When the chosen algorithm asynchronously completes, set
365 // the script's script to the result. At that time, the script is ready."
366 // When the script is ready, PendingScriptClient::pendingScriptFinished()
367 // is used as the notification, and the action to take when
368 // the script is ready is specified later, in
369 // - ScriptLoader::PrepareScript(), or
370 // - HTMLParserScriptRunner,
371 // depending on the conditions in Step 23 of "prepare a script".
296 } 372 }
297 373
298 // 22. "If the element does not have a src content attribute, 374 // 22. "If the element does not have a src content attribute,
299 // run these substeps:" 375 // run these substeps:"
300 376
301 // 22.1. "Let source text be the value of the text IDL attribute." 377 // 22.1. "Let source text be the value of the text IDL attribute."
302 // This step is done later: 378 // This step is done later:
303 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), 379 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause),
304 // as Element::textFromChildren() in ScriptLoader::scriptContent(), 380 // as Element::textFromChildren() in ScriptLoader::scriptContent(),
305 // - in HTMLParserScriptRunner::processScriptElementInternal() 381 // - in HTMLParserScriptRunner::processScriptElementInternal()
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 545
470 if (!ExecuteScript(ClassicScript::Create( 546 if (!ExecuteScript(ClassicScript::Create(
471 ScriptSourceCode(ScriptContent(), script_url, position)))) { 547 ScriptSourceCode(ScriptContent(), script_url, position)))) {
472 DispatchErrorEvent(); 548 DispatchErrorEvent();
473 return false; 549 return false;
474 } 550 }
475 551
476 return true; 552 return true;
477 } 553 }
478 554
479 // Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script 555 bool ScriptLoader::FetchClassicScript(
480 bool ScriptLoader::FetchScript(const String& source_url, 556 const KURL& url,
481 const String& encoding, 557 ResourceFetcher* fetcher,
482 FetchParameters::DeferOption defer) { 558 const String& nonce,
483 Document* element_document = &(element_->GetDocument()); 559 const IntegrityMetadataSet& integrity_metadata,
484 if (!element_->IsConnected() || element_->GetDocument() != element_document) 560 ParserDisposition parser_state,
485 return false; 561 CrossOriginAttributeValue cross_origin,
562 SecurityOrigin* security_origin,
563 const String& encoding) {
564 // https://html.spec.whatwg.org/#prepare-a-script
565 // 21.6, "classic":
566 // "Fetch a classic script given url, settings, ..."
567 ResourceRequest resource_request(url);
486 568
487 DCHECK(!resource_); 569 // [Intervention]
488 // 21. "If the element has a src content attribute, run these substeps:" 570 if (document_write_intervention_ ==
489 if (!StripLeadingAndTrailingHTMLSpaces(source_url).IsEmpty()) { 571 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
490 // 21.4. "Parse src relative to the element's node document." 572 resource_request.SetHTTPHeaderField(
491 ResourceRequest resource_request(element_document->CompleteURL(source_url)); 573 "Intervention",
492 574 "<https://www.chromestatus.com/feature/5718547946799104>");
493 // [Intervention]
494 if (document_write_intervention_ ==
495 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
496 resource_request.SetHTTPHeaderField(
497 "Intervention",
498 "<https://www.chromestatus.com/feature/5718547946799104>");
499 }
500
501 FetchParameters params(resource_request, element_->InitiatorName());
502
503 // 15. "Let CORS setting be the current state of the element's
hiroshige 2017/04/14 00:13:29 Lines 503--544 (Steps 15, 17, 18, 19) are moved to
504 // crossorigin content attribute."
505 CrossOriginAttributeValue cross_origin =
506 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
507
508 // 16. "Let module script credentials mode be determined by switching
509 // on CORS setting:"
510 // TODO(hiroshige): Implement this step for "module".
511
512 // 21.6, "classic": "Fetch a classic script given ... CORS setting
513 // ... and encoding."
514 if (cross_origin != kCrossOriginAttributeNotSet) {
515 params.SetCrossOriginAccessControl(element_document->GetSecurityOrigin(),
516 cross_origin);
517 }
518
519 params.SetCharset(encoding);
520
521 // 17. "If the script element has a nonce attribute,
522 // then let cryptographic nonce be that attribute's value.
523 // Otherwise, let cryptographic nonce be the empty string."
524 if (element_->IsNonceableElement())
525 params.SetContentSecurityPolicyNonce(element_->nonce());
526
527 // 19. "Let parser state be "parser-inserted"
528 // if the script element has been flagged as "parser-inserted",
529 // and "not parser-inserted" otherwise."
530 params.SetParserDisposition(IsParserInserted() ? kParserInserted
531 : kNotParserInserted);
532
533 params.SetDefer(defer);
534
535 // 18. "If the script element has an integrity attribute,
536 // then let integrity metadata be that attribute's value.
537 // Otherwise, let integrity metadata be the empty string."
538 String integrity_attr = element_->IntegrityAttributeValue();
539 if (!integrity_attr.IsEmpty()) {
540 IntegrityMetadataSet metadata_set;
541 SubresourceIntegrity::ParseIntegrityAttribute(
542 integrity_attr, metadata_set, element_document);
543 params.SetIntegrityMetadata(metadata_set);
544 }
545
546 // 21.6. "Switch on the script's type:"
547
548 // - "classic":
549 // "Fetch a classic script given url, settings, cryptographic nonce,
550 // integrity metadata, parser state, CORS setting, and encoding."
551 resource_ = ScriptResource::Fetch(params, element_document->Fetcher());
552
553 // - "module":
554 // "Fetch a module script graph given url, settings, "script",
555 // cryptographic nonce, parser state, and
556 // module script credentials mode."
557 // TODO(kouhei, hiroshige): Implement this.
558
559 // "When the chosen algorithm asynchronously completes, set
560 // the script's script to the result. At that time, the script is ready."
561 // When the script is ready, PendingScriptClient::pendingScriptFinished()
562 // is used as the notification, and the action to take when
563 // the script is ready is specified later, in
564 // - ScriptLoader::prepareScript(), or
565 // - HTMLParserScriptRunner,
566 // depending on the conditions in Step 23 of "prepare a script".
567
568 // 21.3. "Set the element's from an external file flag."
569 is_external_script_ = true;
hiroshige 2017/04/14 00:13:29 Step 21.3 is moved to FetchScript().
570 } 575 }
571 576
572 if (!resource_) { 577 FetchParameters params(resource_request, element_->InitiatorName());
573 // 21.2. "If src is the empty string, queue a task to 578
574 // fire an event named error at the element, and abort these steps." 579 // "... cryptographic nonce, ..."
575 // 21.5. "If the previous step failed, queue a task to 580 params.SetContentSecurityPolicyNonce(nonce);
576 // fire an event named error at the element, and abort these steps." 581
577 // TODO(hiroshige): Make this asynchronous. 582 // "... integrity metadata, ..."
578 DispatchErrorEvent(); 583 params.SetIntegrityMetadata(integrity_metadata);
hiroshige 2017/04/14 00:13:29 This clause handles three different cases, and are
584
585 // "... parser state, ..."
586 params.SetParserDisposition(parser_state);
587
588 // "... CORS setting, ..."
589 if (cross_origin != kCrossOriginAttributeNotSet) {
590 params.SetCrossOriginAccessControl(security_origin, cross_origin);
591 }
592
593 // "... and encoding."
594 params.SetCharset(encoding);
595
596 // This DeferOption logic is only for classic scripts, as we always set
hiroshige 2017/04/14 00:13:29 This logic is moved from PrepareScript() to clarif
597 // |kLazyLoad| for module scripts in ModuleScriptLoader.
598 FetchParameters::DeferOption defer = FetchParameters::kNoDefer;
599 if (!parser_inserted_ || element_->AsyncAttributeValue() ||
600 element_->DeferAttributeValue())
601 defer = FetchParameters::kLazyLoad;
602 if (document_write_intervention_ ==
603 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle)
604 defer = FetchParameters::kIdleLoad;
605 params.SetDefer(defer);
606
607 resource_ = ScriptResource::Fetch(params, fetcher);
608
609 if (!resource_)
579 return false; 610 return false;
580 }
581 611
582 // [Intervention] 612 // [Intervention]
583 if (created_during_document_write_ && 613 if (created_during_document_write_ &&
584 resource_->GetResourceRequest().GetCachePolicy() == 614 resource_->GetResourceRequest().GetCachePolicy() ==
585 WebCachePolicy::kReturnCacheDataDontLoad) { 615 WebCachePolicy::kReturnCacheDataDontLoad) {
586 document_write_intervention_ = 616 document_write_intervention_ =
587 DocumentWriteIntervention::kDoNotFetchDocWrittenScript; 617 DocumentWriteIntervention::kDoNotFetchDocWrittenScript;
588 } 618 }
589 619
590 return true; 620 return true;
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 // then abort these steps at this point. The script is not executed. 811 // then abort these steps at this point. The script is not executed.
782 return DeprecatedEqualIgnoringCase(event_attribute, "onload") || 812 return DeprecatedEqualIgnoringCase(event_attribute, "onload") ||
783 DeprecatedEqualIgnoringCase(event_attribute, "onload()"); 813 DeprecatedEqualIgnoringCase(event_attribute, "onload()");
784 } 814 }
785 815
786 String ScriptLoader::ScriptContent() const { 816 String ScriptLoader::ScriptContent() const {
787 return element_->TextFromChildren(); 817 return element_->TextFromChildren();
788 } 818 }
789 819
790 } // namespace blink 820 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/ScriptLoader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698