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

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: Rebase 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/MemoryCache.h" 51 #include "platform/loader/fetch/MemoryCache.h"
52 #include "platform/loader/fetch/ResourceFetcher.h" 52 #include "platform/loader/fetch/ResourceFetcher.h"
53 #include "platform/network/mime/MIMETypeRegistry.h" 53 #include "platform/network/mime/MIMETypeRegistry.h"
54 #include "platform/weborigin/SecurityOrigin.h" 54 #include "platform/weborigin/SecurityOrigin.h"
55 #include "platform/wtf/StdLibExtras.h" 55 #include "platform/wtf/StdLibExtras.h"
56 #include "platform/wtf/text/StringBuilder.h" 56 #include "platform/wtf/text/StringBuilder.h"
57 #include "platform/wtf/text/StringHash.h" 57 #include "platform/wtf/text/StringHash.h"
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 295
296 // 11. "If the script element has a nomodule content attribute 296 // 11. "If the script element has a nomodule content attribute
297 // and the script's type is "classic", then abort these steps. 297 // and the script's type is "classic", then abort these steps.
298 // The script is not executed." 298 // The script is not executed."
299 // TODO(japhet): Implement this step. 299 // TODO(japhet): Implement this step.
300 300
301 // 13. 301 // 13.
302 if (!IsScriptForEventSupported()) 302 if (!IsScriptForEventSupported())
303 return false; 303 return false;
304 304
305 // 14. "If the script element has a charset attribute, 305 // 14. is handled below.
306 // then let encoding be the result of
307 // getting an encoding from the value of the charset attribute."
308 // "If the script element does not have a charset attribute,
309 // or if getting an encoding failed, let encoding
310 // be the same as the encoding of the script element's node document."
311 // TODO(hiroshige): Should we handle failure in getting an encoding?
312 String encoding;
313 if (!element_->CharsetAttributeValue().IsEmpty())
314 encoding = element_->CharsetAttributeValue();
315 else
316 encoding = element_document.characterSet();
317 306
318 // Steps 15--20 are handled in fetchScript(). 307 // 15. "Let CORS setting be the current state of the element's
308 // crossorigin content attribute."
309 CrossOriginAttributeValue cross_origin =
310 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
311
312 // 16. will be handled below once module script support is implemented.
313
314 // 17. "If the script element has a nonce attribute,
315 // then let cryptographic nonce be that attribute's value.
316 // Otherwise, let cryptographic nonce be the empty string."
317 String nonce;
318 if (element_->IsNonceableElement())
319 nonce = element_->nonce();
320
321 // 18. is handled below.
322
323 // 19. "Let parser state be "parser-inserted"
324 // if the script element has been flagged as "parser-inserted",
325 // and "not parser-inserted" otherwise."
326 ParserDisposition parser_state =
327 IsParserInserted() ? kParserInserted : kNotParserInserted;
319 328
320 // 21. "If the element has a src content attribute, run these substeps:" 329 // 21. "If the element has a src content attribute, run these substeps:"
321 if (element_->HasSourceAttribute()) { 330 if (element_->HasSourceAttribute()) {
322 FetchParameters::DeferOption defer = FetchParameters::kNoDefer; 331 // 21.1. Let src be the value of the element's src attribute.
323 if (!parser_inserted_ || element_->AsyncAttributeValue() || 332 String src =
324 element_->DeferAttributeValue()) 333 StripLeadingAndTrailingHTMLSpaces(element_->SourceAttributeValue());
325 defer = FetchParameters::kLazyLoad; 334
326 if (document_write_intervention_ == 335 // 21.2. "If src is the empty string, queue a task to
327 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) 336 // fire an event named error at the element, and abort these steps."
328 defer = FetchParameters::kIdleLoad; 337 if (src.IsEmpty()) {
329 if (!FetchScript(element_->SourceAttributeValue(), encoding, defer)) 338 // TODO(hiroshige): Make this asynchronous. Currently we fire the error
339 // event synchronously to keep the existing behavior.
340 DispatchErrorEvent();
330 return false; 341 return false;
342 }
343
344 // 21.3. "Set the element's from an external file flag."
345 is_external_script_ = true;
346
347 // 21.4. "Parse src relative to the element's node document."
348 // TODO(hiroshige): Use CompleteURL(src) instead.
349 KURL url = element_document.CompleteURL(element_->SourceAttributeValue());
350
351 // 21.5. "If the previous step failed, queue a task to
352 // fire an event named error at the element, and abort these steps."
353 if (!url.IsValid()) {
354 // TODO(hiroshige): Make this asynchronous. Currently we fire the error
355 // event synchronously to keep the existing behavior.
356 DispatchErrorEvent();
357 return false;
358 }
359
360 DCHECK(!resource_);
361
362 // 21.6. "Switch on the script's type:"
363 // - "classic":
364
365 // 14. "If the script element has a charset attribute,
366 // then let encoding be the result of
367 // getting an encoding from the value of the charset attribute."
368 // "If the script element does not have a charset attribute,
369 // or if getting an encoding failed, let encoding
370 // be the same as the encoding of the script element's node
371 // document."
372 // TODO(hiroshige): Should we handle failure in getting an encoding?
373 String encoding;
374 if (!element_->CharsetAttributeValue().IsEmpty())
375 encoding = element_->CharsetAttributeValue();
376 else
377 encoding = element_document.characterSet();
378
379 // Step 16 is skipped because "module script credentials" is not used
380 // for classic scripts.
381
382 // 18. "If the script element has an integrity attribute,
383 // then let integrity metadata be that attribute's value.
384 // Otherwise, let integrity metadata be the empty string."
385 String integrity_attr = element_->IntegrityAttributeValue();
386 IntegrityMetadataSet integrity_metadata;
387 if (!integrity_attr.IsEmpty()) {
388 SubresourceIntegrity::ParseIntegrityAttribute(
389 integrity_attr, integrity_metadata, &element_document);
390 }
391
392 if (!FetchClassicScript(url, element_document.Fetcher(), nonce,
393 integrity_metadata, parser_state, cross_origin,
394 element_document.GetSecurityOrigin(), encoding)) {
395 // TODO(hiroshige): Make this asynchronous. Currently we fire the error
396 // event synchronously to keep the existing behavior.
397 DispatchErrorEvent();
398 return false;
399 }
400
401 DCHECK(resource_);
402
403 // - "module":
404 // TODO(hiroshige): Implement this.
405
406 // "When the chosen algorithm asynchronously completes, set
407 // the script's script to the result. At that time, the script is ready."
408 // When the script is ready, PendingScriptClient::pendingScriptFinished()
409 // is used as the notification, and the action to take when
410 // the script is ready is specified later, in
411 // - ScriptLoader::PrepareScript(), or
412 // - HTMLParserScriptRunner,
413 // depending on the conditions in Step 23 of "prepare a script".
331 } 414 }
332 415
333 // 22. "If the element does not have a src content attribute, 416 // 22. "If the element does not have a src content attribute,
334 // run these substeps:" 417 // run these substeps:"
335 418
336 // 22.1. "Let source text be the value of the text IDL attribute." 419 // 22.1. "Let source text be the value of the text IDL attribute."
337 // This step is done later: 420 // This step is done later:
338 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), 421 // - in ScriptLoader::pendingScript() (Step 23, 6th Clause),
339 // as Element::textFromChildren() in ScriptLoader::scriptContent(), 422 // as Element::textFromChildren() in ScriptLoader::scriptContent(),
340 // - in HTMLParserScriptRunner::processScriptElementInternal() 423 // - in HTMLParserScriptRunner::processScriptElementInternal()
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 587
505 if (!ExecuteScript(ClassicScript::Create( 588 if (!ExecuteScript(ClassicScript::Create(
506 ScriptSourceCode(ScriptContent(), script_url, position)))) { 589 ScriptSourceCode(ScriptContent(), script_url, position)))) {
507 DispatchErrorEvent(); 590 DispatchErrorEvent();
508 return false; 591 return false;
509 } 592 }
510 593
511 return true; 594 return true;
512 } 595 }
513 596
514 // Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script 597 bool ScriptLoader::FetchClassicScript(
515 bool ScriptLoader::FetchScript(const String& source_url, 598 const KURL& url,
516 const String& encoding, 599 ResourceFetcher* fetcher,
517 FetchParameters::DeferOption defer) { 600 const String& nonce,
518 Document* element_document = &(element_->GetDocument()); 601 const IntegrityMetadataSet& integrity_metadata,
519 if (!element_->IsConnected() || element_->GetDocument() != element_document) 602 ParserDisposition parser_state,
520 return false; 603 CrossOriginAttributeValue cross_origin,
604 SecurityOrigin* security_origin,
605 const String& encoding) {
606 // https://html.spec.whatwg.org/#prepare-a-script
607 // 21.6, "classic":
608 // "Fetch a classic script given url, settings, ..."
609 ResourceRequest resource_request(url);
521 610
522 DCHECK(!resource_); 611 // [Intervention]
523 // 21. "If the element has a src content attribute, run these substeps:" 612 if (document_write_intervention_ ==
524 if (!StripLeadingAndTrailingHTMLSpaces(source_url).IsEmpty()) { 613 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
525 // 21.4. "Parse src relative to the element's node document." 614 resource_request.SetHTTPHeaderField(
526 ResourceRequest resource_request(element_document->CompleteURL(source_url)); 615 "Intervention",
527 616 "<https://www.chromestatus.com/feature/5718547946799104>");
528 // [Intervention]
529 if (document_write_intervention_ ==
530 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
531 resource_request.SetHTTPHeaderField(
532 "Intervention",
533 "<https://www.chromestatus.com/feature/5718547946799104>");
534 }
535
536 FetchParameters params(resource_request, element_->InitiatorName());
537
538 // 15. "Let CORS setting be the current state of the element's
539 // crossorigin content attribute."
540 CrossOriginAttributeValue cross_origin =
541 GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue());
542
543 // 16. "Let module script credentials mode be determined by switching
544 // on CORS setting:"
545 // TODO(hiroshige): Implement this step for "module".
546
547 // 21.6, "classic": "Fetch a classic script given ... CORS setting
548 // ... and encoding."
549 if (cross_origin != kCrossOriginAttributeNotSet) {
550 params.SetCrossOriginAccessControl(element_document->GetSecurityOrigin(),
551 cross_origin);
552 }
553
554 params.SetCharset(encoding);
555
556 // 17. "If the script element has a nonce attribute,
557 // then let cryptographic nonce be that attribute's value.
558 // Otherwise, let cryptographic nonce be the empty string."
559 if (element_->IsNonceableElement())
560 params.SetContentSecurityPolicyNonce(element_->nonce());
561
562 // 19. "Let parser state be "parser-inserted"
563 // if the script element has been flagged as "parser-inserted",
564 // and "not parser-inserted" otherwise."
565 params.SetParserDisposition(IsParserInserted() ? kParserInserted
566 : kNotParserInserted);
567
568 params.SetDefer(defer);
569
570 // 18. "If the script element has an integrity attribute,
571 // then let integrity metadata be that attribute's value.
572 // Otherwise, let integrity metadata be the empty string."
573 String integrity_attr = element_->IntegrityAttributeValue();
574 if (!integrity_attr.IsEmpty()) {
575 IntegrityMetadataSet metadata_set;
576 SubresourceIntegrity::ParseIntegrityAttribute(
577 integrity_attr, metadata_set, element_document);
578 params.SetIntegrityMetadata(metadata_set);
579 }
580
581 // 21.6. "Switch on the script's type:"
582
583 // - "classic":
584 // "Fetch a classic script given url, settings, cryptographic nonce,
585 // integrity metadata, parser state, CORS setting, and encoding."
586 resource_ = ScriptResource::Fetch(params, element_document->Fetcher());
587
588 // - "module":
589 // "Fetch a module script graph given url, settings, "script",
590 // cryptographic nonce, parser state, and
591 // module script credentials mode."
592 // TODO(kouhei, hiroshige): Implement this.
593
594 // "When the chosen algorithm asynchronously completes, set
595 // the script's script to the result. At that time, the script is ready."
596 // When the script is ready, PendingScriptClient::pendingScriptFinished()
597 // is used as the notification, and the action to take when
598 // the script is ready is specified later, in
599 // - ScriptLoader::prepareScript(), or
600 // - HTMLParserScriptRunner,
601 // depending on the conditions in Step 23 of "prepare a script".
602
603 // 21.3. "Set the element's from an external file flag."
604 is_external_script_ = true;
605 } 617 }
606 618
607 if (!resource_) { 619 FetchParameters params(resource_request, element_->InitiatorName());
608 // 21.2. "If src is the empty string, queue a task to 620
609 // fire an event named error at the element, and abort these steps." 621 // "... cryptographic nonce, ..."
610 // 21.5. "If the previous step failed, queue a task to 622 params.SetContentSecurityPolicyNonce(nonce);
611 // fire an event named error at the element, and abort these steps." 623
612 // TODO(hiroshige): Make this asynchronous. 624 // "... integrity metadata, ..."
613 DispatchErrorEvent(); 625 params.SetIntegrityMetadata(integrity_metadata);
626
627 // "... parser state, ..."
628 params.SetParserDisposition(parser_state);
629
630 // "... CORS setting, ..."
631 if (cross_origin != kCrossOriginAttributeNotSet) {
632 params.SetCrossOriginAccessControl(security_origin, cross_origin);
633 }
634
635 // "... and encoding."
636 params.SetCharset(encoding);
637
638 // This DeferOption logic is only for classic scripts, as we always set
639 // |kLazyLoad| for module scripts in ModuleScriptLoader.
640 FetchParameters::DeferOption defer = FetchParameters::kNoDefer;
641 if (!parser_inserted_ || element_->AsyncAttributeValue() ||
642 element_->DeferAttributeValue())
643 defer = FetchParameters::kLazyLoad;
644 if (document_write_intervention_ ==
645 DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle)
646 defer = FetchParameters::kIdleLoad;
647 params.SetDefer(defer);
648
649 resource_ = ScriptResource::Fetch(params, fetcher);
650
651 if (!resource_)
614 return false; 652 return false;
615 }
616 653
617 // [Intervention] 654 // [Intervention]
618 if (created_during_document_write_ && 655 if (created_during_document_write_ &&
619 resource_->GetResourceRequest().GetCachePolicy() == 656 resource_->GetResourceRequest().GetCachePolicy() ==
620 WebCachePolicy::kReturnCacheDataDontLoad) { 657 WebCachePolicy::kReturnCacheDataDontLoad) {
621 document_write_intervention_ = 658 document_write_intervention_ =
622 DocumentWriteIntervention::kDoNotFetchDocWrittenScript; 659 DocumentWriteIntervention::kDoNotFetchDocWrittenScript;
623 } 660 }
624 661
625 return true; 662 return true;
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 // then abort these steps at this point. The script is not executed. 852 // then abort these steps at this point. The script is not executed.
816 return DeprecatedEqualIgnoringCase(event_attribute, "onload") || 853 return DeprecatedEqualIgnoringCase(event_attribute, "onload") ||
817 DeprecatedEqualIgnoringCase(event_attribute, "onload()"); 854 DeprecatedEqualIgnoringCase(event_attribute, "onload()");
818 } 855 }
819 856
820 String ScriptLoader::ScriptContent() const { 857 String ScriptLoader::ScriptContent() const {
821 return element_->TextFromChildren(); 858 return element_->TextFromChildren();
822 } 859 }
823 860
824 } // namespace blink 861 } // 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