Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / permissions / permission_service_impl.cc
blob8e6bcd548982803d21d6f177aaece1b4fc27e06c
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(PermissionServiceContext* context)
66 : context_(context),
67 weak_factory_(this) {
70 PermissionServiceImpl::~PermissionServiceImpl() {
71 DCHECK(pending_requests_.IsEmpty());
74 void PermissionServiceImpl::OnConnectionError() {
75 context_->ServiceHadConnectionError(this);
76 // After that call, |this| will be deleted.
79 void PermissionServiceImpl::RequestPermission(
80 PermissionName permission,
81 const mojo::String& origin,
82 bool user_gesture,
83 const PermissionStatusCallback& callback) {
84 // This condition is valid if the call is coming from a ChildThread instead of
85 // a RenderFrame. Some consumers of the service run in Workers and some in
86 // Frames. In the context of a Worker, it is not possible to show a
87 // permission prompt because there is no tab. In the context of a Frame, we
88 // can. Even if the call comes from a context where it is not possible to show
89 // any UI, we want to still return something relevant so the current
90 // permission status is returned.
91 if (!context_->web_contents()) {
92 // There is no way to show a UI so the call will simply return the current
93 // permission.
94 HasPermission(permission, origin, callback);
95 return;
98 BrowserContext* browser_context = context_->GetBrowserContext();
99 DCHECK(browser_context);
100 if (!browser_context->GetPermissionManager()) {
101 callback.Run(content::PERMISSION_STATUS_DENIED);
102 return;
105 PermissionType permission_type = PermissionNameToPermissionType(permission);
106 int request_id = pending_requests_.Add(
107 new PendingRequest(permission_type, GURL(origin), callback));
109 browser_context->GetPermissionManager()->RequestPermission(
110 permission_type,
111 context_->web_contents(),
112 request_id,
113 GURL(origin),
114 user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
115 base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
116 weak_factory_.GetWeakPtr(),
117 request_id));
120 void PermissionServiceImpl::OnRequestPermissionResponse(
121 int request_id,
122 PermissionStatus status) {
123 PendingRequest* request = pending_requests_.Lookup(request_id);
124 PermissionStatusCallback callback(request->callback);
125 request->callback.reset();
126 pending_requests_.Remove(request_id);
127 callback.Run(status);
130 void PermissionServiceImpl::CancelPendingOperations() {
131 DCHECK(context_->web_contents());
132 DCHECK(context_->GetBrowserContext());
134 PermissionManager* permission_manager =
135 context_->GetBrowserContext()->GetPermissionManager();
136 if (!permission_manager)
137 return;
139 // Cancel pending requests.
140 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
141 !it.IsAtEnd(); it.Advance()) {
142 permission_manager->CancelPermissionRequest(
143 it.GetCurrentValue()->permission,
144 context_->web_contents(),
145 it.GetCurrentKey(),
146 it.GetCurrentValue()->origin);
148 pending_requests_.Clear();
150 // Cancel pending subscriptions.
151 for (SubscriptionsMap::Iterator<PendingSubscription>
152 it(&pending_subscriptions_); !it.IsAtEnd(); it.Advance()) {
153 it.GetCurrentValue()->callback.Run(GetPermissionStatusFromType(
154 it.GetCurrentValue()->permission, it.GetCurrentValue()->origin));
155 it.GetCurrentValue()->callback.reset();
156 permission_manager->UnsubscribePermissionStatusChange(
157 it.GetCurrentValue()->id);
159 pending_subscriptions_.Clear();
162 void PermissionServiceImpl::HasPermission(
163 PermissionName permission,
164 const mojo::String& origin,
165 const PermissionStatusCallback& callback) {
166 callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
169 void PermissionServiceImpl::RevokePermission(
170 PermissionName permission,
171 const mojo::String& origin,
172 const PermissionStatusCallback& callback) {
173 GURL origin_url(origin);
174 PermissionType permission_type = PermissionNameToPermissionType(permission);
175 PermissionStatus status = GetPermissionStatusFromType(permission_type,
176 origin_url);
178 // Resetting the permission should only be possible if the permission is
179 // already granted.
180 if (status != PERMISSION_STATUS_GRANTED) {
181 callback.Run(status);
182 return;
185 ResetPermissionStatus(permission_type, origin_url);
187 callback.Run(GetPermissionStatusFromType(permission_type, origin_url));
190 void PermissionServiceImpl::GetNextPermissionChange(
191 PermissionName permission,
192 const mojo::String& mojo_origin,
193 PermissionStatus last_known_status,
194 const PermissionStatusCallback& callback) {
195 GURL origin(mojo_origin);
196 PermissionStatus current_status =
197 GetPermissionStatusFromName(permission, origin);
198 if (current_status != last_known_status) {
199 callback.Run(current_status);
200 return;
203 BrowserContext* browser_context = context_->GetBrowserContext();
204 DCHECK(browser_context);
205 if (!browser_context->GetPermissionManager()) {
206 callback.Run(current_status);
207 return;
210 PermissionType permission_type = PermissionNameToPermissionType(permission);
212 // We need to pass the id of PendingSubscription in pending_subscriptions_
213 // to the callback but SubscribePermissionStatusChange() will also return an
214 // id which is different.
215 PendingSubscription* subscription =
216 new PendingSubscription(permission_type, origin, callback);
217 int pending_subscription_id = pending_subscriptions_.Add(subscription);
219 GURL embedding_origin = context_->GetEmbeddingOrigin();
220 subscription->id =
221 browser_context->GetPermissionManager()->SubscribePermissionStatusChange(
222 permission_type,
223 origin,
224 // If the embedding_origin is empty, we,ll use the |origin| instead.
225 embedding_origin.is_empty() ? origin : embedding_origin,
226 base::Bind(&PermissionServiceImpl::OnPermissionStatusChanged,
227 weak_factory_.GetWeakPtr(),
228 pending_subscription_id));
231 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
232 PermissionName permission, const GURL& origin) {
233 return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
234 origin);
237 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
238 PermissionType type, const GURL& origin) {
239 BrowserContext* browser_context = context_->GetBrowserContext();
240 DCHECK(browser_context);
241 if (!browser_context->GetPermissionManager())
242 return PERMISSION_STATUS_DENIED;
244 // If the embedding_origin is empty we'll use |origin| instead.
245 GURL embedding_origin = context_->GetEmbeddingOrigin();
246 return browser_context->GetPermissionManager()->GetPermissionStatus(
247 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
250 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type,
251 const GURL& origin) {
252 BrowserContext* browser_context = context_->GetBrowserContext();
253 DCHECK(browser_context);
254 if (!browser_context->GetPermissionManager())
255 return;
257 // If the embedding_origin is empty we'll use |origin| instead.
258 GURL embedding_origin = context_->GetEmbeddingOrigin();
259 browser_context->GetPermissionManager()->ResetPermission(
260 type, origin, embedding_origin.is_empty() ? origin : embedding_origin);
263 void PermissionServiceImpl::OnPermissionStatusChanged(
264 int pending_subscription_id,
265 PermissionStatus status) {
266 PendingSubscription* subscription =
267 pending_subscriptions_.Lookup(pending_subscription_id);
269 BrowserContext* browser_context = context_->GetBrowserContext();
270 DCHECK(browser_context);
271 if (browser_context->GetPermissionManager()) {
272 browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange(
273 subscription->id);
276 PermissionStatusCallback callback = subscription->callback;
278 subscription->callback.reset();
279 pending_subscriptions_.Remove(pending_subscription_id);
281 callback.Run(status);
284 } // namespace content