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"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/permission_manager.h"
10 #include "content/public/browser/permission_type.h"
16 PermissionType
PermissionNameToPermissionType(PermissionName 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_SYSEX
:
25 return PermissionType::MIDI_SYSEX
;
26 case PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER
:
27 return PermissionType::PROTECTED_MEDIA_IDENTIFIER
;
31 return PermissionType::NUM
;
34 } // anonymous namespace
36 PermissionServiceImpl::PendingRequest::PendingRequest(
37 PermissionType permission
,
39 const PermissionStatusCallback
& callback
)
40 : permission(permission
),
45 PermissionServiceImpl::PendingRequest::~PendingRequest() {
46 if (!callback
.is_null())
47 callback
.Run(PERMISSION_STATUS_ASK
);
50 PermissionServiceImpl::PendingSubscription::PendingSubscription(
51 PermissionType permission
,
53 const PermissionStatusCallback
& callback
)
55 permission(permission
),
60 PermissionServiceImpl::PendingSubscription::~PendingSubscription() {
61 if (!callback
.is_null())
62 callback
.Run(PERMISSION_STATUS_ASK
);
65 PermissionServiceImpl::PermissionServiceImpl(
66 PermissionServiceContext
* context
,
67 mojo::InterfaceRequest
<PermissionService
> request
)
69 binding_(this, request
.Pass()),
73 PermissionServiceImpl::~PermissionServiceImpl() {
74 DCHECK(pending_requests_
.IsEmpty());
77 void PermissionServiceImpl::OnConnectionError() {
78 context_
->ServiceHadConnectionError(this);
79 // After that call, |this| will be deleted.
82 void PermissionServiceImpl::RequestPermission(
83 PermissionName permission
,
84 const mojo::String
& origin
,
86 const PermissionStatusCallback
& callback
) {
87 // This condition is valid if the call is coming from a ChildThread instead of
88 // a RenderFrame. Some consumers of the service run in Workers and some in
89 // Frames. In the context of a Worker, it is not possible to show a
90 // permission prompt because there is no tab. In the context of a Frame, we
91 // can. Even if the call comes from a context where it is not possible to show
92 // any UI, we want to still return something relevant so the current
93 // permission status is returned.
94 if (!context_
->render_frame_host()) {
95 // There is no way to show a UI so the call will simply return the current
97 HasPermission(permission
, origin
, callback
);
101 BrowserContext
* browser_context
= context_
->GetBrowserContext();
102 DCHECK(browser_context
);
103 if (!browser_context
->GetPermissionManager()) {
104 callback
.Run(content::PERMISSION_STATUS_DENIED
);
108 PermissionType permission_type
= PermissionNameToPermissionType(permission
);
109 int request_id
= pending_requests_
.Add(
110 new PendingRequest(permission_type
, GURL(origin
), callback
));
112 browser_context
->GetPermissionManager()->RequestPermission(
114 context_
->render_frame_host(),
117 user_gesture
, // TODO(mlamouri): should be removed (crbug.com/423770)
118 base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse
,
119 weak_factory_
.GetWeakPtr(),
123 void PermissionServiceImpl::OnRequestPermissionResponse(
125 PermissionStatus status
) {
126 PendingRequest
* request
= pending_requests_
.Lookup(request_id
);
127 PermissionStatusCallback
callback(request
->callback
);
128 request
->callback
.reset();
129 pending_requests_
.Remove(request_id
);
130 callback
.Run(status
);
133 void PermissionServiceImpl::CancelPendingOperations() {
134 DCHECK(context_
->render_frame_host());
135 DCHECK(context_
->GetBrowserContext());
137 PermissionManager
* permission_manager
=
138 context_
->GetBrowserContext()->GetPermissionManager();
139 if (!permission_manager
)
142 // Cancel pending requests.
143 for (RequestsMap::Iterator
<PendingRequest
> it(&pending_requests_
);
144 !it
.IsAtEnd(); it
.Advance()) {
145 permission_manager
->CancelPermissionRequest(
146 it
.GetCurrentValue()->permission
,
147 context_
->render_frame_host(),
149 it
.GetCurrentValue()->origin
);
151 pending_requests_
.Clear();
153 // Cancel pending subscriptions.
154 for (SubscriptionsMap::Iterator
<PendingSubscription
>
155 it(&pending_subscriptions_
); !it
.IsAtEnd(); it
.Advance()) {
156 it
.GetCurrentValue()->callback
.Run(GetPermissionStatusFromType(
157 it
.GetCurrentValue()->permission
, it
.GetCurrentValue()->origin
));
158 it
.GetCurrentValue()->callback
.reset();
159 permission_manager
->UnsubscribePermissionStatusChange(
160 it
.GetCurrentValue()->id
);
162 pending_subscriptions_
.Clear();
165 void PermissionServiceImpl::HasPermission(
166 PermissionName permission
,
167 const mojo::String
& origin
,
168 const PermissionStatusCallback
& callback
) {
169 callback
.Run(GetPermissionStatusFromName(permission
, GURL(origin
)));
172 void PermissionServiceImpl::RevokePermission(
173 PermissionName permission
,
174 const mojo::String
& origin
,
175 const PermissionStatusCallback
& callback
) {
176 GURL
origin_url(origin
);
177 PermissionType permission_type
= PermissionNameToPermissionType(permission
);
178 PermissionStatus status
= GetPermissionStatusFromType(permission_type
,
181 // Resetting the permission should only be possible if the permission is
183 if (status
!= PERMISSION_STATUS_GRANTED
) {
184 callback
.Run(status
);
188 ResetPermissionStatus(permission_type
, origin_url
);
190 callback
.Run(GetPermissionStatusFromType(permission_type
, origin_url
));
193 void PermissionServiceImpl::GetNextPermissionChange(
194 PermissionName permission
,
195 const mojo::String
& mojo_origin
,
196 PermissionStatus last_known_status
,
197 const PermissionStatusCallback
& callback
) {
198 GURL
origin(mojo_origin
);
199 PermissionStatus current_status
=
200 GetPermissionStatusFromName(permission
, origin
);
201 if (current_status
!= last_known_status
) {
202 callback
.Run(current_status
);
206 BrowserContext
* browser_context
= context_
->GetBrowserContext();
207 DCHECK(browser_context
);
208 if (!browser_context
->GetPermissionManager()) {
209 callback
.Run(current_status
);
213 PermissionType permission_type
= PermissionNameToPermissionType(permission
);
215 // We need to pass the id of PendingSubscription in pending_subscriptions_
216 // to the callback but SubscribePermissionStatusChange() will also return an
217 // id which is different.
218 PendingSubscription
* subscription
=
219 new PendingSubscription(permission_type
, origin
, callback
);
220 int pending_subscription_id
= pending_subscriptions_
.Add(subscription
);
222 GURL embedding_origin
= context_
->GetEmbeddingOrigin();
224 browser_context
->GetPermissionManager()->SubscribePermissionStatusChange(
227 // If the embedding_origin is empty, we,ll use the |origin| instead.
228 embedding_origin
.is_empty() ? origin
: embedding_origin
,
229 base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged
,
230 weak_factory_
.GetWeakPtr(),
231 pending_subscription_id
));
234 PermissionStatus
PermissionServiceImpl::GetPermissionStatusFromName(
235 PermissionName permission
, const GURL
& origin
) {
236 return GetPermissionStatusFromType(PermissionNameToPermissionType(permission
),
240 PermissionStatus
PermissionServiceImpl::GetPermissionStatusFromType(
241 PermissionType type
, const GURL
& origin
) {
242 BrowserContext
* browser_context
= context_
->GetBrowserContext();
243 DCHECK(browser_context
);
244 if (!browser_context
->GetPermissionManager())
245 return PERMISSION_STATUS_DENIED
;
247 // If the embedding_origin is empty we'll use |origin| instead.
248 GURL embedding_origin
= context_
->GetEmbeddingOrigin();
249 return browser_context
->GetPermissionManager()->GetPermissionStatus(
250 type
, origin
, embedding_origin
.is_empty() ? origin
: embedding_origin
);
253 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type
,
254 const GURL
& origin
) {
255 BrowserContext
* browser_context
= context_
->GetBrowserContext();
256 DCHECK(browser_context
);
257 if (!browser_context
->GetPermissionManager())
260 // If the embedding_origin is empty we'll use |origin| instead.
261 GURL embedding_origin
= context_
->GetEmbeddingOrigin();
262 browser_context
->GetPermissionManager()->ResetPermission(
263 type
, origin
, embedding_origin
.is_empty() ? origin
: embedding_origin
);
266 void PermissionServiceImpl::OnPermissionStatusChanged(
267 int pending_subscription_id
,
268 PermissionStatus status
) {
269 PendingSubscription
* subscription
=
270 pending_subscriptions_
.Lookup(pending_subscription_id
);
272 BrowserContext
* browser_context
= context_
->GetBrowserContext();
273 DCHECK(browser_context
);
274 if (browser_context
->GetPermissionManager()) {
275 browser_context
->GetPermissionManager()->UnsubscribePermissionStatusChange(
279 PermissionStatusCallback callback
= subscription
->callback
;
281 subscription
->callback
.reset();
282 pending_subscriptions_
.Remove(pending_subscription_id
);
284 callback
.Run(status
);
287 } // namespace content