blob: 5ee62cfe6198647cc14ca0b388145e94a6140e31 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
#include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
#include "third_party/blink/public/web/web_serialized_script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fetch/headers.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
#include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
namespace blink {
ServiceWorkerGlobalScopeProxy::~ServiceWorkerGlobalScopeProxy() {
DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
// Verify that the proxy has been detached.
DCHECK(!embedded_worker_);
}
void ServiceWorkerGlobalScopeProxy::BindServiceWorker(
mojo::ScopedMessagePipeHandle receiver_pipe) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->BindServiceWorker(
mojo::PendingReceiver<mojom::blink::ServiceWorker>(
std::move(receiver_pipe)));
}
void ServiceWorkerGlobalScopeProxy::BindControllerServiceWorker(
mojo::ScopedMessagePipeHandle receiver_pipe) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->BindControllerServiceWorker(
mojo::PendingReceiver<mojom::blink::ControllerServiceWorker>(
std::move(receiver_pipe)));
}
void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse(
int fetch_event_id,
std::unique_ptr<WebURLResponse> response,
mojo::ScopedDataPipeConsumerHandle data_pipe) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->OnNavigationPreloadResponse(
fetch_event_id, std::move(response), std::move(data_pipe));
}
void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadError(
int fetch_event_id,
std::unique_ptr<WebServiceWorkerError> error) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->OnNavigationPreloadError(fetch_event_id,
std::move(error));
}
void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadComplete(
int fetch_event_id,
base::TimeTicks completion_time,
int64_t encoded_data_length,
int64_t encoded_body_length,
int64_t decoded_body_length) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->OnNavigationPreloadComplete(
fetch_event_id, completion_time, encoded_data_length, encoded_body_length,
decoded_body_length);
}
void ServiceWorkerGlobalScopeProxy::CountFeature(WebFeature feature) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().CountFeature(feature);
}
void ServiceWorkerGlobalScopeProxy::CountDeprecation(WebFeature feature) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
// Go through the same code path with countFeature() because a deprecation
// message is already shown on the worker console and a remaining work is
// just to record an API use.
CountFeature(feature);
}
void ServiceWorkerGlobalScopeProxy::ReportException(
const String& error_message,
std::unique_ptr<SourceLocation> location,
int exception_id) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().ReportException(error_message, location->LineNumber(),
location->ColumnNumber(), location->Url());
}
void ServiceWorkerGlobalScopeProxy::ReportConsoleMessage(
mojom::ConsoleMessageSource source,
mojom::ConsoleMessageLevel level,
const String& message,
SourceLocation* location) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().ReportConsoleMessage(source, level, message, location->LineNumber(),
location->Url());
}
void ServiceWorkerGlobalScopeProxy::WillInitializeWorkerContext() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().WillInitializeWorkerContext();
}
void ServiceWorkerGlobalScopeProxy::DidCreateWorkerGlobalScope(
WorkerOrWorkletGlobalScope* worker_global_scope) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
DCHECK(!worker_global_scope_);
worker_global_scope_ =
static_cast<ServiceWorkerGlobalScope*>(worker_global_scope);
scoped_refptr<base::SequencedTaskRunner> worker_task_runner =
worker_global_scope->GetThread()->GetTaskRunner(
TaskType::kInternalDefault);
Client().WorkerContextStarted(this, std::move(worker_task_runner));
}
void ServiceWorkerGlobalScopeProxy::DidLoadClassicScript() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().WorkerScriptLoadedOnWorkerThread();
}
void ServiceWorkerGlobalScopeProxy::DidFetchScript() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().WorkerScriptLoadedOnWorkerThread();
}
void ServiceWorkerGlobalScopeProxy::DidFailToFetchClassicScript() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().FailedToFetchClassicScript();
}
void ServiceWorkerGlobalScopeProxy::DidFailToFetchModuleScript() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().FailedToFetchModuleScript();
}
void ServiceWorkerGlobalScopeProxy::WillEvaluateClassicScript(
size_t script_size,
size_t cached_metadata_size) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
"ServiceWorker", "ServiceWorkerGlobalScopeProxy::EvaluateClassicScript",
TRACE_ID_LOCAL(this));
// TODO(asamidoi): Remove CountWorkerScript which is called for recording
// metrics if the metrics are no longer referenced, and then merge
// WillEvaluateClassicScript and WillEvaluateModuleScript for cleanup.
worker_global_scope_->CountWorkerScript(script_size, cached_metadata_size);
ScriptState::Scope scope(
WorkerGlobalScope()->ScriptController()->GetScriptState());
Client().WillEvaluateScript(
WorkerGlobalScope()->ScriptController()->GetContext());
}
void ServiceWorkerGlobalScopeProxy::WillEvaluateImportedClassicScript(
size_t script_size,
size_t cached_metadata_size) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
worker_global_scope_->CountImportedScript(script_size, cached_metadata_size);
}
void ServiceWorkerGlobalScopeProxy::WillEvaluateModuleScript() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
ScriptState::Scope scope(
WorkerGlobalScope()->ScriptController()->GetScriptState());
Client().WillEvaluateScript(
WorkerGlobalScope()->ScriptController()->GetContext());
}
void ServiceWorkerGlobalScopeProxy::DidEvaluateClassicScript(bool success) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->DidEvaluateScript();
Client().DidEvaluateScript(success);
TRACE_EVENT_NESTABLE_ASYNC_END1(
"ServiceWorker", "ServiceWorkerGlobalScopeProxy::EvaluateClassicScript",
TRACE_ID_LOCAL(this), "success", success);
}
void ServiceWorkerGlobalScopeProxy::DidEvaluateModuleScript(bool success) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
WorkerGlobalScope()->DidEvaluateScript();
Client().DidEvaluateScript(success);
}
void ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
// close() is not web-exposed for ServiceWorker. This is called when
// ServiceWorkerGlobalScope internally requests close(), for example, due to
// failure on startup when installed scripts couldn't be read.
//
// This may look like a roundabout way to terminate the thread, but close()
// seems like the standard way to initiate termination from inside the thread.
// ServiceWorkerGlobalScope expects us to terminate the thread, so request
// that here.
PostCrossThreadTask(
*parent_thread_default_task_runner_, FROM_HERE,
CrossThreadBindOnce(&WebEmbeddedWorkerImpl::TerminateWorkerContext,
CrossThreadUnretained(embedded_worker_)));
// NOTE: WorkerThread calls WillDestroyWorkerGlobalScope() synchronously after
// this function returns, since it calls DidCloseWorkerGlobalScope() then
// PrepareForShutdownOnWorkerThread().
}
void ServiceWorkerGlobalScopeProxy::WillDestroyWorkerGlobalScope() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
v8::HandleScope handle_scope(WorkerGlobalScope()->GetThread()->GetIsolate());
Client().WillDestroyWorkerContext(
WorkerGlobalScope()->ScriptController()->GetContext());
worker_global_scope_ = nullptr;
}
void ServiceWorkerGlobalScopeProxy::DidTerminateWorkerThread() {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
// This must be called after WillDestroyWorkerGlobalScope().
DCHECK(!worker_global_scope_);
Client().WorkerContextDestroyed();
}
bool ServiceWorkerGlobalScopeProxy::IsServiceWorkerGlobalScopeProxy() const {
return true;
}
void ServiceWorkerGlobalScopeProxy::SetupNavigationPreload(
int fetch_event_id,
const KURL& url,
mojom::blink::FetchEventPreloadHandlePtr preload_handle) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
auto web_preload_handle = std::make_unique<WebFetchEventPreloadHandle>();
web_preload_handle->url_loader = preload_handle->url_loader.PassPipe();
web_preload_handle->url_loader_client_receiver =
preload_handle->url_loader_client_receiver.PassPipe();
Client().SetupNavigationPreload(fetch_event_id, url,
std::move(web_preload_handle));
}
void ServiceWorkerGlobalScopeProxy::RequestTermination(
CrossThreadOnceFunction<void(bool)> callback) {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
Client().RequestTermination(ConvertToBaseOnceCallback(std::move(callback)));
}
ServiceWorkerGlobalScopeProxy::ServiceWorkerGlobalScopeProxy(
WebEmbeddedWorkerImpl& embedded_worker,
WebServiceWorkerContextClient& client,
scoped_refptr<base::SingleThreadTaskRunner>
parent_thread_default_task_runner)
: embedded_worker_(&embedded_worker),
parent_thread_default_task_runner_(
std::move(parent_thread_default_task_runner)),
client_(&client),
worker_global_scope_(nullptr) {
DETACH_FROM_THREAD(worker_thread_checker_);
DCHECK(parent_thread_default_task_runner_);
}
void ServiceWorkerGlobalScopeProxy::Detach() {
DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
embedded_worker_ = nullptr;
client_ = nullptr;
}
void ServiceWorkerGlobalScopeProxy::TerminateWorkerContext() {
DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
embedded_worker_->TerminateWorkerContext();
}
bool ServiceWorkerGlobalScopeProxy::IsWindowInteractionAllowed() {
return WorkerGlobalScope()->IsWindowInteractionAllowed();
}
void ServiceWorkerGlobalScopeProxy::PauseEvaluation() {
WorkerGlobalScope()->PauseEvaluation();
}
void ServiceWorkerGlobalScopeProxy::ResumeEvaluation() {
WorkerGlobalScope()->ResumeEvaluation();
}
WebServiceWorkerContextClient& ServiceWorkerGlobalScopeProxy::Client() const {
DCHECK(client_);
return *client_;
}
ServiceWorkerGlobalScope* ServiceWorkerGlobalScopeProxy::WorkerGlobalScope()
const {
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
DCHECK(worker_global_scope_);
return worker_global_scope_;
}
} // namespace blink