Permission messages: Add a bunch of missing combinations/suppressions.
[chromium-blink-merge.git] / content / browser / permissions / permission_service_impl.cc
blob4a78ccf8b251564bcee25434f39e87b3aaa304ea
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::OnRequestPermissionResponse(
135 int request_id,
136 PermissionStatus status) {
137 PendingRequest* request = pending_requests_.Lookup(request_id);
138 PermissionStatusCallback callback(request->callback);
139 request->callback.reset();
140 pending_requests_.Remove(request_id);
141 callback.Run(status);
144 void PermissionServiceImpl::CancelPendingOperations() {
145 DCHECK(context_->render_frame_host());
146 DCHECK(context_->GetBrowserContext());
148 PermissionManager* permission_manager =
149 context_->GetBrowserContext()->GetPermissionManager();
150 if (!permission_manager)
151 return;
153 // Cancel pending requests.
154 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
155 !it.IsAtEnd(); it.Advance()) {
156 permission_manager->CancelPermissionRequest(
157 it.GetCurrentValue()->permission,
158 context_->render_frame_host(),
159 it.GetCurrentKey(),
160 it.GetCurrentValue()->origin);
162 pending_requests_.Clear();
164 // Cancel pending subscriptions.
165 for (SubscriptionsMap::Iterator<PendingSubscription>
166 it(&pending_subscriptions_); !it.IsAtEnd(); it.Advance()) {
167 it.GetCurrentValue()->callback.Run(GetPermissionStatusFromType(
168 it.GetCurrentValue()->permission, it.GetCurrentValue()->origin));
169 it.GetCurrentValue()->callback.reset();
170 permission_manager->UnsubscribePermissionStatusChange(
171 it.GetCurrentValue()->id);
173 pending_subscriptions_.Clear();
176 void PermissionServiceImpl::HasPermission(
177 PermissionName permission,
178 const mojo::String& origin,
179 const PermissionStatusCallback& callback) {
180 callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
183 void PermissionServiceImpl::RevokePermission(
184 PermissionName permission,
185 const mojo::String& origin,
186 const PermissionStatusCallback& callback) {
187 GURL origin_url(origin);
188 PermissionType permission_type = PermissionNameToPermissionType(permission);
189 PermissionStatus status = GetPermissionStatusFromType(permission_type,
190 origin_url);
192 // Resetting the permission should only be possible if the permission is
193 // already granted.
194 if (status != PERMISSION_STATUS_GRANTED) {
195 callback.Run(status);
196 return;
199 ResetPermissionStatus(permission_type, origin_url);
201 callback.Run(GetPermissionStatusFromType(permission_type, origin_url));
204 void PermissionServiceImpl::GetNextPermissionChange(
205 PermissionName permission,
206 const mojo::String& mojo_origin,
207 PermissionStatus last_known_status,
208 const PermissionStatusCallback& callback) {
209 GURL origin(mojo_origin);
210 PermissionStatus current_status =
211 GetPermissionStatusFromName(permission, origin);
212 if (current_status != last_known_status) {
213 callback.Run(current_status);
214 return;
217 BrowserContext* browser_context = context_->GetBrowserContext();
218 DCHECK(browser_context);
219 if (!browser_context->GetPermissionManager()) {
220 callback.Run(current_status);
221 return;
224 PermissionType permission_type = PermissionNameToPermissionType(permission);
226 // We need to pass the id of PendingSubscription in pending_subscriptions_
227 // to the callback but SubscribePermissionStatusChange() will also return an
228 // id which is different.
229 PendingSubscription* subscription =
230 new PendingSubscription(permission_type, origin, callback);
231 int pending_subscription_id = pending_subscriptions_.Add(subscription);
233 GURL embedding_origin = context_->GetEmbeddingOrigin();
234 subscription->id =
235 browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
236 permission_type,
237 origin,
238 // If the embedding_origin is empty, we,ll use the |origin| instead.
239 embedding_origin.is_empty() ? origin : embedding_origin,
240 base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged,
241 weak_factory_.GetWeakPtr(),
242 pending_subscription_id));
245 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
246 PermissionName permission, const GURL& origin) {
247 return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
248 origin);
251 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
252 PermissionType type, const GURL& origin) {
253 BrowserContext* browser_context = context_->GetBrowserContext();
254 DCHECK(browser_context);
255 if (!browser_context->GetPermissionManager())
256 return PERMISSION_STATUS_DENIED;
258 // If the embedding_origin is empty we'll use |origin| instead.
259 GURL embedding_origin = context_->GetEmbeddingOrigin();
260 return browser_context->GetPermissionManager()->GetPermissionStatus(
261 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
264 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
265 const GURL& origin) {
266 BrowserContext* browser_context = context_->GetBrowserContext();
267 DCHECK(browser_context);
268 if (!browser_context->GetPermissionManager())
269 return;
271 // If the embedding_origin is empty we'll use |origin| instead.
272 GURL embedding_origin = context_->GetEmbeddingOrigin();
273 browser_context->GetPermissionManager()->ResetPermission(
274 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
277 void PermissionServiceImpl::OnPermissionStatusChanged(
278 int pending_subscription_id,
279 PermissionStatus status) {
280 PendingSubscription* subscription =
281 pending_subscriptions_.Lookup(pending_subscription_id);
283 BrowserContext* browser_context = context_->GetBrowserContext();
284 DCHECK(browser_context);
285 if (browser_context->GetPermissionManager()) {
286 browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange(
287 subscription->id);
290 PermissionStatusCallback callback = subscription->callback;
292 subscription->callback.reset();
293 pending_subscriptions_.Remove(pending_subscription_id);
295 callback.Run(status);
298 } // namespace content