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.
4
5#include "chrome/browser/geolocation/geolocation_permission_context.h"
6
7#include <set>
8#include <string>
9#include <utility>
10
11#include "base/bind.h"
12#include "base/containers/hash_tables.h"
13#include "base/id_map.h"
14#include "base/memory/scoped_vector.h"
15#include "base/synchronization/waitable_event.h"
16#include "base/test/simple_test_clock.h"
17#include "base/time/clock.h"
18#include "chrome/browser/chrome_notification_types.h"
19#include "chrome/browser/content_settings/host_content_settings_map.h"
20#include "chrome/browser/content_settings/tab_specific_content_settings.h"
21#include "chrome/browser/geolocation/geolocation_permission_context_factory.h"
22#include "chrome/browser/infobars/infobar_service.h"
23#include "chrome/test/base/chrome_render_view_host_test_harness.h"
24#include "chrome/test/base/testing_profile.h"
25#include "components/content_settings/core/common/permission_request_id.h"
26#include "components/infobars/core/confirm_infobar_delegate.h"
27#include "components/infobars/core/infobar.h"
28#include "content/public/browser/browser_thread.h"
29#include "content/public/browser/navigation_details.h"
30#include "content/public/browser/notification_registrar.h"
31#include "content/public/browser/notification_service.h"
32#include "content/public/browser/web_contents.h"
33#include "content/public/test/mock_render_process_host.h"
34#include "content/public/test/test_renderer_host.h"
35#include "content/public/test/test_utils.h"
36#include "content/public/test/web_contents_tester.h"
37#include "testing/gtest/include/gtest/gtest.h"
38
39#if defined(OS_ANDROID)
40#include "base/prefs/pref_service.h"
41#include "chrome/browser/android/mock_google_location_settings_helper.h"
42#include "chrome/common/pref_names.h"
43#endif
44
45#if defined(ENABLE_EXTENSIONS)
46#include "extensions/browser/view_type_utils.h"
47#endif
48
49using content::MockRenderProcessHost;
50
51
52// ClosedInfoBarTracker -------------------------------------------------------
53
54// We need to track which infobars were closed.
55class ClosedInfoBarTracker : public content::NotificationObserver {
56 public:
57  ClosedInfoBarTracker();
58  virtual ~ClosedInfoBarTracker();
59
60  // content::NotificationObserver:
61  virtual void Observe(int type,
62                       const content::NotificationSource& source,
63                       const content::NotificationDetails& details) OVERRIDE;
64
65  size_t size() const { return removed_infobars_.size(); }
66
67  bool Contains(infobars::InfoBar* infobar) const;
68  void Clear();
69
70 private:
71  FRIEND_TEST_ALL_PREFIXES(GeolocationPermissionContextTests, TabDestroyed);
72  content::NotificationRegistrar registrar_;
73  std::set<infobars::InfoBar*> removed_infobars_;
74};
75
76ClosedInfoBarTracker::ClosedInfoBarTracker() {
77  registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
78                 content::NotificationService::AllSources());
79}
80
81ClosedInfoBarTracker::~ClosedInfoBarTracker() {
82}
83
84void ClosedInfoBarTracker::Observe(
85    int type,
86    const content::NotificationSource& source,
87    const content::NotificationDetails& details) {
88  DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
89  removed_infobars_.insert(
90      content::Details<infobars::InfoBar::RemovedDetails>(details)->first);
91}
92
93bool ClosedInfoBarTracker::Contains(infobars::InfoBar* infobar) const {
94  return removed_infobars_.count(infobar) != 0;
95}
96
97void ClosedInfoBarTracker::Clear() {
98  removed_infobars_.clear();
99}
100
101
102// GeolocationPermissionContextTests ------------------------------------------
103
104class GeolocationPermissionContextTests
105    : public ChromeRenderViewHostTestHarness {
106 protected:
107  // ChromeRenderViewHostTestHarness:
108  virtual void SetUp() OVERRIDE;
109  virtual void TearDown() OVERRIDE;
110
111  PermissionRequestID RequestID(int bridge_id);
112  PermissionRequestID RequestIDForTab(int tab, int bridge_id);
113  InfoBarService* infobar_service() {
114    return InfoBarService::FromWebContents(web_contents());
115  }
116  InfoBarService* infobar_service_for_tab(int tab) {
117    return InfoBarService::FromWebContents(extra_tabs_[tab]);
118  }
119
120  void RequestGeolocationPermission(content::WebContents* web_contents,
121                                    const PermissionRequestID& id,
122                                    const GURL& requesting_frame);
123  void RequestGeolocationPermission(content::WebContents* web_contents,
124                                    const PermissionRequestID& id,
125                                    const GURL& requesting_frame,
126                                    base::Closure* cancel_callback);
127  void PermissionResponse(const PermissionRequestID& id,
128                          bool allowed);
129  void CheckPermissionMessageSent(int bridge_id, bool allowed);
130  void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed);
131  void CheckPermissionMessageSentInternal(MockRenderProcessHost* process,
132                                          int bridge_id,
133                                          bool allowed);
134  void AddNewTab(const GURL& url);
135  void CheckTabContentsState(const GURL& requesting_frame,
136                             ContentSetting expected_content_setting);
137
138  scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
139  ClosedInfoBarTracker closed_infobar_tracker_;
140  ScopedVector<content::WebContents> extra_tabs_;
141
142  // A map between renderer child id and a pair represending the bridge id and
143  // whether the requested permission was allowed.
144  base::hash_map<int, std::pair<int, bool> > responses_;
145};
146
147PermissionRequestID GeolocationPermissionContextTests::RequestID(
148    int bridge_id) {
149  return PermissionRequestID(
150      web_contents()->GetRenderProcessHost()->GetID(),
151      web_contents()->GetRenderViewHost()->GetRoutingID(),
152      bridge_id,
153      GURL());
154}
155
156PermissionRequestID GeolocationPermissionContextTests::RequestIDForTab(
157    int tab,
158    int bridge_id) {
159  return PermissionRequestID(
160      extra_tabs_[tab]->GetRenderProcessHost()->GetID(),
161      extra_tabs_[tab]->GetRenderViewHost()->GetRoutingID(),
162      bridge_id,
163      GURL());
164}
165
166void GeolocationPermissionContextTests::RequestGeolocationPermission(
167    content::WebContents* web_contents,
168    const PermissionRequestID& id,
169    const GURL& requesting_frame) {
170  RequestGeolocationPermission(web_contents, id, requesting_frame, NULL);
171}
172
173void GeolocationPermissionContextTests::RequestGeolocationPermission(
174    content::WebContents* web_contents,
175    const PermissionRequestID& id,
176    const GURL& requesting_frame,
177    base::Closure* cancel_callback) {
178  geolocation_permission_context_->RequestGeolocationPermission(
179      web_contents, id.bridge_id(), requesting_frame, false,
180      base::Bind(&GeolocationPermissionContextTests::PermissionResponse,
181                 base::Unretained(this), id),
182      cancel_callback);
183  content::RunAllBlockingPoolTasksUntilIdle();
184}
185
186void GeolocationPermissionContextTests::PermissionResponse(
187    const PermissionRequestID& id,
188    bool allowed) {
189  responses_[id.render_process_id()] = std::make_pair(id.bridge_id(), allowed);
190}
191
192void GeolocationPermissionContextTests::CheckPermissionMessageSent(
193    int bridge_id,
194    bool allowed) {
195  CheckPermissionMessageSentInternal(process(), bridge_id, allowed);
196}
197
198void GeolocationPermissionContextTests::CheckPermissionMessageSentForTab(
199    int tab,
200    int bridge_id,
201    bool allowed) {
202  CheckPermissionMessageSentInternal(static_cast<MockRenderProcessHost*>(
203      extra_tabs_[tab]->GetRenderProcessHost()),
204      bridge_id, allowed);
205}
206
207void GeolocationPermissionContextTests::CheckPermissionMessageSentInternal(
208    MockRenderProcessHost* process,
209    int bridge_id,
210    bool allowed) {
211  ASSERT_EQ(responses_.count(process->GetID()), 1U);
212  EXPECT_EQ(bridge_id, responses_[process->GetID()].first);
213  EXPECT_EQ(allowed, responses_[process->GetID()].second);
214  responses_.erase(process->GetID());
215}
216
217void GeolocationPermissionContextTests::AddNewTab(const GURL& url) {
218  content::WebContents* new_tab = content::WebContents::Create(
219      content::WebContents::CreateParams(profile()));
220  new_tab->GetController().LoadURL(
221      url, content::Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
222  content::RenderViewHostTester::For(new_tab->GetRenderViewHost())->
223      SendNavigate(extra_tabs_.size() + 1, url);
224
225  // Set up required helpers, and make this be as "tabby" as the code requires.
226#if defined(ENABLE_EXTENSIONS)
227  extensions::SetViewType(new_tab, extensions::VIEW_TYPE_TAB_CONTENTS);
228#endif
229  InfoBarService::CreateForWebContents(new_tab);
230
231  extra_tabs_.push_back(new_tab);
232}
233
234void GeolocationPermissionContextTests::CheckTabContentsState(
235    const GURL& requesting_frame,
236    ContentSetting expected_content_setting) {
237  TabSpecificContentSettings* content_settings =
238      TabSpecificContentSettings::FromWebContents(web_contents());
239  const ContentSettingsUsagesState::StateMap& state_map =
240      content_settings->geolocation_usages_state().state_map();
241  EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin()));
242  EXPECT_EQ(0U, state_map.count(requesting_frame));
243  ContentSettingsUsagesState::StateMap::const_iterator settings =
244      state_map.find(requesting_frame.GetOrigin());
245  ASSERT_FALSE(settings == state_map.end())
246      << "geolocation state not found " << requesting_frame;
247  EXPECT_EQ(expected_content_setting, settings->second);
248}
249
250void GeolocationPermissionContextTests::SetUp() {
251  ChromeRenderViewHostTestHarness::SetUp();
252
253  // Set up required helpers, and make this be as "tabby" as the code requires.
254#if defined(ENABLE_EXTENSIONS)
255  extensions::SetViewType(web_contents(), extensions::VIEW_TYPE_TAB_CONTENTS);
256#endif
257  InfoBarService::CreateForWebContents(web_contents());
258  TabSpecificContentSettings::CreateForWebContents(web_contents());
259#if defined(OS_ANDROID)
260  MockGoogleLocationSettingsHelper::SetLocationStatus(true, true);
261#endif
262  geolocation_permission_context_ =
263      GeolocationPermissionContextFactory::GetForProfile(profile());
264}
265
266void GeolocationPermissionContextTests::TearDown() {
267  extra_tabs_.clear();
268  ChromeRenderViewHostTestHarness::TearDown();
269}
270
271// Tests ----------------------------------------------------------------------
272
273TEST_F(GeolocationPermissionContextTests, SinglePermission) {
274  GURL requesting_frame("http://www.example.com/geolocation");
275  NavigateAndCommit(requesting_frame);
276  EXPECT_EQ(0U, infobar_service()->infobar_count());
277  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
278  ASSERT_EQ(1U, infobar_service()->infobar_count());
279  infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
280  ConfirmInfoBarDelegate* infobar_delegate =
281      infobar->delegate()->AsConfirmInfoBarDelegate();
282  ASSERT_TRUE(infobar_delegate);
283  infobar_delegate->Cancel();
284  infobar_service()->RemoveInfoBar(infobar);
285  EXPECT_EQ(1U, closed_infobar_tracker_.size());
286  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar));
287}
288
289#if defined(OS_ANDROID)
290TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) {
291  GURL requesting_frame("http://www.example.com/geolocation");
292  NavigateAndCommit(requesting_frame);
293  MockGoogleLocationSettingsHelper::SetLocationStatus(true, true);
294  EXPECT_EQ(0U, infobar_service()->infobar_count());
295  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
296  EXPECT_EQ(1U, infobar_service()->infobar_count());
297  ConfirmInfoBarDelegate* infobar_delegate_0 =
298      infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate();
299  ASSERT_TRUE(infobar_delegate_0);
300  base::string16 text_0 = infobar_delegate_0->GetButtonLabel(
301      ConfirmInfoBarDelegate::BUTTON_OK);
302
303  Reload();
304  MockGoogleLocationSettingsHelper::SetLocationStatus(true, false);
305  EXPECT_EQ(0U, infobar_service()->infobar_count());
306  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
307  EXPECT_EQ(0U, infobar_service()->infobar_count());
308}
309
310TEST_F(GeolocationPermissionContextTests, MasterEnabledGoogleAppsEnabled) {
311  GURL requesting_frame("http://www.example.com/geolocation");
312  NavigateAndCommit(requesting_frame);
313  MockGoogleLocationSettingsHelper::SetLocationStatus(true, true);
314  EXPECT_EQ(0U, infobar_service()->infobar_count());
315  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
316  EXPECT_EQ(1U, infobar_service()->infobar_count());
317  ConfirmInfoBarDelegate* infobar_delegate =
318      infobar_service()->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate();
319  ASSERT_TRUE(infobar_delegate);
320  infobar_delegate->Accept();
321  CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
322  CheckPermissionMessageSent(0, true);
323}
324
325TEST_F(GeolocationPermissionContextTests, MasterEnabledGoogleAppsDisabled) {
326  GURL requesting_frame("http://www.example.com/geolocation");
327  NavigateAndCommit(requesting_frame);
328  MockGoogleLocationSettingsHelper::SetLocationStatus(true, false);
329  EXPECT_EQ(0U, infobar_service()->infobar_count());
330  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
331  EXPECT_EQ(0U, infobar_service()->infobar_count());
332}
333#endif
334
335TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
336  GURL requesting_frame_0("http://www.example.com/geolocation");
337  GURL requesting_frame_1("http://www.example-2.com/geolocation");
338  EXPECT_EQ(CONTENT_SETTING_ASK,
339            profile()->GetHostContentSettingsMap()->GetContentSetting(
340                requesting_frame_0, requesting_frame_0,
341                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
342  EXPECT_EQ(CONTENT_SETTING_ASK,
343            profile()->GetHostContentSettingsMap()->GetContentSetting(
344                requesting_frame_1, requesting_frame_0,
345                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
346
347  NavigateAndCommit(requesting_frame_0);
348  EXPECT_EQ(0U, infobar_service()->infobar_count());
349  // Request permission for two frames.
350  RequestGeolocationPermission(
351      web_contents(), RequestID(0), requesting_frame_0);
352  RequestGeolocationPermission(
353      web_contents(), RequestID(1), requesting_frame_1);
354  // Ensure only one infobar is created.
355  ASSERT_EQ(1U, infobar_service()->infobar_count());
356  infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
357  ConfirmInfoBarDelegate* infobar_delegate_0 =
358      infobar_0->delegate()->AsConfirmInfoBarDelegate();
359  ASSERT_TRUE(infobar_delegate_0);
360  base::string16 text_0 = infobar_delegate_0->GetMessageText();
361
362  // Accept the first frame.
363  infobar_delegate_0->Accept();
364  CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
365  CheckPermissionMessageSent(0, true);
366
367  infobar_service()->RemoveInfoBar(infobar_0);
368  EXPECT_EQ(1U, closed_infobar_tracker_.size());
369  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_0));
370  closed_infobar_tracker_.Clear();
371  // Now we should have a new infobar for the second frame.
372  ASSERT_EQ(1U, infobar_service()->infobar_count());
373
374  infobars::InfoBar* infobar_1 = infobar_service()->infobar_at(0);
375  ConfirmInfoBarDelegate* infobar_delegate_1 =
376      infobar_1->delegate()->AsConfirmInfoBarDelegate();
377  ASSERT_TRUE(infobar_delegate_1);
378  base::string16 text_1 = infobar_delegate_1->GetMessageText();
379  EXPECT_NE(text_0, text_1);
380
381  // Cancel (block) this frame.
382  infobar_delegate_1->Cancel();
383  CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_BLOCK);
384  CheckPermissionMessageSent(1, false);
385  infobar_service()->RemoveInfoBar(infobar_1);
386  EXPECT_EQ(1U, closed_infobar_tracker_.size());
387  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_1));
388  EXPECT_EQ(0U, infobar_service()->infobar_count());
389  // Ensure the persisted permissions are ok.
390  EXPECT_EQ(CONTENT_SETTING_ALLOW,
391            profile()->GetHostContentSettingsMap()->GetContentSetting(
392                requesting_frame_0, requesting_frame_0,
393                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
394
395  EXPECT_EQ(CONTENT_SETTING_BLOCK,
396            profile()->GetHostContentSettingsMap()->GetContentSetting(
397                requesting_frame_1, requesting_frame_0,
398                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
399}
400
401TEST_F(GeolocationPermissionContextTests, HashIsIgnored) {
402  GURL url_a("http://www.example.com/geolocation#a");
403  GURL url_b("http://www.example.com/geolocation#b");
404
405  // Navigate to the first url and check permission is requested.
406  NavigateAndCommit(url_a);
407  EXPECT_EQ(0U, infobar_service()->infobar_count());
408  RequestGeolocationPermission(web_contents(), RequestID(0), url_a);
409  ASSERT_EQ(1U, infobar_service()->infobar_count());
410  infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
411  ConfirmInfoBarDelegate* infobar_delegate =
412      infobar->delegate()->AsConfirmInfoBarDelegate();
413  ASSERT_TRUE(infobar_delegate);
414
415  // Change the hash, we'll still be on the same page.
416  NavigateAndCommit(url_b);
417
418  // Accept.
419  infobar_delegate->Accept();
420  CheckTabContentsState(url_a, CONTENT_SETTING_ALLOW);
421  CheckTabContentsState(url_b, CONTENT_SETTING_ALLOW);
422  CheckPermissionMessageSent(0, true);
423
424  // Cleanup.
425  infobar_service()->RemoveInfoBar(infobar);
426  EXPECT_EQ(1U, closed_infobar_tracker_.size());
427  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar));
428}
429
430TEST_F(GeolocationPermissionContextTests, PermissionForFileScheme) {
431  GURL requesting_frame("file://example/geolocation.html");
432  NavigateAndCommit(requesting_frame);
433  EXPECT_EQ(0U, infobar_service()->infobar_count());
434  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
435  EXPECT_EQ(1U, infobar_service()->infobar_count());
436  infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
437  ConfirmInfoBarDelegate* infobar_delegate =
438      infobar->delegate()->AsConfirmInfoBarDelegate();
439  ASSERT_TRUE(infobar_delegate);
440  // Accept the frame.
441  infobar_delegate->Accept();
442  CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
443  CheckPermissionMessageSent(0, true);
444  infobar_service()->RemoveInfoBar(infobar);
445
446  // Make sure the setting is not stored.
447  EXPECT_EQ(CONTENT_SETTING_ASK,
448      profile()->GetHostContentSettingsMap()->GetContentSetting(
449          requesting_frame,
450          requesting_frame,
451          CONTENT_SETTINGS_TYPE_GEOLOCATION,
452          std::string()));
453}
454
455TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
456  GURL requesting_frame_0("http://www.example.com/geolocation");
457  GURL requesting_frame_1("http://www.example-2.com/geolocation");
458  EXPECT_EQ(CONTENT_SETTING_ASK,
459            profile()->GetHostContentSettingsMap()->GetContentSetting(
460                requesting_frame_0, requesting_frame_0,
461                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
462
463  EXPECT_EQ(CONTENT_SETTING_ASK,
464            profile()->GetHostContentSettingsMap()->GetContentSetting(
465                requesting_frame_1, requesting_frame_0,
466                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
467
468  NavigateAndCommit(requesting_frame_0);
469  EXPECT_EQ(0U, infobar_service()->infobar_count());
470  // Request permission for two frames.
471  base::Closure cancel_callback;
472  RequestGeolocationPermission(
473      web_contents(), RequestID(0), requesting_frame_0, &cancel_callback);
474  RequestGeolocationPermission(
475      web_contents(), RequestID(1), requesting_frame_1);
476  ASSERT_EQ(1U, infobar_service()->infobar_count());
477
478  infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
479  ConfirmInfoBarDelegate* infobar_delegate_0 =
480      infobar_0->delegate()->AsConfirmInfoBarDelegate();
481  ASSERT_TRUE(infobar_delegate_0);
482  base::string16 text_0 = infobar_delegate_0->GetMessageText();
483
484  // Simulate the frame going away, ensure the infobar for this frame
485  // is removed and the next pending infobar is created.
486  cancel_callback.Run();
487  EXPECT_EQ(1U, closed_infobar_tracker_.size());
488  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_0));
489  closed_infobar_tracker_.Clear();
490  ASSERT_EQ(1U, infobar_service()->infobar_count());
491
492  infobars::InfoBar* infobar_1 = infobar_service()->infobar_at(0);
493  ConfirmInfoBarDelegate* infobar_delegate_1 =
494      infobar_1->delegate()->AsConfirmInfoBarDelegate();
495  ASSERT_TRUE(infobar_delegate_1);
496  base::string16 text_1 = infobar_delegate_1->GetMessageText();
497  EXPECT_NE(text_0, text_1);
498
499  // Allow this frame.
500  infobar_delegate_1->Accept();
501  CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
502  CheckPermissionMessageSent(1, true);
503  infobar_service()->RemoveInfoBar(infobar_1);
504  EXPECT_EQ(1U, closed_infobar_tracker_.size());
505  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_1));
506  EXPECT_EQ(0U, infobar_service()->infobar_count());
507  // Ensure the persisted permissions are ok.
508  EXPECT_EQ(CONTENT_SETTING_ASK,
509            profile()->GetHostContentSettingsMap()->GetContentSetting(
510                requesting_frame_0, requesting_frame_0,
511                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
512
513  EXPECT_EQ(CONTENT_SETTING_ALLOW,
514            profile()->GetHostContentSettingsMap()->GetContentSetting(
515                requesting_frame_1, requesting_frame_0,
516                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
517}
518
519TEST_F(GeolocationPermissionContextTests, InvalidURL) {
520  GURL invalid_embedder("about:blank");
521  GURL requesting_frame;
522  NavigateAndCommit(invalid_embedder);
523  EXPECT_EQ(0U, infobar_service()->infobar_count());
524  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
525  EXPECT_EQ(0U, infobar_service()->infobar_count());
526  CheckPermissionMessageSent(0, false);
527}
528
529TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) {
530  GURL url_a("http://www.example.com/geolocation");
531  GURL url_b("http://www.example-2.com/geolocation");
532  NavigateAndCommit(url_a);
533  AddNewTab(url_b);
534  AddNewTab(url_a);
535
536  EXPECT_EQ(0U, infobar_service()->infobar_count());
537  RequestGeolocationPermission(web_contents(), RequestID(0), url_a);
538  ASSERT_EQ(1U, infobar_service()->infobar_count());
539
540  RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 0), url_b);
541  EXPECT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
542
543  RequestGeolocationPermission(extra_tabs_[1], RequestIDForTab(1, 0), url_a);
544  ASSERT_EQ(1U, infobar_service_for_tab(1)->infobar_count());
545
546  infobars::InfoBar* removed_infobar =
547      infobar_service_for_tab(1)->infobar_at(0);
548
549  // Accept the first tab.
550  infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
551  ConfirmInfoBarDelegate* infobar_delegate_0 =
552      infobar_0->delegate()->AsConfirmInfoBarDelegate();
553  ASSERT_TRUE(infobar_delegate_0);
554  infobar_delegate_0->Accept();
555  CheckPermissionMessageSent(0, true);
556  infobar_service()->RemoveInfoBar(infobar_0);
557  EXPECT_EQ(2U, closed_infobar_tracker_.size());
558  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_0));
559  // Now the infobar for the tab with the same origin should have gone.
560  EXPECT_EQ(0U, infobar_service_for_tab(1)->infobar_count());
561  CheckPermissionMessageSentForTab(1, 0, true);
562  EXPECT_TRUE(closed_infobar_tracker_.Contains(removed_infobar));
563  closed_infobar_tracker_.Clear();
564
565  // But the other tab should still have the info bar...
566  ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
567  infobars::InfoBar* infobar_1 = infobar_service_for_tab(0)->infobar_at(0);
568  ConfirmInfoBarDelegate* infobar_delegate_1 =
569      infobar_1->delegate()->AsConfirmInfoBarDelegate();
570  ASSERT_TRUE(infobar_delegate_1);
571  infobar_delegate_1->Cancel();
572  infobar_service_for_tab(0)->RemoveInfoBar(infobar_1);
573  EXPECT_EQ(1U, closed_infobar_tracker_.size());
574  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_1));
575}
576
577TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) {
578  GURL url_a("http://www.example.com/geolocation");
579  GURL url_b("http://www.example-2.com/geolocation");
580  NavigateAndCommit(url_a);
581  AddNewTab(url_a);
582
583  EXPECT_EQ(0U, infobar_service()->infobar_count());
584  RequestGeolocationPermission(web_contents(), RequestID(0), url_a);
585  ASSERT_EQ(1U, infobar_service()->infobar_count());
586
587  RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 0), url_a);
588  EXPECT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
589
590  RequestGeolocationPermission(extra_tabs_[0], RequestIDForTab(0, 1), url_b);
591  ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
592
593  infobars::InfoBar* removed_infobar = infobar_service()->infobar_at(0);
594
595  // Accept the second tab.
596  infobars::InfoBar* infobar_0 = infobar_service_for_tab(0)->infobar_at(0);
597  ConfirmInfoBarDelegate* infobar_delegate_0 =
598      infobar_0->delegate()->AsConfirmInfoBarDelegate();
599  ASSERT_TRUE(infobar_delegate_0);
600  infobar_delegate_0->Accept();
601  CheckPermissionMessageSentForTab(0, 0, true);
602  infobar_service_for_tab(0)->RemoveInfoBar(infobar_0);
603  EXPECT_EQ(2U, closed_infobar_tracker_.size());
604  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_0));
605  // Now the infobar for the tab with the same origin should have gone.
606  EXPECT_EQ(0U, infobar_service()->infobar_count());
607  CheckPermissionMessageSent(0, true);
608  EXPECT_TRUE(closed_infobar_tracker_.Contains(removed_infobar));
609  closed_infobar_tracker_.Clear();
610
611  // And we should have the queued infobar displayed now.
612  ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
613
614  // Accept the second infobar.
615  infobars::InfoBar* infobar_1 = infobar_service_for_tab(0)->infobar_at(0);
616  ConfirmInfoBarDelegate* infobar_delegate_1 =
617      infobar_1->delegate()->AsConfirmInfoBarDelegate();
618  ASSERT_TRUE(infobar_delegate_1);
619  infobar_delegate_1->Accept();
620  CheckPermissionMessageSentForTab(0, 1, true);
621  infobar_service_for_tab(0)->RemoveInfoBar(infobar_1);
622  EXPECT_EQ(1U, closed_infobar_tracker_.size());
623  EXPECT_TRUE(closed_infobar_tracker_.Contains(infobar_1));
624}
625
626TEST_F(GeolocationPermissionContextTests, TabDestroyed) {
627  GURL requesting_frame_0("http://www.example.com/geolocation");
628  GURL requesting_frame_1("http://www.example-2.com/geolocation");
629  EXPECT_EQ(CONTENT_SETTING_ASK,
630            profile()->GetHostContentSettingsMap()->GetContentSetting(
631                requesting_frame_0, requesting_frame_0,
632                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
633
634  EXPECT_EQ(CONTENT_SETTING_ASK,
635            profile()->GetHostContentSettingsMap()->GetContentSetting(
636                requesting_frame_1, requesting_frame_0,
637                CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string()));
638
639  NavigateAndCommit(requesting_frame_0);
640  EXPECT_EQ(0U, infobar_service()->infobar_count());
641  // Request permission for two frames.
642  RequestGeolocationPermission(
643      web_contents(), RequestID(0), requesting_frame_0);
644  RequestGeolocationPermission(
645      web_contents(), RequestID(1), requesting_frame_1);
646  // Ensure only one infobar is created.
647  ASSERT_EQ(1U, infobar_service()->infobar_count());
648  infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
649
650  // Delete the tab contents.
651  DeleteContents();
652
653  // During contents destruction, the infobar will have been closed, and the
654  // pending request should have been cleared without an infobar being created.
655  ASSERT_EQ(1U, closed_infobar_tracker_.size());
656  ASSERT_TRUE(closed_infobar_tracker_.Contains(infobar));
657}
658
659TEST_F(GeolocationPermissionContextTests, InfoBarUsesCommittedEntry) {
660  GURL requesting_frame_0("http://www.example.com/geolocation");
661  GURL requesting_frame_1("http://www.example-2.com/geolocation");
662  NavigateAndCommit(requesting_frame_0);
663  NavigateAndCommit(requesting_frame_1);
664  EXPECT_EQ(0U, infobar_service()->infobar_count());
665  // Go back: navigate to a pending entry before requesting geolocation
666  // permission.
667  web_contents()->GetController().GoBack();
668  // Request permission for the committed frame (not the pending one).
669  RequestGeolocationPermission(
670      web_contents(), RequestID(0), requesting_frame_1);
671  // Ensure the infobar is created.
672  ASSERT_EQ(1U, infobar_service()->infobar_count());
673  infobars::InfoBarDelegate* infobar_delegate =
674      infobar_service()->infobar_at(0)->delegate();
675  ASSERT_TRUE(infobar_delegate);
676  // Ensure the infobar wouldn't expire for a navigation to the committed entry.
677  content::LoadCommittedDetails details;
678  details.entry = web_contents()->GetController().GetLastCommittedEntry();
679  EXPECT_FALSE(infobar_delegate->ShouldExpire(
680      InfoBarService::NavigationDetailsFromLoadCommittedDetails(details)));
681  // Ensure the infobar will expire when we commit the pending navigation.
682  details.entry = web_contents()->GetController().GetActiveEntry();
683  EXPECT_TRUE(infobar_delegate->ShouldExpire(
684      InfoBarService::NavigationDetailsFromLoadCommittedDetails(details)));
685
686  // Delete the tab contents.
687  DeleteContents();
688}
689
690TEST_F(GeolocationPermissionContextTests, LastUsageAudited) {
691  GURL requesting_frame("http://www.example.com/geolocation");
692  NavigateAndCommit(requesting_frame);
693
694  base::SimpleTestClock* test_clock = new base::SimpleTestClock;
695  test_clock->SetNow(base::Time::UnixEpoch() +
696                     base::TimeDelta::FromSeconds(10));
697
698  HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
699  map->SetPrefClockForTesting(scoped_ptr<base::Clock>(test_clock));
700
701  // The permission shouldn't have been used yet.
702  EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
703                              requesting_frame.GetOrigin(),
704                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
705            0);
706
707  EXPECT_EQ(0U, infobar_service()->infobar_count());
708  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
709  ASSERT_EQ(1U, infobar_service()->infobar_count());
710  infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
711  ConfirmInfoBarDelegate* infobar_delegate =
712      infobar->delegate()->AsConfirmInfoBarDelegate();
713  ASSERT_TRUE(infobar_delegate);
714  infobar_delegate->Accept();
715  CheckTabContentsState(requesting_frame, CONTENT_SETTING_ALLOW);
716  CheckPermissionMessageSent(0, true);
717
718  // Permission has been used at the starting time.
719  EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
720                              requesting_frame.GetOrigin(),
721                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
722            10);
723
724  test_clock->Advance(base::TimeDelta::FromSeconds(3));
725  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame);
726
727  // Permission has been used three seconds later.
728  EXPECT_EQ(map->GetLastUsage(requesting_frame.GetOrigin(),
729                              requesting_frame.GetOrigin(),
730                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
731            13);
732}
733
734TEST_F(GeolocationPermissionContextTests, LastUsageAuditedMultipleFrames) {
735  base::SimpleTestClock* test_clock = new base::SimpleTestClock;
736  test_clock->SetNow(base::Time::UnixEpoch() +
737                     base::TimeDelta::FromSeconds(10));
738
739  HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
740  map->SetPrefClockForTesting(scoped_ptr<base::Clock>(test_clock));
741
742  GURL requesting_frame_0("http://www.example.com/geolocation");
743  GURL requesting_frame_1("http://www.example-2.com/geolocation");
744
745  // The permission shouldn't have been used yet.
746  EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
747                              requesting_frame_0.GetOrigin(),
748                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
749            0);
750  EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
751                              requesting_frame_0.GetOrigin(),
752                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
753            0);
754
755  NavigateAndCommit(requesting_frame_0);
756  EXPECT_EQ(0U, infobar_service()->infobar_count());
757
758  // Request permission for two frames.
759  RequestGeolocationPermission(
760      web_contents(), RequestID(0), requesting_frame_0);
761  RequestGeolocationPermission(
762      web_contents(), RequestID(1), requesting_frame_1);
763
764  // Ensure only one infobar is created.
765  ASSERT_EQ(1U, infobar_service()->infobar_count());
766  infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
767  ConfirmInfoBarDelegate* infobar_delegate_0 =
768      infobar_0->delegate()->AsConfirmInfoBarDelegate();
769
770  // Accept the first frame.
771  infobar_delegate_0->Accept();
772  CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
773  CheckPermissionMessageSent(0, true);
774  infobar_service()->RemoveInfoBar(infobar_0);
775
776  // Verify that accepting the first didn't accept because it's embedder
777  // in the other.
778  EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
779                              requesting_frame_0.GetOrigin(),
780                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
781            10);
782  EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
783                              requesting_frame_0.GetOrigin(),
784                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
785            0);
786
787  ASSERT_EQ(1U, infobar_service()->infobar_count());
788  infobars::InfoBar* infobar_1 = infobar_service()->infobar_at(0);
789  ConfirmInfoBarDelegate* infobar_delegate_1 =
790      infobar_1->delegate()->AsConfirmInfoBarDelegate();
791
792  test_clock->Advance(base::TimeDelta::FromSeconds(1));
793
794  // Allow the second frame.
795  infobar_delegate_1->Accept();
796  CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
797  CheckPermissionMessageSent(1, true);
798  infobar_service()->RemoveInfoBar(infobar_1);
799
800  // Verify that the times are different.
801  EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
802                              requesting_frame_0.GetOrigin(),
803                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
804            10);
805  EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
806                              requesting_frame_0.GetOrigin(),
807                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
808            11);
809
810  test_clock->Advance(base::TimeDelta::FromSeconds(2));
811  RequestGeolocationPermission(
812      web_contents(), RequestID(0), requesting_frame_0);
813
814  // Verify that requesting permission in one frame doesn't update other where
815  // it is the embedder.
816  EXPECT_EQ(map->GetLastUsage(requesting_frame_0.GetOrigin(),
817                              requesting_frame_0.GetOrigin(),
818                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
819            13);
820  EXPECT_EQ(map->GetLastUsage(requesting_frame_1.GetOrigin(),
821                              requesting_frame_0.GetOrigin(),
822                              CONTENT_SETTINGS_TYPE_GEOLOCATION).ToDoubleT(),
823            11);
824}
825