ServiceWorker: Stop exposing ServiceWorkerContextCore
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blobf0a9c17cb8e6582480cc6fae6247875e000be337
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"
41 namespace content {
43 using StatusCallback = ServiceWorkerVersion::StatusCallback;
44 using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
45 using GetClientsCallback =
46 base::Callback<void(scoped_ptr<ServiceWorkerClients>)>;
48 namespace {
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,
80 const Arg& arg) {
81 CallbackArray callbacks;
82 callbacks.swap(*callbacks_ptr);
83 scoped_refptr<ServiceWorkerVersion> protect(version);
84 for (const auto& callback : callbacks)
85 callback.Run(arg);
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...);
93 iter.Advance();
95 callbacks->Clear();
98 template <typename CallbackType, typename... Params>
99 bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* callbacks,
100 int request_id,
101 const Params&... params) {
102 CallbackType* callback = callbacks->Lookup(request_id);
103 if (!callback)
104 return false;
106 callback->Run(params...);
107 callbacks->Remove(request_id);
108 return true;
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);
127 return;
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);
135 return;
137 task.Run();
140 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
141 ServiceWorkerStatusCode status) {
142 callback.Run(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 {
173 public:
174 WindowOpenedObserver(WebContents* web_contents,
175 const WindowOpenedCallback& callback)
176 : WebContentsObserver(web_contents),
177 callback_(callback)
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())
187 return;
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);
201 private:
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_,
210 render_process_id,
211 render_frame_id));
212 Observe(nullptr);
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);
228 void OpenWindowOnUI(
229 const GURL& url,
230 const GURL& script_url,
231 int process_id,
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()
238 : nullptr;
239 // We are shutting down.
240 if (!browser_context)
241 return;
243 RenderProcessHost* render_process_host =
244 RenderProcessHost::FromID(process_id);
245 if (render_process_host->IsIsolatedGuest()) {
246 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
247 base::Bind(callback,
248 ChildProcessHost::kInvalidUniqueID,
249 MSG_ROUTING_NONE));
250 return;
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) {
283 if (time.is_null())
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),
298 get<1>(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.
304 if (info.IsEmpty())
305 continue;
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())
311 continue;
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)
324 return;
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)
334 return;
335 if (options.client_type != blink::WebServiceWorkerClientTypeAll &&
336 options.client_type != host_client_type)
337 return;
339 ServiceWorkerClientInfo client_info(
340 blink::WebPageVisibilityStateHidden,
341 false, // is_focused
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) {
348 switch (status) {
349 case ServiceWorkerVersion::NEW:
350 case ServiceWorkerVersion::INSTALLING:
351 case ServiceWorkerVersion::REDUNDANT:
352 return false;
353 case ServiceWorkerVersion::INSTALLED:
354 case ServiceWorkerVersion::ACTIVATING:
355 case ServiceWorkerVersion::ACTIVATED:
356 return true;
358 NOTREACHED() << "Unexpected status: " << status;
359 return false;
362 } // namespace
364 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
365 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
367 ServiceWorkerVersion::ServiceWorkerVersion(
368 ServiceWorkerRegistration* registration,
369 const GURL& script_url,
370 int64 version_id,
371 base::WeakPtr<ServiceWorkerContextCore> context)
372 : version_id_(version_id),
373 registration_id_(kInvalidServiceWorkerVersionId),
374 script_url_(script_url),
375 status_(NEW),
376 context_(context),
377 script_cache_map_(this, context),
378 ping_state_(NOT_PINGING),
379 weak_factory_(this) {
380 DCHECK(context_);
381 DCHECK(registration);
382 if (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);
402 if (context_)
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)
409 return;
411 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)
422 callback.Run();
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_)
439 return 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);
444 return info;
447 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
448 StartWorker(false, callback);
451 void ServiceWorkerVersion::StartWorker(
452 bool pause_after_download,
453 const StatusCallback& callback) {
454 if (!context_) {
455 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
456 return;
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(
462 registration_id_,
463 scope_.GetOrigin(),
464 base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
465 weak_factory_.GetWeakPtr(),
466 pause_after_download,
467 callback));
470 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
471 if (running_status() == STOPPED) {
472 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
473 return;
475 if (stop_callbacks_.empty()) {
476 ServiceWorkerStatusCode status = embedded_worker_->Stop();
477 if (status != SERVICE_WORKER_OK) {
478 RunSoon(base::Bind(callback, status));
479 return;
482 stop_callbacks_.push_back(callback);
485 void ServiceWorkerVersion::ScheduleUpdate() {
486 if (update_timer_.IsRunning()) {
487 update_timer_.Reset();
488 return;
490 update_timer_.Start(
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();
503 if (!context_)
504 return;
505 ServiceWorkerRegistration* registration =
506 context_->GetLiveRegistration(registration_id_);
507 if (!registration || !registration->GetNewestVersion())
508 return;
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,
534 callback)));
535 return;
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.
554 StartWorker(
555 base::Bind(&RunTaskAfterStartWorker,
556 weak_factory_.GetWeakPtr(),
557 callback,
558 base::Bind(&self::DispatchInstallEventAfterStartWorker,
559 weak_factory_.GetWeakPtr(),
560 callback)));
561 } else {
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.
572 StartWorker(
573 base::Bind(&RunTaskAfterStartWorker,
574 weak_factory_.GetWeakPtr(),
575 callback,
576 base::Bind(&self::DispatchActivateEventAfterStartWorker,
577 weak_factory_.GetWeakPtr(),
578 callback)));
579 } else {
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(),
597 request,
598 prepare_callback,
599 fetch_callback)));
600 return;
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,
611 fetch_callback,
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);
622 return;
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(),
631 callback)));
632 return;
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)));
656 return;
659 int request_id = AddRequest(callback, &notification_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(),
679 callback, data)));
680 return;
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);
702 return;
705 if (running_status() != RUNNING) {
706 // Schedule calling this method after starting the worker.
707 StartWorker(base::Bind(&RunTaskAfterStartWorker,
708 weak_factory_.GetWeakPtr(),
709 callback,
710 base::Bind(&self::DispatchGeofencingEvent,
711 weak_factory_.GetWeakPtr(),
712 callback,
713 event_type,
714 region_id,
715 region)));
716 return;
719 int request_id =
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);
738 return;
741 if (running_status() != RUNNING) {
742 // Schedule calling this method after starting the worker.
743 StartWorker(
744 base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
745 base::Bind(&RunErrorCrossOriginConnectCallback, callback),
746 base::Bind(&self::DispatchCrossOriginConnectEvent,
747 weak_factory_.GetWeakPtr(), callback, client)));
748 return;
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
768 // here again.
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)));
778 return;
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);
806 if (HasControllee())
807 return;
808 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
809 if (is_doomed_) {
810 DoomInternal();
811 return;
815 void ServiceWorkerVersion::AddStreamingURLRequestJob(
816 const ServiceWorkerURLRequestJob* request_job) {
817 DCHECK(streaming_url_request_jobs_.find(request_job) ==
818 streaming_url_request_jobs_.end());
819 streaming_url_request_jobs_.insert(request_job);
822 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
823 const ServiceWorkerURLRequestJob* request_job) {
824 streaming_url_request_jobs_.erase(request_job);
825 if (is_doomed_)
826 StopWorkerIfIdle();
829 void ServiceWorkerVersion::AddListener(Listener* listener) {
830 listeners_.AddObserver(listener);
833 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
834 listeners_.RemoveObserver(listener);
837 void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status,
838 const std::string& status_message) {
839 if (status_message.empty()) {
840 OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status)),
841 -1, -1, GURL());
842 } else {
843 OnReportException(base::UTF8ToUTF16(status_message), -1, -1, GURL());
847 void ServiceWorkerVersion::Doom() {
848 if (is_doomed_)
849 return;
850 is_doomed_ = true;
851 if (!HasControllee())
852 DoomInternal();
855 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
856 embedded_worker()->set_devtools_attached(attached);
857 if (attached) {
858 // TODO(falken): Canceling the timeouts when debugging could cause
859 // heisenbugs; we should instead run them as normal show an educational
860 // message in DevTools when they occur. crbug.com/470419
862 // Don't record the startup time metric once DevTools is attached.
863 ClearTick(&start_time_);
864 skip_recording_startup_time_ = true;
866 // Cancel request timeouts.
867 SetAllRequestTimes(base::TimeTicks());
868 return;
870 if (!start_callbacks_.empty()) {
871 // Reactivate the timer for start timeout.
872 DCHECK(timeout_timer_.IsRunning());
873 DCHECK(running_status() == STARTING || running_status() == STOPPING)
874 << running_status();
875 RestartTick(&start_time_);
878 // Reactivate request timeouts.
879 SetAllRequestTimes(base::TimeTicks::Now());
882 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
883 const net::HttpResponseInfo& http_info) {
884 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
885 FOR_EACH_OBSERVER(Listener, listeners_,
886 OnMainScriptHttpResponseInfoSet(this));
889 const net::HttpResponseInfo*
890 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
891 return main_script_http_info_.get();
894 ServiceWorkerVersion::RequestInfo::RequestInfo(int id, RequestType type)
895 : id(id), type(type), time(base::TimeTicks::Now()) {
898 ServiceWorkerVersion::RequestInfo::~RequestInfo() {
901 void ServiceWorkerVersion::OnScriptLoaded() {
902 DCHECK_EQ(STARTING, running_status());
903 // Activate ping/pong now that JavaScript execution will start.
904 ping_state_ = PINGING;
907 void ServiceWorkerVersion::OnStarting() {
908 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
911 void ServiceWorkerVersion::OnStarted() {
912 DCHECK_EQ(RUNNING, running_status());
913 RestartTick(&idle_time_);
915 // Fire all start callbacks.
916 scoped_refptr<ServiceWorkerVersion> protect(this);
917 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
918 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
921 void ServiceWorkerVersion::OnStopping() {
922 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
925 void ServiceWorkerVersion::OnStopped(
926 EmbeddedWorkerInstance::Status old_status) {
927 DCHECK_EQ(STOPPED, running_status());
928 scoped_refptr<ServiceWorkerVersion> protect(this);
930 bool should_restart = !is_doomed() && !start_callbacks_.empty() &&
931 (old_status != EmbeddedWorkerInstance::STARTING);
933 StopTimeoutTimer();
934 if (ping_state_ == PING_TIMED_OUT)
935 should_restart = false;
937 // Fire all stop callbacks.
938 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
940 if (!should_restart) {
941 // Let all start callbacks fail.
942 RunCallbacks(this, &start_callbacks_,
943 DeduceStartWorkerFailureReason(
944 SERVICE_WORKER_ERROR_START_WORKER_FAILED));
947 // Let all message callbacks fail (this will also fire and clear all
948 // callbacks for events).
949 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
950 RunIDMapCallbacks(&activate_callbacks_,
951 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
952 RunIDMapCallbacks(&install_callbacks_,
953 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
954 RunIDMapCallbacks(&fetch_callbacks_,
955 SERVICE_WORKER_ERROR_FAILED,
956 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
957 ServiceWorkerResponse());
958 RunIDMapCallbacks(&sync_callbacks_,
959 SERVICE_WORKER_ERROR_FAILED);
960 RunIDMapCallbacks(&notification_click_callbacks_,
961 SERVICE_WORKER_ERROR_FAILED);
962 RunIDMapCallbacks(&push_callbacks_,
963 SERVICE_WORKER_ERROR_FAILED);
964 RunIDMapCallbacks(&geofencing_callbacks_,
965 SERVICE_WORKER_ERROR_FAILED);
966 RunIDMapCallbacks(&cross_origin_connect_callbacks_,
967 SERVICE_WORKER_ERROR_FAILED,
968 false);
970 streaming_url_request_jobs_.clear();
972 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
974 // Restart worker if we have any start callbacks and the worker isn't doomed.
975 if (should_restart)
976 StartWorkerInternal(false /* pause_after_download */);
979 void ServiceWorkerVersion::OnReportException(
980 const base::string16& error_message,
981 int line_number,
982 int column_number,
983 const GURL& source_url) {
984 FOR_EACH_OBSERVER(
985 Listener,
986 listeners_,
987 OnErrorReported(
988 this, error_message, line_number, column_number, source_url));
991 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
992 int message_level,
993 const base::string16& message,
994 int line_number,
995 const GURL& source_url) {
996 FOR_EACH_OBSERVER(Listener,
997 listeners_,
998 OnReportConsoleMessage(this,
999 source_identifier,
1000 message_level,
1001 message,
1002 line_number,
1003 source_url));
1006 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
1007 bool handled = true;
1008 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
1009 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
1010 OnGetClients)
1011 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
1012 OnActivateEventFinished)
1013 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
1014 OnInstallEventFinished)
1015 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
1016 OnFetchEventFinished)
1017 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
1018 OnSyncEventFinished)
1019 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
1020 OnNotificationClickEventFinished)
1021 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
1022 OnPushEventFinished)
1023 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
1024 OnGeofencingEventFinished)
1025 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
1026 OnCrossOriginConnectEventFinished)
1027 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
1028 OnOpenWindow)
1029 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
1030 OnSetCachedMetadata)
1031 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata,
1032 OnClearCachedMetadata)
1033 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient,
1034 OnPostMessageToClient)
1035 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
1036 OnFocusClient)
1037 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
1038 OnSkipWaiting)
1039 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
1040 OnClaimClients)
1041 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
1042 IPC_MESSAGE_UNHANDLED(handled = false)
1043 IPC_END_MESSAGE_MAP()
1044 return handled;
1047 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
1048 ServiceWorkerStatusCode status) {
1049 if (status != SERVICE_WORKER_OK) {
1050 RunCallbacks(this, &start_callbacks_,
1051 DeduceStartWorkerFailureReason(status));
1055 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
1056 const StatusCallback& callback) {
1057 DCHECK_EQ(RUNNING, running_status())
1058 << "Worker stopped too soon after it was started.";
1060 int request_id = AddRequest(callback, &install_callbacks_, REQUEST_INSTALL);
1061 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
1062 ServiceWorkerMsg_InstallEvent(request_id));
1063 if (status != SERVICE_WORKER_OK) {
1064 install_callbacks_.Remove(request_id);
1065 RunSoon(base::Bind(callback, status));
1069 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
1070 const StatusCallback& callback) {
1071 DCHECK_EQ(RUNNING, running_status())
1072 << "Worker stopped too soon after it was started.";
1074 int request_id = AddRequest(callback, &activate_callbacks_, REQUEST_ACTIVATE);
1075 ServiceWorkerStatusCode status =
1076 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
1077 if (status != SERVICE_WORKER_OK) {
1078 activate_callbacks_.Remove(request_id);
1079 RunSoon(base::Bind(callback, status));
1083 void ServiceWorkerVersion::OnGetClients(
1084 int request_id,
1085 const ServiceWorkerClientQueryOptions& options) {
1086 TRACE_EVENT_ASYNC_BEGIN2(
1087 "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id,
1088 "client_type", options.client_type, "include_uncontrolled",
1089 options.include_uncontrolled);
1091 if (controllee_map_.empty() && !options.include_uncontrolled) {
1092 OnGetClientsFinished(request_id, std::vector<ServiceWorkerClientInfo>());
1093 return;
1096 // For Window clients we want to query the info on the UI thread first.
1097 if (options.client_type == blink::WebServiceWorkerClientTypeWindow ||
1098 options.client_type == blink::WebServiceWorkerClientTypeAll) {
1099 GetWindowClients(request_id, options);
1100 return;
1103 ServiceWorkerClients clients;
1104 GetNonWindowClients(request_id, options, &clients);
1105 OnGetClientsFinished(request_id, clients);
1108 void ServiceWorkerVersion::OnGetClientsFinished(
1109 int request_id,
1110 const ServiceWorkerClients& clients) {
1111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1112 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
1113 request_id, "The number of clients", clients.size());
1115 if (running_status() != RUNNING)
1116 return;
1117 embedded_worker_->SendMessage(
1118 ServiceWorkerMsg_DidGetClients(request_id, clients));
1121 void ServiceWorkerVersion::OnActivateEventFinished(
1122 int request_id,
1123 blink::WebServiceWorkerEventResult result) {
1124 DCHECK(ACTIVATING == status() ||
1125 REDUNDANT == status()) << status();
1126 TRACE_EVENT0("ServiceWorker",
1127 "ServiceWorkerVersion::OnActivateEventFinished");
1129 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
1130 if (!callback) {
1131 NOTREACHED() << "Got unexpected message: " << request_id;
1132 return;
1134 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
1135 if (result == blink::WebServiceWorkerEventResultRejected ||
1136 status() != ACTIVATING) {
1137 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
1140 scoped_refptr<ServiceWorkerVersion> protect(this);
1141 callback->Run(rv);
1142 RemoveCallbackAndStopIfDoomed(&activate_callbacks_, request_id);
1145 void ServiceWorkerVersion::OnInstallEventFinished(
1146 int request_id,
1147 blink::WebServiceWorkerEventResult result) {
1148 // Status is REDUNDANT if the worker was doomed while handling the install
1149 // event, and finished handling before being terminated.
1150 DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
1151 TRACE_EVENT0("ServiceWorker",
1152 "ServiceWorkerVersion::OnInstallEventFinished");
1154 StatusCallback* callback = install_callbacks_.Lookup(request_id);
1155 if (!callback) {
1156 NOTREACHED() << "Got unexpected message: " << request_id;
1157 return;
1159 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1160 if (result == blink::WebServiceWorkerEventResultRejected)
1161 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
1163 scoped_refptr<ServiceWorkerVersion> protect(this);
1164 callback->Run(status);
1165 RemoveCallbackAndStopIfDoomed(&install_callbacks_, request_id);
1168 void ServiceWorkerVersion::OnFetchEventFinished(
1169 int request_id,
1170 ServiceWorkerFetchEventResult result,
1171 const ServiceWorkerResponse& response) {
1172 TRACE_EVENT1("ServiceWorker",
1173 "ServiceWorkerVersion::OnFetchEventFinished",
1174 "Request id", request_id);
1175 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
1176 if (!callback) {
1177 NOTREACHED() << "Got unexpected message: " << request_id;
1178 return;
1181 scoped_refptr<ServiceWorkerVersion> protect(this);
1182 callback->Run(SERVICE_WORKER_OK, result, response);
1183 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_, request_id);
1186 void ServiceWorkerVersion::OnSyncEventFinished(
1187 int request_id) {
1188 TRACE_EVENT1("ServiceWorker",
1189 "ServiceWorkerVersion::OnSyncEventFinished",
1190 "Request id", request_id);
1191 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
1192 if (!callback) {
1193 NOTREACHED() << "Got unexpected message: " << request_id;
1194 return;
1197 scoped_refptr<ServiceWorkerVersion> protect(this);
1198 callback->Run(SERVICE_WORKER_OK);
1199 RemoveCallbackAndStopIfDoomed(&sync_callbacks_, request_id);
1202 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1203 int request_id) {
1204 TRACE_EVENT1("ServiceWorker",
1205 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1206 "Request id", request_id);
1207 StatusCallback* callback = notification_click_callbacks_.Lookup(request_id);
1208 if (!callback) {
1209 NOTREACHED() << "Got unexpected message: " << request_id;
1210 return;
1213 scoped_refptr<ServiceWorkerVersion> protect(this);
1214 callback->Run(SERVICE_WORKER_OK);
1215 RemoveCallbackAndStopIfDoomed(&notification_click_callbacks_, request_id);
1218 void ServiceWorkerVersion::OnPushEventFinished(
1219 int request_id,
1220 blink::WebServiceWorkerEventResult result) {
1221 TRACE_EVENT1("ServiceWorker",
1222 "ServiceWorkerVersion::OnPushEventFinished",
1223 "Request id", request_id);
1224 StatusCallback* callback = push_callbacks_.Lookup(request_id);
1225 if (!callback) {
1226 NOTREACHED() << "Got unexpected message: " << request_id;
1227 return;
1229 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1230 if (result == blink::WebServiceWorkerEventResultRejected)
1231 status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
1233 scoped_refptr<ServiceWorkerVersion> protect(this);
1234 callback->Run(status);
1235 RemoveCallbackAndStopIfDoomed(&push_callbacks_, request_id);
1238 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
1239 TRACE_EVENT1("ServiceWorker",
1240 "ServiceWorkerVersion::OnGeofencingEventFinished",
1241 "Request id",
1242 request_id);
1243 StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
1244 if (!callback) {
1245 NOTREACHED() << "Got unexpected message: " << request_id;
1246 return;
1249 scoped_refptr<ServiceWorkerVersion> protect(this);
1250 callback->Run(SERVICE_WORKER_OK);
1251 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_, request_id);
1254 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1255 int request_id,
1256 bool accept_connection) {
1257 TRACE_EVENT1("ServiceWorker",
1258 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1259 "Request id", request_id);
1260 CrossOriginConnectCallback* callback =
1261 cross_origin_connect_callbacks_.Lookup(request_id);
1262 if (!callback) {
1263 NOTREACHED() << "Got unexpected message: " << request_id;
1264 return;
1267 scoped_refptr<ServiceWorkerVersion> protect(this);
1268 callback->Run(SERVICE_WORKER_OK, accept_connection);
1269 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_, request_id);
1272 void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
1273 // Just abort if we are shutting down.
1274 if (!context_)
1275 return;
1277 if (!url.is_valid()) {
1278 DVLOG(1) << "Received unexpected invalid URL from renderer process.";
1279 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1280 base::Bind(&KillEmbeddedWorkerProcess,
1281 embedded_worker_->process_id(),
1282 RESULT_CODE_KILLED_BAD_MESSAGE));
1283 return;
1286 // The renderer treats all URLs in the about: scheme as being about:blank.
1287 // Canonicalize about: URLs to about:blank.
1288 if (url.SchemeIs(url::kAboutScheme))
1289 url = GURL(url::kAboutBlankURL);
1291 // Reject requests for URLs that the process is not allowed to access. It's
1292 // possible to receive such requests since the renderer-side checks are
1293 // slightly different. For example, the view-source scheme will not be
1294 // filtered out by Blink.
1295 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1296 embedded_worker_->process_id(), url)) {
1297 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1298 request_id, url.spec() + " cannot be opened."));
1299 return;
1302 BrowserThread::PostTask(
1303 BrowserThread::UI, FROM_HERE,
1304 base::Bind(&OpenWindowOnUI,
1305 url,
1306 script_url_,
1307 embedded_worker_->process_id(),
1308 make_scoped_refptr(context_->wrapper()),
1309 base::Bind(&ServiceWorkerVersion::DidOpenWindow,
1310 weak_factory_.GetWeakPtr(),
1311 request_id)));
1314 void ServiceWorkerVersion::DidOpenWindow(int request_id,
1315 int render_process_id,
1316 int render_frame_id) {
1317 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1319 if (running_status() != RUNNING)
1320 return;
1322 if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
1323 render_frame_id == MSG_ROUTING_NONE) {
1324 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1325 request_id, "Something went wrong while trying to open the window."));
1326 return;
1329 for (auto it =
1330 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1331 !it->IsAtEnd(); it->Advance()) {
1332 ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
1333 if (provider_host->process_id() != render_process_id ||
1334 provider_host->frame_id() != render_frame_id) {
1335 continue;
1337 provider_host->GetWindowClientInfo(base::Bind(
1338 &ServiceWorkerVersion::OnOpenWindowFinished, weak_factory_.GetWeakPtr(),
1339 request_id, provider_host->client_uuid()));
1340 return;
1343 // If here, it means that no provider_host was found, in which case, the
1344 // renderer should still be informed that the window was opened.
1345 OnOpenWindowFinished(request_id, std::string(), ServiceWorkerClientInfo());
1348 void ServiceWorkerVersion::OnOpenWindowFinished(
1349 int request_id,
1350 const std::string& client_uuid,
1351 const ServiceWorkerClientInfo& client_info) {
1352 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1354 if (running_status() != RUNNING)
1355 return;
1357 ServiceWorkerClientInfo client(client_info);
1359 // If the |client_info| is empty, it means that the opened window wasn't
1360 // controlled but the action still succeeded. The renderer process is
1361 // expecting an empty client in such case.
1362 if (!client.IsEmpty())
1363 client.client_uuid = client_uuid;
1365 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1366 request_id, client));
1369 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
1370 const std::vector<char>& data) {
1371 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1372 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1373 "ServiceWorkerVersion::OnSetCachedMetadata",
1374 callback_id, "URL", url.spec());
1375 script_cache_map_.WriteMetadata(
1376 url, data, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
1377 weak_factory_.GetWeakPtr(), callback_id));
1380 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id,
1381 int result) {
1382 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1383 "ServiceWorkerVersion::OnSetCachedMetadata",
1384 callback_id, "result", result);
1385 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1388 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL& url) {
1389 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1390 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1391 "ServiceWorkerVersion::OnClearCachedMetadata",
1392 callback_id, "URL", url.spec());
1393 script_cache_map_.ClearMetadata(
1394 url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
1395 weak_factory_.GetWeakPtr(), callback_id));
1398 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id,
1399 int result) {
1400 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1401 "ServiceWorkerVersion::OnClearCachedMetadata",
1402 callback_id, "result", result);
1403 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1406 void ServiceWorkerVersion::OnPostMessageToClient(
1407 const std::string& client_uuid,
1408 const base::string16& message,
1409 const std::vector<TransferredMessagePort>& sent_message_ports) {
1410 if (!context_)
1411 return;
1412 TRACE_EVENT1("ServiceWorker",
1413 "ServiceWorkerVersion::OnPostMessageToDocument",
1414 "Client id", client_uuid);
1415 ServiceWorkerProviderHost* provider_host =
1416 context_->GetProviderHostByClientID(client_uuid);
1417 if (!provider_host) {
1418 // The client may already have been closed, just ignore.
1419 return;
1421 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1422 // The client does not belong to the same origin as this ServiceWorker,
1423 // possibly due to timing issue or bad message.
1424 return;
1426 provider_host->PostMessage(message, sent_message_ports);
1429 void ServiceWorkerVersion::OnFocusClient(int request_id,
1430 const std::string& client_uuid) {
1431 if (!context_)
1432 return;
1433 TRACE_EVENT2("ServiceWorker",
1434 "ServiceWorkerVersion::OnFocusClient",
1435 "Request id", request_id,
1436 "Client id", client_uuid);
1437 ServiceWorkerProviderHost* provider_host =
1438 context_->GetProviderHostByClientID(client_uuid);
1439 if (!provider_host) {
1440 // The client may already have been closed, just ignore.
1441 return;
1443 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1444 // The client does not belong to the same origin as this ServiceWorker,
1445 // possibly due to timing issue or bad message.
1446 return;
1448 provider_host->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
1449 weak_factory_.GetWeakPtr(), request_id,
1450 client_uuid));
1453 void ServiceWorkerVersion::OnFocusClientFinished(
1454 int request_id,
1455 const std::string& client_uuid,
1456 const ServiceWorkerClientInfo& client) {
1457 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1459 if (running_status() != RUNNING)
1460 return;
1462 ServiceWorkerClientInfo client_info(client);
1463 client_info.client_uuid = client_uuid;
1465 embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1466 request_id, client_info));
1469 void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
1470 skip_waiting_ = true;
1471 if (status_ != INSTALLED)
1472 return DidSkipWaiting(request_id);
1474 if (!context_)
1475 return;
1476 ServiceWorkerRegistration* registration =
1477 context_->GetLiveRegistration(registration_id_);
1478 if (!registration)
1479 return;
1480 pending_skip_waiting_requests_.push_back(request_id);
1481 if (pending_skip_waiting_requests_.size() == 1)
1482 registration->ActivateWaitingVersionWhenReady();
1485 void ServiceWorkerVersion::DidSkipWaiting(int request_id) {
1486 if (running_status() == STARTING || running_status() == RUNNING)
1487 embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
1490 void ServiceWorkerVersion::OnClaimClients(int request_id) {
1491 if (status_ != ACTIVATING && status_ != ACTIVATED) {
1492 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1493 request_id, blink::WebServiceWorkerError::ErrorTypeState,
1494 base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
1495 return;
1497 if (context_) {
1498 if (ServiceWorkerRegistration* registration =
1499 context_->GetLiveRegistration(registration_id_)) {
1500 registration->ClaimClients();
1501 embedded_worker_->SendMessage(
1502 ServiceWorkerMsg_DidClaimClients(request_id));
1503 return;
1507 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1508 request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
1509 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
1512 void ServiceWorkerVersion::OnPongFromWorker() {
1513 ClearTick(&ping_time_);
1516 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1517 bool pause_after_download,
1518 const StatusCallback& callback,
1519 ServiceWorkerStatusCode status,
1520 const scoped_refptr<ServiceWorkerRegistration>& protect) {
1521 if (status != SERVICE_WORKER_OK || is_doomed()) {
1522 RecordStartWorkerResult(status);
1523 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
1524 return;
1527 switch (running_status()) {
1528 case RUNNING:
1529 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
1530 return;
1531 case STOPPING:
1532 case STOPPED:
1533 case STARTING:
1534 if (start_callbacks_.empty()) {
1535 start_callbacks_.push_back(
1536 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
1537 weak_factory_.GetWeakPtr()));
1539 // Keep the live registration while starting the worker.
1540 start_callbacks_.push_back(
1541 base::Bind(&RunStartWorkerCallback, callback, protect));
1542 StartWorkerInternal(pause_after_download);
1543 return;
1547 void ServiceWorkerVersion::StartWorkerInternal(bool pause_after_download) {
1548 if (!timeout_timer_.IsRunning())
1549 StartTimeoutTimer();
1550 if (running_status() == STOPPED) {
1551 embedded_worker_->Start(
1552 version_id_, scope_, script_url_, pause_after_download,
1553 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
1554 weak_factory_.GetWeakPtr()));
1558 void ServiceWorkerVersion::GetWindowClients(
1559 int request_id,
1560 const ServiceWorkerClientQueryOptions& options) {
1561 DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow ||
1562 options.client_type == blink::WebServiceWorkerClientTypeAll);
1563 std::vector<Tuple<int, int, std::string>> clients_info;
1564 if (!options.include_uncontrolled) {
1565 for (auto& controllee : controllee_map_)
1566 AddWindowClient(controllee.second, &clients_info);
1567 } else {
1568 for (auto it =
1569 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1570 !it->IsAtEnd(); it->Advance()) {
1571 AddWindowClient(it->GetProviderHost(), &clients_info);
1575 if (clients_info.empty()) {
1576 DidGetWindowClients(request_id, options,
1577 make_scoped_ptr(new ServiceWorkerClients));
1578 return;
1581 BrowserThread::PostTask(
1582 BrowserThread::UI, FROM_HERE,
1583 base::Bind(&OnGetWindowClientsFromUI, clients_info, script_url_,
1584 base::Bind(&ServiceWorkerVersion::DidGetWindowClients,
1585 weak_factory_.GetWeakPtr(), request_id, options)));
1588 void ServiceWorkerVersion::DidGetWindowClients(
1589 int request_id,
1590 const ServiceWorkerClientQueryOptions& options,
1591 scoped_ptr<ServiceWorkerClients> clients) {
1592 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1593 if (options.client_type == blink::WebServiceWorkerClientTypeAll)
1594 GetNonWindowClients(request_id, options, clients.get());
1595 OnGetClientsFinished(request_id, *clients);
1598 void ServiceWorkerVersion::GetNonWindowClients(
1599 int request_id,
1600 const ServiceWorkerClientQueryOptions& options,
1601 ServiceWorkerClients* clients) {
1602 if (!options.include_uncontrolled) {
1603 for (auto& controllee : controllee_map_) {
1604 AddNonWindowClient(controllee.second, options, clients);
1606 } else {
1607 for (auto it =
1608 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1609 !it->IsAtEnd(); it->Advance()) {
1610 AddNonWindowClient(it->GetProviderHost(), options, clients);
1615 void ServiceWorkerVersion::StartTimeoutTimer() {
1616 DCHECK(!timeout_timer_.IsRunning());
1618 if (embedded_worker_->devtools_attached()) {
1619 // Don't record the startup time metric once DevTools is attached.
1620 ClearTick(&start_time_);
1621 skip_recording_startup_time_ = true;
1622 } else {
1623 RestartTick(&start_time_);
1624 skip_recording_startup_time_ = false;
1627 ClearTick(&idle_time_);
1628 ClearTick(&ping_time_);
1629 ping_state_ = NOT_PINGING;
1631 timeout_timer_.Start(FROM_HERE,
1632 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
1633 this, &ServiceWorkerVersion::OnTimeoutTimer);
1636 void ServiceWorkerVersion::StopTimeoutTimer() {
1637 timeout_timer_.Stop();
1640 void ServiceWorkerVersion::OnTimeoutTimer() {
1641 DCHECK(running_status() == STARTING || running_status() == RUNNING ||
1642 running_status() == STOPPING)
1643 << running_status();
1645 // Starting a worker hasn't finished within a certain period.
1646 if (GetTickDuration(start_time_) >
1647 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) {
1648 DCHECK(running_status() == STARTING || running_status() == STOPPING)
1649 << running_status();
1650 scoped_refptr<ServiceWorkerVersion> protect(this);
1651 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
1652 if (running_status() == STARTING)
1653 embedded_worker_->Stop();
1654 return;
1657 // Requests have not finished within a certain period.
1658 bool request_timed_out = false;
1659 while (!requests_.empty()) {
1660 RequestInfo info = requests_.front();
1661 if (GetTickDuration(info.time) <
1662 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes))
1663 break;
1664 if (OnRequestTimeout(info))
1665 request_timed_out = true;
1666 requests_.pop();
1668 if (request_timed_out && running_status() != STOPPING)
1669 embedded_worker_->Stop();
1671 // For the timeouts below, there are no callbacks to timeout so there is
1672 // nothing more to do if the worker is already stopping.
1673 if (running_status() == STOPPING)
1674 return;
1676 // The worker has been idle for longer than a certain period.
1677 if (GetTickDuration(idle_time_) >
1678 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) {
1679 StopWorkerIfIdle();
1680 return;
1683 // The worker hasn't responded to ping within a certain period.
1684 if (GetTickDuration(ping_time_) >
1685 base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) {
1686 OnPingTimeout();
1687 return;
1690 if (ping_state_ == PINGING && ping_time_.is_null())
1691 PingWorker();
1694 void ServiceWorkerVersion::PingWorker() {
1695 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1696 DCHECK_EQ(PINGING, ping_state_);
1697 ServiceWorkerStatusCode status =
1698 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
1699 if (status != SERVICE_WORKER_OK) {
1700 // TODO(falken): Maybe try resending Ping a few times first?
1701 ping_state_ = PING_TIMED_OUT;
1702 StopWorkerIfIdle();
1703 return;
1705 RestartTick(&ping_time_);
1708 void ServiceWorkerVersion::OnPingTimeout() {
1709 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1710 ping_state_ = PING_TIMED_OUT;
1711 // TODO(falken): Show a message to the developer that the SW was stopped due
1712 // to timeout (crbug.com/457968). Also, change the error code to
1713 // SERVICE_WORKER_ERROR_TIMEOUT.
1714 StopWorkerIfIdle();
1717 void ServiceWorkerVersion::StopWorkerIfIdle() {
1718 if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT)
1719 return;
1720 if (running_status() == STOPPED || running_status() == STOPPING ||
1721 !stop_callbacks_.empty()) {
1722 return;
1725 // TODO(falken): We may need to handle StopIfIdle failure and
1726 // forcibly fail pending callbacks so no one is stuck waiting
1727 // for the worker.
1728 embedded_worker_->StopIfIdle();
1731 bool ServiceWorkerVersion::HasInflightRequests() const {
1732 return
1733 !activate_callbacks_.IsEmpty() ||
1734 !install_callbacks_.IsEmpty() ||
1735 !fetch_callbacks_.IsEmpty() ||
1736 !sync_callbacks_.IsEmpty() ||
1737 !notification_click_callbacks_.IsEmpty() ||
1738 !push_callbacks_.IsEmpty() ||
1739 !geofencing_callbacks_.IsEmpty() ||
1740 !cross_origin_connect_callbacks_.IsEmpty() ||
1741 !streaming_url_request_jobs_.empty();
1744 void ServiceWorkerVersion::RecordStartWorkerResult(
1745 ServiceWorkerStatusCode status) {
1746 base::TimeTicks start_time = start_time_;
1747 ClearTick(&start_time_);
1749 // Failing to start a doomed worker isn't interesting and very common when
1750 // update dooms because the script is byte-to-byte identical.
1751 if (is_doomed_ || status_ == REDUNDANT)
1752 return;
1754 ServiceWorkerMetrics::RecordStartWorkerStatus(status, IsInstalled(status_));
1756 if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
1757 !skip_recording_startup_time_) {
1758 ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time),
1759 IsInstalled(status_));
1762 if (status != SERVICE_WORKER_ERROR_TIMEOUT)
1763 return;
1764 EmbeddedWorkerInstance::StartingPhase phase =
1765 EmbeddedWorkerInstance::NOT_STARTING;
1766 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
1767 // Build an artifical JavaScript exception to show in the ServiceWorker
1768 // log for developers; it's not user-facing so it's not a localized resource.
1769 std::string message = "ServiceWorker startup timed out. ";
1770 if (running_status != EmbeddedWorkerInstance::STARTING) {
1771 message.append("The worker had unexpected status: ");
1772 message.append(EmbeddedWorkerInstance::StatusToString(running_status));
1773 } else {
1774 phase = embedded_worker_->starting_phase();
1775 message.append("The worker was in startup phase: ");
1776 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
1778 message.append(".");
1779 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
1780 DVLOG(1) << message;
1781 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
1782 phase,
1783 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
1786 void ServiceWorkerVersion::DoomInternal() {
1787 DCHECK(is_doomed_);
1788 DCHECK(!HasControllee());
1789 SetStatus(REDUNDANT);
1790 StopWorkerIfIdle();
1791 if (!context_)
1792 return;
1793 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1794 script_cache_map_.GetResources(&resources);
1795 context_->storage()->PurgeResources(resources);
1798 template <typename IDMAP>
1799 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1800 IDMAP* callbacks,
1801 int request_id) {
1802 RestartTick(&idle_time_);
1803 callbacks->Remove(request_id);
1804 if (is_doomed_) {
1805 // The stop should be already scheduled, but try to stop immediately, in
1806 // order to release worker resources soon.
1807 StopWorkerIfIdle();
1811 template <typename CallbackType>
1812 int ServiceWorkerVersion::AddRequest(
1813 const CallbackType& callback,
1814 IDMap<CallbackType, IDMapOwnPointer>* callback_map,
1815 RequestType request_type) {
1816 int request_id = callback_map->Add(new CallbackType(callback));
1817 requests_.push(RequestInfo(request_id, request_type));
1818 return request_id;
1821 bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo& info) {
1822 switch (info.type) {
1823 case REQUEST_ACTIVATE:
1824 return RunIDMapCallback(&activate_callbacks_, info.id,
1825 SERVICE_WORKER_ERROR_TIMEOUT);
1826 case REQUEST_INSTALL:
1827 return RunIDMapCallback(&install_callbacks_, info.id,
1828 SERVICE_WORKER_ERROR_TIMEOUT);
1829 case REQUEST_FETCH:
1830 return RunIDMapCallback(
1831 &fetch_callbacks_, info.id, SERVICE_WORKER_ERROR_TIMEOUT,
1832 /* The other args are ignored for non-OK status. */
1833 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse());
1834 case REQUEST_SYNC:
1835 return RunIDMapCallback(&sync_callbacks_, info.id,
1836 SERVICE_WORKER_ERROR_TIMEOUT);
1837 case REQUEST_NOTIFICATION_CLICK:
1838 return RunIDMapCallback(&notification_click_callbacks_, info.id,
1839 SERVICE_WORKER_ERROR_TIMEOUT);
1840 case REQUEST_PUSH:
1841 return RunIDMapCallback(&push_callbacks_, info.id,
1842 SERVICE_WORKER_ERROR_TIMEOUT);
1843 case REQUEST_GEOFENCING:
1844 return RunIDMapCallback(&geofencing_callbacks_, info.id,
1845 SERVICE_WORKER_ERROR_TIMEOUT);
1846 case REQUEST_CROSS_ORIGIN_CONNECT:
1847 return RunIDMapCallback(&cross_origin_connect_callbacks_, info.id,
1848 SERVICE_WORKER_ERROR_TIMEOUT,
1849 false /* accept_connection */);
1851 NOTREACHED() << "Got unexpected request type: " << info.type;
1852 return false;
1855 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) {
1856 std::queue<RequestInfo> new_requests;
1857 while (!requests_.empty()) {
1858 RequestInfo info = requests_.front();
1859 info.time = ticks;
1860 new_requests.push(info);
1861 requests_.pop();
1863 requests_ = new_requests;
1866 ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason(
1867 ServiceWorkerStatusCode default_code) {
1868 if (ping_state_ == PING_TIMED_OUT)
1869 return SERVICE_WORKER_ERROR_TIMEOUT;
1871 const net::URLRequestStatus& main_script_status =
1872 script_cache_map()->main_script_status();
1873 if (main_script_status.status() != net::URLRequestStatus::SUCCESS) {
1874 switch (main_script_status.error()) {
1875 case net::ERR_INSECURE_RESPONSE:
1876 case net::ERR_UNSAFE_REDIRECT:
1877 return SERVICE_WORKER_ERROR_SECURITY;
1878 case net::ERR_ABORTED:
1879 return SERVICE_WORKER_ERROR_ABORT;
1880 default:
1881 return SERVICE_WORKER_ERROR_NETWORK;
1885 return default_code;
1888 } // namespace content