diff options
author | falken <falken@chromium.org> | 2015-05-08 02:52:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-08 09:53:01 +0000 |
commit | 4a917d9d08ad3ee2cbb449b591640351ce76605b (patch) | |
tree | 5e9aeffe6d7b99e2f0bf9dad3fd383ecef664c6c /content/browser/push_messaging/push_messaging_router.cc | |
parent | 5b27284e3d228a905ff130869bf1ff2573730ce0 (diff) | |
download | chromium_src-4a917d9d08ad3ee2cbb449b591640351ce76605b.zip chromium_src-4a917d9d08ad3ee2cbb449b591640351ce76605b.tar.gz chromium_src-4a917d9d08ad3ee2cbb449b591640351ce76605b.tar.bz2 |
Push: Fix crash when dispatching push to a registration with no active worker
A registration could have no active worker in some cases:
- The browser shut down while there was a waiting worker. When the browser
starts up again, there will be no active worker until the waiting worker
is promoted (see
ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource)
- The active worker was evicted, because it unexpectedly couldn't be read
from the disk cache: crbug.com/448003
- The subscription occurred while the registration had an active worker in
the activating state, but then activation failed and the worker was booted
(however this behavior will soon change: crbug.com/480050)
BUG=483335
Review URL: https://codereview.chromium.org/1131713003
Cr-Commit-Position: refs/heads/master@{#328940}
Diffstat (limited to 'content/browser/push_messaging/push_messaging_router.cc')
-rw-r--r-- | content/browser/push_messaging/push_messaging_router.cc | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc index 905db11..f5d75f2 100644 --- a/content/browser/push_messaging/push_messaging_router.cc +++ b/content/browser/push_messaging/push_messaging_router.cc @@ -15,6 +15,18 @@ namespace content { +namespace { + +void RunDeliverCallback( + const PushMessagingRouter::DeliverMessageCallback& deliver_message_callback, + PushDeliveryStatus delivery_status) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(deliver_message_callback, delivery_status)); +} + +} // namespace + // static void PushMessagingRouter::DeliverMessage( BrowserContext* browser_context, @@ -65,24 +77,39 @@ void PushMessagingRouter::FindServiceWorkerRegistrationCallback( const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (service_worker_status == SERVICE_WORKER_OK) { - // Hold on to the service worker registration in the callback to keep it - // alive until the callback dies. Otherwise the registration could be - // released when this method returns - before the event is delivered to the - // service worker. - base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback = - base::Bind(&PushMessagingRouter::DeliverMessageEnd, - deliver_message_callback, - service_worker_registration); - service_worker_registration->active_version()->DispatchPushEvent( - dispatch_event_callback, data); - } else { - // TODO(mvanouwerkerk): UMA logging. - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(deliver_message_callback, - PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER)); + // TODO(mvanouwerkerk): UMA logging. + if (service_worker_status != SERVICE_WORKER_OK) { + RunDeliverCallback(deliver_message_callback, + PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER); + return; } + + ServiceWorkerVersion* version = service_worker_registration->active_version(); + if (!version) { + // Using NO_SERVICE_WORKER status will unsubscribe with GCM, so don't use it + // if we have a waiting version in the hopper. On the other hand, if there + // is no waiting version, it's an unexpected error case: we should have been + // informed the registration went away (but we may not have been: + // crbug.com/402458) + // TODO(falken): Promote the waiting version instead of returning error. + if (service_worker_registration->waiting_version()) { + RunDeliverCallback(deliver_message_callback, + PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR); + } else { + RunDeliverCallback(deliver_message_callback, + PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER); + } + return; + } + + // Hold on to the service worker registration in the callback to keep it + // alive until the callback dies. Otherwise the registration could be + // released when this method returns - before the event is delivered to the + // service worker. + base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback = + base::Bind(&PushMessagingRouter::DeliverMessageEnd, + deliver_message_callback, service_worker_registration); + version->DispatchPushEvent(dispatch_event_callback, data); } // static @@ -124,10 +151,7 @@ void PushMessagingRouter::DeliverMessageEnd( delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR; break; } - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(deliver_message_callback, delivery_status)); + RunDeliverCallback(deliver_message_callback, delivery_status); } } // namespace content |