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 43 TestTabContentsWithPendingInfoBar::TestTabContentsWithPendingInfoBar( 44 Profile* profile, 45 SiteInstance* instance) 46 : TestTabContents(profile, instance), 47 removed_infobar_delegate_(NULL) { 48 } 49 50 TestTabContentsWithPendingInfoBar::~TestTabContentsWithPendingInfoBar() { 51 } 52 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 76 int process_id() { return contents()->render_view_host()->process()->id(); } 77 int process_id_for_tab(int tab) { 78 return extra_tabs_[tab]->render_view_host()->process()->id(); 79 } 80 int render_id() { return contents()->render_view_host()->routing_id(); } 81 int render_id_for_tab(int tab) { 82 return extra_tabs_[tab]->render_view_host()->routing_id(); 83 } 84 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 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 117 GeolocationPermissionContextTests::~GeolocationPermissionContextTests() { 118 } 119 120 void GeolocationPermissionContextTests::CheckPermissionMessageSent( 121 int bridge_id, 122 bool allowed) { 123 CheckPermissionMessageSentInternal(process(), bridge_id, allowed); 124 } 125 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 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, ¶m); 145 EXPECT_EQ(bridge_id, param.a); 146 EXPECT_EQ(allowed, param.b); 147 process->sink().ClearMessages(); 148 } 149 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 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 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 187 void GeolocationPermissionContextTests::TearDown() { 188 GeolocationArbitrator::SetDependencyFactoryForTest(NULL); 189 RenderViewHostTestHarness::TearDown(); 190 } 191 192 193 // Tests ---------------------------------------------------------------------- 194 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 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 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 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 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 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 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