| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "core/html/parser/HTMLParserScriptRunner.h" | 26 #include "core/html/parser/HTMLParserScriptRunner.h" |
| 27 | 27 |
| 28 #include <inttypes.h> | 28 #include <inttypes.h> |
| 29 #include <memory> | 29 #include <memory> |
| 30 #include "bindings/core/v8/Microtask.h" | 30 #include "bindings/core/v8/Microtask.h" |
| 31 #include "bindings/core/v8/ScriptSourceCode.h" | 31 #include "bindings/core/v8/ScriptSourceCode.h" |
| 32 #include "bindings/core/v8/V8BindingForCore.h" | 32 #include "bindings/core/v8/V8BindingForCore.h" |
| 33 #include "bindings/core/v8/V8PerIsolateData.h" | 33 #include "bindings/core/v8/V8PerIsolateData.h" |
| 34 #include "core/dom/ClassicPendingScript.h" |
| 34 #include "core/dom/ClassicScript.h" | 35 #include "core/dom/ClassicScript.h" |
| 35 #include "core/dom/DocumentParserTiming.h" | 36 #include "core/dom/DocumentParserTiming.h" |
| 36 #include "core/dom/Element.h" | 37 #include "core/dom/Element.h" |
| 37 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" | 38 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" |
| 38 #include "core/dom/ScriptLoader.h" | 39 #include "core/dom/ScriptLoader.h" |
| 39 #include "core/dom/TaskRunnerHelper.h" | 40 #include "core/dom/TaskRunnerHelper.h" |
| 40 #include "core/events/Event.h" | 41 #include "core/events/Event.h" |
| 41 #include "core/frame/LocalFrame.h" | 42 #include "core/frame/LocalFrame.h" |
| 42 #include "core/html/parser/HTMLInputStream.h" | 43 #include "core/html/parser/HTMLInputStream.h" |
| 43 #include "core/html/parser/HTMLParserScriptRunnerHost.h" | 44 #include "core/html/parser/HTMLParserScriptRunnerHost.h" |
| 44 #include "core/html/parser/NestingLevelIncrementer.h" | 45 #include "core/html/parser/NestingLevelIncrementer.h" |
| 45 #include "core/inspector/ConsoleMessage.h" | 46 #include "core/inspector/ConsoleMessage.h" |
| 46 #include "core/loader/resource/ScriptResource.h" | 47 #include "core/loader/resource/ScriptResource.h" |
| 47 #include "platform/Histogram.h" | 48 #include "platform/Histogram.h" |
| 48 #include "platform/WebFrameScheduler.h" | 49 #include "platform/WebFrameScheduler.h" |
| 49 #include "platform/instrumentation/tracing/TraceEvent.h" | 50 #include "platform/instrumentation/tracing/TraceEvent.h" |
| 50 #include "platform/instrumentation/tracing/TracedValue.h" | 51 #include "platform/instrumentation/tracing/TracedValue.h" |
| 51 #include "platform/loader/fetch/MemoryCache.h" | |
| 52 #include "public/platform/Platform.h" | 52 #include "public/platform/Platform.h" |
| 53 | 53 |
| 54 namespace blink { | 54 namespace blink { |
| 55 | 55 |
| 56 namespace { | 56 namespace { |
| 57 | 57 |
| 58 // TODO(bmcquade): move this to a shared location if we find ourselves wanting | 58 // TODO(bmcquade): move this to a shared location if we find ourselves wanting |
| 59 // to trace similar data elsewhere in the codebase. | 59 // to trace similar data elsewhere in the codebase. |
| 60 std::unique_ptr<TracedValue> GetTraceArgsForScriptElement( | 60 std::unique_ptr<TracedValue> GetTraceArgsForScriptElement( |
| 61 ScriptElementBase* element, | 61 ScriptElementBase* element, |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 void FetchBlockedDocWriteScript(ScriptElementBase* element, | 284 void FetchBlockedDocWriteScript(ScriptElementBase* element, |
| 285 bool is_parser_inserted, | 285 bool is_parser_inserted, |
| 286 const TextPosition& script_start_position) { | 286 const TextPosition& script_start_position) { |
| 287 DCHECK(element); | 287 DCHECK(element); |
| 288 | 288 |
| 289 ScriptLoader* script_loader = | 289 ScriptLoader* script_loader = |
| 290 ScriptLoader::Create(element, is_parser_inserted, false, false); | 290 ScriptLoader::Create(element, is_parser_inserted, false, false); |
| 291 DCHECK(script_loader); | 291 DCHECK(script_loader); |
| 292 script_loader->SetFetchDocWrittenScriptDeferIdle(); | 292 script_loader->SetFetchDocWrittenScriptDeferIdle(); |
| 293 script_loader->PrepareScript(script_start_position); | 293 script_loader->PrepareScript(script_start_position); |
| 294 CHECK_EQ(script_loader->GetScriptType(), ScriptType::kClassic); |
| 294 } | 295 } |
| 295 | 296 |
| 296 void EmitWarningForDocWriteScripts(const String& url, Document& document) { | 297 void EmitWarningForDocWriteScripts(const String& url, Document& document) { |
| 297 String message = | 298 String message = |
| 298 "The Parser-blocking, cross site (i.e. different eTLD+1) " | 299 "The Parser-blocking, cross site (i.e. different eTLD+1) " |
| 299 "script, " + | 300 "script, " + |
| 300 url + | 301 url + |
| 301 ", invoked via document.write was NOT BLOCKED on this page load, but MAY " | 302 ", invoked via document.write was NOT BLOCKED on this page load, but MAY " |
| 302 "be blocked by the browser in future page loads with poor network " | 303 "be blocked by the browser in future page loads with poor network " |
| 303 "connectivity."; | 304 "connectivity."; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 328 | 329 |
| 329 if (ParserBlockingScript() != pending_script) | 330 if (ParserBlockingScript() != pending_script) |
| 330 return; | 331 return; |
| 331 | 332 |
| 332 ScriptElementBase* element = ParserBlockingScript()->GetElement(); | 333 ScriptElementBase* element = ParserBlockingScript()->GetElement(); |
| 333 | 334 |
| 334 ScriptLoader* script_loader = element->Loader(); | 335 ScriptLoader* script_loader = element->Loader(); |
| 335 if (!script_loader || !script_loader->DisallowedFetchForDocWrittenScript()) | 336 if (!script_loader || !script_loader->DisallowedFetchForDocWrittenScript()) |
| 336 return; | 337 return; |
| 337 | 338 |
| 339 // We don't allow document.write() and its intervention with module scripts. |
| 340 CHECK_EQ(pending_script->GetScriptType(), ScriptType::kClassic); |
| 341 |
| 338 if (!pending_script->ErrorOccurred()) { | 342 if (!pending_script->ErrorOccurred()) { |
| 339 EmitWarningForDocWriteScripts( | 343 EmitWarningForDocWriteScripts( |
| 340 pending_script->GetResource()->Url().GetString(), *document_); | 344 pending_script->UrlForClassicScript().GetString(), *document_); |
| 341 return; | 345 return; |
| 342 } | 346 } |
| 343 | 347 |
| 344 // Due to dependency violation, not able to check the exact error to be | 348 // Due to dependency violation, not able to check the exact error to be |
| 345 // ERR_CACHE_MISS but other errors are rare with | 349 // ERR_CACHE_MISS but other errors are rare with |
| 346 // WebCachePolicy::ReturnCacheDataDontLoad. | 350 // WebCachePolicy::ReturnCacheDataDontLoad. |
| 347 | 351 |
| 348 EmitErrorForDocWriteScripts(pending_script->GetResource()->Url().GetString(), | 352 EmitErrorForDocWriteScripts(pending_script->UrlForClassicScript().GetString(), |
| 349 *document_); | 353 *document_); |
| 350 TextPosition starting_position = ParserBlockingScript()->StartingPosition(); | 354 TextPosition starting_position = ParserBlockingScript()->StartingPosition(); |
| 351 bool is_parser_inserted = script_loader->IsParserInserted(); | 355 bool is_parser_inserted = script_loader->IsParserInserted(); |
| 352 // Remove this resource entry from memory cache as the new request | 356 // Remove this resource entry from memory cache as the new request |
| 353 // should not join onto this existing entry. | 357 // should not join onto this existing entry. |
| 354 GetMemoryCache()->Remove(pending_script->GetResource()); | 358 pending_script->RemoveFromMemoryCache(); |
| 355 FetchBlockedDocWriteScript(element, is_parser_inserted, starting_position); | 359 FetchBlockedDocWriteScript(element, is_parser_inserted, starting_position); |
| 356 } | 360 } |
| 357 | 361 |
| 358 void HTMLParserScriptRunner::PendingScriptFinished( | 362 void HTMLParserScriptRunner::PendingScriptFinished( |
| 359 PendingScript* pending_script) { | 363 PendingScript* pending_script) { |
| 360 // Handle cancellations of parser-blocking script loads without | 364 // Handle cancellations of parser-blocking script loads without |
| 361 // notifying the host (i.e., parser) if these were initiated by nested | 365 // notifying the host (i.e., parser) if these were initiated by nested |
| 362 // document.write()s. The cancellation may have been triggered by | 366 // document.write()s. The cancellation may have been triggered by |
| 363 // script execution to signal an abrupt stop (e.g., window.close().) | 367 // script execution to signal an abrupt stop (e.g., window.close().) |
| 364 // | 368 // |
| 365 // The parser is unprepared to be told, and doesn't need to be. | 369 // The parser is unprepared to be told, and doesn't need to be. |
| 366 if (IsExecutingScript() && pending_script->GetResource()->WasCanceled()) { | 370 if (IsExecutingScript() && pending_script->WasCanceled()) { |
| 367 pending_script->Dispose(); | 371 pending_script->Dispose(); |
| 368 | 372 |
| 369 if (pending_script == ParserBlockingScript()) { | 373 if (pending_script == ParserBlockingScript()) { |
| 370 parser_blocking_script_ = nullptr; | 374 parser_blocking_script_ = nullptr; |
| 371 } else { | 375 } else { |
| 372 CHECK_EQ(pending_script, scripts_to_execute_after_parsing_.front()); | 376 CHECK_EQ(pending_script, scripts_to_execute_after_parsing_.front()); |
| 373 | 377 |
| 374 // TODO(hiroshige): Remove this CHECK() before going to beta. | 378 // TODO(hiroshige): Remove this CHECK() before going to beta. |
| 375 // This is only to make clusterfuzz to find a test case that executes | 379 // This is only to make clusterfuzz to find a test case that executes |
| 376 // this code path. | 380 // this code path. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 // Step 3 of https://html.spec.whatwg.org/#the-end: | 502 // Step 3 of https://html.spec.whatwg.org/#the-end: |
| 499 // "If the list of scripts that will execute when the document has | 503 // "If the list of scripts that will execute when the document has |
| 500 // finished parsing is not empty, run these substeps:" | 504 // finished parsing is not empty, run these substeps:" |
| 501 bool HTMLParserScriptRunner::ExecuteScriptsWaitingForParsing() { | 505 bool HTMLParserScriptRunner::ExecuteScriptsWaitingForParsing() { |
| 502 TRACE_EVENT0("blink", | 506 TRACE_EVENT0("blink", |
| 503 "HTMLParserScriptRunner::executeScriptsWaitingForParsing"); | 507 "HTMLParserScriptRunner::executeScriptsWaitingForParsing"); |
| 504 | 508 |
| 505 while (!scripts_to_execute_after_parsing_.IsEmpty()) { | 509 while (!scripts_to_execute_after_parsing_.IsEmpty()) { |
| 506 DCHECK(!IsExecutingScript()); | 510 DCHECK(!IsExecutingScript()); |
| 507 DCHECK(!HasParserBlockingScript()); | 511 DCHECK(!HasParserBlockingScript()); |
| 508 DCHECK(scripts_to_execute_after_parsing_.front()->GetResource()); | 512 DCHECK(scripts_to_execute_after_parsing_.front()->IsExternal()); |
| 509 | 513 |
| 510 // 1. "Spin the event loop until the first script in the list of scripts | 514 // 1. "Spin the event loop until the first script in the list of scripts |
| 511 // that will execute when the document has finished parsing | 515 // that will execute when the document has finished parsing |
| 512 // has its "ready to be parser-executed" flag set and | 516 // has its "ready to be parser-executed" flag set and |
| 513 // the parser's Document has no style sheet that is blocking scripts." | 517 // the parser's Document has no style sheet that is blocking scripts." |
| 514 // TODO(hiroshige): Is the latter part checked anywhere? | 518 // TODO(hiroshige): Is the latter part checked anywhere? |
| 515 if (!scripts_to_execute_after_parsing_.front()->IsReady()) { | 519 if (!scripts_to_execute_after_parsing_.front()->IsReady()) { |
| 516 scripts_to_execute_after_parsing_.front()->WatchForLoad(this); | 520 scripts_to_execute_after_parsing_.front()->WatchForLoad(this); |
| 517 TraceParserBlockingScript(scripts_to_execute_after_parsing_.front().Get(), | 521 TraceParserBlockingScript(scripts_to_execute_after_parsing_.front().Get(), |
| 518 !document_->IsScriptExecutionReady()); | 522 !document_->IsScriptExecutionReady()); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 544 // 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script | 548 // 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script |
| 545 void HTMLParserScriptRunner::RequestParsingBlockingScript(Element* element) { | 549 void HTMLParserScriptRunner::RequestParsingBlockingScript(Element* element) { |
| 546 // "The element is the pending parsing-blocking script of the Document of | 550 // "The element is the pending parsing-blocking script of the Document of |
| 547 // the parser that created the element. | 551 // the parser that created the element. |
| 548 // (There can only be one such script per Document at a time.)" | 552 // (There can only be one such script per Document at a time.)" |
| 549 CHECK(!ParserBlockingScript()); | 553 CHECK(!ParserBlockingScript()); |
| 550 parser_blocking_script_ = RequestPendingScript(element); | 554 parser_blocking_script_ = RequestPendingScript(element); |
| 551 if (!ParserBlockingScript()) | 555 if (!ParserBlockingScript()) |
| 552 return; | 556 return; |
| 553 | 557 |
| 554 DCHECK(ParserBlockingScript()->GetResource()); | 558 DCHECK(ParserBlockingScript()->IsExternal()); |
| 555 | 559 |
| 556 // We only care about a load callback if resource is not already in the cache. | 560 // We only care about a load callback if resource is not already in the cache. |
| 557 // Callers will attempt to run the m_parserBlockingScript if possible before | 561 // Callers will attempt to run the m_parserBlockingScript if possible before |
| 558 // returning control to the parser. | 562 // returning control to the parser. |
| 559 if (!ParserBlockingScript()->IsReady()) { | 563 if (!ParserBlockingScript()->IsReady()) { |
| 560 parser_blocking_script_->StartStreamingIfPossible( | 564 parser_blocking_script_->StartStreamingIfPossible( |
| 561 document_, ScriptStreamer::kParsingBlocking); | 565 document_, ScriptStreamer::kParsingBlocking); |
| 562 parser_blocking_script_->WatchForLoad(this); | 566 parser_blocking_script_->WatchForLoad(this); |
| 563 } | 567 } |
| 564 } | 568 } |
| 565 | 569 |
| 566 // 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script | 570 // 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script |
| 567 void HTMLParserScriptRunner::RequestDeferredScript(Element* element) { | 571 void HTMLParserScriptRunner::RequestDeferredScript(Element* element) { |
| 568 PendingScript* pending_script = RequestPendingScript(element); | 572 PendingScript* pending_script = RequestPendingScript(element); |
| 569 if (!pending_script) | 573 if (!pending_script) |
| 570 return; | 574 return; |
| 571 | 575 |
| 572 if (!pending_script->IsReady()) { | 576 if (!pending_script->IsReady()) { |
| 573 pending_script->StartStreamingIfPossible(document_, | 577 pending_script->StartStreamingIfPossible(document_, |
| 574 ScriptStreamer::kDeferred); | 578 ScriptStreamer::kDeferred); |
| 575 } | 579 } |
| 576 | 580 |
| 577 DCHECK(pending_script->GetResource()); | 581 DCHECK(pending_script->IsExternal()); |
| 578 | 582 |
| 579 // "Add the element to the end of the list of scripts that will execute | 583 // "Add the element to the end of the list of scripts that will execute |
| 580 // when the document has finished parsing associated with the Document | 584 // when the document has finished parsing associated with the Document |
| 581 // of the parser that created the element." | 585 // of the parser that created the element." |
| 582 scripts_to_execute_after_parsing_.push_back(pending_script); | 586 scripts_to_execute_after_parsing_.push_back(pending_script); |
| 583 } | 587 } |
| 584 | 588 |
| 585 PendingScript* HTMLParserScriptRunner::RequestPendingScript( | 589 PendingScript* HTMLParserScriptRunner::RequestPendingScript( |
| 586 Element* element) const { | 590 Element* element) const { |
| 587 ScriptElementBase* script_element = | 591 ScriptElementBase* script_element = |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 } else if (script_loader->ReadyToBeParserExecuted()) { | 641 } else if (script_loader->ReadyToBeParserExecuted()) { |
| 638 // 5th Clause of Step 23. | 642 // 5th Clause of Step 23. |
| 639 // "If ... it's an HTML parser | 643 // "If ... it's an HTML parser |
| 640 // whose script nesting level is not greater than one" | 644 // whose script nesting level is not greater than one" |
| 641 if (reentry_permit_->ScriptNestingLevel() == 1u) { | 645 if (reentry_permit_->ScriptNestingLevel() == 1u) { |
| 642 // "The element is the pending parsing-blocking script of the | 646 // "The element is the pending parsing-blocking script of the |
| 643 // Document of the parser that created the element. | 647 // Document of the parser that created the element. |
| 644 // (There can only be one such script per Document at a time.)" | 648 // (There can only be one such script per Document at a time.)" |
| 645 CHECK(!parser_blocking_script_); | 649 CHECK(!parser_blocking_script_); |
| 646 parser_blocking_script_ = | 650 parser_blocking_script_ = |
| 647 PendingScript::Create(element, script_start_position); | 651 ClassicPendingScript::Create(element, script_start_position); |
| 648 } else { | 652 } else { |
| 649 // 6th Clause of Step 23. | 653 // 6th Clause of Step 23. |
| 650 // "Immediately execute the script block, | 654 // "Immediately execute the script block, |
| 651 // even if other scripts are already executing." | 655 // even if other scripts are already executing." |
| 652 // TODO(hiroshige): Merge the block into ScriptLoader::prepareScript(). | 656 // TODO(hiroshige): Merge the block into ScriptLoader::prepareScript(). |
| 653 DCHECK_GT(reentry_permit_->ScriptNestingLevel(), 1u); | 657 DCHECK_GT(reentry_permit_->ScriptNestingLevel(), 1u); |
| 654 if (parser_blocking_script_) | 658 if (parser_blocking_script_) |
| 655 parser_blocking_script_->Dispose(); | 659 parser_blocking_script_->Dispose(); |
| 656 parser_blocking_script_ = nullptr; | 660 parser_blocking_script_ = nullptr; |
| 657 ScriptSourceCode source_code(script->textContent(), | 661 ScriptSourceCode source_code(script->textContent(), |
| (...skipping 19 matching lines...) Expand all Loading... |
| 677 | 681 |
| 678 DEFINE_TRACE(HTMLParserScriptRunner) { | 682 DEFINE_TRACE(HTMLParserScriptRunner) { |
| 679 visitor->Trace(document_); | 683 visitor->Trace(document_); |
| 680 visitor->Trace(host_); | 684 visitor->Trace(host_); |
| 681 visitor->Trace(parser_blocking_script_); | 685 visitor->Trace(parser_blocking_script_); |
| 682 visitor->Trace(scripts_to_execute_after_parsing_); | 686 visitor->Trace(scripts_to_execute_after_parsing_); |
| 683 PendingScriptClient::Trace(visitor); | 687 PendingScriptClient::Trace(visitor); |
| 684 } | 688 } |
| 685 | 689 |
| 686 } // namespace blink | 690 } // namespace blink |
| OLD | NEW |