Fix various typos, error handling for GN auto-roller.
[chromium-blink-merge.git] / content / child / notifications / notification_manager.cc
blob70a61403338484657403e5b8292d2919f8fbed93
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.
5 #include "content/child/notifications/notification_manager.h"
7 #include <cmath>
9 #include "base/lazy_instance.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread_local.h"
14 #include "content/child/notifications/notification_data_conversions.h"
15 #include "content/child/notifications/notification_dispatcher.h"
16 #include "content/child/service_worker/web_service_worker_registration_impl.h"
17 #include "content/child/thread_safe_sender.h"
18 #include "content/child/worker_task_runner.h"
19 #include "content/public/common/platform_notification_data.h"
20 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
21 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationDelegate.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
24 using blink::WebNotificationPermission;
26 namespace content {
27 namespace {
29 int CurrentWorkerId() {
30 return WorkerTaskRunner::Instance()->CurrentWorkerId();
33 } // namespace
35 static base::LazyInstance<base::ThreadLocalPointer<NotificationManager>>::Leaky
36 g_notification_manager_tls = LAZY_INSTANCE_INITIALIZER;
38 NotificationManager::NotificationManager(
39 ThreadSafeSender* thread_safe_sender,
40 base::SingleThreadTaskRunner* main_thread_task_runner,
41 NotificationDispatcher* notification_dispatcher)
42 : thread_safe_sender_(thread_safe_sender),
43 notification_dispatcher_(notification_dispatcher),
44 pending_notifications_(main_thread_task_runner) {
45 g_notification_manager_tls.Pointer()->Set(this);
48 NotificationManager::~NotificationManager() {
49 g_notification_manager_tls.Pointer()->Set(nullptr);
52 NotificationManager* NotificationManager::ThreadSpecificInstance(
53 ThreadSafeSender* thread_safe_sender,
54 base::SingleThreadTaskRunner* main_thread_task_runner,
55 NotificationDispatcher* notification_dispatcher) {
56 if (g_notification_manager_tls.Pointer()->Get())
57 return g_notification_manager_tls.Pointer()->Get();
59 NotificationManager* manager = new NotificationManager(
60 thread_safe_sender, main_thread_task_runner, notification_dispatcher);
61 if (CurrentWorkerId())
62 WorkerTaskRunner::Instance()->AddStopObserver(manager);
63 return manager;
66 void NotificationManager::OnWorkerRunLoopStopped() {
67 delete this;
70 void NotificationManager::show(
71 const blink::WebSecurityOrigin& origin,
72 const blink::WebNotificationData& notification_data,
73 blink::WebNotificationDelegate* delegate) {
74 if (notification_data.icon.isEmpty()) {
75 DisplayPageNotification(origin, notification_data, delegate, SkBitmap());
76 return;
79 pending_notifications_.FetchPageNotificationResources(
80 notification_data,
81 delegate,
82 base::Bind(&NotificationManager::DisplayPageNotification,
83 base::Unretained(this), // this owns |pending_notifications_|
84 origin,
85 notification_data,
86 delegate));
89 void NotificationManager::showPersistent(
90 const blink::WebSecurityOrigin& origin,
91 const blink::WebNotificationData& notification_data,
92 blink::WebServiceWorkerRegistration* service_worker_registration,
93 blink::WebNotificationShowCallbacks* callbacks) {
94 DCHECK(service_worker_registration);
95 int64_t service_worker_registration_id =
96 static_cast<WebServiceWorkerRegistrationImpl*>(
97 service_worker_registration)->registration_id();
99 scoped_ptr<blink::WebNotificationShowCallbacks> owned_callbacks(callbacks);
101 // Verify that the author-provided payload size does not exceed our limit.
102 // This is an implementation-defined limit to prevent abuse of notification
103 // data as a storage mechanism. A UMA histogram records the requested sizes,
104 // which enables us to track how much data authors are attempting to store.
106 // If the size exceeds this limit, reject the showNotification() promise. This
107 // is outside of the boundaries set by the specification, but it gives authors
108 // an indication that something has gone wrong.
109 size_t author_data_size = notification_data.data.size();
110 UMA_HISTOGRAM_MEMORY_KB("Notifications.AuthorDataSizeKB",
111 static_cast<int>(ceil(author_data_size / 1024.0)));
113 if (author_data_size > PlatformNotificationData::kMaximumDeveloperDataSize) {
114 owned_callbacks->onError();
115 return;
118 if (notification_data.icon.isEmpty()) {
119 DisplayPersistentNotification(origin,
120 notification_data,
121 service_worker_registration_id,
122 owned_callbacks.Pass(),
123 SkBitmap());
124 return;
127 pending_notifications_.FetchPersistentNotificationResources(
128 notification_data,
129 base::Bind(&NotificationManager::DisplayPersistentNotification,
130 base::Unretained(this), // this owns |pending_notifications_|
131 origin,
132 notification_data,
133 service_worker_registration_id,
134 base::Passed(&owned_callbacks)));
137 void NotificationManager::getNotifications(
138 const blink::WebString& filter_tag,
139 blink::WebServiceWorkerRegistration* service_worker_registration,
140 blink::WebNotificationGetCallbacks* callbacks) {
141 DCHECK(service_worker_registration);
142 DCHECK(callbacks);
144 WebServiceWorkerRegistrationImpl* service_worker_registration_impl =
145 static_cast<WebServiceWorkerRegistrationImpl*>(
146 service_worker_registration);
148 GURL origin = GURL(service_worker_registration_impl->scope()).GetOrigin();
149 int64_t service_worker_registration_id =
150 service_worker_registration_impl->registration_id();
152 // TODO(peter): GenerateNotificationId is more of a request id. Consider
153 // renaming the method in the NotificationDispatcher if this makes sense.
154 int request_id =
155 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
157 pending_get_notification_requests_.AddWithID(callbacks, request_id);
159 thread_safe_sender_->Send(
160 new PlatformNotificationHostMsg_GetNotifications(
161 request_id,
162 service_worker_registration_id,
163 origin,
164 base::UTF16ToUTF8(base::StringPiece16(filter_tag))));
167 void NotificationManager::close(blink::WebNotificationDelegate* delegate) {
168 if (pending_notifications_.CancelPageNotificationFetches(delegate))
169 return;
171 for (auto& iter : active_page_notifications_) {
172 if (iter.second != delegate)
173 continue;
175 thread_safe_sender_->Send(
176 new PlatformNotificationHostMsg_Close(iter.first));
177 active_page_notifications_.erase(iter.first);
178 return;
181 // It should not be possible for Blink to call close() on a Notification which
182 // does not exist in either the pending or active notification lists.
183 NOTREACHED();
186 void NotificationManager::closePersistent(
187 const blink::WebSecurityOrigin& origin,
188 int64_t persistent_notification_id) {
189 thread_safe_sender_->Send(new PlatformNotificationHostMsg_ClosePersistent(
190 // TODO(mkwst): This is potentially doing the wrong thing with unique
191 // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
192 // https://crbug.com/490074 for detail.
193 GURL(origin.toString()), persistent_notification_id));
196 void NotificationManager::notifyDelegateDestroyed(
197 blink::WebNotificationDelegate* delegate) {
198 if (pending_notifications_.CancelPageNotificationFetches(delegate))
199 return;
201 for (auto& iter : active_page_notifications_) {
202 if (iter.second != delegate)
203 continue;
205 active_page_notifications_.erase(iter.first);
206 return;
210 WebNotificationPermission NotificationManager::checkPermission(
211 const blink::WebSecurityOrigin& origin) {
212 WebNotificationPermission permission =
213 blink::WebNotificationPermissionAllowed;
214 // TODO(mkwst): This is potentially doing the wrong thing with unique
215 // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
216 // https://crbug.com/490074 for detail.
217 thread_safe_sender_->Send(new PlatformNotificationHostMsg_CheckPermission(
218 GURL(origin.toString()), &permission));
220 return permission;
223 bool NotificationManager::OnMessageReceived(const IPC::Message& message) {
224 bool handled = true;
225 IPC_BEGIN_MESSAGE_MAP(NotificationManager, message)
226 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow, OnDidShow);
227 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent,
228 OnDidShowPersistent)
229 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose, OnDidClose);
230 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick, OnDidClick);
231 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidGetNotifications,
232 OnDidGetNotifications)
233 IPC_MESSAGE_UNHANDLED(handled = false)
234 IPC_END_MESSAGE_MAP()
236 return handled;
239 void NotificationManager::OnDidShow(int notification_id) {
240 const auto& iter = active_page_notifications_.find(notification_id);
241 if (iter == active_page_notifications_.end())
242 return;
244 iter->second->dispatchShowEvent();
247 void NotificationManager::OnDidShowPersistent(int request_id, bool success) {
248 blink::WebNotificationShowCallbacks* callbacks =
249 pending_show_notification_requests_.Lookup(request_id);
250 DCHECK(callbacks);
252 if (!callbacks)
253 return;
255 if (success)
256 callbacks->onSuccess();
257 else
258 callbacks->onError();
260 pending_show_notification_requests_.Remove(request_id);
263 void NotificationManager::OnDidClose(int notification_id) {
264 const auto& iter = active_page_notifications_.find(notification_id);
265 if (iter == active_page_notifications_.end())
266 return;
268 iter->second->dispatchCloseEvent();
269 active_page_notifications_.erase(iter);
272 void NotificationManager::OnDidClick(int notification_id) {
273 const auto& iter = active_page_notifications_.find(notification_id);
274 if (iter == active_page_notifications_.end())
275 return;
277 iter->second->dispatchClickEvent();
280 void NotificationManager::OnDidGetNotifications(
281 int request_id,
282 const std::vector<PersistentNotificationInfo>& notification_infos) {
283 blink::WebNotificationGetCallbacks* callbacks =
284 pending_get_notification_requests_.Lookup(request_id);
285 DCHECK(callbacks);
286 if (!callbacks)
287 return;
289 scoped_ptr<blink::WebVector<blink::WebPersistentNotificationInfo>>
290 notifications(new blink::WebVector<blink::WebPersistentNotificationInfo>(
291 notification_infos.size()));
293 for (size_t i = 0; i < notification_infos.size(); ++i) {
294 blink::WebPersistentNotificationInfo web_notification_info;
295 web_notification_info.persistentId = notification_infos[i].first;
296 web_notification_info.data =
297 ToWebNotificationData(notification_infos[i].second);
299 (*notifications)[i] = web_notification_info;
302 callbacks->onSuccess(notifications.release());
304 pending_get_notification_requests_.Remove(request_id);
307 void NotificationManager::DisplayPageNotification(
308 const blink::WebSecurityOrigin& origin,
309 const blink::WebNotificationData& notification_data,
310 blink::WebNotificationDelegate* delegate,
311 const SkBitmap& icon) {
312 int notification_id =
313 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
315 active_page_notifications_[notification_id] = delegate;
316 // TODO(mkwst): This is potentially doing the wrong thing with unique
317 // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
318 // https://crbug.com/490074 for detail.
319 thread_safe_sender_->Send(new PlatformNotificationHostMsg_Show(
320 notification_id, GURL(origin.toString()), icon,
321 ToPlatformNotificationData(notification_data)));
324 void NotificationManager::DisplayPersistentNotification(
325 const blink::WebSecurityOrigin& origin,
326 const blink::WebNotificationData& notification_data,
327 int64_t service_worker_registration_id,
328 scoped_ptr<blink::WebNotificationShowCallbacks> callbacks,
329 const SkBitmap& icon) {
330 // TODO(peter): GenerateNotificationId is more of a request id. Consider
331 // renaming the method in the NotificationDispatcher if this makes sense.
332 int request_id =
333 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
335 pending_show_notification_requests_.AddWithID(callbacks.release(),
336 request_id);
338 // TODO(mkwst): This is potentially doing the wrong thing with unique
339 // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
340 // https://crbug.com/490074 for detail.
341 thread_safe_sender_->Send(new PlatformNotificationHostMsg_ShowPersistent(
342 request_id, service_worker_registration_id, GURL(origin.toString()), icon,
343 ToPlatformNotificationData(notification_data)));
346 } // namespace content