• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/memory/scoped_vector.h"
6 #include "chrome/browser/geolocation/geolocation_content_settings_map.h"
7 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
8 #include "chrome/test/testing_profile.h"
9 #include "content/browser/browser_thread.h"
10 #include "content/browser/geolocation/arbitrator_dependency_factories_for_test.h"
11 #include "content/browser/geolocation/geolocation_permission_context.h"
12 #include "content/browser/geolocation/location_arbitrator.h"
13 #include "content/browser/geolocation/location_provider.h"
14 #include "content/browser/geolocation/mock_location_provider.h"
15 #include "content/browser/renderer_host/mock_render_process_host.h"
16 #include "content/browser/renderer_host/test_render_view_host.h"
17 #include "content/browser/tab_contents/test_tab_contents.h"
18 #include "content/common/geolocation_messages.h"
19 #include "content/common/notification_details.h"
20 #include "content/common/notification_type.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 // TestTabContentsWithPendingInfoBar ------------------------------------------
24 
25 namespace {
26 
27 // TestTabContents short-circuits TAB_CONTENTS_INFOBAR_REMOVED to call
28 // InfoBarClosed() directly. We need to observe it and call InfoBarClosed()
29 // later.
30 class TestTabContentsWithPendingInfoBar : public TestTabContents {
31  public:
32   TestTabContentsWithPendingInfoBar(Profile* profile, SiteInstance* instance);
33   virtual ~TestTabContentsWithPendingInfoBar();
34 
35   // TestTabContents:
36   virtual void Observe(NotificationType type,
37                        const NotificationSource& source,
38                        const NotificationDetails& details);
39 
40   InfoBarDelegate* removed_infobar_delegate_;
41 };
42 
TestTabContentsWithPendingInfoBar(Profile * profile,SiteInstance * instance)43 TestTabContentsWithPendingInfoBar::TestTabContentsWithPendingInfoBar(
44     Profile* profile,
45     SiteInstance* instance)
46     : TestTabContents(profile, instance),
47       removed_infobar_delegate_(NULL) {
48 }
49 
~TestTabContentsWithPendingInfoBar()50 TestTabContentsWithPendingInfoBar::~TestTabContentsWithPendingInfoBar() {
51 }
52 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)53 void TestTabContentsWithPendingInfoBar::Observe(
54     NotificationType type,
55     const NotificationSource& source,
56     const NotificationDetails& details) {
57   if (type.value == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED)
58     removed_infobar_delegate_ = Details<InfoBarDelegate>(details).ptr();
59   else
60     TestTabContents::Observe(type, source, details);
61 }
62 
63 }  // namespace
64 
65 
66 // GeolocationPermissionContextTests ------------------------------------------
67 
68 // This class sets up GeolocationArbitrator.
69 class GeolocationPermissionContextTests : public RenderViewHostTestHarness {
70  public:
71   GeolocationPermissionContextTests();
72 
73  protected:
74   virtual ~GeolocationPermissionContextTests();
75 
process_id()76   int process_id() { return contents()->render_view_host()->process()->id(); }
process_id_for_tab(int tab)77   int process_id_for_tab(int tab) {
78     return extra_tabs_[tab]->render_view_host()->process()->id();
79   }
render_id()80   int render_id() { return contents()->render_view_host()->routing_id(); }
render_id_for_tab(int tab)81   int render_id_for_tab(int tab) {
82     return extra_tabs_[tab]->render_view_host()->routing_id();
83   }
bridge_id() const84   int bridge_id() const { return 42; }  // Not relevant at this level.
85 
86   void CheckPermissionMessageSent(int bridge_id, bool allowed);
87   void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed);
88   void CheckPermissionMessageSentInternal(MockRenderProcessHost* process,
89                                           int bridge_id,
90                                           bool allowed);
91   void AddNewTab(const GURL& url);
92   void CheckTabContentsState(const GURL& requesting_frame,
93                              ContentSetting expected_content_setting);
94 
95   TestTabContentsWithPendingInfoBar* tab_contents_with_pending_infobar_;
96   scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
97   ScopedVector<TestTabContentsWithPendingInfoBar> extra_tabs_;
98 
99  private:
100   // RenderViewHostTestHarness:
101   virtual void SetUp();
102   virtual void TearDown();
103 
104   BrowserThread ui_thread_;
105   scoped_refptr<GeolocationArbitratorDependencyFactory> dependency_factory_;
106 };
107 
GeolocationPermissionContextTests()108 GeolocationPermissionContextTests::GeolocationPermissionContextTests()
109     : RenderViewHostTestHarness(),
110       tab_contents_with_pending_infobar_(NULL),
111       ui_thread_(BrowserThread::UI, MessageLoop::current()),
112       dependency_factory_(
113           new GeolocationArbitratorDependencyFactoryWithLocationProvider(
114               &NewAutoSuccessMockNetworkLocationProvider)) {
115 }
116 
~GeolocationPermissionContextTests()117 GeolocationPermissionContextTests::~GeolocationPermissionContextTests() {
118 }
119 
CheckPermissionMessageSent(int bridge_id,bool allowed)120 void GeolocationPermissionContextTests::CheckPermissionMessageSent(
121     int bridge_id,
122     bool allowed) {
123   CheckPermissionMessageSentInternal(process(), bridge_id, allowed);
124 }
125 
CheckPermissionMessageSentForTab(int tab,int bridge_id,bool allowed)126 void GeolocationPermissionContextTests::CheckPermissionMessageSentForTab(
127     int tab,
128     int bridge_id,
129     bool allowed) {
130   CheckPermissionMessageSentInternal(static_cast<MockRenderProcessHost*>(
131       extra_tabs_[tab]->render_view_host()->process()), bridge_id, allowed);
132 }
133 
CheckPermissionMessageSentInternal(MockRenderProcessHost * process,int bridge_id,bool allowed)134 void GeolocationPermissionContextTests::CheckPermissionMessageSentInternal(
135     MockRenderProcessHost* process,
136     int bridge_id,
137     bool allowed) {
138   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
139   MessageLoop::current()->Run();
140   const IPC::Message* message = process->sink().GetFirstMessageMatching(
141       GeolocationMsg_PermissionSet::ID);
142   ASSERT_TRUE(message);
143   GeolocationMsg_PermissionSet::Param param;
144   GeolocationMsg_PermissionSet::Read(message, &param);
145   EXPECT_EQ(bridge_id, param.a);
146   EXPECT_EQ(allowed, param.b);
147   process->sink().ClearMessages();
148 }
149 
AddNewTab(const GURL & url)150 void GeolocationPermissionContextTests::AddNewTab(const GURL& url) {
151   TestTabContentsWithPendingInfoBar* new_tab =
152       new TestTabContentsWithPendingInfoBar(profile(), NULL);
153   new_tab->controller().LoadURL(url, GURL(), PageTransition::TYPED);
154   static_cast<TestRenderViewHost*>(new_tab->render_manager()->current_host())->
155       SendNavigate(extra_tabs_.size() + 1, url);
156   extra_tabs_.push_back(new_tab);
157 }
158 
CheckTabContentsState(const GURL & requesting_frame,ContentSetting expected_content_setting)159 void GeolocationPermissionContextTests::CheckTabContentsState(
160     const GURL& requesting_frame,
161     ContentSetting expected_content_setting) {
162   TabSpecificContentSettings* content_settings =
163       contents()->GetTabSpecificContentSettings();
164   const GeolocationSettingsState::StateMap& state_map =
165       content_settings->geolocation_settings_state().state_map();
166   EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin()));
167   EXPECT_EQ(0U, state_map.count(requesting_frame));
168   GeolocationSettingsState::StateMap::const_iterator settings =
169       state_map.find(requesting_frame.GetOrigin());
170   ASSERT_FALSE(settings == state_map.end())
171       << "geolocation state not found " << requesting_frame;
172   EXPECT_EQ(expected_content_setting, settings->second);
173 }
174 
SetUp()175 void GeolocationPermissionContextTests::SetUp() {
176   RenderViewHostTestHarness::SetUp();
177   GeolocationArbitrator::SetDependencyFactoryForTest(
178       dependency_factory_.get());
179   SiteInstance* site_instance = contents()->GetSiteInstance();
180   tab_contents_with_pending_infobar_ =
181       new TestTabContentsWithPendingInfoBar(profile_.get(), site_instance);
182   SetContents(tab_contents_with_pending_infobar_);
183   geolocation_permission_context_ =
184       new GeolocationPermissionContext(profile());
185 }
186 
TearDown()187 void GeolocationPermissionContextTests::TearDown() {
188   GeolocationArbitrator::SetDependencyFactoryForTest(NULL);
189   RenderViewHostTestHarness::TearDown();
190 }
191 
192 
193 // Tests ----------------------------------------------------------------------
194 
TEST_F(GeolocationPermissionContextTests,SinglePermission)195 TEST_F(GeolocationPermissionContextTests, SinglePermission) {
196   GURL requesting_frame("http://www.example.com/geolocation");
197   NavigateAndCommit(requesting_frame);
198   EXPECT_EQ(0U, contents()->infobar_count());
199   geolocation_permission_context_->RequestGeolocationPermission(
200       process_id(), render_id(), bridge_id(), requesting_frame);
201   EXPECT_EQ(1U, contents()->infobar_count());
202 }
203 
TEST_F(GeolocationPermissionContextTests,QueuedPermission)204 TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
205   GURL requesting_frame_0("http://www.example.com/geolocation");
206   GURL requesting_frame_1("http://www.example-2.com/geolocation");
207   EXPECT_EQ(CONTENT_SETTING_ASK,
208       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
209           requesting_frame_0, requesting_frame_0));
210   EXPECT_EQ(CONTENT_SETTING_ASK,
211       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
212           requesting_frame_1, requesting_frame_0));
213 
214   NavigateAndCommit(requesting_frame_0);
215   EXPECT_EQ(0U, contents()->infobar_count());
216   // Request permission for two frames.
217   geolocation_permission_context_->RequestGeolocationPermission(
218       process_id(), render_id(), bridge_id(), requesting_frame_0);
219   geolocation_permission_context_->RequestGeolocationPermission(
220       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
221   // Ensure only one infobar is created.
222   EXPECT_EQ(1U, contents()->infobar_count());
223   ConfirmInfoBarDelegate* infobar_0 =
224       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
225   ASSERT_TRUE(infobar_0);
226   string16 text_0 = infobar_0->GetMessageText();
227 
228   // Accept the first frame.
229   infobar_0->Accept();
230   CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
231   CheckPermissionMessageSent(bridge_id(), true);
232 
233   contents()->RemoveInfoBar(infobar_0);
234   EXPECT_EQ(infobar_0,
235             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
236   infobar_0->InfoBarClosed();
237   // Now we should have a new infobar for the second frame.
238   EXPECT_EQ(1U, contents()->infobar_count());
239 
240   ConfirmInfoBarDelegate* infobar_1 =
241       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
242   ASSERT_TRUE(infobar_1);
243   string16 text_1 = infobar_1->GetMessageText();
244   EXPECT_NE(text_0, text_1);
245 
246   // Cancel (block) this frame.
247   infobar_1->Cancel();
248   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_BLOCK);
249   CheckPermissionMessageSent(bridge_id() + 1, false);
250   contents()->RemoveInfoBar(infobar_1);
251   EXPECT_EQ(infobar_1,
252             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
253   infobar_1->InfoBarClosed();
254   EXPECT_EQ(0U, contents()->infobar_count());
255   // Ensure the persisted permissions are ok.
256   EXPECT_EQ(CONTENT_SETTING_ALLOW,
257       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
258           requesting_frame_0, requesting_frame_0));
259   EXPECT_EQ(CONTENT_SETTING_BLOCK,
260       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
261           requesting_frame_1, requesting_frame_0));
262 }
263 
TEST_F(GeolocationPermissionContextTests,CancelGeolocationPermissionRequest)264 TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
265   GURL requesting_frame_0("http://www.example.com/geolocation");
266   GURL requesting_frame_1("http://www.example-2.com/geolocation");
267   EXPECT_EQ(CONTENT_SETTING_ASK,
268       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
269           requesting_frame_0, requesting_frame_0));
270   EXPECT_EQ(CONTENT_SETTING_ASK,
271       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
272           requesting_frame_1, requesting_frame_0));
273 
274   NavigateAndCommit(requesting_frame_0);
275   EXPECT_EQ(0U, contents()->infobar_count());
276   // Request permission for two frames.
277   geolocation_permission_context_->RequestGeolocationPermission(
278       process_id(), render_id(), bridge_id(), requesting_frame_0);
279   geolocation_permission_context_->RequestGeolocationPermission(
280       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
281   EXPECT_EQ(1U, contents()->infobar_count());
282 
283   ConfirmInfoBarDelegate* infobar_0 =
284       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
285   ASSERT_TRUE(infobar_0);
286   string16 text_0 = infobar_0->GetMessageText();
287 
288   // Simulate the frame going away, ensure the infobar for this frame
289   // is removed and the next pending infobar is created.
290   geolocation_permission_context_->CancelGeolocationPermissionRequest(
291       process_id(), render_id(), bridge_id(), requesting_frame_0);
292   EXPECT_EQ(infobar_0,
293             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
294   infobar_0->InfoBarClosed();
295   EXPECT_EQ(1U, contents()->infobar_count());
296 
297   ConfirmInfoBarDelegate* infobar_1 =
298       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
299   ASSERT_TRUE(infobar_1);
300   string16 text_1 = infobar_1->GetMessageText();
301   EXPECT_NE(text_0, text_1);
302 
303   // Allow this frame.
304   infobar_1->Accept();
305   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
306   CheckPermissionMessageSent(bridge_id() + 1, true);
307   contents()->RemoveInfoBar(infobar_1);
308   EXPECT_EQ(infobar_1,
309             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
310   infobar_1->InfoBarClosed();
311   EXPECT_EQ(0U, contents()->infobar_count());
312   // Ensure the persisted permissions are ok.
313   EXPECT_EQ(CONTENT_SETTING_ASK,
314       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
315           requesting_frame_0, requesting_frame_0));
316   EXPECT_EQ(CONTENT_SETTING_ALLOW,
317       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
318           requesting_frame_1, requesting_frame_0));
319 }
320 
TEST_F(GeolocationPermissionContextTests,InvalidURL)321 TEST_F(GeolocationPermissionContextTests, InvalidURL) {
322   GURL invalid_embedder;
323   GURL requesting_frame("about:blank");
324   NavigateAndCommit(invalid_embedder);
325   EXPECT_EQ(0U, contents()->infobar_count());
326   geolocation_permission_context_->RequestGeolocationPermission(
327       process_id(), render_id(), bridge_id(), requesting_frame);
328   EXPECT_EQ(0U, contents()->infobar_count());
329   CheckPermissionMessageSent(bridge_id(), false);
330 }
331 
TEST_F(GeolocationPermissionContextTests,SameOriginMultipleTabs)332 TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) {
333   GURL url_a("http://www.example.com/geolocation");
334   GURL url_b("http://www.example-2.com/geolocation");
335   NavigateAndCommit(url_a);
336   AddNewTab(url_b);
337   AddNewTab(url_a);
338 
339   EXPECT_EQ(0U, contents()->infobar_count());
340   geolocation_permission_context_->RequestGeolocationPermission(
341       process_id(), render_id(), bridge_id(), url_a);
342   EXPECT_EQ(1U, contents()->infobar_count());
343 
344   geolocation_permission_context_->RequestGeolocationPermission(
345       process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_b);
346   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
347 
348   geolocation_permission_context_->RequestGeolocationPermission(
349       process_id_for_tab(1), render_id_for_tab(1), bridge_id(), url_a);
350   EXPECT_EQ(1U, extra_tabs_[1]->infobar_count());
351 
352   ConfirmInfoBarDelegate* removed_infobar =
353       extra_tabs_[1]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
354 
355   // Accept the first tab.
356   ConfirmInfoBarDelegate* infobar_0 =
357       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
358   ASSERT_TRUE(infobar_0);
359   infobar_0->Accept();
360   CheckPermissionMessageSent(bridge_id(), true);
361   contents()->RemoveInfoBar(infobar_0);
362   EXPECT_EQ(infobar_0,
363             tab_contents_with_pending_infobar_->removed_infobar_delegate_);
364   infobar_0->InfoBarClosed();
365   // Now the infobar for the tab with the same origin should have gone.
366   EXPECT_EQ(0U, extra_tabs_[1]->infobar_count());
367   CheckPermissionMessageSentForTab(1, bridge_id(), true);
368   // Destroy the infobar that has just been removed.
369   removed_infobar->InfoBarClosed();
370 
371   // But the other tab should still have the info bar...
372   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
373   extra_tabs_.reset();
374 }
375 
TEST_F(GeolocationPermissionContextTests,QueuedOriginMultipleTabs)376 TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) {
377   GURL url_a("http://www.example.com/geolocation");
378   GURL url_b("http://www.example-2.com/geolocation");
379   NavigateAndCommit(url_a);
380   AddNewTab(url_a);
381 
382   EXPECT_EQ(0U, contents()->infobar_count());
383   geolocation_permission_context_->RequestGeolocationPermission(
384       process_id(), render_id(), bridge_id(), url_a);
385   EXPECT_EQ(1U, contents()->infobar_count());
386 
387   geolocation_permission_context_->RequestGeolocationPermission(
388       process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_a);
389   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
390 
391   geolocation_permission_context_->RequestGeolocationPermission(
392       process_id_for_tab(0), render_id_for_tab(0), bridge_id() + 1, url_b);
393   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
394 
395   ConfirmInfoBarDelegate* removed_infobar =
396       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
397 
398   // Accept the second tab.
399   ConfirmInfoBarDelegate* infobar_0 =
400       extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
401   ASSERT_TRUE(infobar_0);
402   infobar_0->Accept();
403   CheckPermissionMessageSentForTab(0, bridge_id(), true);
404   extra_tabs_[0]->RemoveInfoBar(infobar_0);
405   EXPECT_EQ(infobar_0,
406             extra_tabs_[0]->removed_infobar_delegate_);
407   infobar_0->InfoBarClosed();
408   // Now the infobar for the tab with the same origin should have gone.
409   EXPECT_EQ(0U, contents()->infobar_count());
410   CheckPermissionMessageSent(bridge_id(), true);
411   // Destroy the infobar that has just been removed.
412   removed_infobar->InfoBarClosed();
413 
414   // And we should have the queued infobar displayed now.
415   EXPECT_EQ(1U, extra_tabs_[0]->infobar_count());
416 
417   // Accept the second infobar.
418   ConfirmInfoBarDelegate* infobar_1 =
419       extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
420   ASSERT_TRUE(infobar_1);
421   infobar_1->Accept();
422   CheckPermissionMessageSentForTab(0, bridge_id() + 1, true);
423   extra_tabs_[0]->RemoveInfoBar(infobar_1);
424   EXPECT_EQ(infobar_1,
425             extra_tabs_[0]->removed_infobar_delegate_);
426   infobar_1->InfoBarClosed();
427 
428   extra_tabs_.reset();
429 }
430 
TEST_F(GeolocationPermissionContextTests,TabDestroyed)431 TEST_F(GeolocationPermissionContextTests, TabDestroyed) {
432   GURL requesting_frame_0("http://www.example.com/geolocation");
433   GURL requesting_frame_1("http://www.example-2.com/geolocation");
434   EXPECT_EQ(
435       CONTENT_SETTING_ASK,
436       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
437           requesting_frame_0, requesting_frame_0));
438   EXPECT_EQ(
439       CONTENT_SETTING_ASK,
440       profile()->GetGeolocationContentSettingsMap()->GetContentSetting(
441           requesting_frame_1, requesting_frame_0));
442 
443   NavigateAndCommit(requesting_frame_0);
444   EXPECT_EQ(0U, contents()->infobar_count());
445   // Request permission for two frames.
446   geolocation_permission_context_->RequestGeolocationPermission(
447       process_id(), render_id(), bridge_id(), requesting_frame_0);
448   geolocation_permission_context_->RequestGeolocationPermission(
449       process_id(), render_id(), bridge_id() + 1, requesting_frame_1);
450   // Ensure only one infobar is created.
451   EXPECT_EQ(1U, contents()->infobar_count());
452   ConfirmInfoBarDelegate* infobar_0 =
453       contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
454   ASSERT_TRUE(infobar_0);
455   string16 text_0 = infobar_0->GetMessageText();
456 
457   // Delete the tab contents.
458   DeleteContents();
459 }
460