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