Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / geolocation / geolocation_permission_context.cc
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.
4
5 #include "chrome/browser/geolocation/geolocation_permission_context.h"
6
7 #include <functional>
8 #include <string>
9 #include <vector>
10
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/tab_specific_content_settings.h"
16 #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"
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"
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
126
127 GeolocationPermissionContext::GeolocationPermissionContext(
128     Profile* profile)
129     : profile_(profile),
130       shutting_down_(false),
131       extensions_context_(profile) {
132 }
133
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());
139 }
140
141 void GeolocationPermissionContext::RequestGeolocationPermission(
142     content::WebContents* web_contents,
143     int bridge_id,
144     const GURL& requesting_frame,
145     bool user_gesture,
146     base::Callback<void(bool)> result_callback,
147     base::Closure* cancel_callback) {
148   GURL requesting_frame_origin = requesting_frame.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
163   bool permission_set;
164   bool new_permission;
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,
170                           new_permission);
171     }
172     return;
173   }
174
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);
181     return;
182   }
183
184   DecidePermission(web_contents, id, requesting_frame_origin, user_gesture,
185                    embedder, result_callback);
186 }
187
188 void GeolocationPermissionContext::CancelGeolocationPermissionRequest(
189     int render_process_id,
190     int render_view_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
197   CancelPendingInfobarRequest(PermissionRequestID(
198       render_process_id, render_view_id, bridge_id, GURL()));
199 }
200
201 void GeolocationPermissionContext::DecidePermission(
202     content::WebContents* web_contents,
203     const PermissionRequestID& id,
204     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) {
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).
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(),
300                                                  allowed);
301   }
302
303   callback.Run(allowed);
304 }
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 }