1// Copyright 2014 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/push_messaging_router.h"
6
7#include "base/bind.h"
8#include "content/browser/service_worker/service_worker_context_wrapper.h"
9#include "content/browser/service_worker/service_worker_registration.h"
10#include "content/browser/service_worker/service_worker_storage.h"
11#include "content/public/browser/browser_context.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/storage_partition.h"
14
15namespace content {
16
17// static
18void PushMessagingRouter::DeliverMessage(
19    BrowserContext* browser_context,
20    const GURL& origin,
21    int64 service_worker_registration_id,
22    const std::string& data,
23    const DeliverMessageCallback& deliver_message_callback) {
24  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
25  StoragePartition* partition =
26      BrowserContext::GetStoragePartitionForSite(browser_context, origin);
27  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
28      static_cast<ServiceWorkerContextWrapper*>(
29          partition->GetServiceWorkerContext());
30  BrowserThread::PostTask(
31      BrowserThread::IO,
32      FROM_HERE,
33      base::Bind(&PushMessagingRouter::FindServiceWorkerRegistration,
34                 origin,
35                 service_worker_registration_id,
36                 data,
37                 deliver_message_callback,
38                 service_worker_context));
39}
40
41// static
42void PushMessagingRouter::FindServiceWorkerRegistration(
43    const GURL& origin,
44    int64 service_worker_registration_id,
45    const std::string& data,
46    const DeliverMessageCallback& deliver_message_callback,
47    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
48  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
49  // Try to acquire the registration from storage. If it's already live we'll
50  // receive it right away. If not, it will be revived from storage.
51  service_worker_context->context()->storage()->FindRegistrationForId(
52      service_worker_registration_id,
53      origin,
54      base::Bind(&PushMessagingRouter::FindServiceWorkerRegistrationCallback,
55                 data,
56                 deliver_message_callback));
57}
58
59// static
60void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
61    const std::string& data,
62    const DeliverMessageCallback& deliver_message_callback,
63    ServiceWorkerStatusCode service_worker_status,
64    const scoped_refptr<ServiceWorkerRegistration>&
65        service_worker_registration) {
66  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
67  if (service_worker_status == SERVICE_WORKER_OK) {
68    // Hold on to the service worker registration in the callback to keep it
69    // alive until the callback dies. Otherwise the registration could be
70    // released when this method returns - before the event is delivered to the
71    // service worker.
72    base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
73        base::Bind(&PushMessagingRouter::DeliverMessageEnd,
74                   deliver_message_callback,
75                   service_worker_registration);
76    service_worker_registration->active_version()->DispatchPushEvent(
77        dispatch_event_callback, data);
78  } else {
79    // TODO(mvanouwerkerk): UMA logging.
80    BrowserThread::PostTask(
81        BrowserThread::UI,
82        FROM_HERE,
83        base::Bind(
84            deliver_message_callback,
85            PUSH_MESSAGING_STATUS_MESSAGE_DELIVERY_FAILED_NO_SERVICE_WORKER));
86  }
87}
88
89// static
90void PushMessagingRouter::DeliverMessageEnd(
91    const DeliverMessageCallback& deliver_message_callback,
92    const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
93    ServiceWorkerStatusCode service_worker_status) {
94  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
95  // TODO(mvanouwerkerk): UMA logging.
96  PushMessagingStatus push_messaging_status =
97      service_worker_status == SERVICE_WORKER_OK
98          ? PUSH_MESSAGING_STATUS_OK
99          : PUSH_MESSAGING_STATUS_MESSAGE_DELIVERY_FAILED_SERVICE_WORKER_ERROR;
100  BrowserThread::PostTask(
101      BrowserThread::UI,
102      FROM_HERE,
103      base::Bind(deliver_message_callback, push_messaging_status));
104}
105
106}  // namespace content
107