1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/service_worker/service_worker_job_coordinator.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/memory/ptr_util.h"
13 #include "content/browser/service_worker/service_worker_register_job_base.h"
14 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
15
16 namespace content {
17
18 ServiceWorkerJobCoordinator::JobQueue::JobQueue() = default;
19
20 ServiceWorkerJobCoordinator::JobQueue::JobQueue(JobQueue&&) = default;
21
~JobQueue()22 ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
23 DCHECK(jobs_.empty()) << "Destroying JobQueue with " << jobs_.size()
24 << " unfinished jobs";
25 }
26
Push(std::unique_ptr<ServiceWorkerRegisterJobBase> job)27 ServiceWorkerRegisterJobBase* ServiceWorkerJobCoordinator::JobQueue::Push(
28 std::unique_ptr<ServiceWorkerRegisterJobBase> job) {
29 if (jobs_.empty()) {
30 jobs_.push_back(std::move(job));
31 StartOneJob();
32 } else if (!job->Equals(jobs_.back().get())) {
33 jobs_.push_back(std::move(job));
34 }
35 // Note we are releasing 'job' here in case neither of the two if() statements
36 // above were true.
37
38 DCHECK(!jobs_.empty());
39 return jobs_.back().get();
40 }
41
Pop(ServiceWorkerRegisterJobBase * job)42 void ServiceWorkerJobCoordinator::JobQueue::Pop(
43 ServiceWorkerRegisterJobBase* job) {
44 DCHECK(job == jobs_.front().get());
45 jobs_.pop_front();
46 if (!jobs_.empty())
47 StartOneJob();
48 }
49
StartOneJob()50 void ServiceWorkerJobCoordinator::JobQueue::StartOneJob() {
51 DCHECK(!jobs_.empty());
52 jobs_.front()->Start();
53 }
54
AbortAll()55 void ServiceWorkerJobCoordinator::JobQueue::AbortAll() {
56 for (const auto& job : jobs_)
57 job->Abort();
58 jobs_.clear();
59 }
60
ClearForShutdown()61 void ServiceWorkerJobCoordinator::JobQueue::ClearForShutdown() {
62 for (const auto& job : jobs_)
63 job->WillShutDown();
64 jobs_.clear();
65 }
66
ServiceWorkerJobCoordinator(ServiceWorkerContextCore * context)67 ServiceWorkerJobCoordinator::ServiceWorkerJobCoordinator(
68 ServiceWorkerContextCore* context)
69 : context_(context) {
70 DCHECK(context_);
71 }
72
~ServiceWorkerJobCoordinator()73 ServiceWorkerJobCoordinator::~ServiceWorkerJobCoordinator() {
74 DCHECK(job_queues_.empty()) << "Destroying ServiceWorkerJobCoordinator with "
75 << job_queues_.size() << " job queues";
76 }
77
Register(const GURL & script_url,const blink::mojom::ServiceWorkerRegistrationOptions & options,blink::mojom::FetchClientSettingsObjectPtr outside_fetch_client_settings_object,ServiceWorkerRegisterJob::RegistrationCallback callback)78 void ServiceWorkerJobCoordinator::Register(
79 const GURL& script_url,
80 const blink::mojom::ServiceWorkerRegistrationOptions& options,
81 blink::mojom::FetchClientSettingsObjectPtr
82 outside_fetch_client_settings_object,
83 ServiceWorkerRegisterJob::RegistrationCallback callback) {
84 std::unique_ptr<ServiceWorkerRegisterJobBase> job(
85 new ServiceWorkerRegisterJob(
86 context_, script_url, options,
87 std::move(outside_fetch_client_settings_object)));
88 ServiceWorkerRegisterJob* queued_job = static_cast<ServiceWorkerRegisterJob*>(
89 job_queues_[options.scope].Push(std::move(job)));
90 queued_job->AddCallback(std::move(callback));
91 }
92
Unregister(const GURL & scope,bool is_immediate,ServiceWorkerUnregisterJob::UnregistrationCallback callback)93 void ServiceWorkerJobCoordinator::Unregister(
94 const GURL& scope,
95 bool is_immediate,
96 ServiceWorkerUnregisterJob::UnregistrationCallback callback) {
97 std::unique_ptr<ServiceWorkerRegisterJobBase> job(
98 new ServiceWorkerUnregisterJob(context_, scope, is_immediate));
99 ServiceWorkerUnregisterJob* queued_job =
100 static_cast<ServiceWorkerUnregisterJob*>(
101 job_queues_[scope].Push(std::move(job)));
102 queued_job->AddCallback(std::move(callback));
103 }
104
Update(ServiceWorkerRegistration * registration,bool force_bypass_cache)105 void ServiceWorkerJobCoordinator::Update(
106 ServiceWorkerRegistration* registration,
107 bool force_bypass_cache) {
108 DCHECK(registration);
109 // Use an empty fetch client settings object because this method is for
110 // browser-initiated update and there is no associated execution context.
111 job_queues_[registration->scope()].Push(
112 base::WrapUnique<ServiceWorkerRegisterJobBase>(
113 new ServiceWorkerRegisterJob(
114 context_, registration, force_bypass_cache,
115 false /* skip_script_comparison */,
116 blink::mojom::FetchClientSettingsObject::New())));
117 }
118
Update(ServiceWorkerRegistration * registration,bool force_bypass_cache,bool skip_script_comparison,blink::mojom::FetchClientSettingsObjectPtr outside_fetch_client_settings_object,ServiceWorkerRegisterJob::RegistrationCallback callback)119 void ServiceWorkerJobCoordinator::Update(
120 ServiceWorkerRegistration* registration,
121 bool force_bypass_cache,
122 bool skip_script_comparison,
123 blink::mojom::FetchClientSettingsObjectPtr
124 outside_fetch_client_settings_object,
125 ServiceWorkerRegisterJob::RegistrationCallback callback) {
126 DCHECK(registration);
127 ServiceWorkerRegisterJob* queued_job = static_cast<ServiceWorkerRegisterJob*>(
128 job_queues_[registration->scope()].Push(
129 base::WrapUnique<ServiceWorkerRegisterJobBase>(
130 new ServiceWorkerRegisterJob(
131 context_, registration, force_bypass_cache,
132 skip_script_comparison,
133 std::move(outside_fetch_client_settings_object)))));
134 queued_job->AddCallback(std::move(callback));
135 }
136
Abort(const GURL & scope)137 void ServiceWorkerJobCoordinator::Abort(const GURL& scope) {
138 auto pending_jobs = job_queues_.find(scope);
139 if (pending_jobs == job_queues_.end())
140 return;
141 pending_jobs->second.AbortAll();
142 job_queues_.erase(pending_jobs);
143 }
144
AbortAll()145 void ServiceWorkerJobCoordinator::AbortAll() {
146 for (auto& job_pair : job_queues_)
147 job_pair.second.AbortAll();
148 job_queues_.clear();
149 }
150
ClearForShutdown()151 void ServiceWorkerJobCoordinator::ClearForShutdown() {
152 for (auto& job_pair : job_queues_)
153 job_pair.second.ClearForShutdown();
154 job_queues_.clear();
155 }
156
FinishJob(const GURL & scope,ServiceWorkerRegisterJobBase * job)157 void ServiceWorkerJobCoordinator::FinishJob(const GURL& scope,
158 ServiceWorkerRegisterJobBase* job) {
159 auto pending_jobs = job_queues_.find(scope);
160 DCHECK(pending_jobs != job_queues_.end()) << "Deleting non-existent job.";
161 pending_jobs->second.Pop(job);
162 if (pending_jobs->second.empty())
163 job_queues_.erase(pending_jobs);
164 }
165
166 } // namespace content
167