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 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 
     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>
     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>
     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.
     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 
     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 
     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 
    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 
    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 
    135 void ServiceWorkerVersion::RegisterStatusChangeCallback(
    136     const base::Closure& callback) {
    137   status_change_callbacks_.push_back(callback);
    138 }
    139 
    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 
    151 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
    152   StartWorkerWithCandidateProcesses(std::vector<int>(), callback);
    153 }
    154 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    336 void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
    337   embedded_worker_->AddProcessReference(process_id);
    338 }
    339 
    340 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
    341   embedded_worker_->ReleaseProcessReference(process_id);
    342 }
    343 
    344 bool ServiceWorkerVersion::HasProcessToRun() const {
    345   return embedded_worker_->HasProcessToRun();
    346 }
    347 
    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 
    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 
    375 void ServiceWorkerVersion::AddWaitingControllee(
    376     ServiceWorkerProviderHost* provider_host) {
    377   AddProcessToWorker(provider_host->process_id());
    378 }
    379 
    380 void ServiceWorkerVersion::RemoveWaitingControllee(
    381     ServiceWorkerProviderHost* provider_host) {
    382   RemoveProcessFromWorker(provider_host->process_id());
    383 }
    384 
    385 void ServiceWorkerVersion::AddListener(Listener* listener) {
    386   listeners_.AddObserver(listener);
    387 }
    388 
    389 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
    390   listeners_.RemoveObserver(listener);
    391 }
    392 
    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 
    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 
    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 
    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 
    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 
    484 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
    485     ServiceWorkerStatusCode status) {
    486   if (status != SERVICE_WORKER_OK)
    487     RunCallbacks(this, &start_callbacks_, status);
    488 }
    489 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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