1 // Copyright 2013 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.
5 #include "content/browser/service_worker/service_worker_version.h"
7 #include "base/command_line.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/message_port_message_filter.h"
13 #include "content/browser/message_port_service.h"
14 #include "content/browser/service_worker/embedded_worker_instance.h"
15 #include "content/browser/service_worker/embedded_worker_registry.h"
16 #include "content/browser/service_worker/service_worker_context_core.h"
17 #include "content/browser/service_worker/service_worker_context_wrapper.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_utils.h"
20 #include "content/browser/storage_partition_impl.h"
21 #include "content/common/service_worker/service_worker_messages.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/page_navigator.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/common/child_process_host.h"
30 #include "content/public/common/content_client.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/result_codes.h"
33 #include "net/http/http_response_info.h"
37 typedef ServiceWorkerVersion::StatusCallback StatusCallback
;
38 typedef ServiceWorkerVersion::MessageCallback MessageCallback
;
40 class ServiceWorkerVersion::GetClientDocumentsCallback
41 : public base::RefCounted
<GetClientDocumentsCallback
> {
43 GetClientDocumentsCallback(int request_id
,
44 ServiceWorkerVersion
* version
)
45 : request_id_(request_id
),
50 void AddClientInfo(int client_id
, const ServiceWorkerClientInfo
& info
) {
51 clients_
.push_back(info
);
52 clients_
.back().client_id
= client_id
;
56 friend class base::RefCounted
<GetClientDocumentsCallback
>;
58 virtual ~GetClientDocumentsCallback() {
59 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
61 if (version_
->running_status() == RUNNING
) {
62 version_
->embedded_worker_
->SendMessage(
63 ServiceWorkerMsg_DidGetClientDocuments(request_id_
, clients_
));
67 std::vector
<ServiceWorkerClientInfo
> clients_
;
69 scoped_refptr
<ServiceWorkerVersion
> version_
;
71 DISALLOW_COPY_AND_ASSIGN(GetClientDocumentsCallback
);
76 // Default delay for scheduled stop.
77 // (Note that if all references to the version is dropped the worker
78 // is also stopped without delay)
79 const int64 kStopWorkerDelay
= 30; // 30 secs.
81 // Delay for attempting to stop a doomed worker with in-flight requests.
82 const int64 kStopDoomedWorkerDelay
= 5; // 5 secs.
84 // Default delay for scheduled update.
85 const int kUpdateDelaySeconds
= 1;
87 const char kClaimClientsStateErrorMesage
[] =
88 "Only the active worker can claim clients.";
90 const char kClaimClientsShutdownErrorMesage
[] =
91 "Failed to claim clients due to Service Worker system shutdown.";
93 void RunSoon(const base::Closure
& callback
) {
94 if (!callback
.is_null())
95 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
98 template <typename CallbackArray
, typename Arg
>
99 void RunCallbacks(ServiceWorkerVersion
* version
,
100 CallbackArray
* callbacks_ptr
,
102 CallbackArray callbacks
;
103 callbacks
.swap(*callbacks_ptr
);
104 scoped_refptr
<ServiceWorkerVersion
> protect(version
);
105 for (const auto& callback
: callbacks
)
109 template <typename IDMAP
, typename
... Params
>
110 void RunIDMapCallbacks(IDMAP
* callbacks
, const Params
&... params
) {
111 typename
IDMAP::iterator
iter(callbacks
);
112 while (!iter
.IsAtEnd()) {
113 iter
.GetCurrentValue()->Run(params
...);
119 // A callback adapter to start a |task| after StartWorker.
120 void RunTaskAfterStartWorker(
121 base::WeakPtr
<ServiceWorkerVersion
> version
,
122 const StatusCallback
& error_callback
,
123 const base::Closure
& task
,
124 ServiceWorkerStatusCode status
) {
125 if (status
!= SERVICE_WORKER_OK
) {
126 if (!error_callback
.is_null())
127 error_callback
.Run(status
);
130 if (version
->running_status() != ServiceWorkerVersion::RUNNING
) {
131 // We've tried to start the worker (and it has succeeded), but
132 // it looks it's not running yet.
133 NOTREACHED() << "The worker's not running after successful StartWorker";
134 if (!error_callback
.is_null())
135 error_callback
.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
141 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback
& callback
,
142 ServiceWorkerStatusCode status
) {
144 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
145 ServiceWorkerResponse());
148 void RunErrorMessageCallback(
149 const std::vector
<int>& sent_message_port_ids
,
150 const ServiceWorkerVersion::StatusCallback
& callback
,
151 ServiceWorkerStatusCode status
) {
152 // Transfering the message ports failed, so destroy the ports.
153 for (int message_port_id
: sent_message_port_ids
) {
154 MessagePortService::GetInstance()->ClosePort(message_port_id
);
156 callback
.Run(status
);
159 void RunErrorCrossOriginConnectCallback(
160 const ServiceWorkerVersion::CrossOriginConnectCallback
& callback
,
161 ServiceWorkerStatusCode status
) {
162 callback
.Run(status
, false);
165 using WindowOpenedCallback
= base::Callback
<void(int, int)>;
167 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
168 // new Window's WebContents to be initialized, run the |callback| passed to its
169 // constructor then self destroy.
170 // The callback will receive the process and frame ids. If something went wrong
171 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
172 // The callback will be called in the IO thread.
173 class WindowOpenedObserver
: public WebContentsObserver
{
175 WindowOpenedObserver(WebContents
* web_contents
,
176 const WindowOpenedCallback
& callback
)
177 : WebContentsObserver(web_contents
),
181 void DidCommitProvisionalLoadForFrame(
182 RenderFrameHost
* render_frame_host
,
183 const GURL
& validated_url
,
184 ui::PageTransition transition_type
) override
{
185 DCHECK(web_contents());
187 if (render_frame_host
!= web_contents()->GetMainFrame())
190 RunCallback(render_frame_host
->GetProcess()->GetID(),
191 render_frame_host
->GetRoutingID());
194 void RenderProcessGone(base::TerminationStatus status
) override
{
195 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
198 void WebContentsDestroyed() override
{
199 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
203 void RunCallback(int render_process_id
, int render_frame_id
) {
204 // After running the callback, |this| will stop observing, thus
205 // web_contents() should return nullptr and |RunCallback| should no longer
206 // be called. Then, |this| will self destroy.
207 DCHECK(web_contents());
209 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
210 base::Bind(callback_
,
214 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
217 const WindowOpenedCallback callback_
;
219 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver
);
224 const GURL
& script_url
,
226 const scoped_refptr
<ServiceWorkerContextWrapper
>& context_wrapper
,
227 const WindowOpenedCallback
& callback
) {
228 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
230 BrowserContext
* browser_context
= context_wrapper
->storage_partition()
231 ? context_wrapper
->storage_partition()->browser_context()
233 // We are shutting down.
234 if (!browser_context
)
237 RenderProcessHost
* render_process_host
=
238 RenderProcessHost::FromID(process_id
);
239 if (render_process_host
->IsIsolatedGuest()) {
240 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
242 ChildProcessHost::kInvalidUniqueID
,
247 OpenURLParams
params(url
,
248 Referrer(script_url
, blink::WebReferrerPolicyDefault
),
250 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
251 true /* is_renderer_initiated */);
253 WebContents
* web_contents
=
254 GetContentClient()->browser()->OpenURL(browser_context
, params
);
255 DCHECK(web_contents
);
257 new WindowOpenedObserver(web_contents
, callback
);
260 void KillEmbeddedWorkerProcess(int process_id
, ResultCode code
) {
261 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
263 RenderProcessHost
* render_process_host
=
264 RenderProcessHost::FromID(process_id
);
265 if (render_process_host
->GetHandle() != base::kNullProcessHandle
)
266 render_process_host
->ReceivedBadMessage();
271 ServiceWorkerVersion::ServiceWorkerVersion(
272 ServiceWorkerRegistration
* registration
,
273 const GURL
& script_url
,
275 base::WeakPtr
<ServiceWorkerContextCore
> context
)
276 : version_id_(version_id
),
277 registration_id_(kInvalidServiceWorkerVersionId
),
278 script_url_(script_url
),
281 script_cache_map_(this, context
),
283 skip_waiting_(false),
284 weak_factory_(this) {
286 DCHECK(registration
);
288 registration_id_
= registration
->id();
289 scope_
= registration
->pattern();
291 context_
->AddLiveVersion(this);
292 embedded_worker_
= context_
->embedded_worker_registry()->CreateWorker();
293 embedded_worker_
->AddListener(this);
296 ServiceWorkerVersion::~ServiceWorkerVersion() {
297 embedded_worker_
->RemoveListener(this);
299 context_
->RemoveLiveVersion(version_id_
);
300 // EmbeddedWorker's dtor sends StopWorker if it's still running.
303 void ServiceWorkerVersion::SetStatus(Status status
) {
304 if (status_
== status
)
309 if (skip_waiting_
&& status_
== ACTIVATED
) {
310 for (int request_id
: pending_skip_waiting_requests_
)
311 DidSkipWaiting(request_id
);
312 pending_skip_waiting_requests_
.clear();
315 std::vector
<base::Closure
> callbacks
;
316 callbacks
.swap(status_change_callbacks_
);
317 for (const auto& callback
: callbacks
)
320 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
323 void ServiceWorkerVersion::RegisterStatusChangeCallback(
324 const base::Closure
& callback
) {
325 status_change_callbacks_
.push_back(callback
);
328 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
330 return ServiceWorkerVersionInfo(
335 embedded_worker()->process_id(),
336 embedded_worker()->thread_id(),
337 embedded_worker()->worker_devtools_agent_route_id());
340 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
341 StartWorker(false, callback
);
344 void ServiceWorkerVersion::StartWorker(
345 bool pause_after_download
,
346 const StatusCallback
& callback
) {
348 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
351 switch (running_status()) {
353 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
358 start_callbacks_
.push_back(callback
);
359 if (running_status() == STOPPED
) {
360 DCHECK(!cache_listener_
.get());
361 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context_
));
362 embedded_worker_
->Start(
366 pause_after_download
,
367 base::Bind(&ServiceWorkerVersion::OnStartMessageSent
,
368 weak_factory_
.GetWeakPtr()));
374 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
375 if (running_status() == STOPPED
) {
376 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
379 if (stop_callbacks_
.empty()) {
380 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
381 if (status
!= SERVICE_WORKER_OK
) {
382 RunSoon(base::Bind(callback
, status
));
386 stop_callbacks_
.push_back(callback
);
389 void ServiceWorkerVersion::ScheduleUpdate() {
390 if (update_timer_
.IsRunning()) {
391 update_timer_
.Reset();
395 FROM_HERE
, base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
396 base::Bind(&ServiceWorkerVersion::StartUpdate
,
397 weak_factory_
.GetWeakPtr()));
400 void ServiceWorkerVersion::DeferScheduledUpdate() {
401 if (update_timer_
.IsRunning())
402 update_timer_
.Reset();
405 void ServiceWorkerVersion::StartUpdate() {
406 update_timer_
.Stop();
409 ServiceWorkerRegistration
* registration
=
410 context_
->GetLiveRegistration(registration_id_
);
411 if (!registration
|| !registration
->GetNewestVersion())
413 context_
->UpdateServiceWorker(registration
);
416 void ServiceWorkerVersion::SendMessage(
417 const IPC::Message
& message
, const StatusCallback
& callback
) {
418 if (running_status() != RUNNING
) {
419 // Schedule calling this method after starting the worker.
420 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
421 weak_factory_
.GetWeakPtr(), callback
,
422 base::Bind(&self::SendMessage
,
423 weak_factory_
.GetWeakPtr(),
424 message
, callback
)));
428 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(message
);
429 RunSoon(base::Bind(callback
, status
));
432 void ServiceWorkerVersion::DispatchMessageEvent(
433 const base::string16
& message
,
434 const std::vector
<int>& sent_message_port_ids
,
435 const StatusCallback
& callback
) {
436 for (int message_port_id
: sent_message_port_ids
) {
437 MessagePortService::GetInstance()->HoldMessages(message_port_id
);
440 DispatchMessageEventInternal(message
, sent_message_port_ids
, callback
);
443 void ServiceWorkerVersion::DispatchMessageEventInternal(
444 const base::string16
& message
,
445 const std::vector
<int>& sent_message_port_ids
,
446 const StatusCallback
& callback
) {
447 if (running_status() != RUNNING
) {
448 // Schedule calling this method after starting the worker.
449 StartWorker(base::Bind(
450 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
451 base::Bind(&RunErrorMessageCallback
, sent_message_port_ids
, callback
),
452 base::Bind(&self::DispatchMessageEventInternal
,
453 weak_factory_
.GetWeakPtr(), message
, sent_message_port_ids
,
458 MessagePortMessageFilter
* filter
=
459 embedded_worker_
->message_port_message_filter();
460 std::vector
<int> new_routing_ids
;
461 filter
->UpdateMessagePortsWithNewRoutes(sent_message_port_ids
,
463 ServiceWorkerStatusCode status
=
464 embedded_worker_
->SendMessage(ServiceWorkerMsg_MessageToWorker(
465 message
, sent_message_port_ids
, new_routing_ids
));
466 RunSoon(base::Bind(callback
, status
));
469 void ServiceWorkerVersion::DispatchInstallEvent(
470 int active_version_id
,
471 const StatusCallback
& callback
) {
472 DCHECK_EQ(INSTALLING
, status()) << status();
474 if (running_status() != RUNNING
) {
475 // Schedule calling this method after starting the worker.
477 base::Bind(&RunTaskAfterStartWorker
,
478 weak_factory_
.GetWeakPtr(),
480 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
481 weak_factory_
.GetWeakPtr(),
485 DispatchInstallEventAfterStartWorker(active_version_id
, callback
);
489 void ServiceWorkerVersion::DispatchActivateEvent(
490 const StatusCallback
& callback
) {
491 DCHECK_EQ(ACTIVATING
, status()) << status();
493 if (running_status() != RUNNING
) {
494 // Schedule calling this method after starting the worker.
496 base::Bind(&RunTaskAfterStartWorker
,
497 weak_factory_
.GetWeakPtr(),
499 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
500 weak_factory_
.GetWeakPtr(),
503 DispatchActivateEventAfterStartWorker(callback
);
507 void ServiceWorkerVersion::DispatchFetchEvent(
508 const ServiceWorkerFetchRequest
& request
,
509 const base::Closure
& prepare_callback
,
510 const FetchCallback
& fetch_callback
) {
511 DCHECK_EQ(ACTIVATED
, status()) << status();
513 if (running_status() != RUNNING
) {
514 // Schedule calling this method after starting the worker.
515 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
516 weak_factory_
.GetWeakPtr(),
517 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
518 base::Bind(&self::DispatchFetchEvent
,
519 weak_factory_
.GetWeakPtr(),
526 prepare_callback
.Run();
528 int request_id
= fetch_callbacks_
.Add(new FetchCallback(fetch_callback
));
529 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
530 ServiceWorkerMsg_FetchEvent(request_id
, request
));
531 if (status
!= SERVICE_WORKER_OK
) {
532 fetch_callbacks_
.Remove(request_id
);
533 RunSoon(base::Bind(&RunErrorFetchCallback
,
535 SERVICE_WORKER_ERROR_FAILED
));
539 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback
& callback
) {
540 DCHECK_EQ(ACTIVATED
, status()) << status();
542 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
543 switches::kEnableServiceWorkerSync
)) {
544 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
548 if (running_status() != RUNNING
) {
549 // Schedule calling this method after starting the worker.
550 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
551 weak_factory_
.GetWeakPtr(), callback
,
552 base::Bind(&self::DispatchSyncEvent
,
553 weak_factory_
.GetWeakPtr(),
558 int request_id
= sync_callbacks_
.Add(new StatusCallback(callback
));
559 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
560 ServiceWorkerMsg_SyncEvent(request_id
));
561 if (status
!= SERVICE_WORKER_OK
) {
562 sync_callbacks_
.Remove(request_id
);
563 RunSoon(base::Bind(callback
, status
));
567 void ServiceWorkerVersion::DispatchNotificationClickEvent(
568 const StatusCallback
& callback
,
569 const std::string
& notification_id
,
570 const PlatformNotificationData
& notification_data
) {
571 DCHECK_EQ(ACTIVATED
, status()) << status();
573 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
574 switches::kEnableExperimentalWebPlatformFeatures
)) {
575 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
579 if (running_status() != RUNNING
) {
580 // Schedule calling this method after starting the worker.
581 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
582 weak_factory_
.GetWeakPtr(), callback
,
583 base::Bind(&self::DispatchNotificationClickEvent
,
584 weak_factory_
.GetWeakPtr(),
585 callback
, notification_id
,
586 notification_data
)));
591 notification_click_callbacks_
.Add(new StatusCallback(callback
));
592 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
593 ServiceWorkerMsg_NotificationClickEvent(request_id
,
596 if (status
!= SERVICE_WORKER_OK
) {
597 notification_click_callbacks_
.Remove(request_id
);
598 RunSoon(base::Bind(callback
, status
));
602 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
603 const std::string
& data
) {
604 DCHECK_EQ(ACTIVATED
, status()) << status();
606 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
607 switches::kEnableExperimentalWebPlatformFeatures
)) {
608 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
612 if (running_status() != RUNNING
) {
613 // Schedule calling this method after starting the worker.
614 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
615 weak_factory_
.GetWeakPtr(), callback
,
616 base::Bind(&self::DispatchPushEvent
,
617 weak_factory_
.GetWeakPtr(),
622 int request_id
= push_callbacks_
.Add(new StatusCallback(callback
));
623 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
624 ServiceWorkerMsg_PushEvent(request_id
, data
));
625 if (status
!= SERVICE_WORKER_OK
) {
626 push_callbacks_
.Remove(request_id
);
627 RunSoon(base::Bind(callback
, status
));
631 void ServiceWorkerVersion::DispatchGeofencingEvent(
632 const StatusCallback
& callback
,
633 blink::WebGeofencingEventType event_type
,
634 const std::string
& region_id
,
635 const blink::WebCircularGeofencingRegion
& region
) {
636 DCHECK_EQ(ACTIVATED
, status()) << status();
638 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
639 switches::kEnableExperimentalWebPlatformFeatures
)) {
640 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
644 if (running_status() != RUNNING
) {
645 // Schedule calling this method after starting the worker.
646 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
647 weak_factory_
.GetWeakPtr(),
649 base::Bind(&self::DispatchGeofencingEvent
,
650 weak_factory_
.GetWeakPtr(),
658 int request_id
= geofencing_callbacks_
.Add(new StatusCallback(callback
));
659 ServiceWorkerStatusCode status
=
660 embedded_worker_
->SendMessage(ServiceWorkerMsg_GeofencingEvent(
661 request_id
, event_type
, region_id
, region
));
662 if (status
!= SERVICE_WORKER_OK
) {
663 geofencing_callbacks_
.Remove(request_id
);
664 RunSoon(base::Bind(callback
, status
));
668 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
669 const CrossOriginConnectCallback
& callback
,
670 const NavigatorConnectClient
& client
) {
671 DCHECK_EQ(ACTIVATED
, status()) << status();
673 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
674 switches::kEnableExperimentalWebPlatformFeatures
)) {
675 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, false);
679 if (running_status() != RUNNING
) {
680 // Schedule calling this method after starting the worker.
682 base::Bind(&RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
683 base::Bind(&RunErrorCrossOriginConnectCallback
, callback
),
684 base::Bind(&self::DispatchCrossOriginConnectEvent
,
685 weak_factory_
.GetWeakPtr(), callback
, client
)));
689 int request_id
= cross_origin_connect_callbacks_
.Add(
690 new CrossOriginConnectCallback(callback
));
691 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
692 ServiceWorkerMsg_CrossOriginConnectEvent(request_id
, client
));
693 if (status
!= SERVICE_WORKER_OK
) {
694 cross_origin_connect_callbacks_
.Remove(request_id
);
695 RunSoon(base::Bind(callback
, status
, false));
699 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
700 const NavigatorConnectClient
& client
,
701 const base::string16
& message
,
702 const std::vector
<int>& sent_message_port_ids
,
703 const StatusCallback
& callback
) {
704 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
705 // have already put all the sent message ports on hold. So no need to do that
708 if (running_status() != RUNNING
) {
709 // Schedule calling this method after starting the worker.
710 StartWorker(base::Bind(
711 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(), callback
,
712 base::Bind(&self::DispatchCrossOriginMessageEvent
,
713 weak_factory_
.GetWeakPtr(), client
, message
,
714 sent_message_port_ids
, callback
)));
718 MessagePortMessageFilter
* filter
=
719 embedded_worker_
->message_port_message_filter();
720 std::vector
<int> new_routing_ids
;
721 filter
->UpdateMessagePortsWithNewRoutes(sent_message_port_ids
,
723 ServiceWorkerStatusCode status
=
724 embedded_worker_
->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
725 client
, message
, sent_message_port_ids
, new_routing_ids
));
726 RunSoon(base::Bind(callback
, status
));
728 void ServiceWorkerVersion::AddControllee(
729 ServiceWorkerProviderHost
* provider_host
) {
730 DCHECK(!ContainsKey(controllee_map_
, provider_host
));
731 int controllee_id
= controllee_by_id_
.Add(provider_host
);
732 // IDMap<>'s last index is kInvalidServiceWorkerClientId.
733 CHECK(controllee_id
!= kInvalidServiceWorkerClientId
);
734 controllee_map_
[provider_host
] = controllee_id
;
735 // Reset the timer if it's running (so that it's kept alive a bit longer
736 // right after a new controllee is added).
737 ScheduleStopWorker();
740 void ServiceWorkerVersion::RemoveControllee(
741 ServiceWorkerProviderHost
* provider_host
) {
742 ControlleeMap::iterator found
= controllee_map_
.find(provider_host
);
743 DCHECK(found
!= controllee_map_
.end());
744 controllee_by_id_
.Remove(found
->second
);
745 controllee_map_
.erase(found
);
748 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
753 // Schedule the stop-worker-timer if it's not running.
754 if (!stop_worker_timer_
.IsRunning())
755 ScheduleStopWorker();
758 void ServiceWorkerVersion::AddStreamingURLRequestJob(
759 const ServiceWorkerURLRequestJob
* request_job
) {
760 DCHECK(streaming_url_request_jobs_
.find(request_job
) ==
761 streaming_url_request_jobs_
.end());
762 streaming_url_request_jobs_
.insert(request_job
);
765 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
766 const ServiceWorkerURLRequestJob
* request_job
) {
767 streaming_url_request_jobs_
.erase(request_job
);
772 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
773 listeners_
.AddObserver(listener
);
776 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
777 listeners_
.RemoveObserver(listener
);
780 void ServiceWorkerVersion::Doom() {
784 if (!HasControllee())
788 void ServiceWorkerVersion::SetDevToolsAttached(bool attached
) {
789 embedded_worker()->set_devtools_attached(attached
);
790 if (!attached
&& !stop_worker_timer_
.IsRunning()) {
791 // If devtools is detached from this version and stop-worker-timer is not
792 // running, try scheduling stop-worker-timer now.
793 ScheduleStopWorker();
797 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
798 const net::HttpResponseInfo
& http_info
) {
799 main_script_http_info_
.reset(new net::HttpResponseInfo(http_info
));
802 const net::HttpResponseInfo
*
803 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
804 return main_script_http_info_
.get();
807 void ServiceWorkerVersion::OnStarted() {
808 DCHECK_EQ(RUNNING
, running_status());
809 DCHECK(cache_listener_
.get());
810 ScheduleStopWorker();
812 // Fire all start callbacks.
813 scoped_refptr
<ServiceWorkerVersion
> protect(this);
814 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
815 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStarted(this));
818 void ServiceWorkerVersion::OnStopped(
819 EmbeddedWorkerInstance::Status old_status
) {
820 DCHECK_EQ(STOPPED
, running_status());
821 scoped_refptr
<ServiceWorkerVersion
> protect(this);
823 bool should_restart
= !is_doomed() && !start_callbacks_
.empty() &&
824 (old_status
!= EmbeddedWorkerInstance::STARTING
);
826 // Fire all stop callbacks.
827 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
829 if (!should_restart
) {
830 // Let all start callbacks fail.
831 RunCallbacks(this, &start_callbacks_
,
832 SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
835 // Let all message callbacks fail (this will also fire and clear all
836 // callbacks for events).
837 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
838 RunIDMapCallbacks(&activate_callbacks_
,
839 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
840 RunIDMapCallbacks(&install_callbacks_
,
841 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
842 RunIDMapCallbacks(&fetch_callbacks_
,
843 SERVICE_WORKER_ERROR_FAILED
,
844 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
845 ServiceWorkerResponse());
846 RunIDMapCallbacks(&sync_callbacks_
,
847 SERVICE_WORKER_ERROR_FAILED
);
848 RunIDMapCallbacks(¬ification_click_callbacks_
,
849 SERVICE_WORKER_ERROR_FAILED
);
850 RunIDMapCallbacks(&push_callbacks_
,
851 SERVICE_WORKER_ERROR_FAILED
);
852 RunIDMapCallbacks(&geofencing_callbacks_
,
853 SERVICE_WORKER_ERROR_FAILED
);
854 RunIDMapCallbacks(&cross_origin_connect_callbacks_
,
855 SERVICE_WORKER_ERROR_FAILED
,
858 streaming_url_request_jobs_
.clear();
860 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStopped(this));
862 // There should be no more communication from/to a stopped worker. Deleting
863 // the listener prevents any pending completion callbacks from causing
864 // messages to be sent to the stopped worker.
865 cache_listener_
.reset();
867 // Restart worker if we have any start callbacks and the worker isn't doomed.
868 if (should_restart
) {
869 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context_
));
870 embedded_worker_
->Start(
871 version_id_
, scope_
, script_url_
, false /* pause_after_download */,
872 base::Bind(&ServiceWorkerVersion::OnStartMessageSent
,
873 weak_factory_
.GetWeakPtr()));
877 void ServiceWorkerVersion::OnReportException(
878 const base::string16
& error_message
,
881 const GURL
& source_url
) {
886 this, error_message
, line_number
, column_number
, source_url
));
889 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
891 const base::string16
& message
,
893 const GURL
& source_url
) {
894 FOR_EACH_OBSERVER(Listener
,
896 OnReportConsoleMessage(this,
904 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
906 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
907 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments
,
908 OnGetClientDocuments
)
909 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
910 OnActivateEventFinished
)
911 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
912 OnInstallEventFinished
)
913 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
914 OnFetchEventFinished
)
915 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished
,
917 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished
,
918 OnNotificationClickEventFinished
)
919 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
921 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished
,
922 OnGeofencingEventFinished
)
923 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished
,
924 OnCrossOriginConnectEventFinished
)
925 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow
,
927 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument
,
928 OnPostMessageToDocument
)
929 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient
,
931 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting
,
933 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients
,
935 IPC_MESSAGE_UNHANDLED(handled
= false)
936 IPC_END_MESSAGE_MAP()
940 void ServiceWorkerVersion::OnStartMessageSent(
941 ServiceWorkerStatusCode status
) {
942 if (status
!= SERVICE_WORKER_OK
)
943 RunCallbacks(this, &start_callbacks_
, status
);
946 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
947 int active_version_id
,
948 const StatusCallback
& callback
) {
949 DCHECK_EQ(RUNNING
, running_status())
950 << "Worker stopped too soon after it was started.";
952 int request_id
= install_callbacks_
.Add(new StatusCallback(callback
));
953 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
954 ServiceWorkerMsg_InstallEvent(request_id
, active_version_id
));
955 if (status
!= SERVICE_WORKER_OK
) {
956 install_callbacks_
.Remove(request_id
);
957 RunSoon(base::Bind(callback
, status
));
961 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
962 const StatusCallback
& callback
) {
963 DCHECK_EQ(RUNNING
, running_status())
964 << "Worker stopped too soon after it was started.";
966 int request_id
= activate_callbacks_
.Add(new StatusCallback(callback
));
967 ServiceWorkerStatusCode status
=
968 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
969 if (status
!= SERVICE_WORKER_OK
) {
970 activate_callbacks_
.Remove(request_id
);
971 RunSoon(base::Bind(callback
, status
));
975 void ServiceWorkerVersion::OnGetClientDocuments(int request_id
) {
976 if (controllee_by_id_
.IsEmpty()) {
977 if (running_status() == RUNNING
) {
978 embedded_worker_
->SendMessage(
979 ServiceWorkerMsg_DidGetClientDocuments(request_id
,
980 std::vector
<ServiceWorkerClientInfo
>()));
984 scoped_refptr
<GetClientDocumentsCallback
> callback(
985 new GetClientDocumentsCallback(request_id
, this));
986 ControlleeByIDMap::iterator
it(&controllee_by_id_
);
987 TRACE_EVENT0("ServiceWorker",
988 "ServiceWorkerVersion::OnGetClientDocuments");
989 while (!it
.IsAtEnd()) {
990 // TODO(mlamouri): we could coalesce those requests into one.
991 it
.GetCurrentValue()->GetClientInfo(
992 base::Bind(&ServiceWorkerVersion::DidGetClientInfo
,
993 weak_factory_
.GetWeakPtr(), it
.GetCurrentKey(), callback
));
998 void ServiceWorkerVersion::OnActivateEventFinished(
1000 blink::WebServiceWorkerEventResult result
) {
1001 DCHECK(ACTIVATING
== status() ||
1002 REDUNDANT
== status()) << status();
1003 TRACE_EVENT0("ServiceWorker",
1004 "ServiceWorkerVersion::OnActivateEventFinished");
1006 StatusCallback
* callback
= activate_callbacks_
.Lookup(request_id
);
1008 NOTREACHED() << "Got unexpected message: " << request_id
;
1011 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
1012 if (result
== blink::WebServiceWorkerEventResultRejected
||
1013 status() != ACTIVATING
) {
1014 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
1017 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1019 RemoveCallbackAndStopIfDoomed(&activate_callbacks_
, request_id
);
1022 void ServiceWorkerVersion::OnInstallEventFinished(
1024 blink::WebServiceWorkerEventResult result
) {
1025 // Status is REDUNDANT if the worker was doomed while handling the install
1026 // event, and finished handling before being terminated.
1027 DCHECK(status() == INSTALLING
|| status() == REDUNDANT
) << status();
1028 TRACE_EVENT0("ServiceWorker",
1029 "ServiceWorkerVersion::OnInstallEventFinished");
1031 StatusCallback
* callback
= install_callbacks_
.Lookup(request_id
);
1033 NOTREACHED() << "Got unexpected message: " << request_id
;
1036 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1037 if (result
== blink::WebServiceWorkerEventResultRejected
)
1038 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
1040 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1041 callback
->Run(status
);
1042 RemoveCallbackAndStopIfDoomed(&install_callbacks_
, request_id
);
1045 void ServiceWorkerVersion::OnFetchEventFinished(
1047 ServiceWorkerFetchEventResult result
,
1048 const ServiceWorkerResponse
& response
) {
1049 TRACE_EVENT1("ServiceWorker",
1050 "ServiceWorkerVersion::OnFetchEventFinished",
1051 "Request id", request_id
);
1052 FetchCallback
* callback
= fetch_callbacks_
.Lookup(request_id
);
1054 NOTREACHED() << "Got unexpected message: " << request_id
;
1058 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1059 callback
->Run(SERVICE_WORKER_OK
, result
, response
);
1060 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_
, request_id
);
1063 void ServiceWorkerVersion::OnSyncEventFinished(
1065 TRACE_EVENT1("ServiceWorker",
1066 "ServiceWorkerVersion::OnSyncEventFinished",
1067 "Request id", request_id
);
1068 StatusCallback
* callback
= sync_callbacks_
.Lookup(request_id
);
1070 NOTREACHED() << "Got unexpected message: " << request_id
;
1074 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1075 callback
->Run(SERVICE_WORKER_OK
);
1076 RemoveCallbackAndStopIfDoomed(&sync_callbacks_
, request_id
);
1079 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1081 TRACE_EVENT1("ServiceWorker",
1082 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1083 "Request id", request_id
);
1084 StatusCallback
* callback
= notification_click_callbacks_
.Lookup(request_id
);
1086 NOTREACHED() << "Got unexpected message: " << request_id
;
1090 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1091 callback
->Run(SERVICE_WORKER_OK
);
1092 RemoveCallbackAndStopIfDoomed(¬ification_click_callbacks_
, request_id
);
1095 void ServiceWorkerVersion::OnPushEventFinished(
1097 blink::WebServiceWorkerEventResult result
) {
1098 TRACE_EVENT1("ServiceWorker",
1099 "ServiceWorkerVersion::OnPushEventFinished",
1100 "Request id", request_id
);
1101 StatusCallback
* callback
= push_callbacks_
.Lookup(request_id
);
1103 NOTREACHED() << "Got unexpected message: " << request_id
;
1106 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1107 if (result
== blink::WebServiceWorkerEventResultRejected
)
1108 status
= SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED
;
1110 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1111 callback
->Run(status
);
1112 RemoveCallbackAndStopIfDoomed(&push_callbacks_
, request_id
);
1115 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id
) {
1116 TRACE_EVENT1("ServiceWorker",
1117 "ServiceWorkerVersion::OnGeofencingEventFinished",
1120 StatusCallback
* callback
= geofencing_callbacks_
.Lookup(request_id
);
1122 NOTREACHED() << "Got unexpected message: " << request_id
;
1126 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1127 callback
->Run(SERVICE_WORKER_OK
);
1128 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_
, request_id
);
1131 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1133 bool accept_connection
) {
1134 TRACE_EVENT1("ServiceWorker",
1135 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1136 "Request id", request_id
);
1137 CrossOriginConnectCallback
* callback
=
1138 cross_origin_connect_callbacks_
.Lookup(request_id
);
1140 NOTREACHED() << "Got unexpected message: " << request_id
;
1144 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1145 callback
->Run(SERVICE_WORKER_OK
, accept_connection
);
1146 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_
, request_id
);
1149 void ServiceWorkerVersion::OnOpenWindow(int request_id
, const GURL
& url
) {
1150 // Just abort if we are shutting down.
1154 if (url
.GetOrigin() != script_url_
.GetOrigin()) {
1155 // There should be a same origin check by Blink, if the request is still not
1156 // same origin, the process might be compromised and should be eliminated.
1157 DVLOG(1) << "Received a cross origin openWindow() request from a service "
1158 "worker. Killing associated process.";
1159 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
1160 base::Bind(&KillEmbeddedWorkerProcess
,
1161 embedded_worker_
->process_id(),
1162 RESULT_CODE_KILLED_BAD_MESSAGE
));
1166 BrowserThread::PostTask(
1167 BrowserThread::UI
, FROM_HERE
,
1168 base::Bind(&OpenWindowOnUI
,
1171 embedded_worker_
->process_id(),
1172 make_scoped_refptr(context_
->wrapper()),
1173 base::Bind(&ServiceWorkerVersion::DidOpenWindow
,
1174 weak_factory_
.GetWeakPtr(),
1178 void ServiceWorkerVersion::DidOpenWindow(int request_id
,
1179 int render_process_id
,
1180 int render_frame_id
) {
1181 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1183 if (running_status() != RUNNING
)
1186 if (render_process_id
== ChildProcessHost::kInvalidUniqueID
&&
1187 render_frame_id
== MSG_ROUTING_NONE
) {
1188 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(request_id
));
1192 for (const auto& it
: controllee_map_
) {
1193 const ServiceWorkerProviderHost
* provider_host
= it
.first
;
1194 if (provider_host
->process_id() != render_process_id
||
1195 provider_host
->frame_id() != render_frame_id
) {
1199 // it.second is the client_id associated with the provider_host.
1200 provider_host
->GetClientInfo(
1201 base::Bind(&ServiceWorkerVersion::OnOpenWindowFinished
,
1202 weak_factory_
.GetWeakPtr(), request_id
, it
.second
));
1206 // If here, it means that no provider_host was found, in which case, the
1207 // renderer should still be informed that the window was opened.
1208 OnOpenWindowFinished(request_id
, 0, ServiceWorkerClientInfo());
1211 void ServiceWorkerVersion::OnOpenWindowFinished(
1214 const ServiceWorkerClientInfo
& client_info
) {
1215 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1217 if (running_status() != RUNNING
)
1220 ServiceWorkerClientInfo
client(client_info
);
1222 // If the |client_info| is empty, it means that the opened window wasn't
1223 // controlled but the action still succeeded. The renderer process is
1224 // expecting an empty client in such case.
1225 if (!client
.IsEmpty())
1226 client
.client_id
= client_id
;
1228 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1229 request_id
, client
));
1232 void ServiceWorkerVersion::OnPostMessageToDocument(
1234 const base::string16
& message
,
1235 const std::vector
<int>& sent_message_port_ids
) {
1236 TRACE_EVENT1("ServiceWorker",
1237 "ServiceWorkerVersion::OnPostMessageToDocument",
1238 "Client id", client_id
);
1239 ServiceWorkerProviderHost
* provider_host
=
1240 controllee_by_id_
.Lookup(client_id
);
1241 if (!provider_host
) {
1242 // The client may already have been closed, just ignore.
1245 provider_host
->PostMessage(message
, sent_message_port_ids
);
1248 void ServiceWorkerVersion::OnFocusClient(int request_id
, int client_id
) {
1249 TRACE_EVENT2("ServiceWorker",
1250 "ServiceWorkerVersion::OnFocusDocument",
1251 "Request id", request_id
,
1252 "Client id", client_id
);
1253 ServiceWorkerProviderHost
* provider_host
=
1254 controllee_by_id_
.Lookup(client_id
);
1255 if (!provider_host
) {
1256 // The client may already have been closed, just ignore.
1260 provider_host
->Focus(
1261 base::Bind(&ServiceWorkerVersion::OnFocusClientFinished
,
1262 weak_factory_
.GetWeakPtr(),
1266 void ServiceWorkerVersion::OnFocusClientFinished(int request_id
, bool result
) {
1267 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1269 if (running_status() != RUNNING
)
1272 embedded_worker_
->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1273 request_id
, result
));
1276 void ServiceWorkerVersion::OnSkipWaiting(int request_id
) {
1277 skip_waiting_
= true;
1278 if (status_
!= INSTALLED
)
1279 return DidSkipWaiting(request_id
);
1283 ServiceWorkerRegistration
* registration
=
1284 context_
->GetLiveRegistration(registration_id_
);
1287 pending_skip_waiting_requests_
.push_back(request_id
);
1288 if (pending_skip_waiting_requests_
.size() == 1)
1289 registration
->ActivateWaitingVersionWhenReady();
1292 void ServiceWorkerVersion::DidSkipWaiting(int request_id
) {
1293 if (running_status() == STARTING
|| running_status() == RUNNING
)
1294 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id
));
1297 void ServiceWorkerVersion::OnClaimClients(int request_id
) {
1298 StatusCallback callback
= base::Bind(&ServiceWorkerVersion::DidClaimClients
,
1299 weak_factory_
.GetWeakPtr(), request_id
);
1300 if (status_
!= ACTIVATING
&& status_
!= ACTIVATED
) {
1301 callback
.Run(SERVICE_WORKER_ERROR_STATE
);
1305 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
1309 ServiceWorkerRegistration
* registration
=
1310 context_
->GetLiveRegistration(registration_id_
);
1311 if (!registration
) {
1312 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
1315 registration
->ClaimClients(callback
);
1318 void ServiceWorkerVersion::DidClaimClients(
1319 int request_id
, ServiceWorkerStatusCode status
) {
1320 if (status
== SERVICE_WORKER_ERROR_STATE
) {
1321 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1322 request_id
, blink::WebServiceWorkerError::ErrorTypeState
,
1323 base::ASCIIToUTF16(kClaimClientsStateErrorMesage
)));
1326 if (status
== SERVICE_WORKER_ERROR_ABORT
) {
1327 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1328 request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
1329 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage
)));
1332 DCHECK(status
== SERVICE_WORKER_OK
);
1333 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidClaimClients(request_id
));
1336 void ServiceWorkerVersion::DidGetClientInfo(
1338 scoped_refptr
<GetClientDocumentsCallback
> callback
,
1339 const ServiceWorkerClientInfo
& info
) {
1340 // If the request to the provider_host returned an empty
1341 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
1342 // it with a valid RenderFrameHost. It might be because the frame was killed
1343 // or navigated in between.
1347 // We can get info for a frame that was navigating end ended up with a
1348 // different URL than expected. In such case, we should make sure to not
1349 // expose cross-origin WindowClient.
1350 if (info
.url
.GetOrigin() != script_url_
.GetOrigin())
1353 callback
->AddClientInfo(client_id
, info
);
1356 void ServiceWorkerVersion::ScheduleStopWorker() {
1357 if (running_status() != RUNNING
)
1359 stop_worker_timer_
.Stop();
1360 stop_worker_timer_
.Start(
1361 FROM_HERE
, base::TimeDelta::FromSeconds(
1362 is_doomed_
? kStopDoomedWorkerDelay
: kStopWorkerDelay
),
1363 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle
,
1364 weak_factory_
.GetWeakPtr()));
1367 void ServiceWorkerVersion::StopWorkerIfIdle() {
1368 // Reschedule the stop the worker while there're inflight requests.
1369 // (Note: we'll probably need to revisit this so that we can kill 'bad' SW.
1370 // See https://github.com/slightlyoff/ServiceWorker/issues/527)
1371 if (HasInflightRequests()) {
1372 ScheduleStopWorker();
1375 if (running_status() == STOPPED
|| running_status() == STOPPING
||
1376 !stop_callbacks_
.empty()) {
1379 embedded_worker_
->StopIfIdle();
1382 bool ServiceWorkerVersion::HasInflightRequests() const {
1384 !activate_callbacks_
.IsEmpty() ||
1385 !install_callbacks_
.IsEmpty() ||
1386 !fetch_callbacks_
.IsEmpty() ||
1387 !sync_callbacks_
.IsEmpty() ||
1388 !notification_click_callbacks_
.IsEmpty() ||
1389 !push_callbacks_
.IsEmpty() ||
1390 !geofencing_callbacks_
.IsEmpty() ||
1391 !cross_origin_connect_callbacks_
.IsEmpty() ||
1392 !streaming_url_request_jobs_
.empty();
1395 void ServiceWorkerVersion::DoomInternal() {
1397 DCHECK(!HasControllee());
1398 SetStatus(REDUNDANT
);
1402 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
1403 script_cache_map_
.GetResources(&resources
);
1404 context_
->storage()->PurgeResources(resources
);
1407 template <typename IDMAP
>
1408 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1411 callbacks
->Remove(request_id
);
1413 // The stop should be already scheduled, but try to stop immediately, in
1414 // order to release worker resources soon.
1419 } // namespace content