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/worker_host/shared_worker_host.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/feature_list.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/no_destructor.h"
13 #include "base/task/post_task.h"
14 #include "base/unguessable_token.h"
15 #include "content/browser/appcache/appcache_navigation_handle.h"
16 #include "content/browser/devtools/shared_worker_devtools_manager.h"
17 #include "content/browser/frame_host/render_frame_host_impl.h"
18 #include "content/browser/interface_provider_filtering.h"
19 #include "content/browser/service_worker/service_worker_main_resource_handle.h"
20 #include "content/browser/service_worker/service_worker_object_host.h"
21 #include "content/browser/storage_partition_impl.h"
22 #include "content/browser/url_loader_factory_params_helper.h"
23 #include "content/browser/webtransport/quic_transport_connector_impl.h"
24 #include "content/browser/worker_host/shared_worker_content_settings_proxy_impl.h"
25 #include "content/browser/worker_host/shared_worker_service_impl.h"
26 #include "content/public/browser/browser_context.h"
27 #include "content/public/browser/browser_task_traits.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/content_browser_client.h"
30 #include "content/public/browser/service_worker_context.h"
31 #include "content/public/common/content_client.h"
32 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
33 #include "net/base/network_isolation_key.h"
34 #include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
35 #include "third_party/blink/public/common/messaging/message_port_channel.h"
36 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
37 #include "third_party/blink/public/mojom/renderer_preference_watcher.mojom.h"
38 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
39 #include "third_party/blink/public/mojom/worker/shared_worker_info.mojom.h"
40 #include "third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom.h"
41
42 namespace content {
43
44 // RAII helper class for talking to SharedWorkerDevToolsManager.
45 class SharedWorkerHost::ScopedDevToolsHandle {
46 public:
ScopedDevToolsHandle(SharedWorkerHost * owner,bool * out_pause_on_start,base::UnguessableToken * out_devtools_worker_token)47 ScopedDevToolsHandle(SharedWorkerHost* owner,
48 bool* out_pause_on_start,
49 base::UnguessableToken* out_devtools_worker_token)
50 : owner_(owner) {
51 SharedWorkerDevToolsManager::GetInstance()->WorkerCreated(
52 owner, out_pause_on_start, out_devtools_worker_token);
53 }
54
~ScopedDevToolsHandle()55 ~ScopedDevToolsHandle() {
56 SharedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(owner_);
57 }
58
WorkerReadyForInspection(mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> agent_host_receiver)59 void WorkerReadyForInspection(
60 mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,
61 mojo::PendingReceiver<blink::mojom::DevToolsAgentHost>
62 agent_host_receiver) {
63 SharedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
64 owner_, std::move(agent_remote), std::move(agent_host_receiver));
65 }
66
67 private:
68 SharedWorkerHost* owner_;
69 DISALLOW_COPY_AND_ASSIGN(ScopedDevToolsHandle);
70 };
71
72 class SharedWorkerHost::ScopedProcessHostRef {
73 public:
ScopedProcessHostRef(RenderProcessHost * render_process_host)74 explicit ScopedProcessHostRef(RenderProcessHost* render_process_host)
75 : render_process_host_(render_process_host) {
76 render_process_host_->IncrementKeepAliveRefCount();
77 }
78
~ScopedProcessHostRef()79 ~ScopedProcessHostRef() {
80 if (!render_process_host_->IsKeepAliveRefCountDisabled())
81 render_process_host_->DecrementKeepAliveRefCount();
82 }
83
84 ScopedProcessHostRef(const ScopedProcessHostRef& other) = delete;
85
86 private:
87 RenderProcessHost* const render_process_host_;
88 };
89
SharedWorkerHost(SharedWorkerServiceImpl * service,SharedWorkerId id,const SharedWorkerInstance & instance,RenderProcessHost * worker_process_host)90 SharedWorkerHost::SharedWorkerHost(SharedWorkerServiceImpl* service,
91 SharedWorkerId id,
92 const SharedWorkerInstance& instance,
93 RenderProcessHost* worker_process_host)
94 : service_(service),
95 id_(id),
96 instance_(instance),
97 worker_process_host_(worker_process_host),
98 scoped_process_host_ref_(
99 std::make_unique<ScopedProcessHostRef>(worker_process_host)),
100 scoped_process_host_observer_(this),
101 next_connection_request_id_(1) {
102 DCHECK(worker_process_host_);
103 DCHECK(!IsShuttingDown(worker_process_host_));
104
105 // Set up the worker pending receiver. This is needed first in either
106 // AddClient() or Start(). AddClient() can sometimes be called before Start()
107 // when two clients call new SharedWorker() at around the same time.
108 worker_receiver_ = worker_.BindNewPipeAndPassReceiver();
109
110 scoped_process_host_observer_.Add(worker_process_host_);
111 }
112
~SharedWorkerHost()113 SharedWorkerHost::~SharedWorkerHost() {
114 if (started_) {
115 // Attempt to notify the worker before disconnecting.
116 if (worker_)
117 worker_->Terminate();
118
119 // Notify the service that each client still connected will be removed and
120 // that the worker will terminate.
121 for (const auto& client : clients_) {
122 service_->NotifyClientRemoved(id_, client.render_frame_host_id);
123 }
124 service_->NotifyWorkerTerminating(id_);
125 } else {
126 // Tell clients that this worker failed to start.
127 for (const ClientInfo& info : clients_)
128 info.client->OnScriptLoadFailed(/*error_message=*/"");
129 }
130 }
131
Start(mojo::PendingRemote<blink::mojom::SharedWorkerFactory> factory,blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loader_factories,blink::mojom::ControllerServiceWorkerInfoPtr controller,base::WeakPtr<ServiceWorkerObjectHost> controller_service_worker_object_host,blink::mojom::FetchClientSettingsObjectPtr outside_fetch_client_settings_object)132 void SharedWorkerHost::Start(
133 mojo::PendingRemote<blink::mojom::SharedWorkerFactory> factory,
134 blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
135 std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
136 subresource_loader_factories,
137 blink::mojom::ControllerServiceWorkerInfoPtr controller,
138 base::WeakPtr<ServiceWorkerObjectHost>
139 controller_service_worker_object_host,
140 blink::mojom::FetchClientSettingsObjectPtr
141 outside_fetch_client_settings_object) {
142 DCHECK_CURRENTLY_ON(BrowserThread::UI);
143 DCHECK(!started_);
144 DCHECK(main_script_load_params);
145 DCHECK(subresource_loader_factories);
146 DCHECK(!subresource_loader_factories->pending_default_factory());
147
148 started_ = true;
149
150 auto options = blink::mojom::WorkerOptions::New(
151 instance_.script_type(), instance_.credentials_mode(), instance_.name());
152 blink::mojom::SharedWorkerInfoPtr info(blink::mojom::SharedWorkerInfo::New(
153 instance_.url(), std::move(options), instance_.content_security_policy(),
154 instance_.content_security_policy_type(),
155 instance_.creation_address_space(),
156 std::move(outside_fetch_client_settings_object)));
157
158 // Register with DevTools.
159 bool pause_on_start;
160 devtools_handle_ = std::make_unique<ScopedDevToolsHandle>(
161 this, &pause_on_start, &dev_tools_token_);
162
163 auto renderer_preferences = blink::mojom::RendererPreferences::New();
164 GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
165 worker_process_host_->GetBrowserContext(), renderer_preferences.get());
166
167 // Create a RendererPreferenceWatcher to observe updates in the preferences.
168 mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher_remote;
169 mojo::PendingReceiver<blink::mojom::RendererPreferenceWatcher>
170 preference_watcher_receiver =
171 watcher_remote.InitWithNewPipeAndPassReceiver();
172 GetContentClient()->browser()->RegisterRendererPreferenceWatcher(
173 worker_process_host_->GetBrowserContext(), std::move(watcher_remote));
174
175 // Set up content settings interface.
176 mojo::PendingRemote<blink::mojom::WorkerContentSettingsProxy>
177 content_settings;
178 content_settings_ = std::make_unique<SharedWorkerContentSettingsProxyImpl>(
179 instance_.url(), this, content_settings.InitWithNewPipeAndPassReceiver());
180
181 // Set up BrowserInterfaceBroker interface
182 mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
183 browser_interface_broker;
184 broker_receiver_.Bind(
185 browser_interface_broker.InitWithNewPipeAndPassReceiver());
186
187 // Set the default factory to the bundle for subresource loading to pass to
188 // the renderer.
189 bool bypass_redirect_checks = false;
190 subresource_loader_factories->pending_default_factory() =
191 CreateNetworkFactoryForSubresources(&bypass_redirect_checks);
192 subresource_loader_factories->set_bypass_redirect_checks(
193 bypass_redirect_checks);
194
195 // Prepare the controller service worker info to pass to the renderer.
196 // |object_info| can be nullptr when the service worker context or the service
197 // worker version is gone during shared worker startup.
198 mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerObject>
199 service_worker_remote_object;
200 blink::mojom::ServiceWorkerState service_worker_sent_state;
201 if (controller && controller->object_info) {
202 controller->object_info->receiver =
203 service_worker_remote_object.InitWithNewEndpointAndPassReceiver();
204 service_worker_sent_state = controller->object_info->state;
205 }
206
207 // Send the CreateSharedWorker message.
208 factory_.Bind(std::move(factory));
209 factory_->CreateSharedWorker(
210 std::move(info), instance_.constructor_origin(),
211 GetContentClient()->browser()->GetUserAgent(),
212 GetContentClient()->browser()->GetUserAgentMetadata(), pause_on_start,
213 dev_tools_token_, std::move(renderer_preferences),
214 std::move(preference_watcher_receiver), std::move(content_settings),
215 service_worker_handle_->TakeProviderInfo(),
216 appcache_handle_
217 ? base::make_optional(appcache_handle_->appcache_host_id())
218 : base::nullopt,
219 std::move(main_script_load_params),
220 std::move(subresource_loader_factories), std::move(controller),
221 receiver_.BindNewPipeAndPassRemote(), std::move(worker_receiver_),
222 std::move(browser_interface_broker));
223
224 // |service_worker_remote_object| is an associated interface ptr, so calls
225 // can't be made on it until its request endpoint is sent. Now that the
226 // request endpoint was sent, it can be used, so add it to
227 // ServiceWorkerObjectHost.
228 if (service_worker_remote_object.is_valid()) {
229 RunOrPostTaskOnThread(
230 FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
231 base::BindOnce(
232 &ServiceWorkerObjectHost::AddRemoteObjectPtrAndUpdateState,
233 controller_service_worker_object_host,
234 std::move(service_worker_remote_object),
235 service_worker_sent_state));
236 }
237
238 // Monitor the lifetime of the worker.
239 worker_.set_disconnect_handler(base::BindOnce(
240 &SharedWorkerHost::OnWorkerConnectionLost, weak_factory_.GetWeakPtr()));
241
242 // Notify the service that the worker was started and that some clients were
243 // already connected.
244 service_->NotifyWorkerStarted(id_, worker_process_host_->GetID(),
245 dev_tools_token_);
246 for (const auto& client : clients_) {
247 service_->NotifyClientAdded(id_, client.render_frame_host_id);
248 }
249 }
250
251 // This is similar to
252 // RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve, but this
253 // host doesn't observe network service crashes. Instead, the renderer detects
254 // the connection error and terminates the worker.
255 mojo::PendingRemote<network::mojom::URLLoaderFactory>
CreateNetworkFactoryForSubresources(bool * bypass_redirect_checks)256 SharedWorkerHost::CreateNetworkFactoryForSubresources(
257 bool* bypass_redirect_checks) {
258 DCHECK_CURRENTLY_ON(BrowserThread::UI);
259 DCHECK(bypass_redirect_checks);
260
261 mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_default_factory;
262 mojo::PendingReceiver<network::mojom::URLLoaderFactory>
263 default_factory_receiver =
264 pending_default_factory.InitWithNewPipeAndPassReceiver();
265
266 const url::Origin& origin = instance_.constructor_origin();
267 // TODO(https://crbug.com/1060832): Implement COEP reporter for shared
268 // workers.
269 network::mojom::URLLoaderFactoryParamsPtr factory_params =
270 URLLoaderFactoryParamsHelper::CreateForWorker(
271 worker_process_host_, origin,
272 net::NetworkIsolationKey(origin, origin),
273 /*coep_reporter=*/mojo::NullRemote());
274 GetContentClient()->browser()->WillCreateURLLoaderFactory(
275 worker_process_host_->GetBrowserContext(),
276 /*frame=*/nullptr, worker_process_host_->GetID(),
277 ContentBrowserClient::URLLoaderFactoryType::kWorkerSubResource, origin,
278 /*navigation_id=*/base::nullopt, &default_factory_receiver,
279 &factory_params->header_client, bypass_redirect_checks,
280 /*disable_secure_dns=*/nullptr, &factory_params->factory_override);
281
282 // TODO(nhiroki): Call devtools_instrumentation::WillCreateURLLoaderFactory()
283 // here.
284
285 // TODO(yhirano): Support COEP.
286 worker_process_host_->CreateURLLoaderFactory(
287 std::move(default_factory_receiver), std::move(factory_params));
288
289 return pending_default_factory;
290 }
291
AllowFileSystem(const GURL & url,base::OnceCallback<void (bool)> callback)292 void SharedWorkerHost::AllowFileSystem(
293 const GURL& url,
294 base::OnceCallback<void(bool)> callback) {
295 GetContentClient()->browser()->AllowWorkerFileSystem(
296 url, worker_process_host_->GetBrowserContext(),
297 GetRenderFrameIDsForWorker(), std::move(callback));
298 }
299
AllowIndexedDB(const GURL & url,base::OnceCallback<void (bool)> callback)300 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
301 base::OnceCallback<void(bool)> callback) {
302 std::move(callback).Run(GetContentClient()->browser()->AllowWorkerIndexedDB(
303 url, worker_process_host_->GetBrowserContext(),
304 GetRenderFrameIDsForWorker()));
305 }
306
AllowCacheStorage(const GURL & url,base::OnceCallback<void (bool)> callback)307 void SharedWorkerHost::AllowCacheStorage(
308 const GURL& url,
309 base::OnceCallback<void(bool)> callback) {
310 std::move(callback).Run(
311 GetContentClient()->browser()->AllowWorkerCacheStorage(
312 url, worker_process_host_->GetBrowserContext(),
313 GetRenderFrameIDsForWorker()));
314 }
315
AllowWebLocks(const GURL & url,base::OnceCallback<void (bool)> callback)316 void SharedWorkerHost::AllowWebLocks(const GURL& url,
317 base::OnceCallback<void(bool)> callback) {
318 std::move(callback).Run(GetContentClient()->browser()->AllowWorkerWebLocks(
319 url, worker_process_host_->GetBrowserContext(),
320 GetRenderFrameIDsForWorker()));
321 }
322
CreateAppCacheBackend(mojo::PendingReceiver<blink::mojom::AppCacheBackend> receiver)323 void SharedWorkerHost::CreateAppCacheBackend(
324 mojo::PendingReceiver<blink::mojom::AppCacheBackend> receiver) {
325 DCHECK_CURRENTLY_ON(BrowserThread::UI);
326 auto* storage_partition_impl = static_cast<StoragePartitionImpl*>(
327 worker_process_host_->GetStoragePartition());
328 if (!storage_partition_impl)
329 return;
330 storage_partition_impl->GetAppCacheService()->CreateBackend(
331 worker_process_host_->GetID(), MSG_ROUTING_NONE, std::move(receiver));
332 }
333
CreateQuicTransportConnector(mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver)334 void SharedWorkerHost::CreateQuicTransportConnector(
335 mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver) {
336 DCHECK_CURRENTLY_ON(BrowserThread::UI);
337 const url::Origin origin = url::Origin::Create(instance().url());
338 mojo::MakeSelfOwnedReceiver(std::make_unique<QuicTransportConnectorImpl>(
339 worker_process_host_->GetID(), origin,
340 net::NetworkIsolationKey(origin, origin)),
341 std::move(receiver));
342 }
343
BindCacheStorage(mojo::PendingReceiver<blink::mojom::CacheStorage> receiver)344 void SharedWorkerHost::BindCacheStorage(
345 mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
346 DCHECK_CURRENTLY_ON(BrowserThread::UI);
347 // TODO(https://crbug.com/1031542): Add support enforcing CORP in
348 // cache.match() for SharedWorker by providing the correct value here.
349 network::CrossOriginEmbedderPolicy cross_origin_embedder_policy;
350
351 // TODO(https://crbug.com/1031542): Plumb a CrossOriginEmbedderPolicyReporter
352 // here to handle reports.
353 mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
354 coep_reporter;
355
356 const url::Origin origin = url::Origin::Create(instance().url());
357 worker_process_host_->BindCacheStorage(cross_origin_embedder_policy,
358 std::move(coep_reporter), origin,
359 std::move(receiver));
360 }
361
Destruct()362 void SharedWorkerHost::Destruct() {
363 // Ask the service to destroy |this| which will terminate the worker.
364 service_->DestroyHost(this);
365 }
366
ClientInfo(mojo::Remote<blink::mojom::SharedWorkerClient> client,int connection_request_id,GlobalFrameRoutingId render_frame_host_id)367 SharedWorkerHost::ClientInfo::ClientInfo(
368 mojo::Remote<blink::mojom::SharedWorkerClient> client,
369 int connection_request_id,
370 GlobalFrameRoutingId render_frame_host_id)
371 : client(std::move(client)),
372 connection_request_id(connection_request_id),
373 render_frame_host_id(render_frame_host_id) {}
374
~ClientInfo()375 SharedWorkerHost::ClientInfo::~ClientInfo() {}
376
OnConnected(int connection_request_id)377 void SharedWorkerHost::OnConnected(int connection_request_id) {
378 for (const ClientInfo& info : clients_) {
379 if (info.connection_request_id != connection_request_id)
380 continue;
381 info.client->OnConnected(std::vector<blink::mojom::WebFeature>(
382 used_features_.begin(), used_features_.end()));
383 return;
384 }
385 }
386
OnContextClosed()387 void SharedWorkerHost::OnContextClosed() {
388 // Not possible: there is no Mojo connection on which OnContextClosed can
389 // be called.
390 DCHECK(started_);
391
392 Destruct();
393 }
394
OnReadyForInspection(mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> agent_host_receiver)395 void SharedWorkerHost::OnReadyForInspection(
396 mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,
397 mojo::PendingReceiver<blink::mojom::DevToolsAgentHost>
398 agent_host_receiver) {
399 if (devtools_handle_) {
400 devtools_handle_->WorkerReadyForInspection(std::move(agent_remote),
401 std::move(agent_host_receiver));
402 }
403 }
404
OnScriptLoadFailed(const std::string & error_message)405 void SharedWorkerHost::OnScriptLoadFailed(const std::string& error_message) {
406 for (const ClientInfo& info : clients_)
407 info.client->OnScriptLoadFailed(error_message);
408 }
409
OnFeatureUsed(blink::mojom::WebFeature feature)410 void SharedWorkerHost::OnFeatureUsed(blink::mojom::WebFeature feature) {
411 // Avoid reporting a feature more than once, and enable any new clients to
412 // observe features that were historically used.
413 if (!used_features_.insert(feature).second)
414 return;
415 for (const ClientInfo& info : clients_)
416 info.client->OnFeatureUsed(feature);
417 }
418
RenderProcessExited(RenderProcessHost * render_process_host,const ChildProcessTerminationInfo & info)419 void SharedWorkerHost::RenderProcessExited(
420 RenderProcessHost* render_process_host,
421 const ChildProcessTerminationInfo& info) {
422 DCHECK_EQ(worker_process_host_, render_process_host);
423 Destruct();
424 }
425
426 std::vector<GlobalFrameRoutingId>
GetRenderFrameIDsForWorker()427 SharedWorkerHost::GetRenderFrameIDsForWorker() {
428 std::vector<GlobalFrameRoutingId> result;
429 result.reserve(clients_.size());
430 for (const ClientInfo& info : clients_)
431 result.push_back(info.render_frame_host_id);
432 return result;
433 }
434
AsWeakPtr()435 base::WeakPtr<SharedWorkerHost> SharedWorkerHost::AsWeakPtr() {
436 return weak_factory_.GetWeakPtr();
437 }
438
ReportNoBinderForInterface(const std::string & error)439 void SharedWorkerHost::ReportNoBinderForInterface(const std::string& error) {
440 broker_receiver_.ReportBadMessage(error + " for the shared worker scope");
441 }
442
AddClient(mojo::PendingRemote<blink::mojom::SharedWorkerClient> client,GlobalFrameRoutingId client_render_frame_host_id,const blink::MessagePortChannel & port)443 void SharedWorkerHost::AddClient(
444 mojo::PendingRemote<blink::mojom::SharedWorkerClient> client,
445 GlobalFrameRoutingId client_render_frame_host_id,
446 const blink::MessagePortChannel& port) {
447 mojo::Remote<blink::mojom::SharedWorkerClient> remote_client(
448 std::move(client));
449
450 // Pass the actual creation context type, so the client can understand if
451 // there is a mismatch between security levels.
452 remote_client->OnCreated(instance_.creation_context_type());
453
454 clients_.emplace_back(std::move(remote_client), next_connection_request_id_++,
455 client_render_frame_host_id);
456 ClientInfo& info = clients_.back();
457
458 // Observe when the client goes away.
459 info.client.set_disconnect_handler(base::BindOnce(
460 &SharedWorkerHost::OnClientConnectionLost, weak_factory_.GetWeakPtr()));
461
462 worker_->Connect(info.connection_request_id, port.ReleaseHandle());
463
464 // Notify that a new client was added now. If the worker is not started, the
465 // Start() function will handle sending a notification for each existing
466 // client.
467 if (started_)
468 service_->NotifyClientAdded(id_, client_render_frame_host_id);
469 }
470
SetAppCacheHandle(std::unique_ptr<AppCacheNavigationHandle> appcache_handle)471 void SharedWorkerHost::SetAppCacheHandle(
472 std::unique_ptr<AppCacheNavigationHandle> appcache_handle) {
473 DCHECK_CURRENTLY_ON(BrowserThread::UI);
474 appcache_handle_ = std::move(appcache_handle);
475 }
476
SetServiceWorkerHandle(std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle)477 void SharedWorkerHost::SetServiceWorkerHandle(
478 std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle) {
479 DCHECK_CURRENTLY_ON(BrowserThread::UI);
480 service_worker_handle_ = std::move(service_worker_handle);
481 }
482
PruneNonExistentClients()483 void SharedWorkerHost::PruneNonExistentClients() {
484 DCHECK(!started_);
485
486 // It isn't necessary to send a notification to the removed clients since they
487 // are about to be destroyed anyway.
488 clients_.remove_if([](const ClientInfo& client_info) {
489 return !RenderFrameHostImpl::FromID(client_info.render_frame_host_id);
490 });
491 }
492
HasClients() const493 bool SharedWorkerHost::HasClients() const {
494 return !clients_.empty();
495 }
496
497 mojo::Remote<blink::mojom::SharedWorker>
TerminateRemoteWorkerForTesting()498 SharedWorkerHost::TerminateRemoteWorkerForTesting() {
499 mojo::Remote<blink::mojom::SharedWorker> worker = std::move(worker_);
500
501 // Tell the remote worker to terminate.
502 if (worker && worker.is_connected()) {
503 worker.reset_on_disconnect();
504 worker->Terminate();
505 }
506
507 return worker;
508 }
509
OnClientConnectionLost()510 void SharedWorkerHost::OnClientConnectionLost() {
511 // We'll get a notification for each dropped connection.
512 for (auto it = clients_.begin(); it != clients_.end(); ++it) {
513 if (!it->client.is_connected()) {
514 // Notify the service that a client was removed while the worker was
515 // running.
516 if (started_) {
517 service_->NotifyClientRemoved(id_, it->render_frame_host_id);
518 }
519 clients_.erase(it);
520 break;
521 }
522 }
523 // If there are no clients left, then it's cleanup time.
524 if (clients_.empty())
525 Destruct();
526 }
527
OnWorkerConnectionLost()528 void SharedWorkerHost::OnWorkerConnectionLost() {
529 // This will destroy |this| resulting in client's observing their mojo
530 // connection being dropped.
531 Destruct();
532 }
533
534 } // namespace content
535