Update broken references to image assets
[chromium-blink-merge.git] / content / browser / permissions / permission_service_impl.cc
blob61ca3a1517a698c37fdf331778d2a849855ca342
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;
34 NOTREACHED();
35 return PermissionType::NUM;
38 } // anonymous namespace
40 PermissionServiceImpl::PendingRequest::PendingRequest(
41 PermissionType permission,
42 const GURL& origin,
43 const PermissionStatusCallback& callback)
44 : permission(permission),
45 origin(origin),
46 callback(callback) {
49 PermissionServiceImpl::PendingRequest::~PendingRequest() {
50 if (!callback.is_null())
51 callback.Run(PERMISSION_STATUS_ASK);
54 PermissionServiceImpl::PendingSubscription::PendingSubscription(
55 PermissionType permission,
56 const GURL& origin,
57 const PermissionStatusCallback& callback)
58 : id(-1),
59 permission(permission),
60 origin(origin),
61 callback(callback) {
64 PermissionServiceImpl::PendingSubscription::~PendingSubscription() {
65 if (!callback.is_null())
66 callback.Run(PERMISSION_STATUS_ASK);
69 PermissionServiceImpl::PermissionServiceImpl(
70 PermissionServiceContext* context,
71 mojo::InterfaceRequest<PermissionService> request)
72 : context_(context),
73 binding_(this, request.Pass()),
74 weak_factory_(this) {
75 binding_.set_connection_error_handler(
76 base::Bind(&PermissionServiceImpl::OnConnectionError,
77 base::Unretained(this)));
80 PermissionServiceImpl::~PermissionServiceImpl() {
81 DCHECK(pending_requests_.IsEmpty());
84 void PermissionServiceImpl::OnConnectionError() {
85 context_->ServiceHadConnectionError(this);
86 // After that call, |this| will be deleted.
89 void PermissionServiceImpl::RequestPermission(
90 PermissionName permission,
91 const mojo::String& origin,
92 bool user_gesture,
93 const PermissionStatusCallback& callback) {
94 // This condition is valid if the call is coming from a ChildThread instead of
95 // a RenderFrame. Some consumers of the service run in Workers and some in
96 // Frames. In the context of a Worker, it is not possible to show a
97 // permission prompt because there is no tab. In the context of a Frame, we
98 // can. Even if the call comes from a context where it is not possible to show
99 // any UI, we want to still return something relevant so the current
100 // permission status is returned.
101 if (!context_->render_frame_host()) {
102 // There is no way to show a UI so the call will simply return the current
103 // permission.
104 HasPermission(permission, origin, callback);
105 return;
108 BrowserContext* browser_context = context_->GetBrowserContext();
109 DCHECK(browser_context);
110 if (!browser_context->GetPermissionManager()) {
111 callback.Run(content::PERMISSION_STATUS_DENIED);
112 return;
115 PermissionType permission_type = PermissionNameToPermissionType(permission);
116 int request_id = pending_requests_.Add(
117 new PendingRequest(permission_type, GURL(origin), callback));
119 browser_context->GetPermissionManager()->RequestPermission(
120 permission_type,
121 context_->render_frame_host(),
122 request_id,
123 GURL(origin),
124 user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
125 base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
126 weak_factory_.GetWeakPtr(),
127 request_id));
130 void PermissionServiceImpl::OnRequestPermissionResponse(
131 int request_id,
132 PermissionStatus status) {
133 PendingRequest* request = pending_requests_.Lookup(request_id);
134 PermissionStatusCallback callback(request->callback);
135 request->callback.reset();
136 pending_requests_.Remove(request_id);
137 callback.Run(status);
140 void PermissionServiceImpl::CancelPendingOperations() {
141 DCHECK(context_->render_frame_host());
142 DCHECK(context_->GetBrowserContext());
144 PermissionManager* permission_manager =
145 context_->GetBrowserContext()->GetPermissionManager();
146 if (!permission_manager)
147 return;
149 // Cancel pending requests.
150 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
151 !it.IsAtEnd(); it.Advance()) {
152 permission_manager->CancelPermissionRequest(
153 it.GetCurrentValue()->permission,
154 context_->render_frame_host(),
155 it.GetCurrentKey(),
156 it.GetCurrentValue()->origin);
158 pending_requests_.Clear();
160 // Cancel pending subscriptions.
161 for (SubscriptionsMap::Iterator<PendingSubscription>
162 it(&pending_subscriptions_); !it.IsAtEnd(); it.Advance()) {
163 it.GetCurrentValue()->callback.Run(GetPermissionStatusFromType(
164 it.GetCurrentValue()->permission, it.GetCurrentValue()->origin));
165 it.GetCurrentValue()->callback.reset();
166 permission_manager->UnsubscribePermissionStatusChange(
167 it.GetCurrentValue()->id);
169 pending_subscriptions_.Clear();
172 void PermissionServiceImpl::HasPermission(
173 PermissionName permission,
174 const mojo::String& origin,
175 const PermissionStatusCallback& callback) {
176 callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
179 void PermissionServiceImpl::RevokePermission(
180 PermissionName permission,
181 const mojo::String& origin,
182 const PermissionStatusCallback& callback) {
183 GURL origin_url(origin);
184 PermissionType permission_type = PermissionNameToPermissionType(permission);
185 PermissionStatus status = GetPermissionStatusFromType(permission_type,
186 origin_url);
188 // Resetting the permission should only be possible if the permission is
189 // already granted.
190 if (status != PERMISSION_STATUS_GRANTED) {
191 callback.Run(status);
192 return;
195 ResetPermissionStatus(permission_type, origin_url);
197 callback.Run(GetPermissionStatusFromType(permission_type, origin_url));
200 void PermissionServiceImpl::GetNextPermissionChange(
201 PermissionName permission,
202 const mojo::String& mojo_origin,
203 PermissionStatus last_known_status,
204 const PermissionStatusCallback& callback) {
205 GURL origin(mojo_origin);
206 PermissionStatus current_status =
207 GetPermissionStatusFromName(permission, origin);
208 if (current_status != last_known_status) {
209 callback.Run(current_status);
210 return;
213 BrowserContext* browser_context = context_->GetBrowserContext();
214 DCHECK(browser_context);
215 if (!browser_context->GetPermissionManager()) {
216 callback.Run(current_status);
217 return;
220 PermissionType permission_type = PermissionNameToPermissionType(permission);
222 // We need to pass the id of PendingSubscription in pending_subscriptions_
223 // to the callback but SubscribePermissionStatusChange() will also return an
224 // id which is different.
225 PendingSubscription* subscription =
226 new PendingSubscription(permission_type, origin, callback);
227 int pending_subscription_id = pending_subscriptions_.Add(subscription);
229 GURL embedding_origin = context_->GetEmbeddingOrigin();
230 subscription->id =
231 browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
232 permission_type,
233 origin,
234 // If the embedding_origin is empty, we,ll use the |origin| instead.
235 embedding_origin.is_empty() ? origin : embedding_origin,
236 base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged,
237 weak_factory_.GetWeakPtr(),
238 pending_subscription_id));
241 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
242 PermissionName permission, const GURL& origin) {
243 return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
244 origin);
247 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
248 PermissionType type, const GURL& origin) {
249 BrowserContext* browser_context = context_->GetBrowserContext();
250 DCHECK(browser_context);
251 if (!browser_context->GetPermissionManager())
252 return PERMISSION_STATUS_DENIED;
254 // If the embedding_origin is empty we'll use |origin| instead.
255 GURL embedding_origin = context_->GetEmbeddingOrigin();
256 return browser_context->GetPermissionManager()->GetPermissionStatus(
257 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
260 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
261 const GURL& origin) {
262 BrowserContext* browser_context = context_->GetBrowserContext();
263 DCHECK(browser_context);
264 if (!browser_context->GetPermissionManager())
265 return;
267 // If the embedding_origin is empty we'll use |origin| instead.
268 GURL embedding_origin = context_->GetEmbeddingOrigin();
269 browser_context->GetPermissionManager()->ResetPermission(
270 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
273 void PermissionServiceImpl::OnPermissionStatusChanged(
274 int pending_subscription_id,
275 PermissionStatus status) {
276 PendingSubscription* subscription =
277 pending_subscriptions_.Lookup(pending_subscription_id);
279 BrowserContext* browser_context = context_->GetBrowserContext();
280 DCHECK(browser_context);
281 if (browser_context->GetPermissionManager()) {
282 browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange(
283 subscription->id);
286 PermissionStatusCallback callback = subscription->callback;
288 subscription->callback.reset();
289 pending_subscriptions_.Remove(pending_subscription_id);
291 callback.Run(status);
294 } // namespace content