1 // Copyright 2012 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 "chrome/browser/geolocation/geolocation_permission_context.h"
11 #include "base/bind.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/content_settings/host_content_settings_map.h"
15 #include "chrome/browser/content_settings/permission_request_id.h"
16 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/tab_contents/tab_util.h"
19 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
20 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "grit/theme_resources.h"
28 #include "net/base/net_util.h"
29 #include "ui/base/l10n/l10n_util.h"
31 class GeolocationPermissionRequest
: public PermissionBubbleRequest
{
33 GeolocationPermissionRequest(GeolocationPermissionContext
* context
,
34 const PermissionRequestID
& id
,
35 const GURL
& requesting_frame
,
38 base::Callback
<void(bool)> callback
,
39 const std::string
& display_languages
);
40 virtual ~GeolocationPermissionRequest();
42 // PermissionBubbleDelegate:
43 virtual int GetIconID() const OVERRIDE
;
44 virtual base::string16
GetMessageText() const OVERRIDE
;
45 virtual base::string16
GetMessageTextFragment() const OVERRIDE
;
46 virtual bool HasUserGesture() const OVERRIDE
;
47 virtual GURL
GetRequestingHostname() const OVERRIDE
;
48 virtual void PermissionGranted() OVERRIDE
;
49 virtual void PermissionDenied() OVERRIDE
;
50 virtual void Cancelled() OVERRIDE
;
51 virtual void RequestFinished() OVERRIDE
;
54 GeolocationPermissionContext
* context_
;
55 PermissionRequestID id_
;
56 GURL requesting_frame_
;
59 base::Callback
<void(bool)> callback_
;
60 std::string display_languages_
;
63 GeolocationPermissionRequest::GeolocationPermissionRequest(
64 GeolocationPermissionContext
* context
,
65 const PermissionRequestID
& id
,
66 const GURL
& requesting_frame
,
69 base::Callback
<void(bool)> callback
,
70 const std::string
& display_languages
)
73 requesting_frame_(requesting_frame
),
75 user_gesture_(user_gesture
),
77 display_languages_(display_languages
) {}
79 GeolocationPermissionRequest::~GeolocationPermissionRequest() {}
81 int GeolocationPermissionRequest::GetIconID() const {
82 return IDR_INFOBAR_GEOLOCATION
;
85 base::string16
GeolocationPermissionRequest::GetMessageText() const {
86 return l10n_util::GetStringFUTF16(
87 IDS_GEOLOCATION_INFOBAR_QUESTION
,
88 net::FormatUrl(requesting_frame_
.GetOrigin(), display_languages_
,
89 net::kFormatUrlOmitUsernamePassword
|
90 net::kFormatUrlOmitTrailingSlashOnBareHostname
,
91 net::UnescapeRule::SPACES
, NULL
, NULL
, NULL
));
94 base::string16
GeolocationPermissionRequest::GetMessageTextFragment() const {
95 return l10n_util::GetStringUTF16(IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT
);
98 bool GeolocationPermissionRequest::HasUserGesture() const {
102 GURL
GeolocationPermissionRequest::GetRequestingHostname() const {
103 return requesting_frame_
;
106 void GeolocationPermissionRequest::PermissionGranted() {
107 context_
->QueueController()->UpdateContentSetting(
108 requesting_frame_
, embedder_
, true);
109 context_
->NotifyPermissionSet(id_
, requesting_frame_
, callback_
, true);
112 void GeolocationPermissionRequest::PermissionDenied() {
113 context_
->QueueController()->UpdateContentSetting(
114 requesting_frame_
, embedder_
, false);
115 context_
->NotifyPermissionSet(id_
, requesting_frame_
, callback_
, false);
118 void GeolocationPermissionRequest::Cancelled() {
121 void GeolocationPermissionRequest::RequestFinished() {
123 context_
->RequestFinished(this);
127 GeolocationPermissionContext::GeolocationPermissionContext(
130 shutting_down_(false),
131 extensions_context_(profile
) {
134 GeolocationPermissionContext::~GeolocationPermissionContext() {
135 // GeolocationPermissionContext may be destroyed on either the UI thread
136 // or the IO thread, but the PermissionQueueController must have been
137 // destroyed on the UI thread.
138 DCHECK(!permission_queue_controller_
.get());
141 void GeolocationPermissionContext::RequestGeolocationPermission(
142 content::WebContents
* web_contents
,
144 const GURL
& requesting_frame
,
146 base::Callback
<void(bool)> result_callback
,
147 base::Closure
* cancel_callback
) {
148 GURL requesting_frame_origin
= requesting_frame
.GetOrigin();
152 int render_process_id
= web_contents
->GetRenderProcessHost()->GetID();
153 int render_view_id
= web_contents
->GetRenderViewHost()->GetRoutingID();
154 if (cancel_callback
) {
155 *cancel_callback
= base::Bind(
156 &GeolocationPermissionContext::CancelGeolocationPermissionRequest
,
157 this, render_process_id
, render_view_id
, bridge_id
);
160 const PermissionRequestID
id(
161 render_process_id
, render_view_id
, bridge_id
, GURL());
165 if (extensions_context_
.RequestPermission(
166 web_contents
, id
, bridge_id
, requesting_frame
, user_gesture
,
167 result_callback
, &permission_set
, &new_permission
)) {
168 if (permission_set
) {
169 NotifyPermissionSet(id
, requesting_frame_origin
, result_callback
,
175 GURL embedder
= web_contents
->GetLastCommittedURL().GetOrigin();
176 if (!requesting_frame_origin
.is_valid() || !embedder
.is_valid()) {
177 LOG(WARNING
) << "Attempt to use geolocation from an invalid URL: "
178 << requesting_frame_origin
<< "," << embedder
179 << " (geolocation is not supported in popups)";
180 NotifyPermissionSet(id
, requesting_frame_origin
, result_callback
, false);
184 DecidePermission(web_contents
, id
, requesting_frame_origin
, user_gesture
,
185 embedder
, result_callback
);
188 void GeolocationPermissionContext::CancelGeolocationPermissionRequest(
189 int render_process_id
,
192 content::WebContents
* web_contents
= tab_util::GetWebContentsByID(
193 render_process_id
, render_view_id
);
194 if (extensions_context_
.CancelPermissionRequest(web_contents
, bridge_id
))
197 CancelPendingInfobarRequest(PermissionRequestID(
198 render_process_id
, render_view_id
, bridge_id
, GURL()));
201 void GeolocationPermissionContext::DecidePermission(
202 content::WebContents
* web_contents
,
203 const PermissionRequestID
& id
,
204 const GURL
& requesting_frame
,
206 const GURL
& embedder
,
207 base::Callback
<void(bool)> callback
) {
208 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
210 ContentSetting content_setting
=
211 profile_
->GetHostContentSettingsMap()
212 ->GetContentSettingAndMaybeUpdateLastUsage(
215 CONTENT_SETTINGS_TYPE_GEOLOCATION
,
217 switch (content_setting
) {
218 case CONTENT_SETTING_BLOCK
:
219 PermissionDecided(id
, requesting_frame
, embedder
, callback
, false);
221 case CONTENT_SETTING_ALLOW
:
222 PermissionDecided(id
, requesting_frame
, embedder
, callback
, true);
225 if (PermissionBubbleManager::Enabled()) {
226 PermissionBubbleManager
* mgr
=
227 PermissionBubbleManager::FromWebContents(web_contents
);
229 scoped_ptr
<GeolocationPermissionRequest
> request_ptr(
230 new GeolocationPermissionRequest(
231 this, id
, requesting_frame
, embedder
, user_gesture
, callback
,
232 profile_
->GetPrefs()->GetString(prefs::kAcceptLanguages
)));
233 GeolocationPermissionRequest
* request
= request_ptr
.get();
234 pending_requests_
.add(id
.ToString(), request_ptr
.Pass());
235 mgr
->AddRequest(request
);
238 // setting == ask. Prompt the user.
239 QueueController()->CreateInfoBarRequest(
240 id
, requesting_frame
, embedder
,
242 &GeolocationPermissionContext::NotifyPermissionSet
,
243 base::Unretained(this), id
, requesting_frame
, callback
));
248 void GeolocationPermissionContext::CreateInfoBarRequest(
249 const PermissionRequestID
& id
,
250 const GURL
& requesting_frame
,
251 const GURL
& embedder
,
252 base::Callback
<void(bool)> callback
) {
253 QueueController()->CreateInfoBarRequest(
254 id
, requesting_frame
, embedder
, base::Bind(
255 &GeolocationPermissionContext::NotifyPermissionSet
,
256 base::Unretained(this), id
, requesting_frame
, callback
));
259 void GeolocationPermissionContext::RequestFinished(
260 GeolocationPermissionRequest
* request
) {
261 base::ScopedPtrHashMap
<std::string
,
262 GeolocationPermissionRequest
>::iterator it
;
263 for (it
= pending_requests_
.begin(); it
!= pending_requests_
.end(); ++it
) {
264 if (it
->second
== request
) {
265 pending_requests_
.take_and_erase(it
);
272 void GeolocationPermissionContext::ShutdownOnUIThread() {
273 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
274 permission_queue_controller_
.reset();
275 shutting_down_
= true;
278 void GeolocationPermissionContext::PermissionDecided(
279 const PermissionRequestID
& id
,
280 const GURL
& requesting_frame
,
281 const GURL
& embedder
,
282 base::Callback
<void(bool)> callback
,
284 NotifyPermissionSet(id
, requesting_frame
, callback
, allowed
);
287 void GeolocationPermissionContext::NotifyPermissionSet(
288 const PermissionRequestID
& id
,
289 const GURL
& requesting_frame
,
290 base::Callback
<void(bool)> callback
,
292 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
294 // WebContents may have gone away (or not exists for extension).
295 TabSpecificContentSettings
* content_settings
=
296 TabSpecificContentSettings::Get(id
.render_process_id(),
297 id
.render_view_id());
298 if (content_settings
) {
299 content_settings
->OnGeolocationPermissionSet(requesting_frame
.GetOrigin(),
303 callback
.Run(allowed
);
306 PermissionQueueController
*
307 GeolocationPermissionContext::QueueController() {
308 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
309 DCHECK(!shutting_down_
);
310 if (!permission_queue_controller_
)
311 permission_queue_controller_
.reset(CreateQueueController());
312 return permission_queue_controller_
.get();
315 PermissionQueueController
*
316 GeolocationPermissionContext::CreateQueueController() {
317 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
318 return new PermissionQueueController(profile(),
319 CONTENT_SETTINGS_TYPE_GEOLOCATION
);
322 void GeolocationPermissionContext::CancelPendingInfobarRequest(
323 const PermissionRequestID
& id
) {
324 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
328 if (PermissionBubbleManager::Enabled()) {
329 GeolocationPermissionRequest
* cancelling
=
330 pending_requests_
.get(id
.ToString());
331 content::WebContents
* web_contents
= tab_util::GetWebContentsByID(
332 id
.render_process_id(), id
.render_view_id());
333 if (cancelling
!= NULL
&& web_contents
!= NULL
&&
334 PermissionBubbleManager::FromWebContents(web_contents
) != NULL
) {
335 PermissionBubbleManager::FromWebContents(web_contents
)->
336 CancelRequest(cancelling
);
341 QueueController()->CancelInfoBarRequest(id
);