blob: f737b142c6323af128eb8e89fd8705b2ef469e52 [file] [log] [blame]
// Copyright 2015 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/workers/InProcessWorkerBase.h"
#include <memory>
#include "bindings/core/v8/ExceptionState.h"
#include "core/dom/ExecutionContext.h"
#include "core/events/MessageEvent.h"
#include "core/probe/CoreProbes.h"
#include "core/workers/InProcessWorkerMessagingProxy.h"
#include "core/workers/WorkerScriptLoader.h"
#include "platform/bindings/ScriptState.h"
#include "platform/loader/fetch/ResourceFetcher.h"
namespace blink {
InProcessWorkerBase::InProcessWorkerBase(ExecutionContext* context)
: AbstractWorker(context), context_proxy_(nullptr) {}
InProcessWorkerBase::~InProcessWorkerBase() {
DCHECK(IsMainThread());
if (!context_proxy_)
return;
context_proxy_->ParentObjectDestroyed();
}
void InProcessWorkerBase::postMessage(ScriptState* script_state,
PassRefPtr<SerializedScriptValue> message,
const MessagePortArray& ports,
ExceptionState& exception_state) {
DCHECK(context_proxy_);
// Disentangle the port in preparation for sending it to the remote context.
MessagePortChannelArray channels = MessagePort::DisentanglePorts(
ExecutionContext::From(script_state), ports, exception_state);
if (exception_state.HadException())
return;
context_proxy_->PostMessageToWorkerGlobalScope(std::move(message),
std::move(channels));
}
bool InProcessWorkerBase::Initialize(ExecutionContext* context,
const String& url,
ExceptionState& exception_state) {
// TODO(mkwst): Revisit the context as
// https://drafts.css-houdini.org/worklets/ evolves.
KURL script_url =
ResolveURL(url, exception_state, WebURLRequest::kRequestContextScript);
if (script_url.IsEmpty())
return false;
WebURLRequest::FetchRequestMode fetch_request_mode =
WebURLRequest::kFetchRequestModeSameOrigin;
WebURLRequest::FetchCredentialsMode fetch_credentials_mode =
WebURLRequest::kFetchCredentialsModeSameOrigin;
if (script_url.ProtocolIsData()) {
fetch_request_mode = WebURLRequest::kFetchRequestModeNoCORS;
fetch_credentials_mode = WebURLRequest::kFetchCredentialsModeInclude;
}
script_loader_ = WorkerScriptLoader::Create();
script_loader_->LoadAsynchronously(
*context, script_url, fetch_request_mode, fetch_credentials_mode,
context->GetSecurityContext().AddressSpace(),
WTF::Bind(&InProcessWorkerBase::OnResponse, WrapPersistent(this)),
WTF::Bind(&InProcessWorkerBase::OnFinished, WrapPersistent(this)));
context_proxy_ = CreateInProcessWorkerMessagingProxy(context);
return true;
}
void InProcessWorkerBase::terminate() {
if (context_proxy_)
context_proxy_->TerminateGlobalScope();
}
void InProcessWorkerBase::ContextDestroyed(ExecutionContext*) {
if (script_loader_)
script_loader_->Cancel();
terminate();
}
bool InProcessWorkerBase::HasPendingActivity() const {
// The worker context does not exist while loading, so we must ensure that the
// worker object is not collected, nor are its event listeners.
return (context_proxy_ && context_proxy_->HasPendingActivity()) ||
script_loader_;
}
void InProcessWorkerBase::OnResponse() {
probe::didReceiveScriptResponse(GetExecutionContext(),
script_loader_->Identifier());
}
void InProcessWorkerBase::OnFinished() {
if (script_loader_->Canceled()) {
// Do nothing.
} else if (script_loader_->Failed()) {
DispatchEvent(Event::CreateCancelable(EventTypeNames::error));
} else {
context_proxy_->StartWorkerGlobalScope(
script_loader_->Url(), GetExecutionContext()->UserAgent(),
script_loader_->SourceText(), script_loader_->GetReferrerPolicy());
probe::scriptImported(GetExecutionContext(), script_loader_->Identifier(),
script_loader_->SourceText());
}
script_loader_ = nullptr;
}
DEFINE_TRACE(InProcessWorkerBase) {
visitor->Trace(context_proxy_);
AbstractWorker::Trace(visitor);
}
} // namespace blink