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