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/metrics/histogram_macros.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "content/browser/bad_message.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/message_port_message_filter.h"
17 #include "content/browser/message_port_service.h"
18 #include "content/browser/service_worker/embedded_worker_instance.h"
19 #include "content/browser/service_worker/embedded_worker_registry.h"
20 #include "content/browser/service_worker/service_worker_context_core.h"
21 #include "content/browser/service_worker/service_worker_context_wrapper.h"
22 #include "content/browser/service_worker/service_worker_metrics.h"
23 #include "content/browser/service_worker/service_worker_registration.h"
24 #include "content/browser/service_worker/service_worker_utils.h"
25 #include "content/browser/storage_partition_impl.h"
26 #include "content/common/service_worker/service_worker_messages.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/content_browser_client.h"
29 #include "content/public/browser/page_navigator.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_observer.h"
34 #include "content/public/common/child_process_host.h"
35 #include "content/public/common/content_client.h"
36 #include "content/public/common/content_switches.h"
37 #include "content/public/common/result_codes.h"
38 #include "net/http/http_response_headers.h"
39 #include "net/http/http_response_info.h"
43 using StatusCallback
= ServiceWorkerVersion::StatusCallback
;
44 using ServiceWorkerClients
= std::vector
<ServiceWorkerClientInfo
>;
45 using GetClientsCallback
=
46 base::Callback
<void(scoped_ptr
<ServiceWorkerClients
>)>;
50 // Delay between the timeout timer firing.
51 const int kTimeoutTimerDelaySeconds
= 30;
53 // Time to wait until stopping an idle worker.
54 const int kIdleWorkerTimeoutSeconds
= 30;
56 // Default delay for scheduled update.
57 const int kUpdateDelaySeconds
= 1;
59 // Timeout for waiting for a response to a ping.
60 const int kPingTimeoutSeconds
= 30;
62 // If the SW was destructed while starting up, how many seconds it
63 // had to start up for this to be considered a timeout occurrence.
64 const int kDestructedStartingWorkerTimeoutThresholdSeconds
= 5;
66 const char kClaimClientsStateErrorMesage
[] =
67 "Only the active worker can claim clients.";
69 const char kClaimClientsShutdownErrorMesage
[] =
70 "Failed to claim clients due to Service Worker system shutdown.";
72 void RunSoon(const base::Closure
& callback
) {
73 if (!callback
.is_null())
74 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
77 template <typename CallbackArray
, typename Arg
>
78 void RunCallbacks(ServiceWorkerVersion
* version
,
79 CallbackArray
* callbacks_ptr
,
81 CallbackArray callbacks
;
82 callbacks
.swap(*callbacks_ptr
);
83 scoped_refptr
<ServiceWorkerVersion
> protect(version
);
84 for (const auto& callback
: callbacks
)
88 template <typename IDMAP
, typename
... Params
>
89 void RunIDMapCallbacks(IDMAP
* callbacks
, const Params
&... params
) {
90 typename
IDMAP::iterator
iter(callbacks
);
91 while (!iter
.IsAtEnd()) {
92 iter
.GetCurrentValue()->Run(params
...);
98 template <typename CallbackType
, typename
... Params
>
99 bool RunIDMapCallback(IDMap
<CallbackType
, IDMapOwnPointer
>* callbacks
,
101 const Params
&... params
) {
102 CallbackType
* callback
= callbacks
->Lookup(request_id
);
106 callback
->Run(params
...);
107 callbacks
->Remove(request_id
);
111 void RunStartWorkerCallback(
112 const StatusCallback
& callback
,
113 scoped_refptr
<ServiceWorkerRegistration
> protect
,
114 ServiceWorkerStatusCode status
) {
115 callback
.Run(status
);
118 // A callback adapter to start a |task| after StartWorker.
119 void RunTaskAfterStartWorker(
120 base::WeakPtr
<ServiceWorkerVersion
> version
,
121 const StatusCallback
& error_callback
,
122 const base::Closure
& task
,
123 ServiceWorkerStatusCode status
) {
124 if (status
!= SERVICE_WORKER_OK
) {
125 if (!error_callback
.is_null())
126 error_callback
.Run(status
);
129 if (version
->running_status() != ServiceWorkerVersion::RUNNING
) {
130 // We've tried to start the worker (and it has succeeded), but
131 // it looks it's not running yet.
132 NOTREACHED() << "The worker's not running after successful StartWorker";
133 if (!error_callback
.is_null())
134 error_callback
.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
140 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback
& callback
,
141 ServiceWorkerStatusCode status
) {
143 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
144 ServiceWorkerResponse());
147 void RunErrorMessageCallback(
148 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
149 const ServiceWorkerVersion::StatusCallback
& callback
,
150 ServiceWorkerStatusCode status
) {
151 // Transfering the message ports failed, so destroy the ports.
152 for (const TransferredMessagePort
& port
: sent_message_ports
) {
153 MessagePortService::GetInstance()->ClosePort(port
.id
);
155 callback
.Run(status
);
158 void RunErrorCrossOriginConnectCallback(
159 const ServiceWorkerVersion::CrossOriginConnectCallback
& callback
,
160 ServiceWorkerStatusCode status
) {
161 callback
.Run(status
, false /* accept_connection */);
164 using WindowOpenedCallback
= base::Callback
<void(int, int)>;
166 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
167 // new Window's WebContents to be initialized, run the |callback| passed to its
168 // constructor then self destroy.
169 // The callback will receive the process and frame ids. If something went wrong
170 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
171 // The callback will be called in the IO thread.
172 class WindowOpenedObserver
: public WebContentsObserver
{
174 WindowOpenedObserver(WebContents
* web_contents
,
175 const WindowOpenedCallback
& callback
)
176 : WebContentsObserver(web_contents
),
180 void DidCommitProvisionalLoadForFrame(
181 RenderFrameHost
* render_frame_host
,
182 const GURL
& validated_url
,
183 ui::PageTransition transition_type
) override
{
184 DCHECK(web_contents());
186 if (render_frame_host
!= web_contents()->GetMainFrame())
189 RunCallback(render_frame_host
->GetProcess()->GetID(),
190 render_frame_host
->GetRoutingID());
193 void RenderProcessGone(base::TerminationStatus status
) override
{
194 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
197 void WebContentsDestroyed() override
{
198 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
202 void RunCallback(int render_process_id
, int render_frame_id
) {
203 // After running the callback, |this| will stop observing, thus
204 // web_contents() should return nullptr and |RunCallback| should no longer
205 // be called. Then, |this| will self destroy.
206 DCHECK(web_contents());
208 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
209 base::Bind(callback_
,
213 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
216 const WindowOpenedCallback callback_
;
218 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver
);
221 void DidOpenURL(const WindowOpenedCallback
& callback
,
222 WebContents
* web_contents
) {
223 DCHECK(web_contents
);
225 new WindowOpenedObserver(web_contents
, callback
);
230 const GURL
& script_url
,
232 const scoped_refptr
<ServiceWorkerContextWrapper
>& context_wrapper
,
233 const WindowOpenedCallback
& callback
) {
234 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
236 BrowserContext
* browser_context
= context_wrapper
->storage_partition()
237 ? context_wrapper
->storage_partition()->browser_context()
239 // We are shutting down.
240 if (!browser_context
)
243 RenderProcessHost
* render_process_host
=
244 RenderProcessHost::FromID(process_id
);
245 if (render_process_host
->IsIsolatedGuest()) {
246 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
248 ChildProcessHost::kInvalidUniqueID
,
253 OpenURLParams
params(
254 url
, Referrer::SanitizeForRequest(
255 url
, Referrer(script_url
, blink::WebReferrerPolicyDefault
)),
256 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
257 true /* is_renderer_initiated */);
259 GetContentClient()->browser()->OpenURL(
260 browser_context
, params
,
261 base::Bind(&DidOpenURL
, callback
));
264 void KillEmbeddedWorkerProcess(int process_id
, ResultCode code
) {
265 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
266 RenderProcessHost
* render_process_host
=
267 RenderProcessHost::FromID(process_id
);
268 if (render_process_host
->GetHandle() != base::kNullProcessHandle
) {
269 bad_message::ReceivedBadMessage(render_process_host
,
270 bad_message::SERVICE_WORKER_BAD_URL
);
274 void ClearTick(base::TimeTicks
* time
) {
275 *time
= base::TimeTicks();
278 void RestartTick(base::TimeTicks
* time
) {
279 *time
= base::TimeTicks().Now();
282 base::TimeDelta
GetTickDuration(const base::TimeTicks
& time
) {
284 return base::TimeDelta();
285 return base::TimeTicks().Now() - time
;
288 void OnGetWindowClientsFromUI(
289 // The tuple contains process_id, frame_id, client_uuid.
290 const std::vector
<Tuple
<int, int, std::string
>>& clients_info
,
291 const GURL
& script_url
,
292 const GetClientsCallback
& callback
) {
293 scoped_ptr
<ServiceWorkerClients
> clients(new ServiceWorkerClients
);
295 for (const auto& it
: clients_info
) {
296 ServiceWorkerClientInfo info
=
297 ServiceWorkerProviderHost::GetWindowClientInfoOnUI(get
<0>(it
),
300 // If the request to the provider_host returned an empty
301 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
302 // it with a valid RenderFrameHost. It might be because the frame was killed
303 // or navigated in between.
307 // We can get info for a frame that was navigating end ended up with a
308 // different URL than expected. In such case, we should make sure to not
309 // expose cross-origin WindowClient.
310 if (info
.url
.GetOrigin() != script_url
.GetOrigin())
313 info
.client_uuid
= get
<2>(it
);
314 clients
->push_back(info
);
317 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
318 base::Bind(callback
, base::Passed(&clients
)));
321 void AddWindowClient(ServiceWorkerProviderHost
* host
,
322 std::vector
<Tuple
<int, int, std::string
>>* client_info
) {
323 if (host
->client_type() != blink::WebServiceWorkerClientTypeWindow
)
325 client_info
->push_back(
326 MakeTuple(host
->process_id(), host
->frame_id(), host
->client_uuid()));
329 void AddNonWindowClient(ServiceWorkerProviderHost
* host
,
330 const ServiceWorkerClientQueryOptions
& options
,
331 ServiceWorkerClients
* clients
) {
332 blink::WebServiceWorkerClientType host_client_type
= host
->client_type();
333 if (host_client_type
== blink::WebServiceWorkerClientTypeWindow
)
335 if (options
.client_type
!= blink::WebServiceWorkerClientTypeAll
&&
336 options
.client_type
!= host_client_type
)
339 ServiceWorkerClientInfo
client_info(
340 blink::WebPageVisibilityStateHidden
,
342 host
->document_url(), REQUEST_CONTEXT_FRAME_TYPE_NONE
, host_client_type
);
343 client_info
.client_uuid
= host
->client_uuid();
344 clients
->push_back(client_info
);
347 bool IsInstalled(ServiceWorkerVersion::Status status
) {
349 case ServiceWorkerVersion::NEW
:
350 case ServiceWorkerVersion::INSTALLING
:
351 case ServiceWorkerVersion::REDUNDANT
:
353 case ServiceWorkerVersion::INSTALLED
:
354 case ServiceWorkerVersion::ACTIVATING
:
355 case ServiceWorkerVersion::ACTIVATED
:
358 NOTREACHED() << "Unexpected status: " << status
;
364 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes
= 5;
365 const int ServiceWorkerVersion::kRequestTimeoutMinutes
= 5;
367 ServiceWorkerVersion::ServiceWorkerVersion(
368 ServiceWorkerRegistration
* registration
,
369 const GURL
& script_url
,
371 base::WeakPtr
<ServiceWorkerContextCore
> context
)
372 : version_id_(version_id
),
373 registration_id_(kInvalidServiceWorkerVersionId
),
374 script_url_(script_url
),
377 script_cache_map_(this, context
),
378 ping_state_(NOT_PINGING
),
379 weak_factory_(this) {
381 DCHECK(registration
);
383 registration_id_
= registration
->id();
384 scope_
= registration
->pattern();
386 context_
->AddLiveVersion(this);
387 embedded_worker_
= context_
->embedded_worker_registry()->CreateWorker();
388 embedded_worker_
->AddListener(this);
391 ServiceWorkerVersion::~ServiceWorkerVersion() {
392 // The user may have closed the tab waiting for SW to start up.
393 if (GetTickDuration(start_time_
) >
394 base::TimeDelta::FromSeconds(
395 kDestructedStartingWorkerTimeoutThresholdSeconds
)) {
396 DCHECK(timeout_timer_
.IsRunning());
397 DCHECK(!embedded_worker_
->devtools_attached());
398 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT
);
401 embedded_worker_
->RemoveListener(this);
403 context_
->RemoveLiveVersion(version_id_
);
404 // EmbeddedWorker's dtor sends StopWorker if it's still running.
407 void ServiceWorkerVersion::SetStatus(Status status
) {
408 if (status_
== status
)
413 if (skip_waiting_
&& status_
== ACTIVATED
) {
414 for (int request_id
: pending_skip_waiting_requests_
)
415 DidSkipWaiting(request_id
);
416 pending_skip_waiting_requests_
.clear();
419 std::vector
<base::Closure
> callbacks
;
420 callbacks
.swap(status_change_callbacks_
);
421 for (const auto& callback
: callbacks
)
424 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
427 void ServiceWorkerVersion::RegisterStatusChangeCallback(
428 const base::Closure
& callback
) {
429 status_change_callbacks_
.push_back(callback
);
432 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
433 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
434 ServiceWorkerVersionInfo
info(
435 running_status(), status(), script_url(), registration_id(), version_id(),
436 embedded_worker()->process_id(), embedded_worker()->thread_id(),
437 embedded_worker()->worker_devtools_agent_route_id());
438 if (!main_script_http_info_
)
440 info
.script_response_time
= main_script_http_info_
->response_time
;
441 if (main_script_http_info_
->headers
)
442 main_script_http_info_
->headers
->GetLastModifiedValue(
443 &info
.script_last_modified
);
447 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
448 StartWorker(false, callback
);
451 void ServiceWorkerVersion::StartWorker(
452 bool pause_after_download
,
453 const StatusCallback
& callback
) {
455 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_ABORT
));
459 // Ensure the live registration during starting worker so that the worker can
460 // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
461 context_
->storage()->FindRegistrationForId(
464 base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker
,
465 weak_factory_
.GetWeakPtr(),
466 pause_after_download
,
470 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
471 if (running_status() == STOPPED
) {
472 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
475 if (stop_callbacks_
.empty()) {
476 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
477 if (status
!= SERVICE_WORKER_OK
) {
478 RunSoon(base::Bind(callback
, status
));
482 stop_callbacks_
.push_back(callback
);
485 void ServiceWorkerVersion::ScheduleUpdate() {
486 if (update_timer_
.IsRunning()) {
487 update_timer_
.Reset();
491 FROM_HERE
, base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
492 base::Bind(&ServiceWorkerVersion::StartUpdate
,
493 weak_factory_
.GetWeakPtr()));
496 void ServiceWorkerVersion::DeferScheduledUpdate() {
497 if (update_timer_
.IsRunning())
498 update_timer_
.Reset();
501 void ServiceWorkerVersion::StartUpdate() {
502 update_timer_
.Stop();
505 ServiceWorkerRegistration
* registration
=
506 context_
->GetLiveRegistration(registration_id_
);
507 if (!registration
|| !registration
->GetNewestVersion())
509 context_
->UpdateServiceWorker(registration
, false /* force_bypass_cache */);
512 void ServiceWorkerVersion::DispatchMessageEvent(
513 const base::string16
& message
,
514 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
515 const StatusCallback
& callback
) {
516 for (const TransferredMessagePort
& port
: sent_message_ports
) {
517 MessagePortService::GetInstance()->HoldMessages(port
.id
);
520 DispatchMessageEventInternal(message
, sent_message_ports
, callback
);
523 void ServiceWorkerVersion::DispatchMessageEventInternal(
524 const base::string16
& message
,
525 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
526 const StatusCallback
& callback
) {
527 if (running_status() != RUNNING
) {
528 // Schedule calling this method after starting the worker.
529 StartWorker(base::Bind(
530 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
531 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
532 base::Bind(&self::DispatchMessageEventInternal
,
533 weak_factory_
.GetWeakPtr(), message
, sent_message_ports
,
538 MessagePortMessageFilter
* filter
=
539 embedded_worker_
->message_port_message_filter();
540 std::vector
<int> new_routing_ids
;
541 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
542 ServiceWorkerStatusCode status
=
543 embedded_worker_
->SendMessage(ServiceWorkerMsg_MessageToWorker(
544 message
, sent_message_ports
, new_routing_ids
));
545 RunSoon(base::Bind(callback
, status
));
548 void ServiceWorkerVersion::DispatchInstallEvent(
549 const StatusCallback
& callback
) {
550 DCHECK_EQ(INSTALLING
, status()) << status();
552 if (running_status() != RUNNING
) {
553 // Schedule calling this method after starting the worker.
555 base::Bind(&RunTaskAfterStartWorker
,
556 weak_factory_
.GetWeakPtr(),
558 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
559 weak_factory_
.GetWeakPtr(),
562 DispatchInstallEventAfterStartWorker(callback
);
566 void ServiceWorkerVersion::DispatchActivateEvent(
567 const StatusCallback
& callback
) {
568 DCHECK_EQ(ACTIVATING
, status()) << status();
570 if (running_status() != RUNNING
) {
571 // Schedule calling this method after starting the worker.
573 base::Bind(&RunTaskAfterStartWorker
,
574 weak_factory_
.GetWeakPtr(),
576 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
577 weak_factory_
.GetWeakPtr(),
580 DispatchActivateEventAfterStartWorker(callback
);
584 void ServiceWorkerVersion::DispatchFetchEvent(
585 const ServiceWorkerFetchRequest
& request
,
586 const base::Closure
& prepare_callback
,
587 const FetchCallback
& fetch_callback
) {
588 DCHECK_EQ(ACTIVATED
, status()) << status();
590 if (running_status() != RUNNING
) {
591 // Schedule calling this method after starting the worker.
592 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
593 weak_factory_
.GetWeakPtr(),
594 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
595 base::Bind(&self::DispatchFetchEvent
,
596 weak_factory_
.GetWeakPtr(),
603 prepare_callback
.Run();
605 int request_id
= AddRequest(fetch_callback
, &fetch_callbacks_
, REQUEST_FETCH
);
606 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
607 ServiceWorkerMsg_FetchEvent(request_id
, request
));
608 if (status
!= SERVICE_WORKER_OK
) {
609 fetch_callbacks_
.Remove(request_id
);
610 RunSoon(base::Bind(&RunErrorFetchCallback
,
612 SERVICE_WORKER_ERROR_FAILED
));
616 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback
& callback
) {
617 DCHECK_EQ(ACTIVATED
, status()) << status();
619 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
620 switches::kEnableServiceWorkerSync
)) {
621 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
625 if (running_status() != RUNNING
) {
626 // Schedule calling this method after starting the worker.
627 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
628 weak_factory_
.GetWeakPtr(), callback
,
629 base::Bind(&self::DispatchSyncEvent
,
630 weak_factory_
.GetWeakPtr(),
635 int request_id
= AddRequest(callback
, &sync_callbacks_
, REQUEST_SYNC
);
636 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
637 ServiceWorkerMsg_SyncEvent(request_id
));
638 if (status
!= SERVICE_WORKER_OK
) {
639 sync_callbacks_
.Remove(request_id
);
640 RunSoon(base::Bind(callback
, status
));
644 void ServiceWorkerVersion::DispatchNotificationClickEvent(
645 const StatusCallback
& callback
,
646 int64_t persistent_notification_id
,
647 const PlatformNotificationData
& notification_data
) {
648 DCHECK_EQ(ACTIVATED
, status()) << status();
649 if (running_status() != RUNNING
) {
650 // Schedule calling this method after starting the worker.
651 StartWorker(base::Bind(
652 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(), callback
,
653 base::Bind(&self::DispatchNotificationClickEvent
,
654 weak_factory_
.GetWeakPtr(), callback
,
655 persistent_notification_id
, notification_data
)));
659 int request_id
= AddRequest(callback
, ¬ification_click_callbacks_
,
660 REQUEST_NOTIFICATION_CLICK
);
661 ServiceWorkerStatusCode status
=
662 embedded_worker_
->SendMessage(ServiceWorkerMsg_NotificationClickEvent(
663 request_id
, persistent_notification_id
, notification_data
));
664 if (status
!= SERVICE_WORKER_OK
) {
665 notification_click_callbacks_
.Remove(request_id
);
666 RunSoon(base::Bind(callback
, status
));
670 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
671 const std::string
& data
) {
672 DCHECK_EQ(ACTIVATED
, status()) << status();
673 if (running_status() != RUNNING
) {
674 // Schedule calling this method after starting the worker.
675 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
676 weak_factory_
.GetWeakPtr(), callback
,
677 base::Bind(&self::DispatchPushEvent
,
678 weak_factory_
.GetWeakPtr(),
683 int request_id
= AddRequest(callback
, &push_callbacks_
, REQUEST_PUSH
);
684 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
685 ServiceWorkerMsg_PushEvent(request_id
, data
));
686 if (status
!= SERVICE_WORKER_OK
) {
687 push_callbacks_
.Remove(request_id
);
688 RunSoon(base::Bind(callback
, status
));
692 void ServiceWorkerVersion::DispatchGeofencingEvent(
693 const StatusCallback
& callback
,
694 blink::WebGeofencingEventType event_type
,
695 const std::string
& region_id
,
696 const blink::WebCircularGeofencingRegion
& region
) {
697 DCHECK_EQ(ACTIVATED
, status()) << status();
699 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
700 switches::kEnableExperimentalWebPlatformFeatures
)) {
701 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
705 if (running_status() != RUNNING
) {
706 // Schedule calling this method after starting the worker.
707 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
708 weak_factory_
.GetWeakPtr(),
710 base::Bind(&self::DispatchGeofencingEvent
,
711 weak_factory_
.GetWeakPtr(),
720 AddRequest(callback
, &geofencing_callbacks_
, REQUEST_GEOFENCING
);
721 ServiceWorkerStatusCode status
=
722 embedded_worker_
->SendMessage(ServiceWorkerMsg_GeofencingEvent(
723 request_id
, event_type
, region_id
, region
));
724 if (status
!= SERVICE_WORKER_OK
) {
725 geofencing_callbacks_
.Remove(request_id
);
726 RunSoon(base::Bind(callback
, status
));
730 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
731 const CrossOriginConnectCallback
& callback
,
732 const NavigatorConnectClient
& client
) {
733 DCHECK_EQ(ACTIVATED
, status()) << status();
735 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
736 switches::kEnableExperimentalWebPlatformFeatures
)) {
737 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, false);
741 if (running_status() != RUNNING
) {
742 // Schedule calling this method after starting the worker.
744 base::Bind(&RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
745 base::Bind(&RunErrorCrossOriginConnectCallback
, callback
),
746 base::Bind(&self::DispatchCrossOriginConnectEvent
,
747 weak_factory_
.GetWeakPtr(), callback
, client
)));
751 int request_id
= AddRequest(callback
, &cross_origin_connect_callbacks_
,
752 REQUEST_CROSS_ORIGIN_CONNECT
);
753 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
754 ServiceWorkerMsg_CrossOriginConnectEvent(request_id
, client
));
755 if (status
!= SERVICE_WORKER_OK
) {
756 cross_origin_connect_callbacks_
.Remove(request_id
);
757 RunSoon(base::Bind(callback
, status
, false));
761 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
762 const NavigatorConnectClient
& client
,
763 const base::string16
& message
,
764 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
765 const StatusCallback
& callback
) {
766 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
767 // have already put all the sent message ports on hold. So no need to do that
770 if (running_status() != RUNNING
) {
771 // Schedule calling this method after starting the worker.
772 StartWorker(base::Bind(
773 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
774 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
775 base::Bind(&self::DispatchCrossOriginMessageEvent
,
776 weak_factory_
.GetWeakPtr(), client
, message
,
777 sent_message_ports
, callback
)));
781 MessagePortMessageFilter
* filter
=
782 embedded_worker_
->message_port_message_filter();
783 std::vector
<int> new_routing_ids
;
784 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
785 ServiceWorkerStatusCode status
=
786 embedded_worker_
->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
787 client
, message
, sent_message_ports
, new_routing_ids
));
788 RunSoon(base::Bind(callback
, status
));
791 void ServiceWorkerVersion::AddControllee(
792 ServiceWorkerProviderHost
* provider_host
) {
793 const std::string
& uuid
= provider_host
->client_uuid();
794 CHECK(!provider_host
->client_uuid().empty());
795 DCHECK(!ContainsKey(controllee_map_
, uuid
));
796 controllee_map_
[uuid
] = provider_host
;
797 // Keep the worker alive a bit longer right after a new controllee is added.
798 RestartTick(&idle_time_
);
801 void ServiceWorkerVersion::RemoveControllee(
802 ServiceWorkerProviderHost
* provider_host
) {
803 const std::string
& uuid
= provider_host
->client_uuid();
804 DCHECK(ContainsKey(controllee_map_
, uuid
));
805 controllee_map_
.erase(uuid
);
808 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
811 void ServiceWorkerVersion::AddStreamingURLRequestJob(
812 const ServiceWorkerURLRequestJob
* request_job
) {
813 DCHECK(streaming_url_request_jobs_
.find(request_job
) ==
814 streaming_url_request_jobs_
.end());
815 streaming_url_request_jobs_
.insert(request_job
);
818 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
819 const ServiceWorkerURLRequestJob
* request_job
) {
820 streaming_url_request_jobs_
.erase(request_job
);
825 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
826 listeners_
.AddObserver(listener
);
829 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
830 listeners_
.RemoveObserver(listener
);
833 void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status
,
834 const std::string
& status_message
) {
835 if (status_message
.empty()) {
836 OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status
)),
839 OnReportException(base::UTF8ToUTF16(status_message
), -1, -1, GURL());
843 void ServiceWorkerVersion::Doom() {
844 DCHECK(!HasControllee());
845 SetStatus(REDUNDANT
);
849 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
850 script_cache_map_
.GetResources(&resources
);
851 context_
->storage()->PurgeResources(resources
);
854 void ServiceWorkerVersion::SetDevToolsAttached(bool attached
) {
855 embedded_worker()->set_devtools_attached(attached
);
857 // TODO(falken): Canceling the timeouts when debugging could cause
858 // heisenbugs; we should instead run them as normal show an educational
859 // message in DevTools when they occur. crbug.com/470419
861 // Don't record the startup time metric once DevTools is attached.
862 ClearTick(&start_time_
);
863 skip_recording_startup_time_
= true;
865 // Cancel request timeouts.
866 SetAllRequestTimes(base::TimeTicks());
869 if (!start_callbacks_
.empty()) {
870 // Reactivate the timer for start timeout.
871 DCHECK(timeout_timer_
.IsRunning());
872 DCHECK(running_status() == STARTING
|| running_status() == STOPPING
)
874 RestartTick(&start_time_
);
877 // Reactivate request timeouts.
878 SetAllRequestTimes(base::TimeTicks::Now());
881 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
882 const net::HttpResponseInfo
& http_info
) {
883 main_script_http_info_
.reset(new net::HttpResponseInfo(http_info
));
884 FOR_EACH_OBSERVER(Listener
, listeners_
,
885 OnMainScriptHttpResponseInfoSet(this));
888 const net::HttpResponseInfo
*
889 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
890 return main_script_http_info_
.get();
893 ServiceWorkerVersion::RequestInfo::RequestInfo(int id
, RequestType type
)
894 : id(id
), type(type
), time(base::TimeTicks::Now()) {
897 ServiceWorkerVersion::RequestInfo::~RequestInfo() {
900 void ServiceWorkerVersion::OnScriptLoaded() {
901 DCHECK_EQ(STARTING
, running_status());
902 // Activate ping/pong now that JavaScript execution will start.
903 ping_state_
= PINGING
;
906 void ServiceWorkerVersion::OnStarting() {
907 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
910 void ServiceWorkerVersion::OnStarted() {
911 DCHECK_EQ(RUNNING
, running_status());
912 RestartTick(&idle_time_
);
914 // Fire all start callbacks.
915 scoped_refptr
<ServiceWorkerVersion
> protect(this);
916 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
917 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
920 void ServiceWorkerVersion::OnStopping() {
921 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
924 void ServiceWorkerVersion::OnStopped(
925 EmbeddedWorkerInstance::Status old_status
) {
926 DCHECK_EQ(STOPPED
, running_status());
927 scoped_refptr
<ServiceWorkerVersion
> protect(this);
929 bool should_restart
= !is_redundant() && !start_callbacks_
.empty() &&
930 (old_status
!= EmbeddedWorkerInstance::STARTING
);
933 if (ping_state_
== PING_TIMED_OUT
)
934 should_restart
= false;
936 // Fire all stop callbacks.
937 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
939 if (!should_restart
) {
940 // Let all start callbacks fail.
941 RunCallbacks(this, &start_callbacks_
,
942 DeduceStartWorkerFailureReason(
943 SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
946 // Let all message callbacks fail (this will also fire and clear all
947 // callbacks for events).
948 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
949 RunIDMapCallbacks(&activate_callbacks_
,
950 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
951 RunIDMapCallbacks(&install_callbacks_
,
952 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
953 RunIDMapCallbacks(&fetch_callbacks_
,
954 SERVICE_WORKER_ERROR_FAILED
,
955 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
956 ServiceWorkerResponse());
957 RunIDMapCallbacks(&sync_callbacks_
,
958 SERVICE_WORKER_ERROR_FAILED
);
959 RunIDMapCallbacks(¬ification_click_callbacks_
,
960 SERVICE_WORKER_ERROR_FAILED
);
961 RunIDMapCallbacks(&push_callbacks_
,
962 SERVICE_WORKER_ERROR_FAILED
);
963 RunIDMapCallbacks(&geofencing_callbacks_
,
964 SERVICE_WORKER_ERROR_FAILED
);
965 RunIDMapCallbacks(&cross_origin_connect_callbacks_
,
966 SERVICE_WORKER_ERROR_FAILED
,
969 streaming_url_request_jobs_
.clear();
971 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
974 StartWorkerInternal(false /* pause_after_download */);
977 void ServiceWorkerVersion::OnReportException(
978 const base::string16
& error_message
,
981 const GURL
& source_url
) {
986 this, error_message
, line_number
, column_number
, source_url
));
989 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
991 const base::string16
& message
,
993 const GURL
& source_url
) {
994 FOR_EACH_OBSERVER(Listener
,
996 OnReportConsoleMessage(this,
1004 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
1005 bool handled
= true;
1006 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
1007 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients
,
1009 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
1010 OnActivateEventFinished
)
1011 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
1012 OnInstallEventFinished
)
1013 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
1014 OnFetchEventFinished
)
1015 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished
,
1016 OnSyncEventFinished
)
1017 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished
,
1018 OnNotificationClickEventFinished
)
1019 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
1020 OnPushEventFinished
)
1021 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished
,
1022 OnGeofencingEventFinished
)
1023 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished
,
1024 OnCrossOriginConnectEventFinished
)
1025 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow
,
1027 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata
,
1028 OnSetCachedMetadata
)
1029 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata
,
1030 OnClearCachedMetadata
)
1031 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient
,
1032 OnPostMessageToClient
)
1033 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient
,
1035 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting
,
1037 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients
,
1039 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong
, OnPongFromWorker
)
1040 IPC_MESSAGE_UNHANDLED(handled
= false)
1041 IPC_END_MESSAGE_MAP()
1045 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
1046 ServiceWorkerStatusCode status
) {
1047 if (status
!= SERVICE_WORKER_OK
) {
1048 RunCallbacks(this, &start_callbacks_
,
1049 DeduceStartWorkerFailureReason(status
));
1053 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
1054 const StatusCallback
& callback
) {
1055 DCHECK_EQ(RUNNING
, running_status())
1056 << "Worker stopped too soon after it was started.";
1058 int request_id
= AddRequest(callback
, &install_callbacks_
, REQUEST_INSTALL
);
1059 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
1060 ServiceWorkerMsg_InstallEvent(request_id
));
1061 if (status
!= SERVICE_WORKER_OK
) {
1062 install_callbacks_
.Remove(request_id
);
1063 RunSoon(base::Bind(callback
, status
));
1067 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
1068 const StatusCallback
& callback
) {
1069 DCHECK_EQ(RUNNING
, running_status())
1070 << "Worker stopped too soon after it was started.";
1072 int request_id
= AddRequest(callback
, &activate_callbacks_
, REQUEST_ACTIVATE
);
1073 ServiceWorkerStatusCode status
=
1074 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
1075 if (status
!= SERVICE_WORKER_OK
) {
1076 activate_callbacks_
.Remove(request_id
);
1077 RunSoon(base::Bind(callback
, status
));
1081 void ServiceWorkerVersion::OnGetClients(
1083 const ServiceWorkerClientQueryOptions
& options
) {
1084 TRACE_EVENT_ASYNC_BEGIN2(
1085 "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id
,
1086 "client_type", options
.client_type
, "include_uncontrolled",
1087 options
.include_uncontrolled
);
1089 if (controllee_map_
.empty() && !options
.include_uncontrolled
) {
1090 OnGetClientsFinished(request_id
, std::vector
<ServiceWorkerClientInfo
>());
1094 // For Window clients we want to query the info on the UI thread first.
1095 if (options
.client_type
== blink::WebServiceWorkerClientTypeWindow
||
1096 options
.client_type
== blink::WebServiceWorkerClientTypeAll
) {
1097 GetWindowClients(request_id
, options
);
1101 ServiceWorkerClients clients
;
1102 GetNonWindowClients(request_id
, options
, &clients
);
1103 OnGetClientsFinished(request_id
, clients
);
1106 void ServiceWorkerVersion::OnGetClientsFinished(
1108 const ServiceWorkerClients
& clients
) {
1109 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1110 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
1111 request_id
, "The number of clients", clients
.size());
1113 if (running_status() != RUNNING
)
1115 embedded_worker_
->SendMessage(
1116 ServiceWorkerMsg_DidGetClients(request_id
, clients
));
1119 void ServiceWorkerVersion::OnActivateEventFinished(
1121 blink::WebServiceWorkerEventResult result
) {
1122 DCHECK(ACTIVATING
== status() ||
1123 REDUNDANT
== status()) << status();
1124 TRACE_EVENT0("ServiceWorker",
1125 "ServiceWorkerVersion::OnActivateEventFinished");
1127 StatusCallback
* callback
= activate_callbacks_
.Lookup(request_id
);
1129 NOTREACHED() << "Got unexpected message: " << request_id
;
1132 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
1133 if (result
== blink::WebServiceWorkerEventResultRejected
||
1134 status() != ACTIVATING
) {
1135 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
1138 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1140 RemoveCallbackAndStopIfRedundant(&activate_callbacks_
, request_id
);
1143 void ServiceWorkerVersion::OnInstallEventFinished(
1145 blink::WebServiceWorkerEventResult result
) {
1146 // Status is REDUNDANT if the worker was doomed while handling the install
1147 // event, and finished handling before being terminated.
1148 DCHECK(status() == INSTALLING
|| status() == REDUNDANT
) << status();
1149 TRACE_EVENT0("ServiceWorker",
1150 "ServiceWorkerVersion::OnInstallEventFinished");
1152 StatusCallback
* callback
= install_callbacks_
.Lookup(request_id
);
1154 NOTREACHED() << "Got unexpected message: " << request_id
;
1157 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1158 if (result
== blink::WebServiceWorkerEventResultRejected
)
1159 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
1161 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1162 callback
->Run(status
);
1163 RemoveCallbackAndStopIfRedundant(&install_callbacks_
, request_id
);
1166 void ServiceWorkerVersion::OnFetchEventFinished(
1168 ServiceWorkerFetchEventResult result
,
1169 const ServiceWorkerResponse
& response
) {
1170 TRACE_EVENT1("ServiceWorker",
1171 "ServiceWorkerVersion::OnFetchEventFinished",
1172 "Request id", request_id
);
1173 FetchCallback
* callback
= fetch_callbacks_
.Lookup(request_id
);
1175 NOTREACHED() << "Got unexpected message: " << request_id
;
1179 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1180 callback
->Run(SERVICE_WORKER_OK
, result
, response
);
1181 RemoveCallbackAndStopIfRedundant(&fetch_callbacks_
, request_id
);
1184 void ServiceWorkerVersion::OnSyncEventFinished(
1186 TRACE_EVENT1("ServiceWorker",
1187 "ServiceWorkerVersion::OnSyncEventFinished",
1188 "Request id", request_id
);
1189 StatusCallback
* callback
= sync_callbacks_
.Lookup(request_id
);
1191 NOTREACHED() << "Got unexpected message: " << request_id
;
1195 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1196 callback
->Run(SERVICE_WORKER_OK
);
1197 RemoveCallbackAndStopIfRedundant(&sync_callbacks_
, request_id
);
1200 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1202 TRACE_EVENT1("ServiceWorker",
1203 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1204 "Request id", request_id
);
1205 StatusCallback
* callback
= notification_click_callbacks_
.Lookup(request_id
);
1207 NOTREACHED() << "Got unexpected message: " << request_id
;
1211 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1212 callback
->Run(SERVICE_WORKER_OK
);
1213 RemoveCallbackAndStopIfRedundant(¬ification_click_callbacks_
, request_id
);
1216 void ServiceWorkerVersion::OnPushEventFinished(
1218 blink::WebServiceWorkerEventResult result
) {
1219 TRACE_EVENT1("ServiceWorker",
1220 "ServiceWorkerVersion::OnPushEventFinished",
1221 "Request id", request_id
);
1222 StatusCallback
* callback
= push_callbacks_
.Lookup(request_id
);
1224 NOTREACHED() << "Got unexpected message: " << request_id
;
1227 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1228 if (result
== blink::WebServiceWorkerEventResultRejected
)
1229 status
= SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED
;
1231 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1232 callback
->Run(status
);
1233 RemoveCallbackAndStopIfRedundant(&push_callbacks_
, request_id
);
1236 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id
) {
1237 TRACE_EVENT1("ServiceWorker",
1238 "ServiceWorkerVersion::OnGeofencingEventFinished",
1241 StatusCallback
* callback
= geofencing_callbacks_
.Lookup(request_id
);
1243 NOTREACHED() << "Got unexpected message: " << request_id
;
1247 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1248 callback
->Run(SERVICE_WORKER_OK
);
1249 RemoveCallbackAndStopIfRedundant(&geofencing_callbacks_
, request_id
);
1252 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1254 bool accept_connection
) {
1255 TRACE_EVENT1("ServiceWorker",
1256 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1257 "Request id", request_id
);
1258 CrossOriginConnectCallback
* callback
=
1259 cross_origin_connect_callbacks_
.Lookup(request_id
);
1261 NOTREACHED() << "Got unexpected message: " << request_id
;
1265 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1266 callback
->Run(SERVICE_WORKER_OK
, accept_connection
);
1267 RemoveCallbackAndStopIfRedundant(&cross_origin_connect_callbacks_
,
1271 void ServiceWorkerVersion::OnOpenWindow(int request_id
, GURL url
) {
1272 // Just abort if we are shutting down.
1276 if (!url
.is_valid()) {
1277 DVLOG(1) << "Received unexpected invalid URL from renderer process.";
1278 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
1279 base::Bind(&KillEmbeddedWorkerProcess
,
1280 embedded_worker_
->process_id(),
1281 RESULT_CODE_KILLED_BAD_MESSAGE
));
1285 // The renderer treats all URLs in the about: scheme as being about:blank.
1286 // Canonicalize about: URLs to about:blank.
1287 if (url
.SchemeIs(url::kAboutScheme
))
1288 url
= GURL(url::kAboutBlankURL
);
1290 // Reject requests for URLs that the process is not allowed to access. It's
1291 // possible to receive such requests since the renderer-side checks are
1292 // slightly different. For example, the view-source scheme will not be
1293 // filtered out by Blink.
1294 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1295 embedded_worker_
->process_id(), url
)) {
1296 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(
1297 request_id
, url
.spec() + " cannot be opened."));
1301 BrowserThread::PostTask(
1302 BrowserThread::UI
, FROM_HERE
,
1303 base::Bind(&OpenWindowOnUI
,
1306 embedded_worker_
->process_id(),
1307 make_scoped_refptr(context_
->wrapper()),
1308 base::Bind(&ServiceWorkerVersion::DidOpenWindow
,
1309 weak_factory_
.GetWeakPtr(),
1313 void ServiceWorkerVersion::DidOpenWindow(int request_id
,
1314 int render_process_id
,
1315 int render_frame_id
) {
1316 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1318 if (running_status() != RUNNING
)
1321 if (render_process_id
== ChildProcessHost::kInvalidUniqueID
&&
1322 render_frame_id
== MSG_ROUTING_NONE
) {
1323 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(
1324 request_id
, "Something went wrong while trying to open the window."));
1329 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1330 !it
->IsAtEnd(); it
->Advance()) {
1331 ServiceWorkerProviderHost
* provider_host
= it
->GetProviderHost();
1332 if (provider_host
->process_id() != render_process_id
||
1333 provider_host
->frame_id() != render_frame_id
) {
1336 provider_host
->GetWindowClientInfo(base::Bind(
1337 &ServiceWorkerVersion::OnOpenWindowFinished
, weak_factory_
.GetWeakPtr(),
1338 request_id
, provider_host
->client_uuid()));
1342 // If here, it means that no provider_host was found, in which case, the
1343 // renderer should still be informed that the window was opened.
1344 OnOpenWindowFinished(request_id
, std::string(), ServiceWorkerClientInfo());
1347 void ServiceWorkerVersion::OnOpenWindowFinished(
1349 const std::string
& client_uuid
,
1350 const ServiceWorkerClientInfo
& client_info
) {
1351 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1353 if (running_status() != RUNNING
)
1356 ServiceWorkerClientInfo
client(client_info
);
1358 // If the |client_info| is empty, it means that the opened window wasn't
1359 // controlled but the action still succeeded. The renderer process is
1360 // expecting an empty client in such case.
1361 if (!client
.IsEmpty())
1362 client
.client_uuid
= client_uuid
;
1364 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1365 request_id
, client
));
1368 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL
& url
,
1369 const std::vector
<char>& data
) {
1370 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1371 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1372 "ServiceWorkerVersion::OnSetCachedMetadata",
1373 callback_id
, "URL", url
.spec());
1374 script_cache_map_
.WriteMetadata(
1375 url
, data
, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished
,
1376 weak_factory_
.GetWeakPtr(), callback_id
));
1379 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id
,
1381 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1382 "ServiceWorkerVersion::OnSetCachedMetadata",
1383 callback_id
, "result", result
);
1384 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1387 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL
& url
) {
1388 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1389 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1390 "ServiceWorkerVersion::OnClearCachedMetadata",
1391 callback_id
, "URL", url
.spec());
1392 script_cache_map_
.ClearMetadata(
1393 url
, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished
,
1394 weak_factory_
.GetWeakPtr(), callback_id
));
1397 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id
,
1399 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1400 "ServiceWorkerVersion::OnClearCachedMetadata",
1401 callback_id
, "result", result
);
1402 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1405 void ServiceWorkerVersion::OnPostMessageToClient(
1406 const std::string
& client_uuid
,
1407 const base::string16
& message
,
1408 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
1411 TRACE_EVENT1("ServiceWorker",
1412 "ServiceWorkerVersion::OnPostMessageToDocument",
1413 "Client id", client_uuid
);
1414 ServiceWorkerProviderHost
* provider_host
=
1415 context_
->GetProviderHostByClientID(client_uuid
);
1416 if (!provider_host
) {
1417 // The client may already have been closed, just ignore.
1420 if (provider_host
->document_url().GetOrigin() != script_url_
.GetOrigin()) {
1421 // The client does not belong to the same origin as this ServiceWorker,
1422 // possibly due to timing issue or bad message.
1425 provider_host
->PostMessage(message
, sent_message_ports
);
1428 void ServiceWorkerVersion::OnFocusClient(int request_id
,
1429 const std::string
& client_uuid
) {
1432 TRACE_EVENT2("ServiceWorker",
1433 "ServiceWorkerVersion::OnFocusClient",
1434 "Request id", request_id
,
1435 "Client id", client_uuid
);
1436 ServiceWorkerProviderHost
* provider_host
=
1437 context_
->GetProviderHostByClientID(client_uuid
);
1438 if (!provider_host
) {
1439 // The client may already have been closed, just ignore.
1442 if (provider_host
->document_url().GetOrigin() != script_url_
.GetOrigin()) {
1443 // The client does not belong to the same origin as this ServiceWorker,
1444 // possibly due to timing issue or bad message.
1447 provider_host
->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished
,
1448 weak_factory_
.GetWeakPtr(), request_id
,
1452 void ServiceWorkerVersion::OnFocusClientFinished(
1454 const std::string
& client_uuid
,
1455 const ServiceWorkerClientInfo
& client
) {
1456 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1458 if (running_status() != RUNNING
)
1461 ServiceWorkerClientInfo
client_info(client
);
1462 client_info
.client_uuid
= client_uuid
;
1464 embedded_worker_
->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1465 request_id
, client_info
));
1468 void ServiceWorkerVersion::OnSkipWaiting(int request_id
) {
1469 skip_waiting_
= true;
1470 if (status_
!= INSTALLED
)
1471 return DidSkipWaiting(request_id
);
1475 ServiceWorkerRegistration
* registration
=
1476 context_
->GetLiveRegistration(registration_id_
);
1479 pending_skip_waiting_requests_
.push_back(request_id
);
1480 if (pending_skip_waiting_requests_
.size() == 1)
1481 registration
->ActivateWaitingVersionWhenReady();
1484 void ServiceWorkerVersion::DidSkipWaiting(int request_id
) {
1485 if (running_status() == STARTING
|| running_status() == RUNNING
)
1486 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id
));
1489 void ServiceWorkerVersion::OnClaimClients(int request_id
) {
1490 if (status_
!= ACTIVATING
&& status_
!= ACTIVATED
) {
1491 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1492 request_id
, blink::WebServiceWorkerError::ErrorTypeState
,
1493 base::ASCIIToUTF16(kClaimClientsStateErrorMesage
)));
1497 if (ServiceWorkerRegistration
* registration
=
1498 context_
->GetLiveRegistration(registration_id_
)) {
1499 registration
->ClaimClients();
1500 embedded_worker_
->SendMessage(
1501 ServiceWorkerMsg_DidClaimClients(request_id
));
1506 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1507 request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
1508 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage
)));
1511 void ServiceWorkerVersion::OnPongFromWorker() {
1512 ClearTick(&ping_time_
);
1515 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1516 bool pause_after_download
,
1517 const StatusCallback
& callback
,
1518 ServiceWorkerStatusCode status
,
1519 const scoped_refptr
<ServiceWorkerRegistration
>& protect
) {
1520 if (status
!= SERVICE_WORKER_OK
|| is_redundant()) {
1521 RecordStartWorkerResult(status
);
1522 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
1526 switch (running_status()) {
1528 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
1533 if (start_callbacks_
.empty()) {
1534 start_callbacks_
.push_back(
1535 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult
,
1536 weak_factory_
.GetWeakPtr()));
1538 // Keep the live registration while starting the worker.
1539 start_callbacks_
.push_back(
1540 base::Bind(&RunStartWorkerCallback
, callback
, protect
));
1541 StartWorkerInternal(pause_after_download
);
1546 void ServiceWorkerVersion::StartWorkerInternal(bool pause_after_download
) {
1547 if (!timeout_timer_
.IsRunning())
1548 StartTimeoutTimer();
1549 if (running_status() == STOPPED
) {
1550 embedded_worker_
->Start(
1551 version_id_
, scope_
, script_url_
, pause_after_download
,
1552 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated
,
1553 weak_factory_
.GetWeakPtr()));
1557 void ServiceWorkerVersion::GetWindowClients(
1559 const ServiceWorkerClientQueryOptions
& options
) {
1560 DCHECK(options
.client_type
== blink::WebServiceWorkerClientTypeWindow
||
1561 options
.client_type
== blink::WebServiceWorkerClientTypeAll
);
1562 std::vector
<Tuple
<int, int, std::string
>> clients_info
;
1563 if (!options
.include_uncontrolled
) {
1564 for (auto& controllee
: controllee_map_
)
1565 AddWindowClient(controllee
.second
, &clients_info
);
1568 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1569 !it
->IsAtEnd(); it
->Advance()) {
1570 AddWindowClient(it
->GetProviderHost(), &clients_info
);
1574 if (clients_info
.empty()) {
1575 DidGetWindowClients(request_id
, options
,
1576 make_scoped_ptr(new ServiceWorkerClients
));
1580 BrowserThread::PostTask(
1581 BrowserThread::UI
, FROM_HERE
,
1582 base::Bind(&OnGetWindowClientsFromUI
, clients_info
, script_url_
,
1583 base::Bind(&ServiceWorkerVersion::DidGetWindowClients
,
1584 weak_factory_
.GetWeakPtr(), request_id
, options
)));
1587 void ServiceWorkerVersion::DidGetWindowClients(
1589 const ServiceWorkerClientQueryOptions
& options
,
1590 scoped_ptr
<ServiceWorkerClients
> clients
) {
1591 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1592 if (options
.client_type
== blink::WebServiceWorkerClientTypeAll
)
1593 GetNonWindowClients(request_id
, options
, clients
.get());
1594 OnGetClientsFinished(request_id
, *clients
);
1597 void ServiceWorkerVersion::GetNonWindowClients(
1599 const ServiceWorkerClientQueryOptions
& options
,
1600 ServiceWorkerClients
* clients
) {
1601 if (!options
.include_uncontrolled
) {
1602 for (auto& controllee
: controllee_map_
) {
1603 AddNonWindowClient(controllee
.second
, options
, clients
);
1607 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1608 !it
->IsAtEnd(); it
->Advance()) {
1609 AddNonWindowClient(it
->GetProviderHost(), options
, clients
);
1614 void ServiceWorkerVersion::StartTimeoutTimer() {
1615 DCHECK(!timeout_timer_
.IsRunning());
1617 if (embedded_worker_
->devtools_attached()) {
1618 // Don't record the startup time metric once DevTools is attached.
1619 ClearTick(&start_time_
);
1620 skip_recording_startup_time_
= true;
1622 RestartTick(&start_time_
);
1623 skip_recording_startup_time_
= false;
1626 ClearTick(&idle_time_
);
1627 ClearTick(&ping_time_
);
1628 ping_state_
= NOT_PINGING
;
1630 timeout_timer_
.Start(FROM_HERE
,
1631 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds
),
1632 this, &ServiceWorkerVersion::OnTimeoutTimer
);
1635 void ServiceWorkerVersion::StopTimeoutTimer() {
1636 timeout_timer_
.Stop();
1639 void ServiceWorkerVersion::OnTimeoutTimer() {
1640 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
||
1641 running_status() == STOPPING
)
1642 << running_status();
1644 // Starting a worker hasn't finished within a certain period.
1645 if (GetTickDuration(start_time_
) >
1646 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes
)) {
1647 DCHECK(running_status() == STARTING
|| running_status() == STOPPING
)
1648 << running_status();
1649 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1650 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_ERROR_TIMEOUT
);
1651 if (running_status() == STARTING
)
1652 embedded_worker_
->Stop();
1656 // Requests have not finished within a certain period.
1657 bool request_timed_out
= false;
1658 while (!requests_
.empty()) {
1659 RequestInfo info
= requests_
.front();
1660 if (GetTickDuration(info
.time
) <
1661 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes
))
1663 if (OnRequestTimeout(info
))
1664 request_timed_out
= true;
1667 if (request_timed_out
&& running_status() != STOPPING
)
1668 embedded_worker_
->Stop();
1670 // For the timeouts below, there are no callbacks to timeout so there is
1671 // nothing more to do if the worker is already stopping.
1672 if (running_status() == STOPPING
)
1675 // The worker has been idle for longer than a certain period.
1676 if (GetTickDuration(idle_time_
) >
1677 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds
)) {
1682 // The worker hasn't responded to ping within a certain period.
1683 if (GetTickDuration(ping_time_
) >
1684 base::TimeDelta::FromSeconds(kPingTimeoutSeconds
)) {
1689 if (ping_state_
== PINGING
&& ping_time_
.is_null())
1693 void ServiceWorkerVersion::PingWorker() {
1694 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
);
1695 DCHECK_EQ(PINGING
, ping_state_
);
1696 ServiceWorkerStatusCode status
=
1697 embedded_worker_
->SendMessage(ServiceWorkerMsg_Ping());
1698 if (status
!= SERVICE_WORKER_OK
) {
1699 // TODO(falken): Maybe try resending Ping a few times first?
1700 ping_state_
= PING_TIMED_OUT
;
1704 RestartTick(&ping_time_
);
1707 void ServiceWorkerVersion::OnPingTimeout() {
1708 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
);
1709 ping_state_
= PING_TIMED_OUT
;
1710 // TODO(falken): Show a message to the developer that the SW was stopped due
1711 // to timeout (crbug.com/457968). Also, change the error code to
1712 // SERVICE_WORKER_ERROR_TIMEOUT.
1716 void ServiceWorkerVersion::StopWorkerIfIdle() {
1717 if (HasInflightRequests() && ping_state_
!= PING_TIMED_OUT
)
1719 if (running_status() == STOPPED
|| running_status() == STOPPING
||
1720 !stop_callbacks_
.empty()) {
1724 // TODO(falken): We may need to handle StopIfIdle failure and
1725 // forcibly fail pending callbacks so no one is stuck waiting
1727 embedded_worker_
->StopIfIdle();
1730 bool ServiceWorkerVersion::HasInflightRequests() const {
1732 !activate_callbacks_
.IsEmpty() ||
1733 !install_callbacks_
.IsEmpty() ||
1734 !fetch_callbacks_
.IsEmpty() ||
1735 !sync_callbacks_
.IsEmpty() ||
1736 !notification_click_callbacks_
.IsEmpty() ||
1737 !push_callbacks_
.IsEmpty() ||
1738 !geofencing_callbacks_
.IsEmpty() ||
1739 !cross_origin_connect_callbacks_
.IsEmpty() ||
1740 !streaming_url_request_jobs_
.empty();
1743 void ServiceWorkerVersion::RecordStartWorkerResult(
1744 ServiceWorkerStatusCode status
) {
1745 base::TimeTicks start_time
= start_time_
;
1746 ClearTick(&start_time_
);
1748 // Failing to start a redundant worker isn't interesting and very common when
1749 // update dooms because the script is byte-to-byte identical.
1753 ServiceWorkerMetrics::RecordStartWorkerStatus(status
, IsInstalled(status_
));
1755 if (status
== SERVICE_WORKER_OK
&& !start_time
.is_null() &&
1756 !skip_recording_startup_time_
) {
1757 ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time
),
1758 IsInstalled(status_
));
1761 if (status
!= SERVICE_WORKER_ERROR_TIMEOUT
)
1763 EmbeddedWorkerInstance::StartingPhase phase
=
1764 EmbeddedWorkerInstance::NOT_STARTING
;
1765 EmbeddedWorkerInstance::Status running_status
= embedded_worker_
->status();
1766 // Build an artifical JavaScript exception to show in the ServiceWorker
1767 // log for developers; it's not user-facing so it's not a localized resource.
1768 std::string message
= "ServiceWorker startup timed out. ";
1769 if (running_status
!= EmbeddedWorkerInstance::STARTING
) {
1770 message
.append("The worker had unexpected status: ");
1771 message
.append(EmbeddedWorkerInstance::StatusToString(running_status
));
1773 phase
= embedded_worker_
->starting_phase();
1774 message
.append("The worker was in startup phase: ");
1775 message
.append(EmbeddedWorkerInstance::StartingPhaseToString(phase
));
1777 message
.append(".");
1778 OnReportException(base::UTF8ToUTF16(message
), -1, -1, GURL());
1779 DVLOG(1) << message
;
1780 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
1782 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE
);
1785 template <typename IDMAP
>
1786 void ServiceWorkerVersion::RemoveCallbackAndStopIfRedundant(IDMAP
* callbacks
,
1788 RestartTick(&idle_time_
);
1789 callbacks
->Remove(request_id
);
1790 if (is_redundant()) {
1791 // The stop should be already scheduled, but try to stop immediately, in
1792 // order to release worker resources soon.
1797 template <typename CallbackType
>
1798 int ServiceWorkerVersion::AddRequest(
1799 const CallbackType
& callback
,
1800 IDMap
<CallbackType
, IDMapOwnPointer
>* callback_map
,
1801 RequestType request_type
) {
1802 int request_id
= callback_map
->Add(new CallbackType(callback
));
1803 requests_
.push(RequestInfo(request_id
, request_type
));
1807 bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo
& info
) {
1808 switch (info
.type
) {
1809 case REQUEST_ACTIVATE
:
1810 return RunIDMapCallback(&activate_callbacks_
, info
.id
,
1811 SERVICE_WORKER_ERROR_TIMEOUT
);
1812 case REQUEST_INSTALL
:
1813 return RunIDMapCallback(&install_callbacks_
, info
.id
,
1814 SERVICE_WORKER_ERROR_TIMEOUT
);
1816 return RunIDMapCallback(
1817 &fetch_callbacks_
, info
.id
, SERVICE_WORKER_ERROR_TIMEOUT
,
1818 /* The other args are ignored for non-OK status. */
1819 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
, ServiceWorkerResponse());
1821 return RunIDMapCallback(&sync_callbacks_
, info
.id
,
1822 SERVICE_WORKER_ERROR_TIMEOUT
);
1823 case REQUEST_NOTIFICATION_CLICK
:
1824 return RunIDMapCallback(¬ification_click_callbacks_
, info
.id
,
1825 SERVICE_WORKER_ERROR_TIMEOUT
);
1827 return RunIDMapCallback(&push_callbacks_
, info
.id
,
1828 SERVICE_WORKER_ERROR_TIMEOUT
);
1829 case REQUEST_GEOFENCING
:
1830 return RunIDMapCallback(&geofencing_callbacks_
, info
.id
,
1831 SERVICE_WORKER_ERROR_TIMEOUT
);
1832 case REQUEST_CROSS_ORIGIN_CONNECT
:
1833 return RunIDMapCallback(&cross_origin_connect_callbacks_
, info
.id
,
1834 SERVICE_WORKER_ERROR_TIMEOUT
,
1835 false /* accept_connection */);
1837 NOTREACHED() << "Got unexpected request type: " << info
.type
;
1841 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks
& ticks
) {
1842 std::queue
<RequestInfo
> new_requests
;
1843 while (!requests_
.empty()) {
1844 RequestInfo info
= requests_
.front();
1846 new_requests
.push(info
);
1849 requests_
= new_requests
;
1852 ServiceWorkerStatusCode
ServiceWorkerVersion::DeduceStartWorkerFailureReason(
1853 ServiceWorkerStatusCode default_code
) {
1854 if (ping_state_
== PING_TIMED_OUT
)
1855 return SERVICE_WORKER_ERROR_TIMEOUT
;
1857 const net::URLRequestStatus
& main_script_status
=
1858 script_cache_map()->main_script_status();
1859 if (main_script_status
.status() != net::URLRequestStatus::SUCCESS
) {
1860 switch (main_script_status
.error()) {
1861 case net::ERR_INSECURE_RESPONSE
:
1862 case net::ERR_UNSAFE_REDIRECT
:
1863 return SERVICE_WORKER_ERROR_SECURITY
;
1864 case net::ERR_ABORTED
:
1865 return SERVICE_WORKER_ERROR_ABORT
;
1867 return SERVICE_WORKER_ERROR_NETWORK
;
1871 return default_code
;
1874 } // namespace content