Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / permissions / permission_service_impl.cc
blob83cb63798235cd02a6bd92c0d2757cba2cb75509
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_SYSEX:
25 return PermissionType::MIDI_SYSEX;
26 case PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER:
27 return PermissionType::PROTECTED_MEDIA_IDENTIFIER;
30 NOTREACHED();
31 return PermissionType::NUM;
34 } // anonymous namespace
36 PermissionServiceImpl::PendingRequest::PendingRequest(
37 PermissionType permission,
38 const GURL& origin,
39 const PermissionStatusCallback& callback)
40 : permission(permission),
41 origin(origin),
42 callback(callback) {
45 PermissionServiceImpl::PendingRequest::~PendingRequest() {
46 if (!callback.is_null())
47 callback.Run(PERMISSION_STATUS_ASK);
50 PermissionServiceImpl::PendingSubscription::PendingSubscription(
51 PermissionType permission,
52 const GURL& origin,
53 const PermissionStatusCallback& callback)
54 : id(-1),
55 permission(permission),
56 origin(origin),
57 callback(callback) {
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)
68 : context_(context),
69 binding_(this, request.Pass()),
70 weak_factory_(this) {
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,
85 bool user_gesture,
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
96 // permission.
97 HasPermission(permission, origin, callback);
98 return;
101 BrowserContext* browser_context = context_->GetBrowserContext();
102 DCHECK(browser_context);
103 if (!browser_context->GetPermissionManager()) {
104 callback.Run(content::PERMISSION_STATUS_DENIED);
105 return;
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(
113 permission_type,
114 context_->render_frame_host(),
115 request_id,
116 GURL(origin),
117 user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
118 base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
119 weak_factory_.GetWeakPtr(),
120 request_id));
123 void PermissionServiceImpl::OnRequestPermissionResponse(
124 int request_id,
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)
140 return;
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(),
148 it.GetCurrentKey(),
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,
179 origin_url);
181 // Resetting the permission should only be possible if the permission is
182 // already granted.
183 if (status != PERMISSION_STATUS_GRANTED) {
184 callback.Run(status);
185 return;
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);
203 return;
206 BrowserContext* browser_context = context_->GetBrowserContext();
207 DCHECK(browser_context);
208 if (!browser_context->GetPermissionManager()) {
209 callback.Run(current_status);
210 return;
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();
223 subscription->id =
224 browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
225 permission_type,
226 origin,
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),
237 origin);
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())
258 return;
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(
276 subscription->id);
279 PermissionStatusCallback callback = subscription->callback;
281 subscription->callback.reset();
282 pending_subscriptions_.Remove(pending_subscription_id);
284 callback.Run(status);
287 } // namespace content