Android Chromoting: Remove exit-fullscreen button.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blob681e2b64677ace43839630b7caade29c79e97a96
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_registration.h"
23 #include "content/browser/service_worker/service_worker_utils.h"
24 #include "content/browser/storage_partition_impl.h"
25 #include "content/common/service_worker/service_worker_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/content_browser_client.h"
28 #include "content/public/browser/page_navigator.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_observer.h"
33 #include "content/public/common/child_process_host.h"
34 #include "content/public/common/content_client.h"
35 #include "content/public/common/content_switches.h"
36 #include "content/public/common/result_codes.h"
37 #include "net/http/http_response_headers.h"
38 #include "net/http/http_response_info.h"
40 namespace content {
42 using StatusCallback = ServiceWorkerVersion::StatusCallback;
43 using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
44 using GetClientsCallback =
45 base::Callback<void(scoped_ptr<ServiceWorkerClients>)>;
47 namespace {
49 // Delay between the timeout timer firing.
50 const int kTimeoutTimerDelaySeconds = 30;
52 // Time to wait until stopping an idle worker.
53 const int kIdleWorkerTimeoutSeconds = 30;
55 // Default delay for scheduled update.
56 const int kUpdateDelaySeconds = 1;
58 // Timeout for waiting for a response to a ping.
59 const int kPingTimeoutSeconds = 30;
61 // If the SW was destructed while starting up, how many seconds it
62 // had to start up for this to be considered a timeout occurrence.
63 const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5;
65 const char kClaimClientsStateErrorMesage[] =
66 "Only the active worker can claim clients.";
68 const char kClaimClientsShutdownErrorMesage[] =
69 "Failed to claim clients due to Service Worker system shutdown.";
71 void RunSoon(const base::Closure& callback) {
72 if (!callback.is_null())
73 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
76 template <typename CallbackArray, typename Arg>
77 void RunCallbacks(ServiceWorkerVersion* version,
78 CallbackArray* callbacks_ptr,
79 const Arg& arg) {
80 CallbackArray callbacks;
81 callbacks.swap(*callbacks_ptr);
82 scoped_refptr<ServiceWorkerVersion> protect(version);
83 for (const auto& callback : callbacks)
84 callback.Run(arg);
87 template <typename IDMAP, typename... Params>
88 void RunIDMapCallbacks(IDMAP* callbacks, const Params&... params) {
89 typename IDMAP::iterator iter(callbacks);
90 while (!iter.IsAtEnd()) {
91 iter.GetCurrentValue()->Run(params...);
92 iter.Advance();
94 callbacks->Clear();
97 template <typename CallbackType, typename... Params>
98 bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* callbacks,
99 int request_id,
100 const Params&... params) {
101 CallbackType* callback = callbacks->Lookup(request_id);
102 if (!callback)
103 return false;
105 callback->Run(params...);
106 callbacks->Remove(request_id);
107 return true;
110 void RunStartWorkerCallback(
111 const StatusCallback& callback,
112 scoped_refptr<ServiceWorkerRegistration> protect,
113 ServiceWorkerStatusCode status) {
114 callback.Run(status);
117 // A callback adapter to start a |task| after StartWorker.
118 void RunTaskAfterStartWorker(
119 base::WeakPtr<ServiceWorkerVersion> version,
120 const StatusCallback& error_callback,
121 const base::Closure& task,
122 ServiceWorkerStatusCode status) {
123 if (status != SERVICE_WORKER_OK) {
124 if (!error_callback.is_null())
125 error_callback.Run(status);
126 return;
128 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
129 // We've tried to start the worker (and it has succeeded), but
130 // it looks it's not running yet.
131 NOTREACHED() << "The worker's not running after successful StartWorker";
132 if (!error_callback.is_null())
133 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
134 return;
136 task.Run();
139 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
140 ServiceWorkerStatusCode status) {
141 callback.Run(status,
142 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
143 ServiceWorkerResponse());
146 void RunErrorMessageCallback(
147 const std::vector<TransferredMessagePort>& sent_message_ports,
148 const ServiceWorkerVersion::StatusCallback& callback,
149 ServiceWorkerStatusCode status) {
150 // Transfering the message ports failed, so destroy the ports.
151 for (const TransferredMessagePort& port : sent_message_ports) {
152 MessagePortService::GetInstance()->ClosePort(port.id);
154 callback.Run(status);
157 void RunErrorCrossOriginConnectCallback(
158 const ServiceWorkerVersion::CrossOriginConnectCallback& callback,
159 ServiceWorkerStatusCode status) {
160 callback.Run(status, false /* accept_connection */);
163 using WindowOpenedCallback = base::Callback<void(int, int)>;
165 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
166 // new Window's WebContents to be initialized, run the |callback| passed to its
167 // constructor then self destroy.
168 // The callback will receive the process and frame ids. If something went wrong
169 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
170 // The callback will be called in the IO thread.
171 class WindowOpenedObserver : public WebContentsObserver {
172 public:
173 WindowOpenedObserver(WebContents* web_contents,
174 const WindowOpenedCallback& callback)
175 : WebContentsObserver(web_contents),
176 callback_(callback)
179 void DidCommitProvisionalLoadForFrame(
180 RenderFrameHost* render_frame_host,
181 const GURL& validated_url,
182 ui::PageTransition transition_type) override {
183 DCHECK(web_contents());
185 if (render_frame_host != web_contents()->GetMainFrame())
186 return;
188 RunCallback(render_frame_host->GetProcess()->GetID(),
189 render_frame_host->GetRoutingID());
192 void RenderProcessGone(base::TerminationStatus status) override {
193 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
196 void WebContentsDestroyed() override {
197 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
200 private:
201 void RunCallback(int render_process_id, int render_frame_id) {
202 // After running the callback, |this| will stop observing, thus
203 // web_contents() should return nullptr and |RunCallback| should no longer
204 // be called. Then, |this| will self destroy.
205 DCHECK(web_contents());
207 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
208 base::Bind(callback_,
209 render_process_id,
210 render_frame_id));
211 Observe(nullptr);
212 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
215 const WindowOpenedCallback callback_;
217 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver);
220 void DidOpenURL(const WindowOpenedCallback& callback,
221 WebContents* web_contents) {
222 DCHECK(web_contents);
224 new WindowOpenedObserver(web_contents, callback);
227 void OpenWindowOnUI(
228 const GURL& url,
229 const GURL& script_url,
230 int process_id,
231 const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper,
232 const WindowOpenedCallback& callback) {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI);
235 BrowserContext* browser_context = context_wrapper->storage_partition()
236 ? context_wrapper->storage_partition()->browser_context()
237 : nullptr;
238 // We are shutting down.
239 if (!browser_context)
240 return;
242 RenderProcessHost* render_process_host =
243 RenderProcessHost::FromID(process_id);
244 if (render_process_host->IsIsolatedGuest()) {
245 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
246 base::Bind(callback,
247 ChildProcessHost::kInvalidUniqueID,
248 MSG_ROUTING_NONE));
249 return;
252 OpenURLParams params(
253 url, Referrer::SanitizeForRequest(
254 url, Referrer(script_url, blink::WebReferrerPolicyDefault)),
255 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
256 true /* is_renderer_initiated */);
258 GetContentClient()->browser()->OpenURL(
259 browser_context, params,
260 base::Bind(&DidOpenURL, callback));
263 void KillEmbeddedWorkerProcess(int process_id, ResultCode code) {
264 DCHECK_CURRENTLY_ON(BrowserThread::UI);
265 RenderProcessHost* render_process_host =
266 RenderProcessHost::FromID(process_id);
267 if (render_process_host->GetHandle() != base::kNullProcessHandle) {
268 bad_message::ReceivedBadMessage(render_process_host,
269 bad_message::SERVICE_WORKER_BAD_URL);
273 void ClearTick(base::TimeTicks* time) {
274 *time = base::TimeTicks();
277 void RestartTick(base::TimeTicks* time) {
278 *time = base::TimeTicks().Now();
281 base::TimeDelta GetTickDuration(const base::TimeTicks& time) {
282 if (time.is_null())
283 return base::TimeDelta();
284 return base::TimeTicks().Now() - time;
287 void OnGetWindowClientsFromUI(
288 // The tuple contains process_id, frame_id, client_uuid.
289 const std::vector<Tuple<int, int, std::string>>& clients_info,
290 const GURL& script_url,
291 const GetClientsCallback& callback) {
292 scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients);
294 for (const auto& it : clients_info) {
295 ServiceWorkerClientInfo info =
296 ServiceWorkerProviderHost::GetWindowClientInfoOnUI(get<0>(it),
297 get<1>(it));
299 // If the request to the provider_host returned an empty
300 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
301 // it with a valid RenderFrameHost. It might be because the frame was killed
302 // or navigated in between.
303 if (info.IsEmpty())
304 continue;
306 // We can get info for a frame that was navigating end ended up with a
307 // different URL than expected. In such case, we should make sure to not
308 // expose cross-origin WindowClient.
309 if (info.url.GetOrigin() != script_url.GetOrigin())
310 continue;
312 info.client_uuid = get<2>(it);
313 clients->push_back(info);
316 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
317 base::Bind(callback, base::Passed(&clients)));
320 void AddWindowClient(ServiceWorkerProviderHost* host,
321 std::vector<Tuple<int, int, std::string>>* client_info) {
322 if (host->client_type() != blink::WebServiceWorkerClientTypeWindow)
323 return;
324 client_info->push_back(
325 MakeTuple(host->process_id(), host->frame_id(), host->client_uuid()));
328 void AddNonWindowClient(ServiceWorkerProviderHost* host,
329 const ServiceWorkerClientQueryOptions& options,
330 ServiceWorkerClients* clients) {
331 blink::WebServiceWorkerClientType host_client_type = host->client_type();
332 if (host_client_type == blink::WebServiceWorkerClientTypeWindow)
333 return;
334 if (options.client_type != blink::WebServiceWorkerClientTypeAll &&
335 options.client_type != host_client_type)
336 return;
338 ServiceWorkerClientInfo client_info(
339 blink::WebPageVisibilityStateHidden,
340 false, // is_focused
341 host->document_url(), REQUEST_CONTEXT_FRAME_TYPE_NONE, host_client_type);
342 client_info.client_uuid = host->client_uuid();
343 clients->push_back(client_info);
346 } // namespace
348 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
349 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
351 ServiceWorkerVersion::ServiceWorkerVersion(
352 ServiceWorkerRegistration* registration,
353 const GURL& script_url,
354 int64 version_id,
355 base::WeakPtr<ServiceWorkerContextCore> context)
356 : version_id_(version_id),
357 registration_id_(kInvalidServiceWorkerVersionId),
358 script_url_(script_url),
359 status_(NEW),
360 context_(context),
361 script_cache_map_(this, context),
362 ping_state_(NOT_PINGING),
363 weak_factory_(this) {
364 DCHECK(context_);
365 DCHECK(registration);
366 if (registration) {
367 registration_id_ = registration->id();
368 scope_ = registration->pattern();
370 context_->AddLiveVersion(this);
371 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
372 embedded_worker_->AddListener(this);
375 ServiceWorkerVersion::~ServiceWorkerVersion() {
376 // The user may have closed the tab waiting for SW to start up.
377 if (GetTickDuration(start_time_) >
378 base::TimeDelta::FromSeconds(
379 kDestructedStartingWorkerTimeoutThresholdSeconds)) {
380 DCHECK(timeout_timer_.IsRunning());
381 DCHECK(!embedded_worker_->devtools_attached());
382 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
385 embedded_worker_->RemoveListener(this);
386 if (context_)
387 context_->RemoveLiveVersion(version_id_);
388 // EmbeddedWorker's dtor sends StopWorker if it's still running.
391 void ServiceWorkerVersion::SetStatus(Status status) {
392 if (status_ == status)
393 return;
395 status_ = status;
397 if (skip_waiting_ && status_ == ACTIVATED) {
398 for (int request_id : pending_skip_waiting_requests_)
399 DidSkipWaiting(request_id);
400 pending_skip_waiting_requests_.clear();
403 std::vector<base::Closure> callbacks;
404 callbacks.swap(status_change_callbacks_);
405 for (const auto& callback : callbacks)
406 callback.Run();
408 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
411 void ServiceWorkerVersion::RegisterStatusChangeCallback(
412 const base::Closure& callback) {
413 status_change_callbacks_.push_back(callback);
416 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
417 DCHECK_CURRENTLY_ON(BrowserThread::IO);
418 ServiceWorkerVersionInfo info(
419 running_status(), status(), script_url(), registration_id(), version_id(),
420 embedded_worker()->process_id(), embedded_worker()->thread_id(),
421 embedded_worker()->worker_devtools_agent_route_id());
422 if (!main_script_http_info_)
423 return info;
424 info.script_response_time = main_script_http_info_->response_time;
425 if (main_script_http_info_->headers)
426 main_script_http_info_->headers->GetLastModifiedValue(
427 &info.script_last_modified);
428 return info;
431 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
432 StartWorker(false, callback);
435 void ServiceWorkerVersion::StartWorker(
436 bool pause_after_download,
437 const StatusCallback& callback) {
438 if (!context_) {
439 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
440 return;
443 // Ensure the live registration during starting worker so that the worker can
444 // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
445 context_->storage()->FindRegistrationForId(
446 registration_id_,
447 scope_.GetOrigin(),
448 base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
449 weak_factory_.GetWeakPtr(),
450 pause_after_download,
451 callback));
454 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
455 if (running_status() == STOPPED) {
456 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
457 return;
459 if (stop_callbacks_.empty()) {
460 ServiceWorkerStatusCode status = embedded_worker_->Stop();
461 if (status != SERVICE_WORKER_OK) {
462 RunSoon(base::Bind(callback, status));
463 return;
466 stop_callbacks_.push_back(callback);
469 void ServiceWorkerVersion::ScheduleUpdate() {
470 if (update_timer_.IsRunning()) {
471 update_timer_.Reset();
472 return;
474 update_timer_.Start(
475 FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
476 base::Bind(&ServiceWorkerVersion::StartUpdate,
477 weak_factory_.GetWeakPtr()));
480 void ServiceWorkerVersion::DeferScheduledUpdate() {
481 if (update_timer_.IsRunning())
482 update_timer_.Reset();
485 void ServiceWorkerVersion::StartUpdate() {
486 update_timer_.Stop();
487 if (!context_)
488 return;
489 ServiceWorkerRegistration* registration =
490 context_->GetLiveRegistration(registration_id_);
491 if (!registration || !registration->GetNewestVersion())
492 return;
493 context_->UpdateServiceWorker(registration);
496 void ServiceWorkerVersion::DispatchMessageEvent(
497 const base::string16& message,
498 const std::vector<TransferredMessagePort>& sent_message_ports,
499 const StatusCallback& callback) {
500 for (const TransferredMessagePort& port : sent_message_ports) {
501 MessagePortService::GetInstance()->HoldMessages(port.id);
504 DispatchMessageEventInternal(message, sent_message_ports, callback);
507 void ServiceWorkerVersion::DispatchMessageEventInternal(
508 const base::string16& message,
509 const std::vector<TransferredMessagePort>& sent_message_ports,
510 const StatusCallback& callback) {
511 if (running_status() != RUNNING) {
512 // Schedule calling this method after starting the worker.
513 StartWorker(base::Bind(
514 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
515 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
516 base::Bind(&self::DispatchMessageEventInternal,
517 weak_factory_.GetWeakPtr(), message, sent_message_ports,
518 callback)));
519 return;
522 MessagePortMessageFilter* filter =
523 embedded_worker_->message_port_message_filter();
524 std::vector<int> new_routing_ids;
525 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
526 ServiceWorkerStatusCode status =
527 embedded_worker_->SendMessage(ServiceWorkerMsg_MessageToWorker(
528 message, sent_message_ports, new_routing_ids));
529 RunSoon(base::Bind(callback, status));
532 void ServiceWorkerVersion::DispatchInstallEvent(
533 const StatusCallback& callback) {
534 DCHECK_EQ(INSTALLING, status()) << status();
536 if (running_status() != RUNNING) {
537 // Schedule calling this method after starting the worker.
538 StartWorker(
539 base::Bind(&RunTaskAfterStartWorker,
540 weak_factory_.GetWeakPtr(),
541 callback,
542 base::Bind(&self::DispatchInstallEventAfterStartWorker,
543 weak_factory_.GetWeakPtr(),
544 callback)));
545 } else {
546 DispatchInstallEventAfterStartWorker(callback);
550 void ServiceWorkerVersion::DispatchActivateEvent(
551 const StatusCallback& callback) {
552 DCHECK_EQ(ACTIVATING, status()) << status();
554 if (running_status() != RUNNING) {
555 // Schedule calling this method after starting the worker.
556 StartWorker(
557 base::Bind(&RunTaskAfterStartWorker,
558 weak_factory_.GetWeakPtr(),
559 callback,
560 base::Bind(&self::DispatchActivateEventAfterStartWorker,
561 weak_factory_.GetWeakPtr(),
562 callback)));
563 } else {
564 DispatchActivateEventAfterStartWorker(callback);
568 void ServiceWorkerVersion::DispatchFetchEvent(
569 const ServiceWorkerFetchRequest& request,
570 const base::Closure& prepare_callback,
571 const FetchCallback& fetch_callback) {
572 DCHECK_EQ(ACTIVATED, status()) << status();
574 if (running_status() != RUNNING) {
575 // Schedule calling this method after starting the worker.
576 StartWorker(base::Bind(&RunTaskAfterStartWorker,
577 weak_factory_.GetWeakPtr(),
578 base::Bind(&RunErrorFetchCallback, fetch_callback),
579 base::Bind(&self::DispatchFetchEvent,
580 weak_factory_.GetWeakPtr(),
581 request,
582 prepare_callback,
583 fetch_callback)));
584 return;
587 prepare_callback.Run();
589 int request_id = AddRequest(fetch_callback, &fetch_callbacks_, REQUEST_FETCH);
590 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
591 ServiceWorkerMsg_FetchEvent(request_id, request));
592 if (status != SERVICE_WORKER_OK) {
593 fetch_callbacks_.Remove(request_id);
594 RunSoon(base::Bind(&RunErrorFetchCallback,
595 fetch_callback,
596 SERVICE_WORKER_ERROR_FAILED));
600 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
601 DCHECK_EQ(ACTIVATED, status()) << status();
603 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
604 switches::kEnableServiceWorkerSync)) {
605 callback.Run(SERVICE_WORKER_ERROR_ABORT);
606 return;
609 if (running_status() != RUNNING) {
610 // Schedule calling this method after starting the worker.
611 StartWorker(base::Bind(&RunTaskAfterStartWorker,
612 weak_factory_.GetWeakPtr(), callback,
613 base::Bind(&self::DispatchSyncEvent,
614 weak_factory_.GetWeakPtr(),
615 callback)));
616 return;
619 int request_id = AddRequest(callback, &sync_callbacks_, REQUEST_SYNC);
620 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
621 ServiceWorkerMsg_SyncEvent(request_id));
622 if (status != SERVICE_WORKER_OK) {
623 sync_callbacks_.Remove(request_id);
624 RunSoon(base::Bind(callback, status));
628 void ServiceWorkerVersion::DispatchNotificationClickEvent(
629 const StatusCallback& callback,
630 const std::string& notification_id,
631 const PlatformNotificationData& notification_data) {
632 DCHECK_EQ(ACTIVATED, status()) << status();
633 if (running_status() != RUNNING) {
634 // Schedule calling this method after starting the worker.
635 StartWorker(base::Bind(&RunTaskAfterStartWorker,
636 weak_factory_.GetWeakPtr(), callback,
637 base::Bind(&self::DispatchNotificationClickEvent,
638 weak_factory_.GetWeakPtr(),
639 callback, notification_id,
640 notification_data)));
641 return;
644 int request_id = AddRequest(callback, &notification_click_callbacks_,
645 REQUEST_NOTIFICATION_CLICK);
646 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
647 ServiceWorkerMsg_NotificationClickEvent(request_id,
648 notification_id,
649 notification_data));
650 if (status != SERVICE_WORKER_OK) {
651 notification_click_callbacks_.Remove(request_id);
652 RunSoon(base::Bind(callback, status));
656 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
657 const std::string& data) {
658 DCHECK_EQ(ACTIVATED, status()) << status();
659 if (running_status() != RUNNING) {
660 // Schedule calling this method after starting the worker.
661 StartWorker(base::Bind(&RunTaskAfterStartWorker,
662 weak_factory_.GetWeakPtr(), callback,
663 base::Bind(&self::DispatchPushEvent,
664 weak_factory_.GetWeakPtr(),
665 callback, data)));
666 return;
669 int request_id = AddRequest(callback, &push_callbacks_, REQUEST_PUSH);
670 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
671 ServiceWorkerMsg_PushEvent(request_id, data));
672 if (status != SERVICE_WORKER_OK) {
673 push_callbacks_.Remove(request_id);
674 RunSoon(base::Bind(callback, status));
678 void ServiceWorkerVersion::DispatchGeofencingEvent(
679 const StatusCallback& callback,
680 blink::WebGeofencingEventType event_type,
681 const std::string& region_id,
682 const blink::WebCircularGeofencingRegion& region) {
683 DCHECK_EQ(ACTIVATED, status()) << status();
685 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
686 switches::kEnableExperimentalWebPlatformFeatures)) {
687 callback.Run(SERVICE_WORKER_ERROR_ABORT);
688 return;
691 if (running_status() != RUNNING) {
692 // Schedule calling this method after starting the worker.
693 StartWorker(base::Bind(&RunTaskAfterStartWorker,
694 weak_factory_.GetWeakPtr(),
695 callback,
696 base::Bind(&self::DispatchGeofencingEvent,
697 weak_factory_.GetWeakPtr(),
698 callback,
699 event_type,
700 region_id,
701 region)));
702 return;
705 int request_id =
706 AddRequest(callback, &geofencing_callbacks_, REQUEST_GEOFENCING);
707 ServiceWorkerStatusCode status =
708 embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
709 request_id, event_type, region_id, region));
710 if (status != SERVICE_WORKER_OK) {
711 geofencing_callbacks_.Remove(request_id);
712 RunSoon(base::Bind(callback, status));
716 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
717 const CrossOriginConnectCallback& callback,
718 const NavigatorConnectClient& client) {
719 DCHECK_EQ(ACTIVATED, status()) << status();
721 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
722 switches::kEnableExperimentalWebPlatformFeatures)) {
723 callback.Run(SERVICE_WORKER_ERROR_ABORT, false);
724 return;
727 if (running_status() != RUNNING) {
728 // Schedule calling this method after starting the worker.
729 StartWorker(
730 base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
731 base::Bind(&RunErrorCrossOriginConnectCallback, callback),
732 base::Bind(&self::DispatchCrossOriginConnectEvent,
733 weak_factory_.GetWeakPtr(), callback, client)));
734 return;
737 int request_id = AddRequest(callback, &cross_origin_connect_callbacks_,
738 REQUEST_CROSS_ORIGIN_CONNECT);
739 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
740 ServiceWorkerMsg_CrossOriginConnectEvent(request_id, client));
741 if (status != SERVICE_WORKER_OK) {
742 cross_origin_connect_callbacks_.Remove(request_id);
743 RunSoon(base::Bind(callback, status, false));
747 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
748 const NavigatorConnectClient& client,
749 const base::string16& message,
750 const std::vector<TransferredMessagePort>& sent_message_ports,
751 const StatusCallback& callback) {
752 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
753 // have already put all the sent message ports on hold. So no need to do that
754 // here again.
756 if (running_status() != RUNNING) {
757 // Schedule calling this method after starting the worker.
758 StartWorker(base::Bind(
759 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
760 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
761 base::Bind(&self::DispatchCrossOriginMessageEvent,
762 weak_factory_.GetWeakPtr(), client, message,
763 sent_message_ports, callback)));
764 return;
767 MessagePortMessageFilter* filter =
768 embedded_worker_->message_port_message_filter();
769 std::vector<int> new_routing_ids;
770 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
771 ServiceWorkerStatusCode status =
772 embedded_worker_->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
773 client, message, sent_message_ports, new_routing_ids));
774 RunSoon(base::Bind(callback, status));
777 void ServiceWorkerVersion::AddControllee(
778 ServiceWorkerProviderHost* provider_host) {
779 const std::string& uuid = provider_host->client_uuid();
780 CHECK(!provider_host->client_uuid().empty());
781 DCHECK(!ContainsKey(controllee_map_, uuid));
782 controllee_map_[uuid] = provider_host;
783 // Keep the worker alive a bit longer right after a new controllee is added.
784 RestartTick(&idle_time_);
787 void ServiceWorkerVersion::RemoveControllee(
788 ServiceWorkerProviderHost* provider_host) {
789 const std::string& uuid = provider_host->client_uuid();
790 DCHECK(ContainsKey(controllee_map_, uuid));
791 controllee_map_.erase(uuid);
792 if (HasControllee())
793 return;
794 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
795 if (is_doomed_) {
796 DoomInternal();
797 return;
801 void ServiceWorkerVersion::AddStreamingURLRequestJob(
802 const ServiceWorkerURLRequestJob* request_job) {
803 DCHECK(streaming_url_request_jobs_.find(request_job) ==
804 streaming_url_request_jobs_.end());
805 streaming_url_request_jobs_.insert(request_job);
808 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
809 const ServiceWorkerURLRequestJob* request_job) {
810 streaming_url_request_jobs_.erase(request_job);
811 if (is_doomed_)
812 StopWorkerIfIdle();
815 void ServiceWorkerVersion::AddListener(Listener* listener) {
816 listeners_.AddObserver(listener);
819 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
820 listeners_.RemoveObserver(listener);
823 void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status,
824 const std::string& status_message) {
825 if (status_message.empty()) {
826 OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status)),
827 -1, -1, GURL());
828 } else {
829 OnReportException(base::UTF8ToUTF16(status_message), -1, -1, GURL());
833 void ServiceWorkerVersion::Doom() {
834 if (is_doomed_)
835 return;
836 is_doomed_ = true;
837 if (!HasControllee())
838 DoomInternal();
841 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
842 embedded_worker()->set_devtools_attached(attached);
843 if (attached) {
844 // TODO(falken): Canceling the timeouts when debugging could cause
845 // heisenbugs; we should instead run them as normal show an educational
846 // message in DevTools when they occur. crbug.com/470419
848 // Don't record the startup time metric once DevTools is attached.
849 ClearTick(&start_time_);
850 skip_recording_startup_time_ = true;
852 // Cancel request timeouts.
853 SetAllRequestTimes(base::TimeTicks());
854 return;
856 if (!start_callbacks_.empty()) {
857 // Reactivate the timer for start timeout.
858 DCHECK(timeout_timer_.IsRunning());
859 DCHECK(running_status() == STARTING || running_status() == STOPPING)
860 << running_status();
861 RestartTick(&start_time_);
864 // Reactivate request timeouts.
865 SetAllRequestTimes(base::TimeTicks::Now());
868 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
869 const net::HttpResponseInfo& http_info) {
870 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
871 FOR_EACH_OBSERVER(Listener, listeners_,
872 OnMainScriptHttpResponseInfoSet(this));
875 const net::HttpResponseInfo*
876 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
877 return main_script_http_info_.get();
880 ServiceWorkerVersion::RequestInfo::RequestInfo(int id, RequestType type)
881 : id(id), type(type), time(base::TimeTicks::Now()) {
884 ServiceWorkerVersion::RequestInfo::~RequestInfo() {
887 void ServiceWorkerVersion::OnScriptLoaded() {
888 DCHECK_EQ(STARTING, running_status());
889 // Activate ping/pong now that JavaScript execution will start.
890 ping_state_ = PINGING;
893 void ServiceWorkerVersion::OnStarting() {
894 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
897 void ServiceWorkerVersion::OnStarted() {
898 DCHECK_EQ(RUNNING, running_status());
899 RestartTick(&idle_time_);
901 // Fire all start callbacks.
902 scoped_refptr<ServiceWorkerVersion> protect(this);
903 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
904 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
907 void ServiceWorkerVersion::OnStopping() {
908 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
911 void ServiceWorkerVersion::OnStopped(
912 EmbeddedWorkerInstance::Status old_status) {
913 DCHECK_EQ(STOPPED, running_status());
914 scoped_refptr<ServiceWorkerVersion> protect(this);
916 bool should_restart = !is_doomed() && !start_callbacks_.empty() &&
917 (old_status != EmbeddedWorkerInstance::STARTING);
919 StopTimeoutTimer();
920 if (ping_state_ == PING_TIMED_OUT)
921 should_restart = false;
923 // Fire all stop callbacks.
924 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
926 if (!should_restart) {
927 // Let all start callbacks fail.
928 RunCallbacks(this, &start_callbacks_,
929 SERVICE_WORKER_ERROR_START_WORKER_FAILED);
932 // Let all message callbacks fail (this will also fire and clear all
933 // callbacks for events).
934 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
935 RunIDMapCallbacks(&activate_callbacks_,
936 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
937 RunIDMapCallbacks(&install_callbacks_,
938 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
939 RunIDMapCallbacks(&fetch_callbacks_,
940 SERVICE_WORKER_ERROR_FAILED,
941 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
942 ServiceWorkerResponse());
943 RunIDMapCallbacks(&sync_callbacks_,
944 SERVICE_WORKER_ERROR_FAILED);
945 RunIDMapCallbacks(&notification_click_callbacks_,
946 SERVICE_WORKER_ERROR_FAILED);
947 RunIDMapCallbacks(&push_callbacks_,
948 SERVICE_WORKER_ERROR_FAILED);
949 RunIDMapCallbacks(&geofencing_callbacks_,
950 SERVICE_WORKER_ERROR_FAILED);
951 RunIDMapCallbacks(&cross_origin_connect_callbacks_,
952 SERVICE_WORKER_ERROR_FAILED,
953 false);
955 streaming_url_request_jobs_.clear();
957 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
959 // Restart worker if we have any start callbacks and the worker isn't doomed.
960 if (should_restart)
961 StartWorkerInternal(false /* pause_after_download */);
964 void ServiceWorkerVersion::OnReportException(
965 const base::string16& error_message,
966 int line_number,
967 int column_number,
968 const GURL& source_url) {
969 FOR_EACH_OBSERVER(
970 Listener,
971 listeners_,
972 OnErrorReported(
973 this, error_message, line_number, column_number, source_url));
976 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
977 int message_level,
978 const base::string16& message,
979 int line_number,
980 const GURL& source_url) {
981 FOR_EACH_OBSERVER(Listener,
982 listeners_,
983 OnReportConsoleMessage(this,
984 source_identifier,
985 message_level,
986 message,
987 line_number,
988 source_url));
991 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
992 bool handled = true;
993 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
994 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
995 OnGetClients)
996 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
997 OnActivateEventFinished)
998 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
999 OnInstallEventFinished)
1000 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
1001 OnFetchEventFinished)
1002 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
1003 OnSyncEventFinished)
1004 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
1005 OnNotificationClickEventFinished)
1006 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
1007 OnPushEventFinished)
1008 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
1009 OnGeofencingEventFinished)
1010 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
1011 OnCrossOriginConnectEventFinished)
1012 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
1013 OnOpenWindow)
1014 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
1015 OnSetCachedMetadata)
1016 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata,
1017 OnClearCachedMetadata)
1018 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient,
1019 OnPostMessageToClient)
1020 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
1021 OnFocusClient)
1022 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
1023 OnSkipWaiting)
1024 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
1025 OnClaimClients)
1026 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
1027 IPC_MESSAGE_UNHANDLED(handled = false)
1028 IPC_END_MESSAGE_MAP()
1029 return handled;
1032 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
1033 ServiceWorkerStatusCode status) {
1034 if (status != SERVICE_WORKER_OK)
1035 RunCallbacks(this, &start_callbacks_, status);
1038 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
1039 const StatusCallback& callback) {
1040 DCHECK_EQ(RUNNING, running_status())
1041 << "Worker stopped too soon after it was started.";
1043 int request_id = AddRequest(callback, &install_callbacks_, REQUEST_INSTALL);
1044 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
1045 ServiceWorkerMsg_InstallEvent(request_id));
1046 if (status != SERVICE_WORKER_OK) {
1047 install_callbacks_.Remove(request_id);
1048 RunSoon(base::Bind(callback, status));
1052 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
1053 const StatusCallback& callback) {
1054 DCHECK_EQ(RUNNING, running_status())
1055 << "Worker stopped too soon after it was started.";
1057 int request_id = AddRequest(callback, &activate_callbacks_, REQUEST_ACTIVATE);
1058 ServiceWorkerStatusCode status =
1059 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
1060 if (status != SERVICE_WORKER_OK) {
1061 activate_callbacks_.Remove(request_id);
1062 RunSoon(base::Bind(callback, status));
1066 void ServiceWorkerVersion::OnGetClients(
1067 int request_id,
1068 const ServiceWorkerClientQueryOptions& options) {
1069 TRACE_EVENT_ASYNC_BEGIN2(
1070 "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id,
1071 "client_type", options.client_type, "include_uncontrolled",
1072 options.include_uncontrolled);
1074 if (controllee_map_.empty() && !options.include_uncontrolled) {
1075 OnGetClientsFinished(request_id, std::vector<ServiceWorkerClientInfo>());
1076 return;
1079 // For Window clients we want to query the info on the UI thread first.
1080 if (options.client_type == blink::WebServiceWorkerClientTypeWindow ||
1081 options.client_type == blink::WebServiceWorkerClientTypeAll) {
1082 GetWindowClients(request_id, options);
1083 return;
1086 ServiceWorkerClients clients;
1087 GetNonWindowClients(request_id, options, &clients);
1088 OnGetClientsFinished(request_id, clients);
1091 void ServiceWorkerVersion::OnGetClientsFinished(
1092 int request_id,
1093 const ServiceWorkerClients& clients) {
1094 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1095 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
1096 request_id, "The number of clients", clients.size());
1098 if (running_status() != RUNNING)
1099 return;
1100 embedded_worker_->SendMessage(
1101 ServiceWorkerMsg_DidGetClients(request_id, clients));
1104 void ServiceWorkerVersion::OnActivateEventFinished(
1105 int request_id,
1106 blink::WebServiceWorkerEventResult result) {
1107 DCHECK(ACTIVATING == status() ||
1108 REDUNDANT == status()) << status();
1109 TRACE_EVENT0("ServiceWorker",
1110 "ServiceWorkerVersion::OnActivateEventFinished");
1112 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
1113 if (!callback) {
1114 NOTREACHED() << "Got unexpected message: " << request_id;
1115 return;
1117 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
1118 if (result == blink::WebServiceWorkerEventResultRejected ||
1119 status() != ACTIVATING) {
1120 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
1123 scoped_refptr<ServiceWorkerVersion> protect(this);
1124 callback->Run(rv);
1125 RemoveCallbackAndStopIfDoomed(&activate_callbacks_, request_id);
1128 void ServiceWorkerVersion::OnInstallEventFinished(
1129 int request_id,
1130 blink::WebServiceWorkerEventResult result) {
1131 // Status is REDUNDANT if the worker was doomed while handling the install
1132 // event, and finished handling before being terminated.
1133 DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
1134 TRACE_EVENT0("ServiceWorker",
1135 "ServiceWorkerVersion::OnInstallEventFinished");
1137 StatusCallback* callback = install_callbacks_.Lookup(request_id);
1138 if (!callback) {
1139 NOTREACHED() << "Got unexpected message: " << request_id;
1140 return;
1142 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1143 if (result == blink::WebServiceWorkerEventResultRejected)
1144 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
1146 scoped_refptr<ServiceWorkerVersion> protect(this);
1147 callback->Run(status);
1148 RemoveCallbackAndStopIfDoomed(&install_callbacks_, request_id);
1151 void ServiceWorkerVersion::OnFetchEventFinished(
1152 int request_id,
1153 ServiceWorkerFetchEventResult result,
1154 const ServiceWorkerResponse& response) {
1155 TRACE_EVENT1("ServiceWorker",
1156 "ServiceWorkerVersion::OnFetchEventFinished",
1157 "Request id", request_id);
1158 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
1159 if (!callback) {
1160 NOTREACHED() << "Got unexpected message: " << request_id;
1161 return;
1164 scoped_refptr<ServiceWorkerVersion> protect(this);
1165 callback->Run(SERVICE_WORKER_OK, result, response);
1166 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_, request_id);
1169 void ServiceWorkerVersion::OnSyncEventFinished(
1170 int request_id) {
1171 TRACE_EVENT1("ServiceWorker",
1172 "ServiceWorkerVersion::OnSyncEventFinished",
1173 "Request id", request_id);
1174 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
1175 if (!callback) {
1176 NOTREACHED() << "Got unexpected message: " << request_id;
1177 return;
1180 scoped_refptr<ServiceWorkerVersion> protect(this);
1181 callback->Run(SERVICE_WORKER_OK);
1182 RemoveCallbackAndStopIfDoomed(&sync_callbacks_, request_id);
1185 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1186 int request_id) {
1187 TRACE_EVENT1("ServiceWorker",
1188 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1189 "Request id", request_id);
1190 StatusCallback* callback = notification_click_callbacks_.Lookup(request_id);
1191 if (!callback) {
1192 NOTREACHED() << "Got unexpected message: " << request_id;
1193 return;
1196 scoped_refptr<ServiceWorkerVersion> protect(this);
1197 callback->Run(SERVICE_WORKER_OK);
1198 RemoveCallbackAndStopIfDoomed(&notification_click_callbacks_, request_id);
1201 void ServiceWorkerVersion::OnPushEventFinished(
1202 int request_id,
1203 blink::WebServiceWorkerEventResult result) {
1204 TRACE_EVENT1("ServiceWorker",
1205 "ServiceWorkerVersion::OnPushEventFinished",
1206 "Request id", request_id);
1207 StatusCallback* callback = push_callbacks_.Lookup(request_id);
1208 if (!callback) {
1209 NOTREACHED() << "Got unexpected message: " << request_id;
1210 return;
1212 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1213 if (result == blink::WebServiceWorkerEventResultRejected)
1214 status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
1216 scoped_refptr<ServiceWorkerVersion> protect(this);
1217 callback->Run(status);
1218 RemoveCallbackAndStopIfDoomed(&push_callbacks_, request_id);
1221 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
1222 TRACE_EVENT1("ServiceWorker",
1223 "ServiceWorkerVersion::OnGeofencingEventFinished",
1224 "Request id",
1225 request_id);
1226 StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
1227 if (!callback) {
1228 NOTREACHED() << "Got unexpected message: " << request_id;
1229 return;
1232 scoped_refptr<ServiceWorkerVersion> protect(this);
1233 callback->Run(SERVICE_WORKER_OK);
1234 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_, request_id);
1237 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1238 int request_id,
1239 bool accept_connection) {
1240 TRACE_EVENT1("ServiceWorker",
1241 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1242 "Request id", request_id);
1243 CrossOriginConnectCallback* callback =
1244 cross_origin_connect_callbacks_.Lookup(request_id);
1245 if (!callback) {
1246 NOTREACHED() << "Got unexpected message: " << request_id;
1247 return;
1250 scoped_refptr<ServiceWorkerVersion> protect(this);
1251 callback->Run(SERVICE_WORKER_OK, accept_connection);
1252 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_, request_id);
1255 void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
1256 // Just abort if we are shutting down.
1257 if (!context_)
1258 return;
1260 if (!url.is_valid()) {
1261 DVLOG(1) << "Received unexpected invalid URL from renderer process.";
1262 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1263 base::Bind(&KillEmbeddedWorkerProcess,
1264 embedded_worker_->process_id(),
1265 RESULT_CODE_KILLED_BAD_MESSAGE));
1266 return;
1269 // The renderer treats all URLs in the about: scheme as being about:blank.
1270 // Canonicalize about: URLs to about:blank.
1271 if (url.SchemeIs(url::kAboutScheme))
1272 url = GURL(url::kAboutBlankURL);
1274 // Reject requests for URLs that the process is not allowed to access. It's
1275 // possible to receive such requests since the renderer-side checks are
1276 // slightly different. For example, the view-source scheme will not be
1277 // filtered out by Blink.
1278 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1279 embedded_worker_->process_id(), url)) {
1280 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1281 request_id, url.spec() + " cannot be opened."));
1282 return;
1285 BrowserThread::PostTask(
1286 BrowserThread::UI, FROM_HERE,
1287 base::Bind(&OpenWindowOnUI,
1288 url,
1289 script_url_,
1290 embedded_worker_->process_id(),
1291 make_scoped_refptr(context_->wrapper()),
1292 base::Bind(&ServiceWorkerVersion::DidOpenWindow,
1293 weak_factory_.GetWeakPtr(),
1294 request_id)));
1297 void ServiceWorkerVersion::DidOpenWindow(int request_id,
1298 int render_process_id,
1299 int render_frame_id) {
1300 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1302 if (running_status() != RUNNING)
1303 return;
1305 if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
1306 render_frame_id == MSG_ROUTING_NONE) {
1307 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1308 request_id, "Something went wrong while trying to open the window."));
1309 return;
1312 for (auto it =
1313 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1314 !it->IsAtEnd(); it->Advance()) {
1315 ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
1316 if (provider_host->process_id() != render_process_id ||
1317 provider_host->frame_id() != render_frame_id) {
1318 continue;
1320 provider_host->GetWindowClientInfo(base::Bind(
1321 &ServiceWorkerVersion::OnOpenWindowFinished, weak_factory_.GetWeakPtr(),
1322 request_id, provider_host->client_uuid()));
1323 return;
1326 // If here, it means that no provider_host was found, in which case, the
1327 // renderer should still be informed that the window was opened.
1328 OnOpenWindowFinished(request_id, std::string(), ServiceWorkerClientInfo());
1331 void ServiceWorkerVersion::OnOpenWindowFinished(
1332 int request_id,
1333 const std::string& client_uuid,
1334 const ServiceWorkerClientInfo& client_info) {
1335 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1337 if (running_status() != RUNNING)
1338 return;
1340 ServiceWorkerClientInfo client(client_info);
1342 // If the |client_info| is empty, it means that the opened window wasn't
1343 // controlled but the action still succeeded. The renderer process is
1344 // expecting an empty client in such case.
1345 if (!client.IsEmpty())
1346 client.client_uuid = client_uuid;
1348 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1349 request_id, client));
1352 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
1353 const std::vector<char>& data) {
1354 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1355 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1356 "ServiceWorkerVersion::OnSetCachedMetadata",
1357 callback_id, "URL", url.spec());
1358 script_cache_map_.WriteMetadata(
1359 url, data, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
1360 weak_factory_.GetWeakPtr(), callback_id));
1363 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id,
1364 int result) {
1365 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1366 "ServiceWorkerVersion::OnSetCachedMetadata",
1367 callback_id, "result", result);
1368 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1371 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL& url) {
1372 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1373 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1374 "ServiceWorkerVersion::OnClearCachedMetadata",
1375 callback_id, "URL", url.spec());
1376 script_cache_map_.ClearMetadata(
1377 url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
1378 weak_factory_.GetWeakPtr(), callback_id));
1381 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id,
1382 int result) {
1383 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1384 "ServiceWorkerVersion::OnClearCachedMetadata",
1385 callback_id, "result", result);
1386 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1389 void ServiceWorkerVersion::OnPostMessageToClient(
1390 const std::string& client_uuid,
1391 const base::string16& message,
1392 const std::vector<TransferredMessagePort>& sent_message_ports) {
1393 if (!context_)
1394 return;
1395 TRACE_EVENT1("ServiceWorker",
1396 "ServiceWorkerVersion::OnPostMessageToDocument",
1397 "Client id", client_uuid);
1398 ServiceWorkerProviderHost* provider_host =
1399 context_->GetProviderHostByClientID(client_uuid);
1400 if (!provider_host) {
1401 // The client may already have been closed, just ignore.
1402 return;
1404 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1405 // The client does not belong to the same origin as this ServiceWorker,
1406 // possibly due to timing issue or bad message.
1407 return;
1409 provider_host->PostMessage(message, sent_message_ports);
1412 void ServiceWorkerVersion::OnFocusClient(int request_id,
1413 const std::string& client_uuid) {
1414 if (!context_)
1415 return;
1416 TRACE_EVENT2("ServiceWorker",
1417 "ServiceWorkerVersion::OnFocusClient",
1418 "Request id", request_id,
1419 "Client id", client_uuid);
1420 ServiceWorkerProviderHost* provider_host =
1421 context_->GetProviderHostByClientID(client_uuid);
1422 if (!provider_host) {
1423 // The client may already have been closed, just ignore.
1424 return;
1426 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1427 // The client does not belong to the same origin as this ServiceWorker,
1428 // possibly due to timing issue or bad message.
1429 return;
1431 provider_host->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
1432 weak_factory_.GetWeakPtr(), request_id,
1433 client_uuid));
1436 void ServiceWorkerVersion::OnFocusClientFinished(
1437 int request_id,
1438 const std::string& client_uuid,
1439 const ServiceWorkerClientInfo& client) {
1440 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1442 if (running_status() != RUNNING)
1443 return;
1445 ServiceWorkerClientInfo client_info(client);
1446 client_info.client_uuid = client_uuid;
1448 embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1449 request_id, client_info));
1452 void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
1453 skip_waiting_ = true;
1454 if (status_ != INSTALLED)
1455 return DidSkipWaiting(request_id);
1457 if (!context_)
1458 return;
1459 ServiceWorkerRegistration* registration =
1460 context_->GetLiveRegistration(registration_id_);
1461 if (!registration)
1462 return;
1463 pending_skip_waiting_requests_.push_back(request_id);
1464 if (pending_skip_waiting_requests_.size() == 1)
1465 registration->ActivateWaitingVersionWhenReady();
1468 void ServiceWorkerVersion::DidSkipWaiting(int request_id) {
1469 if (running_status() == STARTING || running_status() == RUNNING)
1470 embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
1473 void ServiceWorkerVersion::OnClaimClients(int request_id) {
1474 if (status_ != ACTIVATING && status_ != ACTIVATED) {
1475 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1476 request_id, blink::WebServiceWorkerError::ErrorTypeState,
1477 base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
1478 return;
1480 if (context_) {
1481 if (ServiceWorkerRegistration* registration =
1482 context_->GetLiveRegistration(registration_id_)) {
1483 registration->ClaimClients();
1484 embedded_worker_->SendMessage(
1485 ServiceWorkerMsg_DidClaimClients(request_id));
1486 return;
1490 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1491 request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
1492 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
1495 void ServiceWorkerVersion::OnPongFromWorker() {
1496 ClearTick(&ping_time_);
1499 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1500 bool pause_after_download,
1501 const StatusCallback& callback,
1502 ServiceWorkerStatusCode status,
1503 const scoped_refptr<ServiceWorkerRegistration>& protect) {
1504 if (status != SERVICE_WORKER_OK || is_doomed()) {
1505 RecordStartWorkerResult(status);
1506 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
1507 return;
1510 switch (running_status()) {
1511 case RUNNING:
1512 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
1513 return;
1514 case STOPPING:
1515 case STOPPED:
1516 case STARTING:
1517 if (start_callbacks_.empty()) {
1518 start_callbacks_.push_back(
1519 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
1520 weak_factory_.GetWeakPtr()));
1522 // Keep the live registration while starting the worker.
1523 start_callbacks_.push_back(
1524 base::Bind(&RunStartWorkerCallback, callback, protect));
1525 StartWorkerInternal(pause_after_download);
1526 return;
1530 void ServiceWorkerVersion::StartWorkerInternal(bool pause_after_download) {
1531 if (!timeout_timer_.IsRunning())
1532 StartTimeoutTimer();
1533 if (running_status() == STOPPED) {
1534 embedded_worker_->Start(
1535 version_id_, scope_, script_url_, pause_after_download,
1536 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
1537 weak_factory_.GetWeakPtr()));
1541 void ServiceWorkerVersion::GetWindowClients(
1542 int request_id,
1543 const ServiceWorkerClientQueryOptions& options) {
1544 DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow ||
1545 options.client_type == blink::WebServiceWorkerClientTypeAll);
1546 std::vector<Tuple<int, int, std::string>> clients_info;
1547 if (!options.include_uncontrolled) {
1548 for (auto& controllee : controllee_map_)
1549 AddWindowClient(controllee.second, &clients_info);
1550 } else {
1551 for (auto it =
1552 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1553 !it->IsAtEnd(); it->Advance()) {
1554 AddWindowClient(it->GetProviderHost(), &clients_info);
1558 if (clients_info.empty()) {
1559 DidGetWindowClients(request_id, options,
1560 make_scoped_ptr(new ServiceWorkerClients));
1561 return;
1564 BrowserThread::PostTask(
1565 BrowserThread::UI, FROM_HERE,
1566 base::Bind(&OnGetWindowClientsFromUI, clients_info, script_url_,
1567 base::Bind(&ServiceWorkerVersion::DidGetWindowClients,
1568 weak_factory_.GetWeakPtr(), request_id, options)));
1571 void ServiceWorkerVersion::DidGetWindowClients(
1572 int request_id,
1573 const ServiceWorkerClientQueryOptions& options,
1574 scoped_ptr<ServiceWorkerClients> clients) {
1575 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1576 if (options.client_type == blink::WebServiceWorkerClientTypeAll)
1577 GetNonWindowClients(request_id, options, clients.get());
1578 OnGetClientsFinished(request_id, *clients);
1581 void ServiceWorkerVersion::GetNonWindowClients(
1582 int request_id,
1583 const ServiceWorkerClientQueryOptions& options,
1584 ServiceWorkerClients* clients) {
1585 if (!options.include_uncontrolled) {
1586 for (auto& controllee : controllee_map_) {
1587 AddNonWindowClient(controllee.second, options, clients);
1589 } else {
1590 for (auto it =
1591 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1592 !it->IsAtEnd(); it->Advance()) {
1593 AddNonWindowClient(it->GetProviderHost(), options, clients);
1598 void ServiceWorkerVersion::StartTimeoutTimer() {
1599 DCHECK(!timeout_timer_.IsRunning());
1601 if (embedded_worker_->devtools_attached()) {
1602 // Don't record the startup time metric once DevTools is attached.
1603 ClearTick(&start_time_);
1604 skip_recording_startup_time_ = true;
1605 } else {
1606 RestartTick(&start_time_);
1607 skip_recording_startup_time_ = false;
1610 ClearTick(&idle_time_);
1611 ClearTick(&ping_time_);
1612 ping_state_ = NOT_PINGING;
1614 timeout_timer_.Start(FROM_HERE,
1615 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
1616 this, &ServiceWorkerVersion::OnTimeoutTimer);
1619 void ServiceWorkerVersion::StopTimeoutTimer() {
1620 timeout_timer_.Stop();
1623 void ServiceWorkerVersion::OnTimeoutTimer() {
1624 DCHECK(running_status() == STARTING || running_status() == RUNNING ||
1625 running_status() == STOPPING)
1626 << running_status();
1628 // Starting a worker hasn't finished within a certain period.
1629 if (GetTickDuration(start_time_) >
1630 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) {
1631 DCHECK(running_status() == STARTING || running_status() == STOPPING)
1632 << running_status();
1633 scoped_refptr<ServiceWorkerVersion> protect(this);
1634 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
1635 if (running_status() == STARTING)
1636 embedded_worker_->Stop();
1637 return;
1640 // Requests have not finished within a certain period.
1641 bool request_timed_out = false;
1642 while (!requests_.empty()) {
1643 RequestInfo info = requests_.front();
1644 if (GetTickDuration(info.time) <
1645 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes))
1646 break;
1647 if (OnRequestTimeout(info))
1648 request_timed_out = true;
1649 requests_.pop();
1651 if (request_timed_out && running_status() != STOPPING)
1652 embedded_worker_->Stop();
1654 // For the timeouts below, there are no callbacks to timeout so there is
1655 // nothing more to do if the worker is already stopping.
1656 if (running_status() == STOPPING)
1657 return;
1659 // The worker has been idle for longer than a certain period.
1660 if (GetTickDuration(idle_time_) >
1661 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) {
1662 StopWorkerIfIdle();
1663 return;
1666 // The worker hasn't responded to ping within a certain period.
1667 if (GetTickDuration(ping_time_) >
1668 base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) {
1669 OnPingTimeout();
1670 return;
1673 if (ping_state_ == PINGING && ping_time_.is_null())
1674 PingWorker();
1677 void ServiceWorkerVersion::PingWorker() {
1678 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1679 DCHECK_EQ(PINGING, ping_state_);
1680 ServiceWorkerStatusCode status =
1681 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
1682 if (status != SERVICE_WORKER_OK) {
1683 // TODO(falken): Maybe try resending Ping a few times first?
1684 ping_state_ = PING_TIMED_OUT;
1685 StopWorkerIfIdle();
1686 return;
1688 RestartTick(&ping_time_);
1691 void ServiceWorkerVersion::OnPingTimeout() {
1692 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1693 ping_state_ = PING_TIMED_OUT;
1694 // TODO(falken): Show a message to the developer that the SW was stopped due
1695 // to timeout (crbug.com/457968). Also, change the error code to
1696 // SERVICE_WORKER_ERROR_TIMEOUT.
1697 StopWorkerIfIdle();
1700 void ServiceWorkerVersion::StopWorkerIfIdle() {
1701 if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT)
1702 return;
1703 if (running_status() == STOPPED || running_status() == STOPPING ||
1704 !stop_callbacks_.empty()) {
1705 return;
1708 // TODO(falken): We may need to handle StopIfIdle failure and
1709 // forcibly fail pending callbacks so no one is stuck waiting
1710 // for the worker.
1711 embedded_worker_->StopIfIdle();
1714 bool ServiceWorkerVersion::HasInflightRequests() const {
1715 return
1716 !activate_callbacks_.IsEmpty() ||
1717 !install_callbacks_.IsEmpty() ||
1718 !fetch_callbacks_.IsEmpty() ||
1719 !sync_callbacks_.IsEmpty() ||
1720 !notification_click_callbacks_.IsEmpty() ||
1721 !push_callbacks_.IsEmpty() ||
1722 !geofencing_callbacks_.IsEmpty() ||
1723 !cross_origin_connect_callbacks_.IsEmpty() ||
1724 !streaming_url_request_jobs_.empty();
1727 void ServiceWorkerVersion::RecordStartWorkerResult(
1728 ServiceWorkerStatusCode status) {
1729 base::TimeTicks start_time = start_time_;
1730 ClearTick(&start_time_);
1732 // Failing to start a doomed worker isn't interesting and very common when
1733 // update dooms because the script is byte-to-byte identical.
1734 if (is_doomed_)
1735 return;
1737 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status,
1738 SERVICE_WORKER_ERROR_MAX_VALUE);
1739 if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
1740 !skip_recording_startup_time_) {
1741 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time",
1742 GetTickDuration(start_time));
1745 if (status != SERVICE_WORKER_ERROR_TIMEOUT)
1746 return;
1747 EmbeddedWorkerInstance::StartingPhase phase =
1748 EmbeddedWorkerInstance::NOT_STARTING;
1749 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
1750 // Build an artifical JavaScript exception to show in the ServiceWorker
1751 // log for developers; it's not user-facing so it's not a localized resource.
1752 std::string message = "ServiceWorker startup timed out. ";
1753 if (running_status != EmbeddedWorkerInstance::STARTING) {
1754 message.append("The worker had unexpected status: ");
1755 message.append(EmbeddedWorkerInstance::StatusToString(running_status));
1756 } else {
1757 phase = embedded_worker_->starting_phase();
1758 message.append("The worker was in startup phase: ");
1759 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
1761 message.append(".");
1762 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
1763 DVLOG(1) << message;
1764 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
1765 phase,
1766 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
1769 void ServiceWorkerVersion::DoomInternal() {
1770 DCHECK(is_doomed_);
1771 DCHECK(!HasControllee());
1772 SetStatus(REDUNDANT);
1773 StopWorkerIfIdle();
1774 if (!context_)
1775 return;
1776 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1777 script_cache_map_.GetResources(&resources);
1778 context_->storage()->PurgeResources(resources);
1781 template <typename IDMAP>
1782 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1783 IDMAP* callbacks,
1784 int request_id) {
1785 RestartTick(&idle_time_);
1786 callbacks->Remove(request_id);
1787 if (is_doomed_) {
1788 // The stop should be already scheduled, but try to stop immediately, in
1789 // order to release worker resources soon.
1790 StopWorkerIfIdle();
1794 template <typename CallbackType>
1795 int ServiceWorkerVersion::AddRequest(
1796 const CallbackType& callback,
1797 IDMap<CallbackType, IDMapOwnPointer>* callback_map,
1798 RequestType request_type) {
1799 int request_id = callback_map->Add(new CallbackType(callback));
1800 requests_.push(RequestInfo(request_id, request_type));
1801 return request_id;
1804 bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo& info) {
1805 switch (info.type) {
1806 case REQUEST_ACTIVATE:
1807 return RunIDMapCallback(&activate_callbacks_, info.id,
1808 SERVICE_WORKER_ERROR_TIMEOUT);
1809 case REQUEST_INSTALL:
1810 return RunIDMapCallback(&install_callbacks_, info.id,
1811 SERVICE_WORKER_ERROR_TIMEOUT);
1812 case REQUEST_FETCH:
1813 return RunIDMapCallback(
1814 &fetch_callbacks_, info.id, SERVICE_WORKER_ERROR_TIMEOUT,
1815 /* The other args are ignored for non-OK status. */
1816 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse());
1817 case REQUEST_SYNC:
1818 return RunIDMapCallback(&sync_callbacks_, info.id,
1819 SERVICE_WORKER_ERROR_TIMEOUT);
1820 case REQUEST_NOTIFICATION_CLICK:
1821 return RunIDMapCallback(&notification_click_callbacks_, info.id,
1822 SERVICE_WORKER_ERROR_TIMEOUT);
1823 case REQUEST_PUSH:
1824 return RunIDMapCallback(&push_callbacks_, info.id,
1825 SERVICE_WORKER_ERROR_TIMEOUT);
1826 case REQUEST_GEOFENCING:
1827 return RunIDMapCallback(&geofencing_callbacks_, info.id,
1828 SERVICE_WORKER_ERROR_TIMEOUT);
1829 case REQUEST_CROSS_ORIGIN_CONNECT:
1830 return RunIDMapCallback(&cross_origin_connect_callbacks_, info.id,
1831 SERVICE_WORKER_ERROR_TIMEOUT,
1832 false /* accept_connection */);
1834 NOTREACHED() << "Got unexpected request type: " << info.type;
1835 return false;
1838 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) {
1839 std::queue<RequestInfo> new_requests;
1840 while (!requests_.empty()) {
1841 RequestInfo info = requests_.front();
1842 info.time = ticks;
1843 new_requests.push(info);
1844 requests_.pop();
1846 requests_ = new_requests;
1849 } // namespace content