blob: 072868318a39554ef136687a8b668dbc823ff4bc [file] [log] [blame]
// Copyright 2022 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/worker/service_worker_registration.h"
#include <utility>
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/task_runner.h"
#include "base/trace_event/trace_event.h"
#include "cobalt/script/environment_settings.h"
#include "cobalt/web/context.h"
#include "cobalt/web/dom_exception.h"
#include "cobalt/web/environment_settings.h"
#include "cobalt/web/window_or_worker_global_scope.h"
#include "cobalt/worker/service_worker.h"
#include "cobalt/worker/service_worker_global_scope.h"
#include "cobalt/worker/service_worker_jobs.h"
#include "cobalt/worker/service_worker_registration_object.h"
namespace cobalt {
namespace worker {
ServiceWorkerRegistration::ServiceWorkerRegistration(
script::EnvironmentSettings* settings,
worker::ServiceWorkerRegistrationObject* registration)
: web::EventTarget(settings), registration_(registration) {}
script::HandlePromiseWrappable ServiceWorkerRegistration::Update() {
TRACE_EVENT0("cobalt::worker", "ServiceWorkerRegistration::Update()");
// Algorithm for update():
// https://w3c.github.io/ServiceWorker/#service-worker-registration-update
script::HandlePromiseWrappable promise =
environment_settings()
->context()
->global_environment()
->script_value_factory()
->CreateInterfacePromise<scoped_refptr<ServiceWorkerRegistration>>();
std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
new script::ValuePromiseWrappable::Reference(this, promise));
// Perform the rest of the steps in a task, because the promise has to be
// returned before we can safely reject or resolve it.
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&ServiceWorkerRegistration::UpdateTask,
base::Unretained(this), std::move(promise_reference)));
// 9. Return promise.
return promise;
}
void ServiceWorkerRegistration::UpdateTask(
std::unique_ptr<script::ValuePromiseWrappable::Reference>
promise_reference) {
TRACE_EVENT0("cobalt::worker", "ServiceWorkerRegistration::UpdateTask()");
DCHECK_EQ(base::MessageLoop::current(),
environment_settings()->context()->message_loop());
// Algorithm for update():
// https://w3c.github.io/ServiceWorker/#service-worker-registration-update
// 1. Let registration be the service worker registration.
// 2. Let newestWorker be the result of running Get Newest Worker algorithm
// passing registration as its argument.
ServiceWorkerObject* newest_worker = registration_->GetNewestWorker();
// 3. If newestWorker is null, return a promise rejected with an
// "InvalidStateError" DOMException and abort these steps.
if (!newest_worker) {
promise_reference->value().Reject(
new web::DOMException(web::DOMException::kInvalidStateErr));
return;
}
// 4. If this's relevant global object globalObject is a
// ServiceWorkerGlobalScope object, and globalObject’s associated service
// worker's state is "installing", return a promise rejected with an
// "InvalidStateError" DOMException and abort these steps.
web::WindowOrWorkerGlobalScope* window_or_worker_global_scope =
environment_settings()->context()->GetWindowOrWorkerGlobalScope();
if (window_or_worker_global_scope->IsServiceWorker()) {
ServiceWorkerGlobalScope* global_object =
base::polymorphic_downcast<ServiceWorkerGlobalScope*>(
window_or_worker_global_scope);
ServiceWorker* service_worker = global_object->service_worker();
if (service_worker &&
service_worker->state() == kServiceWorkerStateInstalling) {
promise_reference->value().Reject(
new web::DOMException(web::DOMException::kInvalidStateErr));
return;
}
}
// 5. Let promise be a promise.
// 6. Let job be the result of running Create Job with update, registration’s
// storage key, registration’s scope url, newestWorker’s script url,
// promise, and this's relevant settings object.
worker::ServiceWorkerJobs* jobs =
environment_settings()->context()->service_worker_jobs();
std::unique_ptr<ServiceWorkerJobs::Job> job = jobs->CreateJob(
ServiceWorkerJobs::JobType::kUpdate, registration_->storage_key(),
registration_->scope_url(), newest_worker->script_url(),
std::move(promise_reference), environment_settings());
DCHECK(!promise_reference);
// 7. Set job’s worker type to newestWorker’s type.
// Cobalt only supports 'classic' worker type.
// 8. Invoke Schedule Job with job.
jobs->message_loop()->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
base::Unretained(jobs), std::move(job)));
DCHECK(!job.get());
}
script::HandlePromiseBool ServiceWorkerRegistration::Unregister() {
// Algorithm for unregister():
// https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister
// 1. Let registration be the service worker registration.
// 2. Let promise be a new promise.
script::HandlePromiseBool promise = environment_settings()
->context()
->global_environment()
->script_value_factory()
->CreateBasicPromise<bool>();
std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference(
new script::ValuePromiseBool::Reference(this, promise));
// Perform the rest of the steps in a task, so that unregister doesn't race
// past any previously submitted update requests.
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&ServiceWorkerRegistration::UnregisterTask,
base::Unretained(this), std::move(promise_reference)));
// 5. Return promise.
return promise;
}
void ServiceWorkerRegistration::UnregisterTask(
std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference) {
// Algorithm for unregister():
// https://w3c.github.io/ServiceWorker/#navigator-service-worker-unregister
// 3. Let job be the result of running Create Job with unregister,
// registration’s storage key, registration’s scope url, null, promise, and
// this's relevant settings object.
worker::ServiceWorkerJobs* jobs =
environment_settings()->context()->service_worker_jobs();
std::unique_ptr<ServiceWorkerJobs::Job> job = jobs->CreateJob(
ServiceWorkerJobs::JobType::kUnregister, registration_->storage_key(),
registration_->scope_url(), GURL(), std::move(promise_reference),
environment_settings());
DCHECK(!promise_reference);
// 4. Invoke Schedule Job with job.
jobs->message_loop()->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
base::Unretained(jobs), std::move(job)));
DCHECK(!job.get());
}
std::string ServiceWorkerRegistration::scope() const {
return registration_->scope_url().GetContent();
}
ServiceWorkerUpdateViaCache ServiceWorkerRegistration::update_via_cache()
const {
return registration_->update_via_cache_mode();
}
void ServiceWorkerRegistration::EnableNavigationPreload(bool enable) {
// Todo: Implement the logic for set header
}
void ServiceWorkerRegistration::SetNavigationPreloadHeader() {
// Todo: Implement the logic for set header
}
} // namespace worker
} // namespace cobalt