NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / geolocation / chrome_geolocation_permission_context.cc
blobe414cb3045b5e59679755d18bb85ffc1ca786544
1 // Copyright (c) 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/chrome_geolocation_permission_context.h"
7 #include <functional>
8 #include <string>
9 #include <vector>
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/extensions/suggest_permission_util.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/tab_contents/tab_util.h"
20 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
21 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/browser/process_map.h"
28 #include "extensions/browser/view_type_utils.h"
29 #include "extensions/common/extension.h"
30 #include "grit/generated_resources.h"
31 #include "net/base/net_util.h"
32 #include "ui/base/l10n/l10n_util.h"
34 using extensions::APIPermission;
35 using extensions::ExtensionRegistry;
37 class GeolocationPermissionRequest : public PermissionBubbleRequest {
38 public:
39 GeolocationPermissionRequest(
40 ChromeGeolocationPermissionContext* context,
41 const PermissionRequestID& id,
42 const GURL& requesting_frame,
43 base::Callback<void(bool)> callback,
44 const std::string& display_languages);
45 virtual ~GeolocationPermissionRequest();
47 // PermissionBubbleDelegate:
48 virtual base::string16 GetMessageText() const OVERRIDE;
49 virtual base::string16 GetMessageTextFragment() const OVERRIDE;
50 virtual base::string16 GetAlternateAcceptButtonText() const OVERRIDE;
51 virtual base::string16 GetAlternateDenyButtonText() const OVERRIDE;
52 virtual void PermissionGranted() OVERRIDE;
53 virtual void PermissionDenied() OVERRIDE;
54 virtual void Cancelled() OVERRIDE;
55 virtual void RequestFinished() OVERRIDE;
57 private:
58 ChromeGeolocationPermissionContext* context_;
59 PermissionRequestID id_;
60 GURL requesting_frame_;
61 base::Callback<void(bool)> callback_;
62 std::string display_languages_;
65 GeolocationPermissionRequest::GeolocationPermissionRequest(
66 ChromeGeolocationPermissionContext* context,
67 const PermissionRequestID& id,
68 const GURL& requesting_frame,
69 base::Callback<void(bool)> callback,
70 const std::string& display_languages)
71 : context_(context),
72 id_(id),
73 requesting_frame_(requesting_frame),
74 callback_(callback),
75 display_languages_(display_languages) {}
77 GeolocationPermissionRequest::~GeolocationPermissionRequest() {}
79 base::string16 GeolocationPermissionRequest::GetMessageText() const {
80 return l10n_util::GetStringFUTF16(IDS_GEOLOCATION_INFOBAR_QUESTION,
81 net::FormatUrl(requesting_frame_, display_languages_));
84 base::string16 GeolocationPermissionRequest::GetMessageTextFragment() const {
85 return l10n_util::GetStringUTF16(IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT);
88 base::string16
89 GeolocationPermissionRequest::GetAlternateAcceptButtonText() const {
90 return l10n_util::GetStringUTF16(IDS_GEOLOCATION_ALLOW_BUTTON);
93 base::string16
94 GeolocationPermissionRequest::GetAlternateDenyButtonText() const {
95 return l10n_util::GetStringUTF16(IDS_GEOLOCATION_DENY_BUTTON);
98 void GeolocationPermissionRequest::PermissionGranted() {
99 context_->NotifyPermissionSet(id_, requesting_frame_, callback_, true);
102 void GeolocationPermissionRequest::PermissionDenied() {
103 context_->NotifyPermissionSet(id_, requesting_frame_, callback_, false);
106 void GeolocationPermissionRequest::Cancelled() {
107 context_->NotifyPermissionSet(id_, requesting_frame_, callback_, false);
110 void GeolocationPermissionRequest::RequestFinished() {
111 delete this;
115 ChromeGeolocationPermissionContext::ChromeGeolocationPermissionContext(
116 Profile* profile)
117 : profile_(profile),
118 shutting_down_(false) {
121 ChromeGeolocationPermissionContext::~ChromeGeolocationPermissionContext() {
122 // ChromeGeolocationPermissionContext may be destroyed on either the UI thread
123 // or the IO thread, but the PermissionQueueController must have been
124 // destroyed on the UI thread.
125 DCHECK(!permission_queue_controller_.get());
128 void ChromeGeolocationPermissionContext::RequestGeolocationPermission(
129 int render_process_id,
130 int render_view_id,
131 int bridge_id,
132 const GURL& requesting_frame,
133 base::Callback<void(bool)> callback) {
134 GURL requesting_frame_origin = requesting_frame.GetOrigin();
135 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
136 content::BrowserThread::PostTask(
137 content::BrowserThread::UI, FROM_HERE,
138 base::Bind(
139 &ChromeGeolocationPermissionContext::RequestGeolocationPermission,
140 this, render_process_id, render_view_id, bridge_id,
141 requesting_frame_origin, callback));
142 return;
145 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
146 if (shutting_down_)
147 return;
149 content::WebContents* web_contents =
150 tab_util::GetWebContentsByID(render_process_id, render_view_id);
151 const PermissionRequestID id(render_process_id, render_view_id, bridge_id, 0);
152 ExtensionRegistry* extension_registry = ExtensionRegistry::Get(profile_);
153 if (extension_registry) {
154 const extensions::Extension* extension =
155 extension_registry->enabled_extensions().GetExtensionOrAppByURL(
156 requesting_frame_origin);
157 if (IsExtensionWithPermissionOrSuggestInConsole(APIPermission::kGeolocation,
158 extension,
159 profile_)) {
160 // Make sure the extension is in the calling process.
161 if (extensions::ProcessMap::Get(profile_)
162 ->Contains(extension->id(), id.render_process_id())) {
163 NotifyPermissionSet(id, requesting_frame_origin, callback, true);
164 return;
169 if (extensions::GetViewType(web_contents) !=
170 extensions::VIEW_TYPE_TAB_CONTENTS) {
171 // The tab may have gone away, or the request may not be from a tab at all.
172 // TODO(mpcomplete): the request could be from a background page or
173 // extension popup (web_contents will have a different ViewType). But why do
174 // we care? Shouldn't we still put an infobar up in the current tab?
175 LOG(WARNING) << "Attempt to use geolocation tabless renderer: "
176 << id.ToString()
177 << " (can't prompt user without a visible tab)";
178 NotifyPermissionSet(id, requesting_frame_origin, callback, false);
179 return;
182 GURL embedder = web_contents->GetLastCommittedURL().GetOrigin();
183 if (!requesting_frame_origin.is_valid() || !embedder.is_valid()) {
184 LOG(WARNING) << "Attempt to use geolocation from an invalid URL: "
185 << requesting_frame_origin << "," << embedder
186 << " (geolocation is not supported in popups)";
187 NotifyPermissionSet(id, requesting_frame_origin, callback, false);
188 return;
191 DecidePermission(web_contents, id, requesting_frame_origin,
192 embedder, callback);
195 void ChromeGeolocationPermissionContext::CancelGeolocationPermissionRequest(
196 int render_process_id,
197 int render_view_id,
198 int bridge_id,
199 const GURL& requesting_frame) {
200 CancelPendingInfobarRequest(PermissionRequestID(
201 render_process_id, render_view_id, bridge_id, 0));
204 void ChromeGeolocationPermissionContext::DecidePermission(
205 content::WebContents* web_contents,
206 const PermissionRequestID& id,
207 const GURL& requesting_frame,
208 const GURL& embedder,
209 base::Callback<void(bool)> callback) {
210 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
212 ContentSetting content_setting =
213 profile_->GetHostContentSettingsMap()->GetContentSetting(
214 requesting_frame, embedder, CONTENT_SETTINGS_TYPE_GEOLOCATION,
215 std::string());
216 switch (content_setting) {
217 case CONTENT_SETTING_BLOCK:
218 PermissionDecided(id, requesting_frame, embedder, callback, false);
219 break;
220 case CONTENT_SETTING_ALLOW:
221 PermissionDecided(id, requesting_frame, embedder, callback, true);
222 break;
223 default:
224 if (PermissionBubbleManager::Enabled()) {
225 PermissionBubbleManager* mgr =
226 PermissionBubbleManager::FromWebContents(web_contents);
227 mgr->AddRequest(new GeolocationPermissionRequest(
228 this, id, requesting_frame, callback,
229 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)));
230 } else {
231 // setting == ask. Prompt the user.
232 QueueController()->CreateInfoBarRequest(
233 id, requesting_frame, embedder, base::Bind(
234 &ChromeGeolocationPermissionContext::NotifyPermissionSet,
235 base::Unretained(this), id, requesting_frame, callback));
240 void ChromeGeolocationPermissionContext::ShutdownOnUIThread() {
241 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
242 permission_queue_controller_.reset();
243 shutting_down_ = true;
246 void ChromeGeolocationPermissionContext::PermissionDecided(
247 const PermissionRequestID& id,
248 const GURL& requesting_frame,
249 const GURL& embedder,
250 base::Callback<void(bool)> callback,
251 bool allowed) {
252 NotifyPermissionSet(id, requesting_frame, callback, allowed);
255 void ChromeGeolocationPermissionContext::NotifyPermissionSet(
256 const PermissionRequestID& id,
257 const GURL& requesting_frame,
258 base::Callback<void(bool)> callback,
259 bool allowed) {
260 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
262 // WebContents may have gone away (or not exists for extension).
263 TabSpecificContentSettings* content_settings =
264 TabSpecificContentSettings::Get(id.render_process_id(),
265 id.render_view_id());
266 if (content_settings) {
267 content_settings->OnGeolocationPermissionSet(requesting_frame.GetOrigin(),
268 allowed);
271 callback.Run(allowed);
274 PermissionQueueController*
275 ChromeGeolocationPermissionContext::QueueController() {
276 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
277 DCHECK(!shutting_down_);
278 if (!permission_queue_controller_)
279 permission_queue_controller_.reset(CreateQueueController());
280 return permission_queue_controller_.get();
283 PermissionQueueController*
284 ChromeGeolocationPermissionContext::CreateQueueController() {
285 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
286 return new PermissionQueueController(profile(),
287 CONTENT_SETTINGS_TYPE_GEOLOCATION);
290 void ChromeGeolocationPermissionContext::CancelPendingInfobarRequest(
291 const PermissionRequestID& id) {
292 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
293 content::BrowserThread::PostTask(
294 content::BrowserThread::UI, FROM_HERE,
295 base::Bind(
296 &ChromeGeolocationPermissionContext::CancelPendingInfobarRequest,
297 this, id));
298 return;
300 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
301 if (shutting_down_)
302 return;
304 // TODO(gbillock): handle permission bubble cancellation.
305 QueueController()->CancelInfoBarRequest(id);