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.
4
5 #include "content/browser/service_worker/service_worker_version.h"
6
7 #include "base/command_line.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string16.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_registration.h"
14 #include "content/browser/service_worker/service_worker_utils.h"
15 #include "content/common/service_worker/service_worker_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_switches.h"
18
19 namespace content {
20
21 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
22 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
23
24 namespace {
25
26 // Default delay to stop the worker context after all documents that
27 // are associated to the worker are closed.
28 // (Note that if all references to the version is dropped the worker
29 // is also stopped without delay)
30 const int64 kStopWorkerDelay = 30; // 30 secs.
31
RunSoon(const base::Closure & callback)32 void RunSoon(const base::Closure& callback) {
33 if (!callback.is_null())
34 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
35 }
36
37 template <typename CallbackArray, typename Arg>
RunCallbacks(ServiceWorkerVersion * version,CallbackArray * callbacks_ptr,const Arg & arg)38 void RunCallbacks(ServiceWorkerVersion* version,
39 CallbackArray* callbacks_ptr,
40 const Arg& arg) {
41 CallbackArray callbacks;
42 callbacks.swap(*callbacks_ptr);
43 scoped_refptr<ServiceWorkerVersion> protect(version);
44 for (typename CallbackArray::const_iterator i = callbacks.begin();
45 i != callbacks.end(); ++i)
46 (*i).Run(arg);
47 }
48
49 template <typename IDMAP, typename Method, typename Params>
RunIDMapCallbacks(IDMAP * callbacks,Method method,const Params & params)50 void RunIDMapCallbacks(IDMAP* callbacks, Method method, const Params& params) {
51 typename IDMAP::iterator iter(callbacks);
52 while (!iter.IsAtEnd()) {
53 DispatchToMethod(iter.GetCurrentValue(), method, params);
54 iter.Advance();
55 }
56 callbacks->Clear();
57 }
58
59 // A callback adapter to start a |task| after StartWorker.
RunTaskAfterStartWorker(base::WeakPtr<ServiceWorkerVersion> version,const StatusCallback & error_callback,const base::Closure & task,ServiceWorkerStatusCode status)60 void RunTaskAfterStartWorker(
61 base::WeakPtr<ServiceWorkerVersion> version,
62 const StatusCallback& error_callback,
63 const base::Closure& task,
64 ServiceWorkerStatusCode status) {
65 if (status != SERVICE_WORKER_OK) {
66 if (!error_callback.is_null())
67 error_callback.Run(status);
68 return;
69 }
70 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
71 // We've tried to start the worker (and it has succeeded), but
72 // it looks it's not running yet.
73 NOTREACHED() << "The worker's not running after successful StartWorker";
74 if (!error_callback.is_null())
75 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
76 return;
77 }
78 task.Run();
79 }
80
RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback & callback,ServiceWorkerStatusCode status)81 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
82 ServiceWorkerStatusCode status) {
83 callback.Run(status,
84 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
85 ServiceWorkerResponse());
86 }
87
88 } // namespace
89
ServiceWorkerVersion(ServiceWorkerRegistration * registration,int64 version_id,base::WeakPtr<ServiceWorkerContextCore> context)90 ServiceWorkerVersion::ServiceWorkerVersion(
91 ServiceWorkerRegistration* registration,
92 int64 version_id,
93 base::WeakPtr<ServiceWorkerContextCore> context)
94 : version_id_(version_id),
95 registration_id_(kInvalidServiceWorkerVersionId),
96 status_(NEW),
97 context_(context),
98 script_cache_map_(this, context),
99 weak_factory_(this) {
100 DCHECK(context_);
101 DCHECK(registration);
102 if (registration) {
103 registration_id_ = registration->id();
104 script_url_ = registration->script_url();
105 scope_ = registration->pattern();
106 }
107 context_->AddLiveVersion(this);
108 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
109 embedded_worker_->AddListener(this);
110 }
111
~ServiceWorkerVersion()112 ServiceWorkerVersion::~ServiceWorkerVersion() {
113 embedded_worker_->RemoveListener(this);
114 if (context_)
115 context_->RemoveLiveVersion(version_id_);
116 // EmbeddedWorker's dtor sends StopWorker if it's still running.
117 }
118
SetStatus(Status status)119 void ServiceWorkerVersion::SetStatus(Status status) {
120 if (status_ == status)
121 return;
122
123 status_ = status;
124
125 std::vector<base::Closure> callbacks;
126 callbacks.swap(status_change_callbacks_);
127 for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
128 i != callbacks.end(); ++i) {
129 (*i).Run();
130 }
131
132 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
133 }
134
RegisterStatusChangeCallback(const base::Closure & callback)135 void ServiceWorkerVersion::RegisterStatusChangeCallback(
136 const base::Closure& callback) {
137 status_change_callbacks_.push_back(callback);
138 }
139
GetInfo()140 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 return ServiceWorkerVersionInfo(
143 running_status(),
144 status(),
145 version_id(),
146 embedded_worker()->process_id(),
147 embedded_worker()->thread_id(),
148 embedded_worker()->worker_devtools_agent_route_id());
149 }
150
StartWorker(const StatusCallback & callback)151 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
152 StartWorkerWithCandidateProcesses(std::vector<int>(), callback);
153 }
154
StartWorkerWithCandidateProcesses(const std::vector<int> & possible_process_ids,const StatusCallback & callback)155 void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
156 const std::vector<int>& possible_process_ids,
157 const StatusCallback& callback) {
158 switch (running_status()) {
159 case RUNNING:
160 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
161 return;
162 case STOPPING:
163 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
164 return;
165 case STOPPED:
166 case STARTING:
167 start_callbacks_.push_back(callback);
168 if (running_status() == STOPPED) {
169 embedded_worker_->Start(
170 version_id_,
171 scope_,
172 script_url_,
173 possible_process_ids,
174 base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
175 weak_factory_.GetWeakPtr()));
176 }
177 return;
178 }
179 }
180
StopWorker(const StatusCallback & callback)181 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
182 if (running_status() == STOPPED) {
183 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
184 return;
185 }
186 if (stop_callbacks_.empty()) {
187 ServiceWorkerStatusCode status = embedded_worker_->Stop();
188 if (status != SERVICE_WORKER_OK) {
189 RunSoon(base::Bind(callback, status));
190 return;
191 }
192 }
193 stop_callbacks_.push_back(callback);
194 }
195
SendMessage(const IPC::Message & message,const StatusCallback & callback)196 void ServiceWorkerVersion::SendMessage(
197 const IPC::Message& message, const StatusCallback& callback) {
198 if (running_status() != RUNNING) {
199 // Schedule calling this method after starting the worker.
200 StartWorker(base::Bind(&RunTaskAfterStartWorker,
201 weak_factory_.GetWeakPtr(), callback,
202 base::Bind(&self::SendMessage,
203 weak_factory_.GetWeakPtr(),
204 message, callback)));
205 return;
206 }
207
208 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
209 RunSoon(base::Bind(callback, status));
210 }
211
DispatchInstallEvent(int active_version_id,const StatusCallback & callback)212 void ServiceWorkerVersion::DispatchInstallEvent(
213 int active_version_id,
214 const StatusCallback& callback) {
215 DCHECK_EQ(NEW, status()) << status();
216 SetStatus(INSTALLING);
217
218 if (running_status() != RUNNING) {
219 // Schedule calling this method after starting the worker.
220 StartWorker(
221 base::Bind(&RunTaskAfterStartWorker,
222 weak_factory_.GetWeakPtr(),
223 callback,
224 base::Bind(&self::DispatchInstallEventAfterStartWorker,
225 weak_factory_.GetWeakPtr(),
226 active_version_id,
227 callback)));
228 } else {
229 DispatchInstallEventAfterStartWorker(active_version_id, callback);
230 }
231 }
232
DispatchActivateEvent(const StatusCallback & callback)233 void ServiceWorkerVersion::DispatchActivateEvent(
234 const StatusCallback& callback) {
235 DCHECK_EQ(INSTALLED, status()) << status();
236 SetStatus(ACTIVATING);
237
238 if (running_status() != RUNNING) {
239 // Schedule calling this method after starting the worker.
240 StartWorker(
241 base::Bind(&RunTaskAfterStartWorker,
242 weak_factory_.GetWeakPtr(),
243 callback,
244 base::Bind(&self::DispatchActivateEventAfterStartWorker,
245 weak_factory_.GetWeakPtr(),
246 callback)));
247 } else {
248 DispatchActivateEventAfterStartWorker(callback);
249 }
250 }
251
DispatchFetchEvent(const ServiceWorkerFetchRequest & request,const FetchCallback & callback)252 void ServiceWorkerVersion::DispatchFetchEvent(
253 const ServiceWorkerFetchRequest& request,
254 const FetchCallback& callback) {
255 DCHECK_EQ(ACTIVE, status()) << status();
256
257 if (running_status() != RUNNING) {
258 // Schedule calling this method after starting the worker.
259 StartWorker(base::Bind(&RunTaskAfterStartWorker,
260 weak_factory_.GetWeakPtr(),
261 base::Bind(&RunErrorFetchCallback, callback),
262 base::Bind(&self::DispatchFetchEvent,
263 weak_factory_.GetWeakPtr(),
264 request, callback)));
265 return;
266 }
267
268 int request_id = fetch_callbacks_.Add(new FetchCallback(callback));
269 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
270 ServiceWorkerMsg_FetchEvent(request_id, request));
271 if (status != SERVICE_WORKER_OK) {
272 fetch_callbacks_.Remove(request_id);
273 RunSoon(base::Bind(&RunErrorFetchCallback,
274 callback,
275 SERVICE_WORKER_ERROR_FAILED));
276 }
277 }
278
DispatchSyncEvent(const StatusCallback & callback)279 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
280 DCHECK_EQ(ACTIVE, status()) << status();
281
282 if (!CommandLine::ForCurrentProcess()->HasSwitch(
283 switches::kEnableServiceWorkerSync)) {
284 callback.Run(SERVICE_WORKER_ERROR_ABORT);
285 return;
286 }
287
288 if (running_status() != RUNNING) {
289 // Schedule calling this method after starting the worker.
290 StartWorker(base::Bind(&RunTaskAfterStartWorker,
291 weak_factory_.GetWeakPtr(), callback,
292 base::Bind(&self::DispatchSyncEvent,
293 weak_factory_.GetWeakPtr(),
294 callback)));
295 return;
296 }
297
298 int request_id = sync_callbacks_.Add(new StatusCallback(callback));
299 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
300 ServiceWorkerMsg_SyncEvent(request_id));
301 if (status != SERVICE_WORKER_OK) {
302 sync_callbacks_.Remove(request_id);
303 RunSoon(base::Bind(callback, status));
304 }
305 }
306
DispatchPushEvent(const StatusCallback & callback,const std::string & data)307 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
308 const std::string& data) {
309 DCHECK_EQ(ACTIVE, status()) << status();
310
311 if (!CommandLine::ForCurrentProcess()->HasSwitch(
312 switches::kEnableExperimentalWebPlatformFeatures)) {
313 callback.Run(SERVICE_WORKER_ERROR_ABORT);
314 return;
315 }
316
317 if (running_status() != RUNNING) {
318 // Schedule calling this method after starting the worker.
319 StartWorker(base::Bind(&RunTaskAfterStartWorker,
320 weak_factory_.GetWeakPtr(), callback,
321 base::Bind(&self::DispatchPushEvent,
322 weak_factory_.GetWeakPtr(),
323 callback, data)));
324 return;
325 }
326
327 int request_id = push_callbacks_.Add(new StatusCallback(callback));
328 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
329 ServiceWorkerMsg_PushEvent(request_id, data));
330 if (status != SERVICE_WORKER_OK) {
331 push_callbacks_.Remove(request_id);
332 RunSoon(base::Bind(callback, status));
333 }
334 }
335
AddProcessToWorker(int process_id)336 void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
337 embedded_worker_->AddProcessReference(process_id);
338 }
339
RemoveProcessFromWorker(int process_id)340 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
341 embedded_worker_->ReleaseProcessReference(process_id);
342 }
343
HasProcessToRun() const344 bool ServiceWorkerVersion::HasProcessToRun() const {
345 return embedded_worker_->HasProcessToRun();
346 }
347
AddControllee(ServiceWorkerProviderHost * provider_host)348 void ServiceWorkerVersion::AddControllee(
349 ServiceWorkerProviderHost* provider_host) {
350 DCHECK(!ContainsKey(controllee_map_, provider_host));
351 int controllee_id = controllee_by_id_.Add(provider_host);
352 controllee_map_[provider_host] = controllee_id;
353 AddProcessToWorker(provider_host->process_id());
354 if (stop_worker_timer_.IsRunning())
355 stop_worker_timer_.Stop();
356 }
357
RemoveControllee(ServiceWorkerProviderHost * provider_host)358 void ServiceWorkerVersion::RemoveControllee(
359 ServiceWorkerProviderHost* provider_host) {
360 ControlleeMap::iterator found = controllee_map_.find(provider_host);
361 DCHECK(found != controllee_map_.end());
362 controllee_by_id_.Remove(found->second);
363 controllee_map_.erase(found);
364 RemoveProcessFromWorker(provider_host->process_id());
365 if (!HasControllee())
366 ScheduleStopWorker();
367 // TODO(kinuko): Fire NoControllees notification when the # of controllees
368 // reaches 0, so that a new pending version can be activated (which will
369 // deactivate this version).
370 // TODO(michaeln): On no controllees call storage DeleteVersionResources
371 // if this version has been deactivated. Probably storage can listen for
372 // NoControllees for versions that have been deleted.
373 }
374
AddWaitingControllee(ServiceWorkerProviderHost * provider_host)375 void ServiceWorkerVersion::AddWaitingControllee(
376 ServiceWorkerProviderHost* provider_host) {
377 AddProcessToWorker(provider_host->process_id());
378 }
379
RemoveWaitingControllee(ServiceWorkerProviderHost * provider_host)380 void ServiceWorkerVersion::RemoveWaitingControllee(
381 ServiceWorkerProviderHost* provider_host) {
382 RemoveProcessFromWorker(provider_host->process_id());
383 }
384
AddListener(Listener * listener)385 void ServiceWorkerVersion::AddListener(Listener* listener) {
386 listeners_.AddObserver(listener);
387 }
388
RemoveListener(Listener * listener)389 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
390 listeners_.RemoveObserver(listener);
391 }
392
OnStarted()393 void ServiceWorkerVersion::OnStarted() {
394 DCHECK_EQ(RUNNING, running_status());
395 // Fire all start callbacks.
396 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
397 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
398 }
399
OnStopped()400 void ServiceWorkerVersion::OnStopped() {
401 DCHECK_EQ(STOPPED, running_status());
402 scoped_refptr<ServiceWorkerVersion> protect(this);
403
404 // Fire all stop callbacks.
405 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
406
407 // Let all start callbacks fail.
408 RunCallbacks(
409 this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
410
411 // Let all message callbacks fail (this will also fire and clear all
412 // callbacks for events).
413 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
414 RunIDMapCallbacks(&activate_callbacks_,
415 &StatusCallback::Run,
416 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
417 RunIDMapCallbacks(&install_callbacks_,
418 &StatusCallback::Run,
419 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
420 RunIDMapCallbacks(&fetch_callbacks_,
421 &FetchCallback::Run,
422 MakeTuple(SERVICE_WORKER_ERROR_FAILED,
423 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
424 ServiceWorkerResponse()));
425 RunIDMapCallbacks(&sync_callbacks_,
426 &StatusCallback::Run,
427 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
428 RunIDMapCallbacks(&push_callbacks_,
429 &StatusCallback::Run,
430 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
431
432 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
433 }
434
OnReportException(const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)435 void ServiceWorkerVersion::OnReportException(
436 const base::string16& error_message,
437 int line_number,
438 int column_number,
439 const GURL& source_url) {
440 FOR_EACH_OBSERVER(
441 Listener,
442 listeners_,
443 OnErrorReported(
444 this, error_message, line_number, column_number, source_url));
445 }
446
OnReportConsoleMessage(int source_identifier,int message_level,const base::string16 & message,int line_number,const GURL & source_url)447 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
448 int message_level,
449 const base::string16& message,
450 int line_number,
451 const GURL& source_url) {
452 FOR_EACH_OBSERVER(Listener,
453 listeners_,
454 OnReportConsoleMessage(this,
455 source_identifier,
456 message_level,
457 message,
458 line_number,
459 source_url));
460 }
461
OnMessageReceived(const IPC::Message & message)462 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
463 bool handled = true;
464 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
465 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
466 OnGetClientDocuments)
467 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
468 OnActivateEventFinished)
469 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
470 OnInstallEventFinished)
471 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
472 OnFetchEventFinished)
473 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
474 OnSyncEventFinished)
475 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
476 OnPushEventFinished)
477 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
478 OnPostMessageToDocument)
479 IPC_MESSAGE_UNHANDLED(handled = false)
480 IPC_END_MESSAGE_MAP()
481 return handled;
482 }
483
RunStartWorkerCallbacksOnError(ServiceWorkerStatusCode status)484 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
485 ServiceWorkerStatusCode status) {
486 if (status != SERVICE_WORKER_OK)
487 RunCallbacks(this, &start_callbacks_, status);
488 }
489
DispatchInstallEventAfterStartWorker(int active_version_id,const StatusCallback & callback)490 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
491 int active_version_id,
492 const StatusCallback& callback) {
493 DCHECK_EQ(RUNNING, running_status())
494 << "Worker stopped too soon after it was started.";
495 int request_id = install_callbacks_.Add(new StatusCallback(callback));
496 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
497 ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
498 if (status != SERVICE_WORKER_OK) {
499 install_callbacks_.Remove(request_id);
500 RunSoon(base::Bind(callback, status));
501 }
502 }
503
DispatchActivateEventAfterStartWorker(const StatusCallback & callback)504 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
505 const StatusCallback& callback) {
506 DCHECK_EQ(RUNNING, running_status())
507 << "Worker stopped too soon after it was started.";
508 int request_id = activate_callbacks_.Add(new StatusCallback(callback));
509 ServiceWorkerStatusCode status =
510 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
511 if (status != SERVICE_WORKER_OK) {
512 activate_callbacks_.Remove(request_id);
513 RunSoon(base::Bind(callback, status));
514 }
515 }
516
OnGetClientDocuments(int request_id)517 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
518 std::vector<int> client_ids;
519 ControlleeByIDMap::iterator it(&controllee_by_id_);
520 while (!it.IsAtEnd()) {
521 client_ids.push_back(it.GetCurrentKey());
522 it.Advance();
523 }
524 // Don't bother if it's no longer running.
525 if (running_status() == RUNNING) {
526 embedded_worker_->SendMessage(
527 ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
528 }
529 }
530
OnActivateEventFinished(int request_id,blink::WebServiceWorkerEventResult result)531 void ServiceWorkerVersion::OnActivateEventFinished(
532 int request_id,
533 blink::WebServiceWorkerEventResult result) {
534 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
535 if (!callback) {
536 NOTREACHED() << "Got unexpected message: " << request_id;
537 return;
538 }
539 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
540 if (result == blink::WebServiceWorkerEventResultRejected)
541 status = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
542 else
543 SetStatus(ACTIVE);
544
545 scoped_refptr<ServiceWorkerVersion> protect(this);
546 callback->Run(status);
547 activate_callbacks_.Remove(request_id);
548 }
549
OnInstallEventFinished(int request_id,blink::WebServiceWorkerEventResult result)550 void ServiceWorkerVersion::OnInstallEventFinished(
551 int request_id,
552 blink::WebServiceWorkerEventResult result) {
553 StatusCallback* callback = install_callbacks_.Lookup(request_id);
554 if (!callback) {
555 NOTREACHED() << "Got unexpected message: " << request_id;
556 return;
557 }
558 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
559 if (result == blink::WebServiceWorkerEventResultRejected)
560 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
561 else
562 SetStatus(INSTALLED);
563
564 scoped_refptr<ServiceWorkerVersion> protect(this);
565 callback->Run(status);
566 install_callbacks_.Remove(request_id);
567 }
568
OnFetchEventFinished(int request_id,ServiceWorkerFetchEventResult result,const ServiceWorkerResponse & response)569 void ServiceWorkerVersion::OnFetchEventFinished(
570 int request_id,
571 ServiceWorkerFetchEventResult result,
572 const ServiceWorkerResponse& response) {
573 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
574 if (!callback) {
575 NOTREACHED() << "Got unexpected message: " << request_id;
576 return;
577 }
578
579 scoped_refptr<ServiceWorkerVersion> protect(this);
580 callback->Run(SERVICE_WORKER_OK, result, response);
581 fetch_callbacks_.Remove(request_id);
582 }
583
OnSyncEventFinished(int request_id)584 void ServiceWorkerVersion::OnSyncEventFinished(
585 int request_id) {
586 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
587 if (!callback) {
588 NOTREACHED() << "Got unexpected message: " << request_id;
589 return;
590 }
591
592 scoped_refptr<ServiceWorkerVersion> protect(this);
593 callback->Run(SERVICE_WORKER_OK);
594 sync_callbacks_.Remove(request_id);
595 }
596
OnPushEventFinished(int request_id)597 void ServiceWorkerVersion::OnPushEventFinished(
598 int request_id) {
599 StatusCallback* callback = push_callbacks_.Lookup(request_id);
600 if (!callback) {
601 NOTREACHED() << "Got unexpected message: " << request_id;
602 return;
603 }
604
605 scoped_refptr<ServiceWorkerVersion> protect(this);
606 callback->Run(SERVICE_WORKER_OK);
607 push_callbacks_.Remove(request_id);
608 }
609
OnPostMessageToDocument(int client_id,const base::string16 & message,const std::vector<int> & sent_message_port_ids)610 void ServiceWorkerVersion::OnPostMessageToDocument(
611 int client_id,
612 const base::string16& message,
613 const std::vector<int>& sent_message_port_ids) {
614 ServiceWorkerProviderHost* provider_host =
615 controllee_by_id_.Lookup(client_id);
616 if (!provider_host) {
617 // The client may already have been closed, just ignore.
618 return;
619 }
620 provider_host->PostMessage(message, sent_message_port_ids);
621 }
622
ScheduleStopWorker()623 void ServiceWorkerVersion::ScheduleStopWorker() {
624 if (running_status() != RUNNING)
625 return;
626 if (stop_worker_timer_.IsRunning()) {
627 stop_worker_timer_.Reset();
628 return;
629 }
630 stop_worker_timer_.Start(
631 FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
632 base::Bind(&ServiceWorkerVersion::StopWorker,
633 weak_factory_.GetWeakPtr(),
634 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
635 }
636
637 } // namespace content
638