Commit 77c5ade4 authored by hiroshige's avatar hiroshige Committed by Commit bot

Reland of Split PendingScript into PendingScript and ClassicPendingScript

This is preparation for introducing ModulePendingScript.

This CL shouldn't change the behavior.

This has been reverted due to crashing (Issue 711703) because
ResourceOwner's prefinalizer is called before PendingScript's prefinalizer,
causing CheckState() assertion failure.
This reland fixes this issue by registering PendingScript::Dispose() also
as the prefinalizer of ClassicPendingScript, which is called before
ResourceOwner's prefinalizer.

A unit test for the crash will be added by
https://codereview.chromium.org/2828973002/.

BUG=594639, 686281, 711703

Review-Url: https://codereview.chromium.org/2653923008
Cr-Original-Commit-Position: refs/heads/master@{#464494}
Committed: https://chromium.googlesource.com/chromium/src/+/d512803299c01324b92ffd8c962da97e3bc8ccff
Review-Url: https://codereview.chromium.org/2653923008
Cr-Commit-Position: refs/heads/master@{#466899}
parent 63575c0e
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
#include <memory> #include <memory>
#include "bindings/core/v8/ScriptStreamerThread.h" #include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/V8ScriptRunner.h" #include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/ClassicPendingScript.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/Element.h" #include "core/dom/Element.h"
#include "core/dom/PendingScript.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "core/html/parser/TextResourceDecoder.h" #include "core/html/parser/TextResourceDecoder.h"
#include "core/loader/resource/ScriptResource.h" #include "core/loader/resource/ScriptResource.h"
...@@ -327,7 +327,7 @@ class SourceStream : public v8::ScriptCompiler::ExternalSourceStream { ...@@ -327,7 +327,7 @@ class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
size_t ScriptStreamer::small_script_threshold_ = 30 * 1024; size_t ScriptStreamer::small_script_threshold_ = 30 * 1024;
void ScriptStreamer::StartStreaming(PendingScript* script, void ScriptStreamer::StartStreaming(ClassicPendingScript* script,
Type script_type, Type script_type,
Settings* settings, Settings* settings,
ScriptState* script_state, ScriptState* script_state,
...@@ -517,7 +517,7 @@ void ScriptStreamer::NotifyFinished(Resource* resource) { ...@@ -517,7 +517,7 @@ void ScriptStreamer::NotifyFinished(Resource* resource) {
} }
ScriptStreamer::ScriptStreamer( ScriptStreamer::ScriptStreamer(
PendingScript* script, ClassicPendingScript* script,
Type script_type, Type script_type,
ScriptState* script_state, ScriptState* script_state,
v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::CompileOptions compile_options,
...@@ -581,7 +581,7 @@ void ScriptStreamer::NotifyFinishedToClient() { ...@@ -581,7 +581,7 @@ void ScriptStreamer::NotifyFinishedToClient() {
} }
bool ScriptStreamer::StartStreamingInternal( bool ScriptStreamer::StartStreamingInternal(
PendingScript* script, ClassicPendingScript* script,
Type script_type, Type script_type,
Settings* settings, Settings* settings,
ScriptState* script_state, ScriptState* script_state,
...@@ -600,7 +600,7 @@ bool ScriptStreamer::StartStreamingInternal( ...@@ -600,7 +600,7 @@ bool ScriptStreamer::StartStreamingInternal(
if (resource->IsCacheValidator()) { if (resource->IsCacheValidator()) {
RecordNotStreamingReasonHistogram(script_type, kReload); RecordNotStreamingReasonHistogram(script_type, kReload);
// This happens e.g., during reloads. We're actually not going to load // This happens e.g., during reloads. We're actually not going to load
// the current Resource of the PendingScript but switch to another // the current Resource of the ClassicPendingScript but switch to another
// Resource -> don't stream. // Resource -> don't stream.
return false; return false;
} }
...@@ -615,8 +615,8 @@ bool ScriptStreamer::StartStreamingInternal( ...@@ -615,8 +615,8 @@ bool ScriptStreamer::StartStreamingInternal(
if (settings->GetV8CacheOptions() == kV8CacheOptionsParse) if (settings->GetV8CacheOptions() == kV8CacheOptionsParse)
compile_option = v8::ScriptCompiler::kProduceParserCache; compile_option = v8::ScriptCompiler::kProduceParserCache;
// The Resource might go out of scope if the script is no longer // The Resource might go out of scope if the script is no longer needed.
// needed. This makes PendingScript notify the ScriptStreamer when it is // This makes ClassicPendingScript notify the ScriptStreamer when it is
// destroyed. // destroyed.
script->SetStreamer(ScriptStreamer::Create(script, script_type, script_state, script->SetStreamer(ScriptStreamer::Create(script, script_type, script_state,
compile_option, compile_option,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "platform/WebTaskRunner.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "platform/wtf/Noncopyable.h" #include "platform/wtf/Noncopyable.h"
#include "platform/wtf/text/WTFString.h" #include "platform/wtf/text/WTFString.h"
...@@ -15,21 +16,20 @@ ...@@ -15,21 +16,20 @@
namespace blink { namespace blink {
class PendingScript; class ClassicPendingScript;
class Resource; class Resource;
class ScriptResource; class ScriptResource;
class ScriptState; class ScriptState;
class Settings; class Settings;
class SourceStream; class SourceStream;
class WebTaskRunner;
// ScriptStreamer streams incomplete script data to V8 so that it can be parsed // ScriptStreamer streams incomplete script data to V8 so that it can be parsed
// while it's loaded. PendingScript holds a reference to ScriptStreamer. At the // while it's loaded. ClassicPendingScript holds a reference to ScriptStreamer.
// moment, ScriptStreamer is only used for parser blocking scripts; this means // At the moment, ScriptStreamer is only used for parser blocking scripts; this
// that the Document stays stable and no other scripts are executing while we're // means that the Document stays stable and no other scripts are executing
// streaming. It is possible, though, that Document and the PendingScript are // while we're streaming. It is possible, though, that Document and the
// destroyed while the streaming is in progress, and ScriptStreamer handles it // ClassicPendingScript are destroyed while the streaming is in progress, and
// gracefully. // ScriptStreamer handles it gracefully.
class CORE_EXPORT ScriptStreamer final class CORE_EXPORT ScriptStreamer final
: public GarbageCollectedFinalized<ScriptStreamer> { : public GarbageCollectedFinalized<ScriptStreamer> {
WTF_MAKE_NONCOPYABLE(ScriptStreamer); WTF_MAKE_NONCOPYABLE(ScriptStreamer);
...@@ -41,8 +41,8 @@ class CORE_EXPORT ScriptStreamer final ...@@ -41,8 +41,8 @@ class CORE_EXPORT ScriptStreamer final
DECLARE_TRACE(); DECLARE_TRACE();
// Launches a task (on a background thread) which will stream the given // Launches a task (on a background thread) which will stream the given
// PendingScript into V8 as it loads. // ClassicPendingScript into V8 as it loads.
static void StartStreaming(PendingScript*, static void StartStreaming(ClassicPendingScript*,
Type, Type,
Settings*, Settings*,
ScriptState*, ScriptState*,
...@@ -58,9 +58,9 @@ class CORE_EXPORT ScriptStreamer final ...@@ -58,9 +58,9 @@ class CORE_EXPORT ScriptStreamer final
ScriptResource* GetResource() const { return resource_; } ScriptResource* GetResource() const { return resource_; }
// Called when the script is not needed any more (e.g., loading was // Called when the script is not needed any more (e.g., loading was
// cancelled). After calling cancel, PendingScript can drop its reference to // cancelled). After calling cancel, ClassicPendingScript can drop its
// ScriptStreamer, and ScriptStreamer takes care of eventually deleting // reference to ScriptStreamer, and ScriptStreamer takes care of eventually
// itself (after the V8 side has finished too). // deleting itself (after the V8 side has finished too).
void Cancel(); void Cancel();
// When the streaming is suppressed, the data is not given to V8, but // When the streaming is suppressed, the data is not given to V8, but
...@@ -72,7 +72,7 @@ class CORE_EXPORT ScriptStreamer final ...@@ -72,7 +72,7 @@ class CORE_EXPORT ScriptStreamer final
void SuppressStreaming(); void SuppressStreaming();
bool StreamingSuppressed() const { return streaming_suppressed_; } bool StreamingSuppressed() const { return streaming_suppressed_; }
// Called by PendingScript when data arrives from the network. // Called by ClassicPendingScript when data arrives from the network.
void NotifyAppendData(ScriptResource*); void NotifyAppendData(ScriptResource*);
void NotifyFinished(Resource*); void NotifyFinished(Resource*);
...@@ -95,7 +95,7 @@ class CORE_EXPORT ScriptStreamer final ...@@ -95,7 +95,7 @@ class CORE_EXPORT ScriptStreamer final
static size_t small_script_threshold_; static size_t small_script_threshold_;
static ScriptStreamer* Create( static ScriptStreamer* Create(
PendingScript* script, ClassicPendingScript* script,
Type script_type, Type script_type,
ScriptState* script_state, ScriptState* script_state,
v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::CompileOptions compile_options,
...@@ -103,7 +103,7 @@ class CORE_EXPORT ScriptStreamer final ...@@ -103,7 +103,7 @@ class CORE_EXPORT ScriptStreamer final
return new ScriptStreamer(script, script_type, script_state, return new ScriptStreamer(script, script_type, script_state,
compile_options, std::move(loading_task_runner)); compile_options, std::move(loading_task_runner));
} }
ScriptStreamer(PendingScript*, ScriptStreamer(ClassicPendingScript*,
Type, Type,
ScriptState*, ScriptState*,
v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::CompileOptions,
...@@ -112,16 +112,16 @@ class CORE_EXPORT ScriptStreamer final ...@@ -112,16 +112,16 @@ class CORE_EXPORT ScriptStreamer final
void StreamingComplete(); void StreamingComplete();
void NotifyFinishedToClient(); void NotifyFinishedToClient();
static bool StartStreamingInternal(PendingScript*, static bool StartStreamingInternal(ClassicPendingScript*,
Type, Type,
Settings*, Settings*,
ScriptState*, ScriptState*,
RefPtr<WebTaskRunner>); RefPtr<WebTaskRunner>);
Member<PendingScript> pending_script_; Member<ClassicPendingScript> pending_script_;
// This pointer is weak. If PendingScript and its Resource are deleted // This pointer is weak. If ClassicPendingScript and its Resource are deleted
// before ScriptStreamer, PendingScript will notify ScriptStreamer of its // before ScriptStreamer, ClassicPendingScript will notify ScriptStreamer of
// deletion by calling cancel(). // its deletion by calling cancel().
Member<ScriptResource> resource_; Member<ScriptResource> resource_;
// Whether ScriptStreamer is detached from the Resource. In those cases, the // Whether ScriptStreamer is detached from the Resource. In those cases, the
// script data is not needed any more, and the client won't get notified // script data is not needed any more, and the client won't get notified
......
...@@ -11,9 +11,8 @@ ...@@ -11,9 +11,8 @@
#include "bindings/core/v8/V8BindingForCore.h" #include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/V8BindingForTesting.h" #include "bindings/core/v8/V8BindingForTesting.h"
#include "bindings/core/v8/V8ScriptRunner.h" #include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/ClassicPendingScript.h"
#include "core/dom/ClassicScript.h" #include "core/dom/ClassicScript.h"
#include "core/dom/Element.h"
#include "core/dom/PendingScript.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "platform/testing/UnitTestHelpers.h" #include "platform/testing/UnitTestHelpers.h"
...@@ -36,9 +35,10 @@ class ScriptStreamingTest : public ::testing::Test { ...@@ -36,9 +35,10 @@ class ScriptStreamingTest : public ::testing::Test {
settings_(Settings::Create()), settings_(Settings::Create()),
resource_request_("http://www.streaming-test.com/"), resource_request_("http://www.streaming-test.com/"),
resource_(ScriptResource::Create(resource_request_, "UTF-8")), resource_(ScriptResource::Create(resource_request_, "UTF-8")),
pending_script_(PendingScript::CreateForTesting(resource_.Get())) { pending_script_(
ClassicPendingScript::CreateForTesting(resource_.Get())) {
resource_->SetStatus(ResourceStatus::kPending); resource_->SetStatus(ResourceStatus::kPending);
pending_script_ = PendingScript::CreateForTesting(resource_.Get()); pending_script_ = ClassicPendingScript::CreateForTesting(resource_.Get());
ScriptStreamer::SetSmallScriptThresholdForTesting(0); ScriptStreamer::SetSmallScriptThresholdForTesting(0);
} }
...@@ -47,7 +47,9 @@ class ScriptStreamingTest : public ::testing::Test { ...@@ -47,7 +47,9 @@ class ScriptStreamingTest : public ::testing::Test {
pending_script_->Dispose(); pending_script_->Dispose();
} }
PendingScript* GetPendingScript() const { return pending_script_.Get(); } ClassicPendingScript* GetPendingScript() const {
return pending_script_.Get();
}
protected: protected:
void AppendData(const char* data) { void AppendData(const char* data) {
...@@ -90,7 +92,7 @@ class ScriptStreamingTest : public ::testing::Test { ...@@ -90,7 +92,7 @@ class ScriptStreamingTest : public ::testing::Test {
// ScriptResource::appendData. // ScriptResource::appendData.
ResourceRequest resource_request_; ResourceRequest resource_request_;
Persistent<ScriptResource> resource_; Persistent<ScriptResource> resource_;
Persistent<PendingScript> pending_script_; Persistent<ClassicPendingScript> pending_script_;
}; };
class TestPendingScriptClient class TestPendingScriptClient
......
...@@ -33,6 +33,8 @@ blink_core_sources("dom") { ...@@ -33,6 +33,8 @@ blink_core_sources("dom") {
"ChildNodeList.h", "ChildNodeList.h",
"ClassCollection.cpp", "ClassCollection.cpp",
"ClassCollection.h", "ClassCollection.h",
"ClassicPendingScript.cpp",
"ClassicPendingScript.h",
"ClassicScript.cpp", "ClassicScript.cpp",
"ClassicScript.h", "ClassicScript.h",
"ClientRect.cpp", "ClientRect.cpp",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/dom/ClassicPendingScript.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ScriptStreamer.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/dom/Document.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/SubresourceIntegrity.h"
#include "platform/loader/fetch/MemoryCache.h"
namespace blink {
ClassicPendingScript* ClassicPendingScript::Create(ScriptElementBase* element,
ScriptResource* resource) {
return new ClassicPendingScript(element, resource, TextPosition());
}
ClassicPendingScript* ClassicPendingScript::Create(
ScriptElementBase* element,
const TextPosition& starting_position) {
return new ClassicPendingScript(element, nullptr, starting_position);
}
ClassicPendingScript* ClassicPendingScript::CreateForTesting(
ScriptResource* resource) {
return new ClassicPendingScript(nullptr, resource, TextPosition(), true);
}
ClassicPendingScript::ClassicPendingScript(
ScriptElementBase* element,
ScriptResource* resource,
const TextPosition& starting_position,
bool is_for_testing)
: PendingScript(element, starting_position),
integrity_failure_(false),
is_for_testing_(is_for_testing) {
CheckState();
SetResource(resource);
MemoryCoordinator::Instance().RegisterClient(this);
}
ClassicPendingScript::~ClassicPendingScript() {}
NOINLINE void ClassicPendingScript::CheckState() const {
// TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
CHECK(is_for_testing_ || GetElement());
CHECK(GetResource() || !streamer_);
CHECK(!streamer_ || streamer_->GetResource() == GetResource());
}
NOINLINE void ClassicPendingScript::Dispose() {
PendingScript::Dispose();
}
void ClassicPendingScript::DisposeInternal() {
MemoryCoordinator::Instance().UnregisterClient(this);
SetResource(nullptr);
integrity_failure_ = false;
if (streamer_)
streamer_->Cancel();
streamer_ = nullptr;
}
void ClassicPendingScript::StreamingFinished() {
CheckState();
DCHECK(GetResource());
if (Client())
Client()->PendingScriptFinished(this);
}
// Returns true if SRI check passed.
static bool CheckScriptResourceIntegrity(Resource* resource,
ScriptElementBase* element) {
DCHECK_EQ(resource->GetType(), Resource::kScript);
ScriptResource* script_resource = ToScriptResource(resource);
String integrity_attr = element->IntegrityAttributeValue();
// It is possible to get back a script resource with integrity metadata
// for a request with an empty integrity attribute. In that case, the
// integrity check should be skipped, so this check ensures that the
// integrity attribute isn't empty in addition to checking if the
// resource has empty integrity metadata.
if (integrity_attr.IsEmpty() ||
script_resource->IntegrityMetadata().IsEmpty())
return true;
switch (script_resource->IntegrityDisposition()) {
case ResourceIntegrityDisposition::kPassed:
return true;
case ResourceIntegrityDisposition::kFailed:
// TODO(jww): This should probably also generate a console
// message identical to the one produced by
// CheckSubresourceIntegrity below. See https://crbug.com/585267.
return false;
case ResourceIntegrityDisposition::kNotChecked: {
if (!resource->ResourceBuffer())
return true;
bool passed = SubresourceIntegrity::CheckSubresourceIntegrity(
script_resource->IntegrityMetadata(), element->GetDocument(),
resource->ResourceBuffer()->Data(),
resource->ResourceBuffer()->size(), resource->Url(), *resource);
script_resource->SetIntegrityDisposition(
passed ? ResourceIntegrityDisposition::kPassed
: ResourceIntegrityDisposition::kFailed);
return passed;
}
}
NOTREACHED();
return true;
}
void ClassicPendingScript::NotifyFinished(Resource* resource) {
// The following SRI checks need to be here because, unfortunately, fetches
// are not done purely according to the Fetch spec. In particular,
// different requests for the same resource do not have different
// responses; the memory cache can (and will) return the exact same
// Resource object.
//
// For different requests, the same Resource object will be returned and
// will not be associated with the particular request. Therefore, when the
// body of the response comes in, there's no way to validate the integrity
// of the Resource object against a particular request (since there may be
// several pending requests all tied to the identical object, and the
// actual requests are not stored).
//
// In order to simulate the correct behavior, Blink explicitly does the SRI
// checks here, when a PendingScript tied to a particular request is
// finished (and in the case of a StyleSheet, at the point of execution),
// while having proper Fetch checks in the fetch module for use in the
// fetch JavaScript API. In a future world where the ResourceFetcher uses
// the Fetch algorithm, this should be fixed by having separate Response
// objects (perhaps attached to identical Resource objects) per request.
//
// See https://crbug.com/500701 for more information.
CheckState();
if (!is_for_testing_ && GetElement()) {
integrity_failure_ = !CheckScriptResourceIntegrity(resource, GetElement());
}
// If script streaming is in use, the client will be notified in
// streamingFinished.
if (streamer_)
streamer_->NotifyFinished(resource);
else if (Client())
Client()->PendingScriptFinished(this);
}
void ClassicPendingScript::NotifyAppendData(ScriptResource* resource) {
if (streamer_)
streamer_->NotifyAppendData(resource);
}
DEFINE_TRACE(ClassicPendingScript) {
visitor->Trace(streamer_);
ResourceOwner<ScriptResource>::Trace(visitor);
MemoryCoordinatorClient::Trace(visitor);
PendingScript::Trace(visitor);
}
ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url,
bool& error_occurred) const {
CheckState();
error_occurred = this->ErrorOccurred();
if (GetResource()) {
DCHECK(GetResource()->IsLoaded());
if (streamer_ && !streamer_->StreamingSuppressed())
return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource()));
return ClassicScript::Create(ScriptSourceCode(GetResource()));
}
return ClassicScript::Create(ScriptSourceCode(
GetElement()->TextContent(), document_url, StartingPosition()));
}
void ClassicPendingScript::SetStreamer(ScriptStreamer* streamer) {
DCHECK(!streamer_);
DCHECK(!IsWatchingForLoad());
streamer_ = streamer;
CheckState();
}
bool ClassicPendingScript::IsReady() const {
CheckState();
if (GetResource()) {
return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished());
}
return true;
}
bool ClassicPendingScript::ErrorOccurred() const {
CheckState();
if (GetResource())
return GetResource()->ErrorOccurred() || integrity_failure_;
return false;
}
void ClassicPendingScript::OnPurgeMemory() {
CheckState();
if (!streamer_)
return;
streamer_->Cancel();
streamer_ = nullptr;
}
void ClassicPendingScript::StartStreamingIfPossible(
Document* document,
ScriptStreamer::Type streamer_type) {
if (!document->GetFrame())
return;
ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame());
if (!script_state)
return;
ScriptStreamer::StartStreaming(
this, streamer_type, document->GetFrame()->GetSettings(), script_state,
TaskRunnerHelper::Get(TaskType::kNetworking, document));
}
bool ClassicPendingScript::WasCanceled() const {
return GetResource()->WasCanceled();
}
KURL ClassicPendingScript::Url() const {
return GetResource()->Url();
}
void ClassicPendingScript::RemoveFromMemoryCache() {
GetMemoryCache()->Remove(GetResource());
}
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ClassicPendingScript_h
#define ClassicPendingScript_h
#include "bindings/core/v8/ScriptStreamer.h"
#include "core/dom/ClassicScript.h"
#include "core/dom/PendingScript.h"
#include "core/loader/resource/ScriptResource.h"
#include "platform/MemoryCoordinator.h"
#include "platform/loader/fetch/ResourceOwner.h"
namespace blink {
// PendingScript for a classic script
// https://html.spec.whatwg.org/#classic-script.
//
// TODO(kochi): The comment below is from pre-oilpan age and may not be correct
// now.
// A RefPtr alone does not prevent the underlying Resource from purging its data
// buffer. This class holds a dummy client open for its lifetime in order to
// guarantee that the data buffer will not be purged.
class CORE_EXPORT ClassicPendingScript final
: public PendingScript,
public ResourceOwner<ScriptResource>,
public MemoryCoordinatorClient {
USING_GARBAGE_COLLECTED_MIXIN(ClassicPendingScript);
// In order to call Dispose() before ResourceOwner's prefinalizer, we
// also register ClassicPendingScript::Dispose() as the prefinalizer of
// ClassicPendingScript here. https://crbug.com/711703
USING_PRE_FINALIZER(ClassicPendingScript, Dispose);
public:
// For script from an external file.
static ClassicPendingScript* Create(ScriptElementBase*, ScriptResource*);
// For inline script.
static ClassicPendingScript* Create(ScriptElementBase*, const TextPosition&);
static ClassicPendingScript* CreateForTesting(ScriptResource*);
~ClassicPendingScript() override;
void SetStreamer(ScriptStreamer*);
void StreamingFinished();
DECLARE_TRACE();
blink::ScriptType GetScriptType() const override {
return blink::ScriptType::kClassic;
}
ClassicScript* GetSource(const KURL& document_url,
bool& error_occurred) const override;
bool IsReady() const override;
KURL Url() const override;
bool IsExternal() const override { return GetResource(); }
bool ErrorOccurred() const override;
bool WasCanceled() const override;
void StartStreamingIfPossible(Document*, ScriptStreamer::Type) override;
void RemoveFromMemoryCache() override;
void DisposeInternal() override;
// Just used as the prefinalizer, does the same as PendingScript::Dispose().
// We define Dispose() with NOINLINE in ClassicPendingScript just to make
// the prefinalizers of PendingScript and ClassicPendingScript have
// different addresses to avoid assertion failures on Windows test bots.
void Dispose();
private:
ClassicPendingScript(ScriptElementBase*,
ScriptResource*,
const TextPosition&,
bool is_for_testing = false);
ClassicPendingScript() = delete;
void CheckState() const override;
// ScriptResourceClient
void NotifyFinished(Resource*) override;
String DebugName() const override { return "PendingScript"; }
void NotifyAppendData(ScriptResource*) override;
// MemoryCoordinatorClient
void OnPurgeMemory() override;
bool integrity_failure_;
Member<ScriptStreamer> streamer_;
// This flag is used to skip non-null checks of |m_element| in unit
// tests, because |m_element| can be null in unit tests.
const bool is_for_testing_;
};
} // namespace blink
#endif // PendingScript_h
...@@ -25,79 +25,37 @@ ...@@ -25,79 +25,37 @@
#include "core/dom/PendingScript.h" #include "core/dom/PendingScript.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/dom/ClassicScript.h"
#include "core/dom/Document.h"
#include "core/dom/ScriptElementBase.h" #include "core/dom/ScriptElementBase.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/SubresourceIntegrity.h"
#include "platform/SharedBuffer.h"
#include "platform/wtf/CurrentTime.h" #include "platform/wtf/CurrentTime.h"
namespace blink { namespace blink {
PendingScript* PendingScript::Create(ScriptElementBase* element,
ScriptResource* resource) {
return new PendingScript(element, resource, TextPosition());
}
PendingScript* PendingScript::Create(ScriptElementBase* element,
const TextPosition& starting_position) {
return new PendingScript(element, nullptr, starting_position);
}
PendingScript* PendingScript::CreateForTesting(ScriptResource* resource) {
return new PendingScript(nullptr, resource, TextPosition(), true);
}
PendingScript::PendingScript(ScriptElementBase* element, PendingScript::PendingScript(ScriptElementBase* element,
ScriptResource* resource, const TextPosition& starting_position)
const TextPosition& starting_position,
bool is_for_testing)
: watching_for_load_(false), : watching_for_load_(false),
element_(element), element_(element),
starting_position_(starting_position), starting_position_(starting_position),
integrity_failure_(false),
parser_blocking_load_start_time_(0), parser_blocking_load_start_time_(0),
client_(nullptr), client_(nullptr) {}
is_for_testing_(is_for_testing) {
CheckState();
SetResource(resource);
MemoryCoordinator::Instance().RegisterClient(this);
}
PendingScript::~PendingScript() {} PendingScript::~PendingScript() {}
NOINLINE void PendingScript::CheckState() const {
// TODO(hiroshige): Turn these CHECK()s into DCHECK() before going to beta.
CHECK(is_for_testing_ || element_);
CHECK(GetResource() || !streamer_);
CHECK(!streamer_ || streamer_->GetResource() == GetResource());
}
void PendingScript::Dispose() { void PendingScript::Dispose() {
StopWatchingForLoad(); StopWatchingForLoad();
DCHECK(!client_); DCHECK(!Client());
DCHECK(!watching_for_load_); DCHECK(!IsWatchingForLoad());
MemoryCoordinator::Instance().UnregisterClient(this);
SetResource(nullptr);
starting_position_ = TextPosition::BelowRangePosition(); starting_position_ = TextPosition::BelowRangePosition();
integrity_failure_ = false;
parser_blocking_load_start_time_ = 0; parser_blocking_load_start_time_ = 0;
if (streamer_)
streamer_->Cancel(); DisposeInternal();
streamer_ = nullptr;
element_ = nullptr; element_ = nullptr;
} }
void PendingScript::WatchForLoad(PendingScriptClient* client) { void PendingScript::WatchForLoad(PendingScriptClient* client) {
CheckState(); CheckState();
DCHECK(!watching_for_load_); DCHECK(!IsWatchingForLoad());
// addClient() will call streamingFinished() if the load is complete. Callers // addClient() will call streamingFinished() if the load is complete. Callers
// who do not expect to be re-entered from this call should not call // who do not expect to be re-entered from this call should not call
// watchForLoad for a PendingScript which isReady. We also need to set // watchForLoad for a PendingScript which isReady. We also need to set
...@@ -110,10 +68,10 @@ void PendingScript::WatchForLoad(PendingScriptClient* client) { ...@@ -110,10 +68,10 @@ void PendingScript::WatchForLoad(PendingScriptClient* client) {
} }
void PendingScript::StopWatchingForLoad() { void PendingScript::StopWatchingForLoad() {
if (!watching_for_load_) if (!IsWatchingForLoad())
return; return;
CheckState(); CheckState();
DCHECK(GetResource()); DCHECK(IsExternal());
client_ = nullptr; client_ = nullptr;
watching_for_load_ = false; watching_for_load_ = false;
} }
...@@ -126,173 +84,14 @@ ScriptElementBase* PendingScript::GetElement() const { ...@@ -126,173 +84,14 @@ ScriptElementBase* PendingScript::GetElement() const {
return element_.Get(); return element_.Get();
} }
void PendingScript::StreamingFinished() {
CheckState();
DCHECK(GetResource());
if (client_)
client_->PendingScriptFinished(this);
}
void PendingScript::MarkParserBlockingLoadStartTime() { void PendingScript::MarkParserBlockingLoadStartTime() {
DCHECK_EQ(parser_blocking_load_start_time_, 0.0); DCHECK_EQ(parser_blocking_load_start_time_, 0.0);
parser_blocking_load_start_time_ = MonotonicallyIncreasingTime(); parser_blocking_load_start_time_ = MonotonicallyIncreasingTime();
} }
// Returns true if SRI check passed.
static bool CheckScriptResourceIntegrity(Resource* resource,
ScriptElementBase* element) {
DCHECK_EQ(resource->GetType(), Resource::kScript);
ScriptResource* script_resource = ToScriptResource(resource);
String integrity_attr = element->IntegrityAttributeValue();
// It is possible to get back a script resource with integrity metadata
// for a request with an empty integrity attribute. In that case, the
// integrity check should be skipped, so this check ensures that the
// integrity attribute isn't empty in addition to checking if the
// resource has empty integrity metadata.
if (integrity_attr.IsEmpty() ||
script_resource->IntegrityMetadata().IsEmpty())
return true;
switch (script_resource->IntegrityDisposition()) {
case ResourceIntegrityDisposition::kPassed:
return true;
case ResourceIntegrityDisposition::kFailed:
// TODO(jww): This should probably also generate a console
// message identical to the one produced by
// CheckSubresourceIntegrity below. See https://crbug.com/585267.
return false;
case ResourceIntegrityDisposition::kNotChecked: {
if (!resource->ResourceBuffer())
return true;
bool passed = SubresourceIntegrity::CheckSubresourceIntegrity(
script_resource->IntegrityMetadata(), element->GetDocument(),
resource->ResourceBuffer()->Data(),
resource->ResourceBuffer()->size(), resource->Url(), *resource);
script_resource->SetIntegrityDisposition(
passed ? ResourceIntegrityDisposition::kPassed
: ResourceIntegrityDisposition::kFailed);
return passed;
}
}
NOTREACHED();
return true;
}
void PendingScript::NotifyFinished(Resource* resource) {
// The following SRI checks need to be here because, unfortunately, fetches
// are not done purely according to the Fetch spec. In particular,
// different requests for the same resource do not have different
// responses; the memory cache can (and will) return the exact same
// Resource object.
//
// For different requests, the same Resource object will be returned and
// will not be associated with the particular request. Therefore, when the
// body of the response comes in, there's no way to validate the integrity
// of the Resource object against a particular request (since there may be
// several pending requests all tied to the identical object, and the
// actual requests are not stored).
//
// In order to simulate the correct behavior, Blink explicitly does the SRI
// checks here, when a PendingScript tied to a particular request is
// finished (and in the case of a StyleSheet, at the point of execution),
// while having proper Fetch checks in the fetch module for use in the
// fetch JavaScript API. In a future world where the ResourceFetcher uses
// the Fetch algorithm, this should be fixed by having separate Response
// objects (perhaps attached to identical Resource objects) per request.
//
// See https://crbug.com/500701 for more information.
CheckState();
if (element_) {
integrity_failure_ = !CheckScriptResourceIntegrity(resource, element_);
}
// If script streaming is in use, the client will be notified in
// streamingFinished.
if (streamer_)
streamer_->NotifyFinished(resource);
else if (client_)
client_->PendingScriptFinished(this);
}
void PendingScript::NotifyAppendData(ScriptResource* resource) {
if (streamer_)
streamer_->NotifyAppendData(resource);
}
DEFINE_TRACE(PendingScript) { DEFINE_TRACE(PendingScript) {
visitor->Trace(element_); visitor->Trace(element_);
visitor->Trace(streamer_);
visitor->Trace(client_); visitor->Trace(client_);
ResourceOwner<ScriptResource>::Trace(visitor);
MemoryCoordinatorClient::Trace(visitor);
}
ClassicScript* PendingScript::GetSource(const KURL& document_url,
bool& error_occurred) const {
CheckState();
error_occurred = this->ErrorOccurred();
if (GetResource()) {
DCHECK(GetResource()->IsLoaded());
if (streamer_ && !streamer_->StreamingSuppressed())
return ClassicScript::Create(ScriptSourceCode(streamer_, GetResource()));
return ClassicScript::Create(ScriptSourceCode(GetResource()));
}
return ClassicScript::Create(ScriptSourceCode(
element_->TextContent(), document_url, StartingPosition()));
}
void PendingScript::SetStreamer(ScriptStreamer* streamer) {
DCHECK(!streamer_);
DCHECK(!watching_for_load_);
streamer_ = streamer;
CheckState();
}
bool PendingScript::IsReady() const {
CheckState();
if (GetResource()) {
return GetResource()->IsLoaded() && (!streamer_ || streamer_->IsFinished());
}
return true;
}
bool PendingScript::ErrorOccurred() const {
CheckState();
if (GetResource())
return GetResource()->ErrorOccurred() || integrity_failure_;
return false;
}
void PendingScript::OnPurgeMemory() {
CheckState();
if (!streamer_)
return;
streamer_->Cancel();
streamer_ = nullptr;
}
void PendingScript::StartStreamingIfPossible(
Document* document,
ScriptStreamer::Type streamer_type) {
if (!document->GetFrame())
return;
ScriptState* script_state = ToScriptStateForMainWorld(document->GetFrame());
if (!script_state)
return;
ScriptStreamer::StartStreaming(
this, streamer_type, document->GetFrame()->GetSettings(), script_state,
TaskRunnerHelper::Get(TaskType::kNetworking, document));
} }
} // namespace blink } // namespace blink
...@@ -28,25 +28,24 @@ ...@@ -28,25 +28,24 @@
#include "bindings/core/v8/ScriptStreamer.h" #include "bindings/core/v8/ScriptStreamer.h"
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "core/dom/Script.h"
#include "core/dom/ScriptElementBase.h" #include "core/dom/ScriptElementBase.h"
#include "core/loader/resource/ScriptResource.h"
#include "platform/MemoryCoordinator.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "platform/loader/fetch/ResourceOwner.h" #include "platform/weborigin/KURL.h"
#include "platform/wtf/Noncopyable.h" #include "platform/wtf/Noncopyable.h"
#include "platform/wtf/text/TextPosition.h" #include "platform/wtf/text/TextPosition.h"
namespace blink { namespace blink {
class Document;
class PendingScript; class PendingScript;
class ClassicScript;
class CORE_EXPORT PendingScriptClient : public GarbageCollectedMixin { class CORE_EXPORT PendingScriptClient : public GarbageCollectedMixin {
public: public:
virtual ~PendingScriptClient() {} virtual ~PendingScriptClient() {}
// Invoked when the pending script has finished loading. This could be during // Invoked when the pending script is ready. This could be during
// |watchForLoad| (if the pending script was already ready), or when the // WatchForLoad() (if the pending script was already ready), or when the
// resource loads (if script streaming is not occurring), or when script // resource loads (if script streaming is not occurring), or when script
// streaming finishes. // streaming finishes.
virtual void PendingScriptFinished(PendingScript*) = 0; virtual void PendingScriptFinished(PendingScript*) = 0;
...@@ -55,29 +54,15 @@ class CORE_EXPORT PendingScriptClient : public GarbageCollectedMixin { ...@@ -55,29 +54,15 @@ class CORE_EXPORT PendingScriptClient : public GarbageCollectedMixin {
}; };
// A container for an external script which may be loaded and executed. // A container for an external script which may be loaded and executed.
// // This is used to receive a notification of "script is ready"
// TODO(kochi): The comment below is from pre-oilpan age and may not be correct // https://html.spec.whatwg.org/#the-script-is-ready via PendingScriptClient.
// now. class CORE_EXPORT PendingScript
// A RefPtr alone does not prevent the underlying Resource from purging its data : public GarbageCollectedFinalized<PendingScript> {
// buffer. This class holds a dummy client open for its lifetime in order to
// guarantee that the data buffer will not be purged.
class CORE_EXPORT PendingScript final
: public GarbageCollectedFinalized<PendingScript>,
public ResourceOwner<ScriptResource>,
public MemoryCoordinatorClient {
USING_GARBAGE_COLLECTED_MIXIN(PendingScript);
USING_PRE_FINALIZER(PendingScript, Dispose); USING_PRE_FINALIZER(PendingScript, Dispose);
WTF_MAKE_NONCOPYABLE(PendingScript); WTF_MAKE_NONCOPYABLE(PendingScript);
public: public:
// For script from an external file. virtual ~PendingScript();
static PendingScript* Create(ScriptElementBase*, ScriptResource*);
// For inline script.
static PendingScript* Create(ScriptElementBase*, const TextPosition&);
static PendingScript* CreateForTesting(ScriptResource*);
~PendingScript() override;
TextPosition StartingPosition() const { return starting_position_; } TextPosition StartingPosition() const { return starting_position_; }
void MarkParserBlockingLoadStartTime(); void MarkParserBlockingLoadStartTime();
...@@ -93,37 +78,39 @@ class CORE_EXPORT PendingScript final ...@@ -93,37 +78,39 @@ class CORE_EXPORT PendingScript final
ScriptElementBase* GetElement() const; ScriptElementBase* GetElement() const;
DECLARE_TRACE(); virtual ScriptType GetScriptType() const = 0;
DECLARE_VIRTUAL_TRACE();
virtual Script* GetSource(const KURL& document_url,
bool& error_occurred) const = 0;
ClassicScript* GetSource(const KURL& document_url, // https://html.spec.whatwg.org/#the-script-is-ready
bool& error_occurred) const; virtual bool IsReady() const = 0;
void SetStreamer(ScriptStreamer*); virtual KURL Url() const = 0;
void StreamingFinished(); virtual bool IsExternal() const = 0;
virtual bool ErrorOccurred() const = 0;
virtual bool WasCanceled() const = 0;
virtual void StartStreamingIfPossible(Document*, ScriptStreamer::Type) = 0;
bool IsReady() const; // Used for document.write() intervention.
bool ErrorOccurred() const; // Has effects only for classic scripts.
virtual void RemoveFromMemoryCache() = 0;
void StartStreamingIfPossible(Document*, ScriptStreamer::Type);
void Dispose(); void Dispose();
private: protected:
PendingScript(ScriptElementBase*, PendingScript(ScriptElementBase*, const TextPosition& starting_position);
ScriptResource*,
const TextPosition&,
bool is_for_testing = false);
PendingScript() = delete;
void CheckState() const; virtual void DisposeInternal() = 0;
// ScriptResourceClient PendingScriptClient* Client() { return client_; }
void NotifyFinished(Resource*) override; bool IsWatchingForLoad() const { return watching_for_load_; }
String DebugName() const override { return "PendingScript"; }
void NotifyAppendData(ScriptResource*) override;
// MemoryCoordinatorClient virtual void CheckState() const = 0;
void OnPurgeMemory() override;
private:
bool watching_for_load_; bool watching_for_load_;
// |m_element| must points to the corresponding ScriptLoader's // |m_element| must points to the corresponding ScriptLoader's
...@@ -132,15 +119,9 @@ class CORE_EXPORT PendingScript final ...@@ -132,15 +119,9 @@ class CORE_EXPORT PendingScript final
Member<ScriptElementBase> element_; Member<ScriptElementBase> element_;
TextPosition starting_position_; // Only used for inline script tags. TextPosition starting_position_; // Only used for inline script tags.
bool integrity_failure_;
double parser_blocking_load_start_time_; double parser_blocking_load_start_time_;
Member<ScriptStreamer> streamer_;
Member<PendingScriptClient> client_; Member<PendingScriptClient> client_;
// This flag is used to skip non-null checks of |m_element| in unit
// tests, because |m_element| can be null in unit tests.
const bool is_for_testing_;
}; };
} // namespace blink } // namespace blink
......
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
#include "bindings/core/v8/ScriptController.h" #include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/HTMLNames.h" #include "core/HTMLNames.h"
#include "core/SVGNames.h" #include "core/SVGNames.h"
#include "core/dom/ClassicPendingScript.h"
#include "core/dom/ClassicScript.h" #include "core/dom/ClassicScript.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/DocumentParserTiming.h" #include "core/dom/DocumentParserTiming.h"
...@@ -48,7 +48,6 @@ ...@@ -48,7 +48,6 @@
#include "platform/WebFrameScheduler.h" #include "platform/WebFrameScheduler.h"
#include "platform/loader/fetch/AccessControlStatus.h" #include "platform/loader/fetch/AccessControlStatus.h"
#include "platform/loader/fetch/FetchParameters.h" #include "platform/loader/fetch/FetchParameters.h"
#include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/ResourceFetcher.h" #include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/network/mime/MIMETypeRegistry.h" #include "platform/network/mime/MIMETypeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/SecurityOrigin.h"
...@@ -670,7 +669,7 @@ bool ScriptLoader::FetchClassicScript( ...@@ -670,7 +669,7 @@ bool ScriptLoader::FetchClassicScript(
PendingScript* ScriptLoader::CreatePendingScript() { PendingScript* ScriptLoader::CreatePendingScript() {
CHECK(resource_); CHECK(resource_);
return PendingScript::Create(element_, resource_); return ClassicPendingScript::Create(element_, resource_);
} }
bool ScriptLoader::ExecuteScript(const Script* script) { bool ScriptLoader::ExecuteScript(const Script* script) {
...@@ -776,13 +775,14 @@ bool ScriptLoader::DoExecuteScript(const Script* script) { ...@@ -776,13 +775,14 @@ bool ScriptLoader::DoExecuteScript(const Script* script) {
void ScriptLoader::Execute() { void ScriptLoader::Execute() {
DCHECK(!will_be_parser_executed_); DCHECK(!will_be_parser_executed_);
DCHECK(async_exec_type_ != ScriptRunner::kNone); DCHECK(async_exec_type_ != ScriptRunner::kNone);
DCHECK(pending_script_->GetResource()); DCHECK(pending_script_->IsExternal());
bool error_occurred = false; bool error_occurred = false;
Script* script = pending_script_->GetSource(KURL(), error_occurred); Script* script = pending_script_->GetSource(KURL(), error_occurred);
const bool wasCanceled = pending_script_->WasCanceled();
DetachPendingScript(); DetachPendingScript();
if (error_occurred) { if (error_occurred) {
DispatchErrorEvent(); DispatchErrorEvent();
} else if (!resource_->WasCanceled()) { } else if (!wasCanceled) {
if (ExecuteScript(script)) if (ExecuteScript(script))
DispatchLoadEvent(); DispatchLoadEvent();
else else
...@@ -794,7 +794,6 @@ void ScriptLoader::Execute() { ...@@ -794,7 +794,6 @@ void ScriptLoader::Execute() {
void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) { void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) {
DCHECK(!will_be_parser_executed_); DCHECK(!will_be_parser_executed_);
DCHECK_EQ(pending_script_, pending_script); DCHECK_EQ(pending_script_, pending_script);
DCHECK_EQ(pending_script->GetResource(), resource_);
// We do not need this script in the memory cache. The primary goals of // We do not need this script in the memory cache. The primary goals of
// sending this fetch request are to let the third party server know // sending this fetch request are to let the third party server know
...@@ -802,7 +801,8 @@ void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) { ...@@ -802,7 +801,8 @@ void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) {
// cache for subsequent uses. // cache for subsequent uses.
if (document_write_intervention_ == if (document_write_intervention_ ==
DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) {
GetMemoryCache()->Remove(pending_script_->GetResource()); DCHECK_EQ(pending_script_->GetScriptType(), ScriptType::kClassic);
pending_script_->RemoveFromMemoryCache();
pending_script_->StopWatchingForLoad(); pending_script_->StopWatchingForLoad();
return; return;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/V8BindingForCore.h" #include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/V8PerIsolateData.h" #include "bindings/core/v8/V8PerIsolateData.h"
#include "core/dom/ClassicPendingScript.h"
#include "core/dom/ClassicScript.h" #include "core/dom/ClassicScript.h"
#include "core/dom/DocumentParserTiming.h" #include "core/dom/DocumentParserTiming.h"
#include "core/dom/Element.h" #include "core/dom/Element.h"
...@@ -48,7 +49,6 @@ ...@@ -48,7 +49,6 @@
#include "platform/WebFrameScheduler.h" #include "platform/WebFrameScheduler.h"
#include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/instrumentation/tracing/TraceEvent.h"
#include "platform/instrumentation/tracing/TracedValue.h" #include "platform/instrumentation/tracing/TracedValue.h"
#include "platform/loader/fetch/MemoryCache.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
namespace blink { namespace blink {
...@@ -335,9 +335,12 @@ void HTMLParserScriptRunner::PossiblyFetchBlockedDocWriteScript( ...@@ -335,9 +335,12 @@ void HTMLParserScriptRunner::PossiblyFetchBlockedDocWriteScript(
if (!script_loader || !script_loader->DisallowedFetchForDocWrittenScript()) if (!script_loader || !script_loader->DisallowedFetchForDocWrittenScript())
return; return;
// We don't allow document.write() and its intervention with module scripts.
CHECK_EQ(pending_script->GetScriptType(), ScriptType::kClassic);
if (!pending_script->ErrorOccurred()) { if (!pending_script->ErrorOccurred()) {
EmitWarningForDocWriteScripts( EmitWarningForDocWriteScripts(pending_script->Url().GetString(),
pending_script->GetResource()->Url().GetString(), *document_); *document_);
return; return;
} }
...@@ -345,13 +348,12 @@ void HTMLParserScriptRunner::PossiblyFetchBlockedDocWriteScript( ...@@ -345,13 +348,12 @@ void HTMLParserScriptRunner::PossiblyFetchBlockedDocWriteScript(
// ERR_CACHE_MISS but other errors are rare with // ERR_CACHE_MISS but other errors are rare with
// WebCachePolicy::ReturnCacheDataDontLoad. // WebCachePolicy::ReturnCacheDataDontLoad.
EmitErrorForDocWriteScripts(pending_script->GetResource()->Url().GetString(), EmitErrorForDocWriteScripts(pending_script->Url().GetString(), *document_);
*document_);
TextPosition starting_position = ParserBlockingScript()->StartingPosition(); TextPosition starting_position = ParserBlockingScript()->StartingPosition();
bool is_parser_inserted = script_loader->IsParserInserted(); bool is_parser_inserted = script_loader->IsParserInserted();
// Remove this resource entry from memory cache as the new request // Remove this resource entry from memory cache as the new request
// should not join onto this existing entry. // should not join onto this existing entry.
GetMemoryCache()->Remove(pending_script->GetResource()); pending_script->RemoveFromMemoryCache();
FetchBlockedDocWriteScript(element, is_parser_inserted, starting_position); FetchBlockedDocWriteScript(element, is_parser_inserted, starting_position);
} }
...@@ -363,7 +365,7 @@ void HTMLParserScriptRunner::PendingScriptFinished( ...@@ -363,7 +365,7 @@ void HTMLParserScriptRunner::PendingScriptFinished(
// script execution to signal an abrupt stop (e.g., window.close().) // script execution to signal an abrupt stop (e.g., window.close().)
// //
// The parser is unprepared to be told, and doesn't need to be. // The parser is unprepared to be told, and doesn't need to be.
if (IsExecutingScript() && pending_script->GetResource()->WasCanceled()) { if (IsExecutingScript() && pending_script->WasCanceled()) {
pending_script->Dispose(); pending_script->Dispose();
if (pending_script == ParserBlockingScript()) { if (pending_script == ParserBlockingScript()) {
...@@ -505,7 +507,7 @@ bool HTMLParserScriptRunner::ExecuteScriptsWaitingForParsing() { ...@@ -505,7 +507,7 @@ bool HTMLParserScriptRunner::ExecuteScriptsWaitingForParsing() {
while (!scripts_to_execute_after_parsing_.IsEmpty()) { while (!scripts_to_execute_after_parsing_.IsEmpty()) {
DCHECK(!IsExecutingScript()); DCHECK(!IsExecutingScript());
DCHECK(!HasParserBlockingScript()); DCHECK(!HasParserBlockingScript());
DCHECK(scripts_to_execute_after_parsing_.front()->GetResource()); DCHECK(scripts_to_execute_after_parsing_.front()->IsExternal());
// 1. "Spin the event loop until the first script in the list of scripts // 1. "Spin the event loop until the first script in the list of scripts
// that will execute when the document has finished parsing // that will execute when the document has finished parsing
...@@ -551,7 +553,7 @@ void HTMLParserScriptRunner::RequestParsingBlockingScript(Element* element) { ...@@ -551,7 +553,7 @@ void HTMLParserScriptRunner::RequestParsingBlockingScript(Element* element) {
if (!ParserBlockingScript()) if (!ParserBlockingScript())
return; return;
DCHECK(ParserBlockingScript()->GetResource()); DCHECK(ParserBlockingScript()->IsExternal());
// We only care about a load callback if resource is not already in the cache. // We only care about a load callback if resource is not already in the cache.
// Callers will attempt to run the m_parserBlockingScript if possible before // Callers will attempt to run the m_parserBlockingScript if possible before
...@@ -574,7 +576,7 @@ void HTMLParserScriptRunner::RequestDeferredScript(Element* element) { ...@@ -574,7 +576,7 @@ void HTMLParserScriptRunner::RequestDeferredScript(Element* element) {
ScriptStreamer::kDeferred); ScriptStreamer::kDeferred);
} }
DCHECK(pending_script->GetResource()); DCHECK(pending_script->IsExternal());
// "Add the element to the end of the list of scripts that will execute // "Add the element to the end of the list of scripts that will execute
// when the document has finished parsing associated with the Document // when the document has finished parsing associated with the Document
...@@ -644,7 +646,7 @@ void HTMLParserScriptRunner::ProcessScriptElementInternal( ...@@ -644,7 +646,7 @@ void HTMLParserScriptRunner::ProcessScriptElementInternal(
// (There can only be one such script per Document at a time.)" // (There can only be one such script per Document at a time.)"
CHECK(!parser_blocking_script_); CHECK(!parser_blocking_script_);
parser_blocking_script_ = parser_blocking_script_ =
PendingScript::Create(element, script_start_position); ClassicPendingScript::Create(element, script_start_position);
} else { } else {
// 6th Clause of Step 23. // 6th Clause of Step 23.
// "Immediately execute the script block, // "Immediately execute the script block,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment