OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/geolocation/geolocation_permission_context.h" | 5 #include "chrome/browser/geolocation/geolocation_permission_context.h" |
6 | 6 |
7 #include <functional> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | 7 #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/tab_specific_content_settings.h" | 8 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
16 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/tab_contents/tab_util.h" | |
18 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h" | |
19 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" | |
20 #include "chrome/common/pref_names.h" | |
21 #include "chrome/grit/generated_resources.h" | |
22 #include "components/content_settings/core/common/permission_request_id.h" | 10 #include "components/content_settings/core/common/permission_request_id.h" |
23 #include "content/public/browser/browser_thread.h" | 11 #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" | 12 #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" | |
30 | |
31 class GeolocationPermissionRequest : public PermissionBubbleRequest { | |
32 public: | |
33 GeolocationPermissionRequest(GeolocationPermissionContext* context, | |
34 const PermissionRequestID& id, | |
35 const GURL& requesting_frame, | |
36 const GURL& embedder, | |
37 bool user_gesture, | |
38 base::Callback<void(bool)> callback, | |
39 const std::string& display_languages); | |
40 virtual ~GeolocationPermissionRequest(); | |
41 | |
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; | |
52 | |
53 private: | |
54 GeolocationPermissionContext* context_; | |
55 PermissionRequestID id_; | |
56 GURL requesting_frame_; | |
57 GURL embedder_; | |
58 bool user_gesture_; | |
59 base::Callback<void(bool)> callback_; | |
60 std::string display_languages_; | |
61 }; | |
62 | |
63 GeolocationPermissionRequest::GeolocationPermissionRequest( | |
64 GeolocationPermissionContext* context, | |
65 const PermissionRequestID& id, | |
66 const GURL& requesting_frame, | |
67 const GURL& embedder, | |
68 bool user_gesture, | |
69 base::Callback<void(bool)> callback, | |
70 const std::string& display_languages) | |
71 : context_(context), | |
72 id_(id), | |
73 requesting_frame_(requesting_frame), | |
74 embedder_(embedder), | |
75 user_gesture_(user_gesture), | |
76 callback_(callback), | |
77 display_languages_(display_languages) {} | |
78 | |
79 GeolocationPermissionRequest::~GeolocationPermissionRequest() {} | |
80 | |
81 int GeolocationPermissionRequest::GetIconID() const { | |
82 return IDR_INFOBAR_GEOLOCATION; | |
83 } | |
84 | |
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)); | |
92 } | |
93 | |
94 base::string16 GeolocationPermissionRequest::GetMessageTextFragment() const { | |
95 return l10n_util::GetStringUTF16(IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT); | |
96 } | |
97 | |
98 bool GeolocationPermissionRequest::HasUserGesture() const { | |
99 return user_gesture_; | |
100 } | |
101 | |
102 GURL GeolocationPermissionRequest::GetRequestingHostname() const { | |
103 return requesting_frame_; | |
104 } | |
105 | |
106 void GeolocationPermissionRequest::PermissionGranted() { | |
107 context_->QueueController()->UpdateContentSetting( | |
108 requesting_frame_, embedder_, true); | |
109 context_->NotifyPermissionSet(id_, requesting_frame_, callback_, true); | |
110 } | |
111 | |
112 void GeolocationPermissionRequest::PermissionDenied() { | |
113 context_->QueueController()->UpdateContentSetting( | |
114 requesting_frame_, embedder_, false); | |
115 context_->NotifyPermissionSet(id_, requesting_frame_, callback_, false); | |
116 } | |
117 | |
118 void GeolocationPermissionRequest::Cancelled() { | |
119 } | |
120 | |
121 void GeolocationPermissionRequest::RequestFinished() { | |
122 // Deletes 'this'. | |
123 context_->RequestFinished(this); | |
124 } | |
125 | 13 |
126 | 14 |
127 GeolocationPermissionContext::GeolocationPermissionContext( | 15 GeolocationPermissionContext::GeolocationPermissionContext( |
128 Profile* profile) | 16 Profile* profile) |
129 : profile_(profile), | 17 : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_GEOLOCATION), |
130 shutting_down_(false), | |
131 extensions_context_(profile) { | 18 extensions_context_(profile) { |
132 } | 19 } |
133 | 20 |
134 GeolocationPermissionContext::~GeolocationPermissionContext() { | 21 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()); | |
139 } | 22 } |
140 | 23 |
141 void GeolocationPermissionContext::RequestGeolocationPermission( | 24 void GeolocationPermissionContext::RequestPermission( |
142 content::WebContents* web_contents, | 25 content::WebContents* web_contents, |
143 int bridge_id, | 26 const PermissionRequestID& id, |
144 const GURL& requesting_frame, | 27 const GURL& requesting_frame_origin, |
145 bool user_gesture, | 28 bool user_gesture, |
146 base::Callback<void(bool)> result_callback, | 29 const BrowserPermissionCallback& callback) { |
147 base::Closure* cancel_callback) { | 30 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
148 GURL requesting_frame_origin = requesting_frame.GetOrigin(); | 31 GURL embedder_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
149 if (shutting_down_) | |
150 return; | |
151 | |
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); | |
158 } | |
159 | |
160 const PermissionRequestID id( | |
161 render_process_id, render_view_id, bridge_id, GURL()); | |
162 | 32 |
163 bool permission_set; | 33 bool permission_set; |
164 bool new_permission; | 34 bool new_permission; |
165 if (extensions_context_.RequestPermission( | 35 if (extensions_context_.RequestPermission( |
166 web_contents, id, bridge_id, requesting_frame, user_gesture, | 36 web_contents, id, id.bridge_id(), requesting_frame_origin, user_gesture, |
167 result_callback, &permission_set, &new_permission)) { | 37 callback, &permission_set, &new_permission)) { |
168 if (permission_set) { | 38 if (permission_set) { |
169 NotifyPermissionSet(id, requesting_frame_origin, result_callback, | 39 NotifyPermissionSet(id, requesting_frame_origin, embedder_origin, |
170 new_permission); | 40 callback, true, new_permission); |
171 } | 41 } |
172 return; | 42 return; |
173 } | 43 } |
174 | 44 |
175 GURL embedder = web_contents->GetLastCommittedURL().GetOrigin(); | 45 if (!requesting_frame_origin.is_valid() || !embedder_origin.is_valid()) { |
176 if (!requesting_frame_origin.is_valid() || !embedder.is_valid()) { | |
177 LOG(WARNING) << "Attempt to use geolocation from an invalid URL: " | 46 LOG(WARNING) << "Attempt to use geolocation from an invalid URL: " |
178 << requesting_frame_origin << "," << embedder | 47 << requesting_frame_origin << "," << embedder_origin |
179 << " (geolocation is not supported in popups)"; | 48 << " (geolocation is not supported in popups)"; |
180 NotifyPermissionSet(id, requesting_frame_origin, result_callback, false); | 49 NotifyPermissionSet(id, requesting_frame_origin, embedder_origin, |
| 50 callback, false /* persist */, false /* allowed */); |
181 return; | 51 return; |
182 } | 52 } |
183 | 53 |
184 DecidePermission(web_contents, id, requesting_frame_origin, user_gesture, | 54 PermissionContextBase::RequestPermission(web_contents, id, |
185 embedder, result_callback); | 55 requesting_frame_origin, |
| 56 user_gesture, |
| 57 callback); |
186 } | 58 } |
187 | 59 |
188 void GeolocationPermissionContext::CancelGeolocationPermissionRequest( | 60 void GeolocationPermissionContext::CancelPermissionRequest( |
189 int render_process_id, | 61 content::WebContents* web_contents, |
190 int render_view_id, | 62 const PermissionRequestID& id) { |
191 int bridge_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)) | |
195 return; | |
196 | 63 |
197 CancelPendingInfobarRequest(PermissionRequestID( | 64 if (extensions_context_.CancelPermissionRequest( |
198 render_process_id, render_view_id, bridge_id, GURL())); | 65 web_contents, id.bridge_id())) |
| 66 return; |
| 67 PermissionContextBase::CancelPermissionRequest(web_contents, id); |
199 } | 68 } |
200 | 69 |
201 void GeolocationPermissionContext::DecidePermission( | 70 void GeolocationPermissionContext::UpdateTabContext( |
202 content::WebContents* web_contents, | |
203 const PermissionRequestID& id, | 71 const PermissionRequestID& id, |
204 const GURL& requesting_frame, | 72 const GURL& requesting_frame, |
205 bool user_gesture, | |
206 const GURL& embedder, | |
207 base::Callback<void(bool)> callback) { | |
208 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
209 | |
210 ContentSetting content_setting = | |
211 profile_->GetHostContentSettingsMap() | |
212 ->GetContentSettingAndMaybeUpdateLastUsage( | |
213 requesting_frame, | |
214 embedder, | |
215 CONTENT_SETTINGS_TYPE_GEOLOCATION, | |
216 std::string()); | |
217 switch (content_setting) { | |
218 case CONTENT_SETTING_BLOCK: | |
219 PermissionDecided(id, requesting_frame, embedder, callback, false); | |
220 break; | |
221 case CONTENT_SETTING_ALLOW: | |
222 PermissionDecided(id, requesting_frame, embedder, callback, true); | |
223 break; | |
224 default: | |
225 if (PermissionBubbleManager::Enabled()) { | |
226 PermissionBubbleManager* mgr = | |
227 PermissionBubbleManager::FromWebContents(web_contents); | |
228 if (mgr) { | |
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); | |
236 } | |
237 } else { | |
238 // setting == ask. Prompt the user. | |
239 QueueController()->CreateInfoBarRequest( | |
240 id, requesting_frame, embedder, | |
241 base::Bind( | |
242 &GeolocationPermissionContext::NotifyPermissionSet, | |
243 base::Unretained(this), id, requesting_frame, callback)); | |
244 } | |
245 } | |
246 } | |
247 | |
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)); | |
257 } | |
258 | |
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); | |
266 return; | |
267 } | |
268 } | |
269 } | |
270 | |
271 | |
272 void GeolocationPermissionContext::ShutdownOnUIThread() { | |
273 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
274 permission_queue_controller_.reset(); | |
275 shutting_down_ = true; | |
276 } | |
277 | |
278 void GeolocationPermissionContext::PermissionDecided( | |
279 const PermissionRequestID& id, | |
280 const GURL& requesting_frame, | |
281 const GURL& embedder, | |
282 base::Callback<void(bool)> callback, | |
283 bool allowed) { | 73 bool allowed) { |
284 NotifyPermissionSet(id, requesting_frame, callback, allowed); | |
285 } | |
286 | |
287 void GeolocationPermissionContext::NotifyPermissionSet( | |
288 const PermissionRequestID& id, | |
289 const GURL& requesting_frame, | |
290 base::Callback<void(bool)> callback, | |
291 bool allowed) { | |
292 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
293 | |
294 // WebContents may have gone away (or not exists for extension). | 74 // WebContents may have gone away (or not exists for extension). |
295 TabSpecificContentSettings* content_settings = | 75 TabSpecificContentSettings* content_settings = |
296 TabSpecificContentSettings::Get(id.render_process_id(), | 76 TabSpecificContentSettings::Get(id.render_process_id(), |
297 id.render_view_id()); | 77 id.render_view_id()); |
298 if (content_settings) { | 78 if (content_settings) |
299 content_settings->OnGeolocationPermissionSet(requesting_frame.GetOrigin(), | 79 content_settings->OnGeolocationPermissionSet( |
300 allowed); | 80 requesting_frame.GetOrigin(), allowed); |
301 } | |
302 | |
303 callback.Run(allowed); | |
304 } | 81 } |
305 | |
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(); | |
313 } | |
314 | |
315 PermissionQueueController* | |
316 GeolocationPermissionContext::CreateQueueController() { | |
317 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
318 return new PermissionQueueController(profile(), | |
319 CONTENT_SETTINGS_TYPE_GEOLOCATION); | |
320 } | |
321 | |
322 void GeolocationPermissionContext::CancelPendingInfobarRequest( | |
323 const PermissionRequestID& id) { | |
324 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
325 if (shutting_down_) | |
326 return; | |
327 | |
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); | |
337 } | |
338 return; | |
339 } | |
340 | |
341 QueueController()->CancelInfoBarRequest(id); | |
342 } | |
OLD | NEW |