[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / permissions / permission_service_impl.cc
blob23bf0981c4b12940354476927567553a8690b584
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/browser/permissions/permission_service_impl.h"
7 #include "base/bind.h"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/permission_manager.h"
10 #include "content/public/browser/permission_type.h"
12 namespace content {
14 namespace {
16 PermissionType PermissionNameToPermissionType(PermissionName name) {
17 switch(name) {
18 case PERMISSION_NAME_GEOLOCATION:
19 return PermissionType::GEOLOCATION;
20 case PERMISSION_NAME_NOTIFICATIONS:
21 return PermissionType::NOTIFICATIONS;
22 case PERMISSION_NAME_PUSH_NOTIFICATIONS:
23 return PermissionType::PUSH_MESSAGING;
24 case PERMISSION_NAME_MIDI:
25 return PermissionType::MIDI;
26 case PERMISSION_NAME_MIDI_SYSEX:
27 return PermissionType::MIDI_SYSEX;
28 case PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER:
29 return PermissionType::PROTECTED_MEDIA_IDENTIFIER;
30 case PERMISSION_NAME_DURABLE_STORAGE:
31 return PermissionType::DURABLE_STORAGE;
32 case PERMISSION_NAME_AUDIO_CAPTURE:
33 return PermissionType::AUDIO_CAPTURE;
34 case PERMISSION_NAME_VIDEO_CAPTURE:
35 return PermissionType::VIDEO_CAPTURE;
38 NOTREACHED();
39 return PermissionType::NUM;
42 } // anonymous namespace
44 PermissionServiceImpl::PendingRequest::PendingRequest(
45 PermissionType permission,
46 const GURL& origin,
47 const PermissionStatusCallback& callback)
48 : permission(permission),
49 origin(origin),
50 callback(callback) {
53 PermissionServiceImpl::PendingRequest::~PendingRequest() {
54 if (!callback.is_null())
55 callback.Run(PERMISSION_STATUS_ASK);
58 PermissionServiceImpl::PendingSubscription::PendingSubscription(
59 PermissionType permission,
60 const GURL& origin,
61 const PermissionStatusCallback& callback)
62 : id(-1),
63 permission(permission),
64 origin(origin),
65 callback(callback) {
68 PermissionServiceImpl::PendingSubscription::~PendingSubscription() {
69 if (!callback.is_null())
70 callback.Run(PERMISSION_STATUS_ASK);
73 PermissionServiceImpl::PermissionServiceImpl(
74 PermissionServiceContext* context,
75 mojo::InterfaceRequest<PermissionService> request)
76 : context_(context),
77 binding_(this, request.Pass()),
78 weak_factory_(this) {
79 binding_.set_connection_error_handler(
80 base::Bind(&PermissionServiceImpl::OnConnectionError,
81 base::Unretained(this)));
84 PermissionServiceImpl::~PermissionServiceImpl() {
85 DCHECK(pending_requests_.IsEmpty());
88 void PermissionServiceImpl::OnConnectionError() {
89 context_->ServiceHadConnectionError(this);
90 // After that call, |this| will be deleted.
93 void PermissionServiceImpl::RequestPermission(
94 PermissionName permission,
95 const mojo::String& origin,
96 bool user_gesture,
97 const PermissionStatusCallback& callback) {
98 // This condition is valid if the call is coming from a ChildThread instead of
99 // a RenderFrame. Some consumers of the service run in Workers and some in
100 // Frames. In the context of a Worker, it is not possible to show a
101 // permission prompt because there is no tab. In the context of a Frame, we
102 // can. Even if the call comes from a context where it is not possible to show
103 // any UI, we want to still return something relevant so the current
104 // permission status is returned.
105 if (!context_->render_frame_host()) {
106 // There is no way to show a UI so the call will simply return the current
107 // permission.
108 HasPermission(permission, origin, callback);
109 return;
112 BrowserContext* browser_context = context_->GetBrowserContext();
113 DCHECK(browser_context);
114 if (!browser_context->GetPermissionManager()) {
115 callback.Run(content::PERMISSION_STATUS_DENIED);
116 return;
119 PermissionType permission_type = PermissionNameToPermissionType(permission);
120 int request_id = pending_requests_.Add(
121 new PendingRequest(permission_type, GURL(origin), callback));
123 browser_context->GetPermissionManager()->RequestPermission(
124 permission_type,
125 context_->render_frame_host(),
126 request_id,
127 GURL(origin),
128 user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
129 base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
130 weak_factory_.GetWeakPtr(),
131 request_id));
134 void PermissionServiceImpl::RequestPermissions(
135 mojo::Array<PermissionName> permissions,
136 const mojo::String& origin,
137 bool user_gesture,
138 const PermissionsStatusCallback& callback) {
139 NOTIMPLEMENTED();
141 // TODO(lalitm,mlamouri): this is returning the current permission statuses
142 // in order for the call to successfully return. It will be changed later.
143 // See https://crbug.com/516626
144 mojo::Array<PermissionStatus> result(permissions.size());
145 for (size_t i = 0; i < permissions.size(); ++i)
146 result[i] = GetPermissionStatusFromName(permissions[i], GURL(origin));
147 callback.Run(result.Pass());
150 void PermissionServiceImpl::OnRequestPermissionResponse(
151 int request_id,
152 PermissionStatus status) {
153 PendingRequest* request = pending_requests_.Lookup(request_id);
154 PermissionStatusCallback callback(request->callback);
155 request->callback.reset();
156 pending_requests_.Remove(request_id);
157 callback.Run(status);
160 void PermissionServiceImpl::CancelPendingOperations() {
161 DCHECK(context_->render_frame_host());
162 DCHECK(context_->GetBrowserContext());
164 PermissionManager* permission_manager =
165 context_->GetBrowserContext()->GetPermissionManager();
166 if (!permission_manager)
167 return;
169 // Cancel pending requests.
170 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
171 !it.IsAtEnd(); it.Advance()) {
172 permission_manager->CancelPermissionRequest(
173 it.GetCurrentValue()->permission,
174 context_->render_frame_host(),
175 it.GetCurrentKey(),
176 it.GetCurrentValue()->origin);
178 pending_requests_.Clear();
180 // Cancel pending subscriptions.
181 for (SubscriptionsMap::Iterator<PendingSubscription>
182 it(&pending_subscriptions_); !it.IsAtEnd(); it.Advance()) {
183 it.GetCurrentValue()->callback.Run(GetPermissionStatusFromType(
184 it.GetCurrentValue()->permission, it.GetCurrentValue()->origin));
185 it.GetCurrentValue()->callback.reset();
186 permission_manager->UnsubscribePermissionStatusChange(
187 it.GetCurrentValue()->id);
189 pending_subscriptions_.Clear();
192 void PermissionServiceImpl::HasPermission(
193 PermissionName permission,
194 const mojo::String& origin,
195 const PermissionStatusCallback& callback) {
196 callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
199 void PermissionServiceImpl::RevokePermission(
200 PermissionName permission,
201 const mojo::String& origin,
202 const PermissionStatusCallback& callback) {
203 GURL origin_url(origin);
204 PermissionType permission_type = PermissionNameToPermissionType(permission);
205 PermissionStatus status = GetPermissionStatusFromType(permission_type,
206 origin_url);
208 // Resetting the permission should only be possible if the permission is
209 // already granted.
210 if (status != PERMISSION_STATUS_GRANTED) {
211 callback.Run(status);
212 return;
215 ResetPermissionStatus(permission_type, origin_url);
217 callback.Run(GetPermissionStatusFromType(permission_type, origin_url));
220 void PermissionServiceImpl::GetNextPermissionChange(
221 PermissionName permission,
222 const mojo::String& mojo_origin,
223 PermissionStatus last_known_status,
224 const PermissionStatusCallback& callback) {
225 GURL origin(mojo_origin);
226 PermissionStatus current_status =
227 GetPermissionStatusFromName(permission, origin);
228 if (current_status != last_known_status) {
229 callback.Run(current_status);
230 return;
233 BrowserContext* browser_context = context_->GetBrowserContext();
234 DCHECK(browser_context);
235 if (!browser_context->GetPermissionManager()) {
236 callback.Run(current_status);
237 return;
240 PermissionType permission_type = PermissionNameToPermissionType(permission);
242 // We need to pass the id of PendingSubscription in pending_subscriptions_
243 // to the callback but SubscribePermissionStatusChange() will also return an
244 // id which is different.
245 PendingSubscription* subscription =
246 new PendingSubscription(permission_type, origin, callback);
247 int pending_subscription_id = pending_subscriptions_.Add(subscription);
249 GURL embedding_origin = context_->GetEmbeddingOrigin();
250 subscription->id =
251 browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
252 permission_type,
253 origin,
254 // If the embedding_origin is empty, we,ll use the |origin| instead.
255 embedding_origin.is_empty() ? origin : embedding_origin,
256 base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged,
257 weak_factory_.GetWeakPtr(),
258 pending_subscription_id));
261 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
262 PermissionName permission, const GURL& origin) {
263 return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
264 origin);
267 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
268 PermissionType type, const GURL& origin) {
269 BrowserContext* browser_context = context_->GetBrowserContext();
270 DCHECK(browser_context);
271 if (!browser_context->GetPermissionManager())
272 return PERMISSION_STATUS_DENIED;
274 // If the embedding_origin is empty we'll use |origin| instead.
275 GURL embedding_origin = context_->GetEmbeddingOrigin();
276 return browser_context->GetPermissionManager()->GetPermissionStatus(
277 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
280 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
281 const GURL& origin) {
282 BrowserContext* browser_context = context_->GetBrowserContext();
283 DCHECK(browser_context);
284 if (!browser_context->GetPermissionManager())
285 return;
287 // If the embedding_origin is empty we'll use |origin| instead.
288 GURL embedding_origin = context_->GetEmbeddingOrigin();
289 browser_context->GetPermissionManager()->ResetPermission(
290 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
293 void PermissionServiceImpl::OnPermissionStatusChanged(
294 int pending_subscription_id,
295 PermissionStatus status) {
296 PendingSubscription* subscription =
297 pending_subscriptions_.Lookup(pending_subscription_id);
299 BrowserContext* browser_context = context_->GetBrowserContext();
300 DCHECK(browser_context);
301 if (browser_context->GetPermissionManager()) {
302 browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange(
303 subscription->id);
306 PermissionStatusCallback callback = subscription->callback;
308 subscription->callback.reset();
309 pending_subscriptions_.Remove(pending_subscription_id);
311 callback.Run(status);
314 } // namespace content