summaryrefslogtreecommitdiffstats
path: root/content/browser/push_messaging/push_messaging_router.cc
diff options
context:
space:
mode:
authorfalken <falken@chromium.org>2015-05-08 02:52:28 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-08 09:53:01 +0000
commit4a917d9d08ad3ee2cbb449b591640351ce76605b (patch)
tree5e9aeffe6d7b99e2f0bf9dad3fd383ecef664c6c /content/browser/push_messaging/push_messaging_router.cc
parent5b27284e3d228a905ff130869bf1ff2573730ce0 (diff)
downloadchromium_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.cc66
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