Commit 4be1c8bc authored by Nate Chapin's avatar Nate Chapin Committed by Commit Bot

Make DedicatedWorker classes safe for use off the main thread.

This is in preparation for nested dedicated workers.

Bug: 829119

Change-Id: Ifedf3a9b3d57a2e88b294280f148d25b6071a170
Reviewed-on: https://chromium-review.googlesource.com/993773
Commit-Queue: Nate Chapin <japhet@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548229}
parent 8629c39b
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "core/workers/WorkerClassicScriptLoader.h" #include "core/workers/WorkerClassicScriptLoader.h"
#include "core/workers/WorkerClients.h" #include "core/workers/WorkerClients.h"
#include "core/workers/WorkerContentSettingsClient.h" #include "core/workers/WorkerContentSettingsClient.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerModuleFetchCoordinator.h" #include "core/workers/WorkerModuleFetchCoordinator.h"
#include "core/workers/WorkerOrWorkletModuleFetchCoordinator.h" #include "core/workers/WorkerOrWorkletModuleFetchCoordinator.h"
#include "platform/bindings/ScriptState.h" #include "platform/bindings/ScriptState.h"
...@@ -37,10 +38,10 @@ namespace { ...@@ -37,10 +38,10 @@ namespace {
service_manager::mojom::blink::InterfaceProviderPtrInfo service_manager::mojom::blink::InterfaceProviderPtrInfo
ConnectToWorkerInterfaceProvider( ConnectToWorkerInterfaceProvider(
Document* document, ExecutionContext* execution_context,
scoped_refptr<const SecurityOrigin> script_origin) { scoped_refptr<const SecurityOrigin> script_origin) {
mojom::blink::DedicatedWorkerFactoryPtr worker_factory; mojom::blink::DedicatedWorkerFactoryPtr worker_factory;
document->GetInterfaceProvider()->GetInterface(&worker_factory); execution_context->GetInterfaceProvider()->GetInterface(&worker_factory);
service_manager::mojom::blink::InterfaceProviderPtrInfo service_manager::mojom::blink::InterfaceProviderPtrInfo
interface_provider_ptr; interface_provider_ptr;
worker_factory->CreateDedicatedWorker( worker_factory->CreateDedicatedWorker(
...@@ -54,10 +55,9 @@ DedicatedWorker* DedicatedWorker::Create(ExecutionContext* context, ...@@ -54,10 +55,9 @@ DedicatedWorker* DedicatedWorker::Create(ExecutionContext* context,
const String& url, const String& url,
const WorkerOptions& options, const WorkerOptions& options,
ExceptionState& exception_state) { ExceptionState& exception_state) {
DCHECK(IsMainThread()); DCHECK(context->IsContextThread());
Document* document = ToDocument(context);
UseCounter::Count(context, WebFeature::kWorkerStart); UseCounter::Count(context, WebFeature::kWorkerStart);
if (!document->GetPage()) { if (context->IsContextDestroyed()) {
exception_state.ThrowDOMException(kInvalidAccessError, exception_state.ThrowDOMException(kInvalidAccessError,
"The context provided is invalid."); "The context provided is invalid.");
return nullptr; return nullptr;
...@@ -82,6 +82,9 @@ DedicatedWorker* DedicatedWorker::Create(ExecutionContext* context, ...@@ -82,6 +82,9 @@ DedicatedWorker* DedicatedWorker::Create(ExecutionContext* context,
return nullptr; return nullptr;
} }
if (context->IsWorkerGlobalScope())
ToWorkerGlobalScope(context)->EnsureFetcher();
DedicatedWorker* worker = new DedicatedWorker(context, script_url, options); DedicatedWorker* worker = new DedicatedWorker(context, script_url, options);
worker->Start(); worker->Start();
return worker; return worker;
...@@ -94,15 +97,15 @@ DedicatedWorker::DedicatedWorker(ExecutionContext* context, ...@@ -94,15 +97,15 @@ DedicatedWorker::DedicatedWorker(ExecutionContext* context,
script_url_(script_url), script_url_(script_url),
options_(options), options_(options),
context_proxy_(new DedicatedWorkerMessagingProxy(context, this)), context_proxy_(new DedicatedWorkerMessagingProxy(context, this)),
module_fetch_coordinator_(WorkerModuleFetchCoordinator::Create( module_fetch_coordinator_(
ToDocument(context)->Fetcher())) { WorkerModuleFetchCoordinator::Create(context->Fetcher())) {
DCHECK(IsMainThread()); DCHECK(context->IsContextThread());
DCHECK(script_url_.IsValid()); DCHECK(script_url_.IsValid());
DCHECK(context_proxy_); DCHECK(context_proxy_);
} }
DedicatedWorker::~DedicatedWorker() { DedicatedWorker::~DedicatedWorker() {
DCHECK(IsMainThread()); DCHECK(!GetExecutionContext() || GetExecutionContext()->IsContextThread());
context_proxy_->ParentObjectDestroyed(); context_proxy_->ParentObjectDestroyed();
} }
...@@ -110,24 +113,25 @@ void DedicatedWorker::postMessage(ScriptState* script_state, ...@@ -110,24 +113,25 @@ void DedicatedWorker::postMessage(ScriptState* script_state,
scoped_refptr<SerializedScriptValue> message, scoped_refptr<SerializedScriptValue> message,
const MessagePortArray& ports, const MessagePortArray& ports,
ExceptionState& exception_state) { ExceptionState& exception_state) {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
// Disentangle the port in preparation for sending it to the remote context. // Disentangle the port in preparation for sending it to the remote context.
auto channels = MessagePort::DisentanglePorts( auto channels = MessagePort::DisentanglePorts(
ExecutionContext::From(script_state), ports, exception_state); ExecutionContext::From(script_state), ports, exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
v8_inspector::V8StackTraceId stack_id = v8_inspector::V8StackTraceId stack_id =
MainThreadDebugger::Instance()->StoreCurrentStackTrace( ThreadDebugger::From(script_state->GetIsolate())
"Worker.postMessage"); ->StoreCurrentStackTrace("Worker.postMessage");
context_proxy_->PostMessageToWorkerGlobalScope(std::move(message), context_proxy_->PostMessageToWorkerGlobalScope(std::move(message),
std::move(channels), stack_id); std::move(channels), stack_id);
} }
void DedicatedWorker::Start() { void DedicatedWorker::Start() {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
v8_inspector::V8StackTraceId stack_id = v8_inspector::V8StackTraceId stack_id =
MainThreadDebugger::Instance()->StoreCurrentStackTrace("Worker Created"); ThreadDebugger::From(ToIsolate(GetExecutionContext()))
->StoreCurrentStackTrace("Worker Created");
if (options_.type() == "classic") { if (options_.type() == "classic") {
network::mojom::FetchRequestMode fetch_request_mode = network::mojom::FetchRequestMode fetch_request_mode =
...@@ -162,12 +166,12 @@ void DedicatedWorker::Start() { ...@@ -162,12 +166,12 @@ void DedicatedWorker::Start() {
} }
void DedicatedWorker::terminate() { void DedicatedWorker::terminate() {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
context_proxy_->TerminateGlobalScope(); context_proxy_->TerminateGlobalScope();
} }
void DedicatedWorker::ContextDestroyed(ExecutionContext*) { void DedicatedWorker::ContextDestroyed(ExecutionContext*) {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
if (classic_script_loader_) if (classic_script_loader_)
classic_script_loader_->Cancel(); classic_script_loader_->Cancel();
module_fetch_coordinator_->Dispose(); module_fetch_coordinator_->Dispose();
...@@ -175,36 +179,40 @@ void DedicatedWorker::ContextDestroyed(ExecutionContext*) { ...@@ -175,36 +179,40 @@ void DedicatedWorker::ContextDestroyed(ExecutionContext*) {
} }
bool DedicatedWorker::HasPendingActivity() const { bool DedicatedWorker::HasPendingActivity() const {
DCHECK(IsMainThread()); DCHECK(!GetExecutionContext() || GetExecutionContext()->IsContextThread());
// The worker context does not exist while loading, so we must ensure that the // The worker context does not exist while loading, so we must ensure that the
// worker object is not collected, nor are its event listeners. // worker object is not collected, nor are its event listeners.
return context_proxy_->HasPendingActivity() || classic_script_loader_; return context_proxy_->HasPendingActivity() || classic_script_loader_;
} }
WorkerClients* DedicatedWorker::CreateWorkerClients() { WorkerClients* DedicatedWorker::CreateWorkerClients() {
Document* document = ToDocument(GetExecutionContext());
WebLocalFrameImpl* web_frame =
WebLocalFrameImpl::FromFrame(document->GetFrame());
WorkerClients* worker_clients = WorkerClients::Create(); WorkerClients* worker_clients = WorkerClients::Create();
CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker( CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker(
*worker_clients); *worker_clients);
CoreInitializer::GetInstance().ProvideIndexedDBClientToWorker( CoreInitializer::GetInstance().ProvideIndexedDBClientToWorker(
*worker_clients); *worker_clients);
ProvideContentSettingsClientToWorker(
worker_clients, web_frame->Client()->CreateWorkerContentSettingsClient());
std::unique_ptr<WebContentSettingsClient> client;
if (GetExecutionContext()->IsDocument()) {
WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(
ToDocument(GetExecutionContext())->GetFrame());
client = web_frame->Client()->CreateWorkerContentSettingsClient();
}
// TODO(japhet): WorkerContentsSettingsClient should be cloned between
// worker threads for nested workers.
ProvideContentSettingsClientToWorker(worker_clients, std::move(client));
return worker_clients; return worker_clients;
} }
void DedicatedWorker::OnResponse() { void DedicatedWorker::OnResponse() {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
probe::didReceiveScriptResponse(GetExecutionContext(), probe::didReceiveScriptResponse(GetExecutionContext(),
classic_script_loader_->Identifier()); classic_script_loader_->Identifier());
} }
void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) { void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) {
DCHECK(IsMainThread()); DCHECK(GetExecutionContext()->IsContextThread());
if (classic_script_loader_->Canceled()) { if (classic_script_loader_->Canceled()) {
// Do nothing. // Do nothing.
} else if (classic_script_loader_->Failed()) { } else if (classic_script_loader_->Failed()) {
...@@ -231,20 +239,31 @@ void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) { ...@@ -231,20 +239,31 @@ void DedicatedWorker::OnFinished(const v8_inspector::V8StackTraceId& stack_id) {
std::unique_ptr<GlobalScopeCreationParams> std::unique_ptr<GlobalScopeCreationParams>
DedicatedWorker::CreateGlobalScopeCreationParams() { DedicatedWorker::CreateGlobalScopeCreationParams() {
Document* document = ToDocument(GetExecutionContext()); base::UnguessableToken devtools_worker_token;
const SecurityOrigin* starter_origin = document->GetSecurityOrigin(); std::unique_ptr<WorkerSettings> settings;
base::UnguessableToken devtools_worker_token = if (GetExecutionContext()->IsDocument()) {
document->GetFrame() ? document->GetFrame()->GetDevToolsFrameToken() Document* document = ToDocument(GetExecutionContext());
: base::UnguessableToken::Create(); devtools_worker_token = document->GetFrame()
? document->GetFrame()->GetDevToolsFrameToken()
: base::UnguessableToken::Create();
settings = std::make_unique<WorkerSettings>(document->GetSettings());
} else {
WorkerGlobalScope* worker_global_scope =
ToWorkerGlobalScope(GetExecutionContext());
devtools_worker_token = worker_global_scope->GetParentDevToolsToken();
settings = WorkerSettings::Copy(worker_global_scope->GetWorkerSettings());
}
return std::make_unique<GlobalScopeCreationParams>( return std::make_unique<GlobalScopeCreationParams>(
script_url_, GetExecutionContext()->UserAgent(), script_url_, GetExecutionContext()->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(), GetExecutionContext()->GetContentSecurityPolicy()->Headers().get(),
kReferrerPolicyDefault, starter_origin, document->IsSecureContext(), kReferrerPolicyDefault, GetExecutionContext()->GetSecurityOrigin(),
CreateWorkerClients(), document->AddressSpace(), GetExecutionContext()->IsSecureContext(), CreateWorkerClients(),
OriginTrialContext::GetTokens(document).get(), devtools_worker_token, GetExecutionContext()->GetSecurityContext().AddressSpace(),
std::make_unique<WorkerSettings>(document->GetSettings()), OriginTrialContext::GetTokens(GetExecutionContext()).get(),
kV8CacheOptionsDefault, module_fetch_coordinator_.Get(), devtools_worker_token, std::move(settings), kV8CacheOptionsDefault,
ConnectToWorkerInterfaceProvider(document, module_fetch_coordinator_.Get(),
ConnectToWorkerInterfaceProvider(GetExecutionContext(),
SecurityOrigin::Create(script_url_))); SecurityOrigin::Create(script_url_)));
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "core/events/MessageEvent.h" #include "core/events/MessageEvent.h"
#include "core/fetch/Request.h" #include "core/fetch/Request.h"
#include "core/frame/csp/ContentSecurityPolicy.h" #include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/inspector/MainThreadDebugger.h" #include "core/inspector/ThreadDebugger.h"
#include "core/workers/DedicatedWorker.h" #include "core/workers/DedicatedWorker.h"
#include "core/workers/DedicatedWorkerObjectProxy.h" #include "core/workers/DedicatedWorkerObjectProxy.h"
#include "core/workers/DedicatedWorkerThread.h" #include "core/workers/DedicatedWorkerThread.h"
...@@ -135,12 +135,14 @@ void DedicatedWorkerMessagingProxy::PostMessageToWorkerObject( ...@@ -135,12 +135,14 @@ void DedicatedWorkerMessagingProxy::PostMessageToWorkerObject(
if (!worker_object_ || AskedToTerminate()) if (!worker_object_ || AskedToTerminate())
return; return;
ThreadDebugger* debugger =
ThreadDebugger::From(ToIsolate(GetExecutionContext()));
MessagePortArray* ports = MessagePortArray* ports =
MessagePort::EntanglePorts(*GetExecutionContext(), std::move(channels)); MessagePort::EntanglePorts(*GetExecutionContext(), std::move(channels));
MainThreadDebugger::Instance()->ExternalAsyncTaskStarted(stack_id); debugger->ExternalAsyncTaskStarted(stack_id);
worker_object_->DispatchEvent( worker_object_->DispatchEvent(
MessageEvent::Create(ports, std::move(message))); MessageEvent::Create(ports, std::move(message)));
MainThreadDebugger::Instance()->ExternalAsyncTaskFinished(stack_id); debugger->ExternalAsyncTaskFinished(stack_id);
} }
void DedicatedWorkerMessagingProxy::DispatchErrorEvent( void DedicatedWorkerMessagingProxy::DispatchErrorEvent(
......
...@@ -50,6 +50,8 @@ FrameScheduler* GetFrameScheduler(ThreadableLoadingContext* loading_context) { ...@@ -50,6 +50,8 @@ FrameScheduler* GetFrameScheduler(ThreadableLoadingContext* loading_context) {
// |loading_context| can be null in unittests. // |loading_context| can be null in unittests.
if (!loading_context) if (!loading_context)
return nullptr; return nullptr;
if (!loading_context->GetExecutionContext()->IsDocument())
return nullptr;
return ToDocument(loading_context->GetExecutionContext()) return ToDocument(loading_context->GetExecutionContext())
->GetFrame() ->GetFrame()
->GetFrameScheduler(); ->GetFrameScheduler();
......
...@@ -11,6 +11,23 @@ WorkerSettings::WorkerSettings(Settings* settings) { ...@@ -11,6 +11,23 @@ WorkerSettings::WorkerSettings(Settings* settings) {
this->CopyFlagValuesFromSettings(settings); this->CopyFlagValuesFromSettings(settings);
} }
std::unique_ptr<WorkerSettings> WorkerSettings::Copy(
WorkerSettings* old_settings) {
std::unique_ptr<WorkerSettings> new_settings =
std::make_unique<WorkerSettings>(nullptr);
new_settings->disable_reading_from_canvas_ =
old_settings->disable_reading_from_canvas_;
new_settings->strict_mixed_content_checking_ =
old_settings->strict_mixed_content_checking_;
new_settings->allow_running_of_insecure_content_ =
old_settings->allow_running_of_insecure_content_;
new_settings->strictly_block_blockable_mixed_content_ =
old_settings->strictly_block_blockable_mixed_content_;
old_settings->generic_font_family_settings_.IsolatedCopyTo(
new_settings->generic_font_family_settings_);
return new_settings;
}
void WorkerSettings::CopyFlagValuesFromSettings(Settings* settings) { void WorkerSettings::CopyFlagValuesFromSettings(Settings* settings) {
disable_reading_from_canvas_ = settings->GetDisableReadingFromCanvas(); disable_reading_from_canvas_ = settings->GetDisableReadingFromCanvas();
strict_mixed_content_checking_ = settings->GetStrictMixedContentChecking(); strict_mixed_content_checking_ = settings->GetStrictMixedContentChecking();
......
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class CORE_EXPORT WorkerSettings { class CORE_EXPORT WorkerSettings {
public: public:
explicit WorkerSettings(Settings*); explicit WorkerSettings(Settings*);
static std::unique_ptr<WorkerSettings> Copy(WorkerSettings*);
bool DisableReadingFromCanvas() const { return disable_reading_from_canvas_; } bool DisableReadingFromCanvas() const { return disable_reading_from_canvas_; }
bool GetStrictMixedContentChecking() const { bool GetStrictMixedContentChecking() const {
......
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