Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / content / child / permissions / permission_dispatcher.cc
blob4fa87ebb30c53c11381c95c935286ddd670f5016
1 // Copyright 2015 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/permissions/permission_dispatcher.h"
7 #include "base/callback.h"
8 #include "content/child/worker_task_runner.h"
9 #include "content/public/common/service_registry.h"
10 #include "third_party/WebKit/public/platform/WebURL.h"
11 #include "third_party/WebKit/public/platform/modules/permissions/WebPermissionObserver.h"
12 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
14 using blink::WebPermissionObserver;
16 namespace content {
18 namespace {
20 PermissionName GetPermissionName(blink::WebPermissionType type) {
21 switch (type) {
22 case blink::WebPermissionTypeGeolocation:
23 return PERMISSION_NAME_GEOLOCATION;
24 case blink::WebPermissionTypeNotifications:
25 return PERMISSION_NAME_NOTIFICATIONS;
26 case blink::WebPermissionTypePushNotifications:
27 return PERMISSION_NAME_PUSH_NOTIFICATIONS;
28 case blink::WebPermissionTypeMidiSysEx:
29 return PERMISSION_NAME_MIDI_SYSEX;
30 default:
31 // The default statement is only there to prevent compilation failures if
32 // WebPermissionType enum gets extended.
33 NOTREACHED();
34 return PERMISSION_NAME_GEOLOCATION;
38 PermissionStatus GetPermissionStatus(blink::WebPermissionStatus status) {
39 switch (status) {
40 case blink::WebPermissionStatusGranted:
41 return PERMISSION_STATUS_GRANTED;
42 case blink::WebPermissionStatusDenied:
43 return PERMISSION_STATUS_DENIED;
44 case blink::WebPermissionStatusPrompt:
45 return PERMISSION_STATUS_ASK;
48 NOTREACHED();
49 return PERMISSION_STATUS_DENIED;
52 blink::WebPermissionStatus GetWebPermissionStatus(PermissionStatus status) {
53 switch (status) {
54 case PERMISSION_STATUS_GRANTED:
55 return blink::WebPermissionStatusGranted;
56 case PERMISSION_STATUS_DENIED:
57 return blink::WebPermissionStatusDenied;
58 case PERMISSION_STATUS_ASK:
59 return blink::WebPermissionStatusPrompt;
62 NOTREACHED();
63 return blink::WebPermissionStatusDenied;
66 const int kNoWorkerThread = 0;
68 } // anonymous namespace
70 // static
71 bool PermissionDispatcher::IsObservable(blink::WebPermissionType type) {
72 return type == blink::WebPermissionTypeGeolocation ||
73 type == blink::WebPermissionTypeNotifications ||
74 type == blink::WebPermissionTypePushNotifications ||
75 type == blink::WebPermissionTypeMidiSysEx;
78 PermissionDispatcher::CallbackInformation::CallbackInformation(
79 blink::WebPermissionCallback* callback,
80 int worker_thread_id)
81 : callback_(callback),
82 worker_thread_id_(worker_thread_id) {
85 blink::WebPermissionCallback*
86 PermissionDispatcher::CallbackInformation::callback() const {
87 return callback_.get();
90 int PermissionDispatcher::CallbackInformation::worker_thread_id() const {
91 return worker_thread_id_;
94 blink::WebPermissionCallback*
95 PermissionDispatcher::CallbackInformation::ReleaseCallback() {
96 return callback_.release();
99 PermissionDispatcher::CallbackInformation::~CallbackInformation() {
102 PermissionDispatcher::PermissionDispatcher(ServiceRegistry* service_registry)
103 : service_registry_(service_registry) {
106 PermissionDispatcher::~PermissionDispatcher() {
109 void PermissionDispatcher::queryPermission(
110 blink::WebPermissionType type,
111 const blink::WebURL& origin,
112 blink::WebPermissionCallback* callback) {
113 QueryPermissionInternal(
114 type, origin.string().utf8(), callback, kNoWorkerThread);
117 void PermissionDispatcher::requestPermission(
118 blink::WebPermissionType type,
119 const blink::WebURL& origin,
120 blink::WebPermissionCallback* callback) {
121 RequestPermissionInternal(
122 type, origin.string().utf8(), callback, kNoWorkerThread);
125 void PermissionDispatcher::revokePermission(
126 blink::WebPermissionType type,
127 const blink::WebURL& origin,
128 blink::WebPermissionCallback* callback) {
129 RevokePermissionInternal(
130 type, origin.string().utf8(), callback, kNoWorkerThread);
133 void PermissionDispatcher::startListening(
134 blink::WebPermissionType type,
135 const blink::WebURL& origin,
136 WebPermissionObserver* observer) {
137 if (!IsObservable(type))
138 return;
140 RegisterObserver(observer);
142 GetNextPermissionChange(type,
143 origin.string().utf8(),
144 observer,
145 // We initialize with an arbitrary value because the
146 // mojo service wants a value. Worst case, the
147 // observer will get notified about a non-change which
148 // should be a no-op. After the first notification,
149 // GetNextPermissionChange will be called with the
150 // latest known value.
151 PERMISSION_STATUS_ASK);
154 void PermissionDispatcher::stopListening(WebPermissionObserver* observer) {
155 UnregisterObserver(observer);
158 void PermissionDispatcher::QueryPermissionForWorker(
159 blink::WebPermissionType type,
160 const std::string& origin,
161 blink::WebPermissionCallback* callback,
162 int worker_thread_id) {
163 QueryPermissionInternal(type, origin, callback, worker_thread_id);
166 void PermissionDispatcher::RequestPermissionForWorker(
167 blink::WebPermissionType type,
168 const std::string& origin,
169 blink::WebPermissionCallback* callback,
170 int worker_thread_id) {
171 RequestPermissionInternal(type, origin, callback, worker_thread_id);
174 void PermissionDispatcher::RevokePermissionForWorker(
175 blink::WebPermissionType type,
176 const std::string& origin,
177 blink::WebPermissionCallback* callback,
178 int worker_thread_id) {
179 RevokePermissionInternal(type, origin, callback, worker_thread_id);
182 void PermissionDispatcher::StartListeningForWorker(
183 blink::WebPermissionType type,
184 const std::string& origin,
185 int worker_thread_id,
186 const base::Callback<void(blink::WebPermissionStatus)>& callback) {
187 GetPermissionServicePtr()->GetNextPermissionChange(
188 GetPermissionName(type),
189 origin,
190 // We initialize with an arbitrary value because the mojo service wants a
191 // value. Worst case, the observer will get notified about a non-change
192 // which should be a no-op. After the first notification,
193 // GetNextPermissionChange will be called with the latest known value.
194 PERMISSION_STATUS_ASK,
195 base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
196 base::Unretained(this),
197 worker_thread_id,
198 callback));
201 void PermissionDispatcher::GetNextPermissionChangeForWorker(
202 blink::WebPermissionType type,
203 const std::string& origin,
204 blink::WebPermissionStatus status,
205 int worker_thread_id,
206 const base::Callback<void(blink::WebPermissionStatus)>& callback) {
207 GetPermissionServicePtr()->GetNextPermissionChange(
208 GetPermissionName(type),
209 origin,
210 GetPermissionStatus(status),
211 base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
212 base::Unretained(this),
213 worker_thread_id,
214 callback));
217 // static
218 void PermissionDispatcher::RunCallbackOnWorkerThread(
219 blink::WebPermissionCallback* callback,
220 scoped_ptr<blink::WebPermissionStatus> status) {
221 callback->onSuccess(status.release());
222 delete callback;
225 PermissionServicePtr& PermissionDispatcher::GetPermissionServicePtr() {
226 if (!permission_service_.get()) {
227 service_registry_->ConnectToRemoteService(
228 mojo::GetProxy(&permission_service_));
230 return permission_service_;
233 void PermissionDispatcher::QueryPermissionInternal(
234 blink::WebPermissionType type,
235 const std::string& origin,
236 blink::WebPermissionCallback* callback,
237 int worker_thread_id) {
238 // We need to save the |callback| in an IDMap so if |this| gets deleted, the
239 // callback will not leak. In the case of |this| gets deleted, the
240 // |permission_service_| pipe will be destroyed too so OnQueryPermission will
241 // not be called.
242 int request_id = pending_callbacks_.Add(
243 new CallbackInformation(callback, worker_thread_id));
244 GetPermissionServicePtr()->HasPermission(
245 GetPermissionName(type),
246 origin,
247 base::Bind(&PermissionDispatcher::OnPermissionResponse,
248 base::Unretained(this),
249 request_id));
252 void PermissionDispatcher::RequestPermissionInternal(
253 blink::WebPermissionType type,
254 const std::string& origin,
255 blink::WebPermissionCallback* callback,
256 int worker_thread_id) {
257 // We need to save the |callback| in an IDMap so if |this| gets deleted, the
258 // callback will not leak. In the case of |this| gets deleted, the
259 // |permission_service_| pipe will be destroyed too so OnQueryPermission will
260 // not be called.
261 int request_id = pending_callbacks_.Add(
262 new CallbackInformation(callback, worker_thread_id));
263 GetPermissionServicePtr()->RequestPermission(
264 GetPermissionName(type),
265 origin,
266 blink::WebUserGestureIndicator::isProcessingUserGesture(),
267 base::Bind(&PermissionDispatcher::OnPermissionResponse,
268 base::Unretained(this),
269 request_id));
272 void PermissionDispatcher::RevokePermissionInternal(
273 blink::WebPermissionType type,
274 const std::string& origin,
275 blink::WebPermissionCallback* callback,
276 int worker_thread_id) {
277 // We need to save the |callback| in an IDMap so if |this| gets deleted, the
278 // callback will not leak. In the case of |this| gets deleted, the
279 // |permission_service_| pipe will be destroyed too so OnQueryPermission will
280 // not be called.
281 int request_id = pending_callbacks_.Add(
282 new CallbackInformation(callback, worker_thread_id));
283 GetPermissionServicePtr()->RevokePermission(
284 GetPermissionName(type),
285 origin,
286 base::Bind(&PermissionDispatcher::OnPermissionResponse,
287 base::Unretained(this),
288 request_id));
291 void PermissionDispatcher::OnPermissionResponse(int request_id,
292 PermissionStatus result) {
293 CallbackInformation* callback_information =
294 pending_callbacks_.Lookup(request_id);
295 DCHECK(callback_information && callback_information->callback());
296 scoped_ptr<blink::WebPermissionStatus> status(
297 new blink::WebPermissionStatus(GetWebPermissionStatus(result)));
299 if (callback_information->worker_thread_id() != kNoWorkerThread) {
300 blink::WebPermissionCallback* callback =
301 callback_information->ReleaseCallback();
302 int worker_thread_id = callback_information->worker_thread_id();
303 pending_callbacks_.Remove(request_id);
305 // If the worker is no longer running, ::PostTask() will return false and
306 // gracefully fail, destroying the callback too.
307 WorkerTaskRunner::Instance()->PostTask(
308 worker_thread_id,
309 base::Bind(&PermissionDispatcher::RunCallbackOnWorkerThread,
310 base::Unretained(callback),
311 base::Passed(&status)));
312 return;
315 callback_information->callback()->onSuccess(status.release());
316 pending_callbacks_.Remove(request_id);
319 void PermissionDispatcher::OnPermissionChanged(
320 blink::WebPermissionType type,
321 const std::string& origin,
322 WebPermissionObserver* observer,
323 PermissionStatus status) {
324 if (!IsObserverRegistered(observer))
325 return;
327 observer->permissionChanged(type, GetWebPermissionStatus(status));
329 GetNextPermissionChange(type, origin, observer, status);
332 void PermissionDispatcher::OnPermissionChangedForWorker(
333 int worker_thread_id,
334 const base::Callback<void(blink::WebPermissionStatus)>& callback,
335 PermissionStatus status) {
336 DCHECK(worker_thread_id != kNoWorkerThread);
338 WorkerTaskRunner::Instance()->PostTask(
339 worker_thread_id, base::Bind(callback, GetWebPermissionStatus(status)));
342 void PermissionDispatcher::GetNextPermissionChange(
343 blink::WebPermissionType type,
344 const std::string& origin,
345 WebPermissionObserver* observer,
346 PermissionStatus current_status) {
347 GetPermissionServicePtr()->GetNextPermissionChange(
348 GetPermissionName(type),
349 origin,
350 current_status,
351 base::Bind(&PermissionDispatcher::OnPermissionChanged,
352 base::Unretained(this),
353 type,
354 origin,
355 base::Unretained(observer)));
358 } // namespace content