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 <string> 6 7 #include "base/compiler_specific.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/content_settings/content_settings_usages_state.h" 13 #include "chrome/browser/content_settings/host_content_settings_map.h" 14 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 15 #include "chrome/browser/infobars/confirm_infobar_delegate.h" 16 #include "chrome/browser/infobars/infobar.h" 17 #include "chrome/browser/infobars/infobar_service.h" 18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser_commands.h" 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" 22 #include "chrome/common/chrome_paths.h" 23 #include "chrome/common/content_settings_pattern.h" 24 #include "chrome/test/base/in_process_browser_test.h" 25 #include "chrome/test/base/ui_test_utils.h" 26 #include "content/public/browser/dom_operation_notification_details.h" 27 #include "content/public/browser/navigation_controller.h" 28 #include "content/public/browser/notification_details.h" 29 #include "content/public/browser/notification_service.h" 30 #include "content/public/browser/render_view_host.h" 31 #include "content/public/browser/web_contents.h" 32 #include "content/public/test/browser_test_utils.h" 33 #include "net/base/net_util.h" 34 #include "net/test/embedded_test_server/embedded_test_server.h" 35 36 using content::DomOperationNotificationDetails; 37 using content::NavigationController; 38 using content::WebContents; 39 40 namespace { 41 42 43 // IFrameLoader --------------------------------------------------------------- 44 45 // Used to block until an iframe is loaded via a javascript call. 46 // Note: NavigateToURLBlockUntilNavigationsComplete doesn't seem to work for 47 // multiple embedded iframes, as notifications seem to be 'batched'. Instead, we 48 // load and wait one single frame here by calling a javascript function. 49 class IFrameLoader : public content::NotificationObserver { 50 public: 51 IFrameLoader(Browser* browser, int iframe_id, const GURL& url); 52 virtual ~IFrameLoader(); 53 54 // content::NotificationObserver: 55 virtual void Observe(int type, 56 const content::NotificationSource& source, 57 const content::NotificationDetails& details) OVERRIDE; 58 59 const GURL& iframe_url() const { return iframe_url_; } 60 61 private: 62 content::NotificationRegistrar registrar_; 63 64 // If true the navigation has completed. 65 bool navigation_completed_; 66 67 // If true the javascript call has completed. 68 bool javascript_completed_; 69 70 std::string javascript_response_; 71 72 // The URL for the iframe we just loaded. 73 GURL iframe_url_; 74 75 DISALLOW_COPY_AND_ASSIGN(IFrameLoader); 76 }; 77 78 IFrameLoader::IFrameLoader(Browser* browser, int iframe_id, const GURL& url) 79 : navigation_completed_(false), 80 javascript_completed_(false) { 81 WebContents* web_contents = 82 browser->tab_strip_model()->GetActiveWebContents(); 83 NavigationController* controller = &web_contents->GetController(); 84 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 85 content::Source<NavigationController>(controller)); 86 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE, 87 content::NotificationService::AllSources()); 88 std::string script(base::StringPrintf( 89 "window.domAutomationController.setAutomationId(0);" 90 "window.domAutomationController.send(addIFrame(%d, \"%s\"));", 91 iframe_id, url.spec().c_str())); 92 web_contents->GetRenderViewHost()->ExecuteJavascriptInWebFrame( 93 string16(), UTF8ToUTF16(script)); 94 content::RunMessageLoop(); 95 96 EXPECT_EQ(base::StringPrintf("\"%d\"", iframe_id), javascript_response_); 97 registrar_.RemoveAll(); 98 // Now that we loaded the iframe, let's fetch its src. 99 script = base::StringPrintf( 100 "window.domAutomationController.send(getIFrameSrc(%d))", iframe_id); 101 std::string iframe_src; 102 EXPECT_TRUE(content::ExecuteScriptAndExtractString(web_contents, script, 103 &iframe_src)); 104 iframe_url_ = GURL(iframe_src); 105 } 106 107 IFrameLoader::~IFrameLoader() { 108 } 109 110 void IFrameLoader::Observe(int type, 111 const content::NotificationSource& source, 112 const content::NotificationDetails& details) { 113 if (type == content::NOTIFICATION_LOAD_STOP) { 114 navigation_completed_ = true; 115 } else if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) { 116 content::Details<DomOperationNotificationDetails> dom_op_details(details); 117 javascript_response_ = dom_op_details->json; 118 javascript_completed_ = true; 119 } 120 if (javascript_completed_ && navigation_completed_) 121 base::MessageLoopForUI::current()->Quit(); 122 } 123 124 125 // GeolocationNotificationObserver -------------------------------------------- 126 127 class GeolocationNotificationObserver : public content::NotificationObserver { 128 public: 129 // If |wait_for_infobar| is true, AddWatchAndWaitForNotification will block 130 // until the infobar has been displayed; otherwise it will block until the 131 // navigation is completed. 132 explicit GeolocationNotificationObserver(bool wait_for_infobar); 133 virtual ~GeolocationNotificationObserver(); 134 135 // content::NotificationObserver: 136 virtual void Observe(int type, 137 const content::NotificationSource& source, 138 const content::NotificationDetails& details) OVERRIDE; 139 140 void AddWatchAndWaitForNotification(content::RenderViewHost* render_view_host, 141 const std::string& iframe_xpath); 142 143 bool has_infobar() const { return !!infobar_; } 144 InfoBarDelegate* infobar() { return infobar_; } 145 146 private: 147 content::NotificationRegistrar registrar_; 148 bool wait_for_infobar_; 149 InfoBarDelegate* infobar_; 150 bool navigation_started_; 151 bool navigation_completed_; 152 std::string javascript_response_; 153 154 DISALLOW_COPY_AND_ASSIGN(GeolocationNotificationObserver); 155 }; 156 157 GeolocationNotificationObserver::GeolocationNotificationObserver( 158 bool wait_for_infobar) 159 : wait_for_infobar_(wait_for_infobar), 160 infobar_(NULL), 161 navigation_started_(false), 162 navigation_completed_(false) { 163 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE, 164 content::NotificationService::AllSources()); 165 if (wait_for_infobar) { 166 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, 167 content::NotificationService::AllSources()); 168 } else { 169 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 170 content::NotificationService::AllSources()); 171 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 172 content::NotificationService::AllSources()); 173 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 174 content::NotificationService::AllSources()); 175 } 176 } 177 178 GeolocationNotificationObserver::~GeolocationNotificationObserver() { 179 } 180 181 void GeolocationNotificationObserver::Observe( 182 int type, 183 const content::NotificationSource& source, 184 const content::NotificationDetails& details) { 185 if (type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED) { 186 infobar_ = content::Details<InfoBarAddedDetails>(details).ptr(); 187 ASSERT_FALSE(infobar_->GetIcon().IsEmpty()); 188 ASSERT_TRUE(infobar_->AsConfirmInfoBarDelegate()); 189 } else if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) { 190 content::Details<DomOperationNotificationDetails> dom_op_details(details); 191 javascript_response_ = dom_op_details->json; 192 LOG(WARNING) << "javascript_response " << javascript_response_; 193 } else if ((type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) || 194 (type == content::NOTIFICATION_LOAD_START)) { 195 navigation_started_ = true; 196 } else if ((type == content::NOTIFICATION_LOAD_STOP) && navigation_started_) { 197 navigation_started_ = false; 198 navigation_completed_ = true; 199 } 200 201 // We're either waiting for just the inforbar, or for both a javascript 202 // prompt and response. 203 if ((wait_for_infobar_ && infobar_) || 204 (navigation_completed_ && !javascript_response_.empty())) 205 base::MessageLoopForUI::current()->Quit(); 206 } 207 208 void GeolocationNotificationObserver::AddWatchAndWaitForNotification( 209 content::RenderViewHost* render_view_host, 210 const std::string& iframe_xpath) { 211 LOG(WARNING) << "will add geolocation watch"; 212 std::string script( 213 "window.domAutomationController.setAutomationId(0);" 214 "window.domAutomationController.send(geoStart());"); 215 render_view_host->ExecuteJavascriptInWebFrame(UTF8ToUTF16(iframe_xpath), 216 UTF8ToUTF16(script)); 217 content::RunMessageLoop(); 218 registrar_.RemoveAll(); 219 LOG(WARNING) << "got geolocation watch" << javascript_response_; 220 EXPECT_NE("\"0\"", javascript_response_); 221 EXPECT_TRUE(wait_for_infobar_ ? (infobar_ != NULL) : navigation_completed_); 222 } 223 224 } // namespace 225 226 227 // GeolocationBrowserTest ----------------------------------------------------- 228 229 // This is a browser test for Geolocation. 230 // It exercises various integration points from javascript <-> browser: 231 // 1. Infobar is displayed when a geolocation is requested from an unauthorized 232 // origin. 233 // 2. Denying the infobar triggers the correct error callback. 234 // 3. Allowing the infobar does not trigger an error, and allow a geoposition to 235 // be passed to javascript. 236 // 4. Permissions persisted in disk are respected. 237 // 5. Incognito profiles don't use saved permissions. 238 class GeolocationBrowserTest : public InProcessBrowserTest { 239 public: 240 enum InitializationOptions { 241 INITIALIZATION_NONE, 242 INITIALIZATION_OFFTHERECORD, 243 INITIALIZATION_NEWTAB, 244 INITIALIZATION_IFRAMES, 245 }; 246 247 GeolocationBrowserTest(); 248 virtual ~GeolocationBrowserTest(); 249 250 // InProcessBrowserTest: 251 virtual void SetUpOnMainThread() OVERRIDE; 252 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE; 253 254 Browser* current_browser() { return current_browser_; } 255 void set_html_for_tests(const std::string& html_for_tests) { 256 html_for_tests_ = html_for_tests; 257 } 258 const std::string& iframe_xpath() const { return iframe_xpath_; } 259 void set_iframe_xpath(const std::string& iframe_xpath) { 260 iframe_xpath_ = iframe_xpath; 261 } 262 const GURL& current_url() const { return current_url_; } 263 const GURL& iframe_url(size_t i) const { return iframe_urls_[i]; } 264 double fake_latitude() const { return fake_latitude_; } 265 double fake_longitude() const { return fake_longitude_; } 266 267 bool Initialize(InitializationOptions options) WARN_UNUSED_RESULT; 268 void LoadIFrames(int number_iframes); 269 void AddGeolocationWatch(bool wait_for_infobar); 270 void CheckGeoposition(double latitude, double longitude); 271 void SetInfoBarResponse(const GURL& requesting_url, bool allowed); 272 void CheckStringValueFromJavascriptForTab(const std::string& expected, 273 const std::string& function, 274 WebContents* web_contents); 275 void CheckStringValueFromJavascript(const std::string& expected, 276 const std::string& function); 277 void NotifyGeoposition(double latitude, double longitude); 278 279 private: 280 InfoBarDelegate* infobar_; 281 Browser* current_browser_; 282 // path element of a URL referencing the html content for this test. 283 std::string html_for_tests_; 284 // This member defines the iframe (or top-level page, if empty) where the 285 // javascript calls will run. 286 std::string iframe_xpath_; 287 // The current url for the top level page. 288 GURL current_url_; 289 // If not empty, the GURLs for the iframes loaded by LoadIFrames(). 290 std::vector<GURL> iframe_urls_; 291 double fake_latitude_; 292 double fake_longitude_; 293 294 DISALLOW_COPY_AND_ASSIGN(GeolocationBrowserTest); 295 }; 296 297 GeolocationBrowserTest::GeolocationBrowserTest() 298 : infobar_(NULL), 299 current_browser_(NULL), 300 html_for_tests_("/geolocation/simple.html"), 301 fake_latitude_(1.23), 302 fake_longitude_(4.56) { 303 } 304 305 GeolocationBrowserTest::~GeolocationBrowserTest() { 306 } 307 308 void GeolocationBrowserTest::SetUpOnMainThread() { 309 ui_test_utils::OverrideGeolocation(fake_latitude_, fake_longitude_); 310 } 311 312 void GeolocationBrowserTest::TearDownInProcessBrowserTestFixture() { 313 LOG(WARNING) << "TearDownInProcessBrowserTestFixture. Test Finished."; 314 } 315 316 bool GeolocationBrowserTest::Initialize(InitializationOptions options) { 317 if (!embedded_test_server()->Started() && 318 !embedded_test_server()->InitializeAndWaitUntilReady()) { 319 ADD_FAILURE() << "Test server failed to start."; 320 return false; 321 } 322 323 current_url_ = embedded_test_server()->GetURL(html_for_tests_); 324 LOG(WARNING) << "before navigate"; 325 if (options == INITIALIZATION_OFFTHERECORD) { 326 current_browser_ = ui_test_utils::OpenURLOffTheRecord( 327 browser()->profile(), current_url_); 328 } else { 329 current_browser_ = browser(); 330 if (options == INITIALIZATION_NEWTAB) 331 chrome::NewTab(current_browser_); 332 ui_test_utils::NavigateToURL(current_browser_, current_url_); 333 } 334 LOG(WARNING) << "after navigate"; 335 336 EXPECT_TRUE(current_browser_); 337 return !!current_browser_; 338 } 339 340 void GeolocationBrowserTest::LoadIFrames(int number_iframes) { 341 // Limit to 3 iframes. 342 DCHECK_LT(0, number_iframes); 343 DCHECK_LE(number_iframes, 3); 344 iframe_urls_.resize(number_iframes); 345 for (int i = 0; i < number_iframes; ++i) { 346 IFrameLoader loader(current_browser_, i, GURL()); 347 iframe_urls_[i] = loader.iframe_url(); 348 } 349 } 350 351 void GeolocationBrowserTest::AddGeolocationWatch(bool wait_for_infobar) { 352 GeolocationNotificationObserver notification_observer(wait_for_infobar); 353 notification_observer.AddWatchAndWaitForNotification( 354 current_browser_->tab_strip_model()->GetActiveWebContents()-> 355 GetRenderViewHost(), 356 iframe_xpath()); 357 if (wait_for_infobar) { 358 EXPECT_TRUE(notification_observer.has_infobar()); 359 infobar_ = notification_observer.infobar(); 360 } 361 } 362 363 void GeolocationBrowserTest::CheckGeoposition(double latitude, 364 double longitude) { 365 // Checks we have no error. 366 CheckStringValueFromJavascript("0", "geoGetLastError()"); 367 CheckStringValueFromJavascript(base::DoubleToString(latitude), 368 "geoGetLastPositionLatitude()"); 369 CheckStringValueFromJavascript(base::DoubleToString(longitude), 370 "geoGetLastPositionLongitude()"); 371 } 372 373 void GeolocationBrowserTest::SetInfoBarResponse(const GURL& requesting_url, 374 bool allowed) { 375 WebContents* web_contents = 376 current_browser_->tab_strip_model()->GetActiveWebContents(); 377 TabSpecificContentSettings* content_settings = 378 TabSpecificContentSettings::FromWebContents(web_contents); 379 const ContentSettingsUsagesState& usages_state = 380 content_settings->geolocation_usages_state(); 381 size_t state_map_size = usages_state.state_map().size(); 382 ASSERT_TRUE(infobar_); 383 LOG(WARNING) << "will set infobar response"; 384 { 385 content::WindowedNotificationObserver observer( 386 content::NOTIFICATION_LOAD_STOP, 387 content::Source<NavigationController>(&web_contents->GetController())); 388 if (allowed) 389 infobar_->AsConfirmInfoBarDelegate()->Accept(); 390 else 391 infobar_->AsConfirmInfoBarDelegate()->Cancel(); 392 observer.Wait(); 393 } 394 395 InfoBarService::FromWebContents(web_contents)->RemoveInfoBar(infobar_); 396 LOG(WARNING) << "infobar response set"; 397 infobar_ = NULL; 398 EXPECT_GT(usages_state.state_map().size(), state_map_size); 399 GURL requesting_origin(requesting_url.GetOrigin()); 400 EXPECT_EQ(1U, usages_state.state_map().count(requesting_origin)); 401 ContentSetting expected_setting = 402 allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; 403 EXPECT_EQ(expected_setting, 404 usages_state.state_map().find(requesting_origin)->second); 405 } 406 407 void GeolocationBrowserTest::CheckStringValueFromJavascriptForTab( 408 const std::string& expected, 409 const std::string& function, 410 WebContents* web_contents) { 411 std::string script(base::StringPrintf( 412 "window.domAutomationController.send(%s)", function.c_str())); 413 std::string result; 414 ASSERT_TRUE(content::ExecuteScriptInFrameAndExtractString( 415 web_contents, iframe_xpath_, script, &result)); 416 EXPECT_EQ(expected, result); 417 } 418 419 void GeolocationBrowserTest::CheckStringValueFromJavascript( 420 const std::string& expected, 421 const std::string& function) { 422 CheckStringValueFromJavascriptForTab( 423 expected, function, 424 current_browser_->tab_strip_model()->GetActiveWebContents()); 425 } 426 427 void GeolocationBrowserTest::NotifyGeoposition(double latitude, 428 double longitude) { 429 fake_latitude_ = latitude; 430 fake_longitude_ = longitude; 431 ui_test_utils::OverrideGeolocation(latitude, longitude); 432 LOG(WARNING) << "MockLocationProvider listeners updated"; 433 } 434 435 436 // Tests ---------------------------------------------------------------------- 437 438 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DisplaysPermissionBar) { 439 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 440 AddGeolocationWatch(true); 441 } 442 443 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, Geoposition) { 444 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 445 AddGeolocationWatch(true); 446 SetInfoBarResponse(current_url(), true); 447 CheckGeoposition(fake_latitude(), fake_longitude()); 448 } 449 450 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, 451 ErrorOnPermissionDenied) { 452 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 453 AddGeolocationWatch(true); 454 // Infobar was displayed, deny access and check for error code. 455 SetInfoBarResponse(current_url(), false); 456 CheckStringValueFromJavascript("1", "geoGetLastError()"); 457 } 458 459 // http://crbug.com/44589. Hangs on Mac, crashes on Windows 460 #if defined(OS_MACOSX) || defined(OS_WIN) 461 #define MAYBE_NoInfobarForSecondTab DISABLED_NoInfobarForSecondTab 462 #else 463 #define MAYBE_NoInfobarForSecondTab NoInfobarForSecondTab 464 #endif 465 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForSecondTab) { 466 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 467 AddGeolocationWatch(true); 468 SetInfoBarResponse(current_url(), true); 469 // Disables further prompts from this tab. 470 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 471 472 // Checks infobar will not be created a second tab. 473 ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB)); 474 AddGeolocationWatch(false); 475 CheckGeoposition(fake_latitude(), fake_longitude()); 476 } 477 478 // http://crbug.com/44589. Hangs on Mac, crashes on Windows 479 #if defined(OS_MACOSX) || defined(OS_WIN) 480 #define MAYBE_NoInfobarForDeniedOrigin DISABLED_NoInfobarForDeniedOrigin 481 #else 482 #define MAYBE_NoInfobarForDeniedOrigin NoInfobarForDeniedOrigin 483 #endif 484 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForDeniedOrigin) { 485 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 486 current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( 487 ContentSettingsPattern::FromURLNoWildcard(current_url()), 488 ContentSettingsPattern::FromURLNoWildcard(current_url()), 489 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_BLOCK); 490 AddGeolocationWatch(false); 491 // Checks we have an error for this denied origin. 492 CheckStringValueFromJavascript("1", "geoGetLastError()"); 493 // Checks infobar will not be created a second tab. 494 ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB)); 495 AddGeolocationWatch(false); 496 CheckStringValueFromJavascript("1", "geoGetLastError()"); 497 } 498 499 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForAllowedOrigin) { 500 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 501 current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( 502 ContentSettingsPattern::FromURLNoWildcard(current_url()), 503 ContentSettingsPattern::FromURLNoWildcard(current_url()), 504 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_ALLOW); 505 // Checks no infobar will be created and there's no error callback. 506 AddGeolocationWatch(false); 507 CheckGeoposition(fake_latitude(), fake_longitude()); 508 } 509 510 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForOffTheRecord) { 511 // First, check infobar will be created for regular profile 512 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 513 AddGeolocationWatch(true); 514 // Response will be persisted 515 SetInfoBarResponse(current_url(), true); 516 CheckGeoposition(fake_latitude(), fake_longitude()); 517 // Disables further prompts from this tab. 518 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 519 // Go incognito, and checks no infobar will be created. 520 ASSERT_TRUE(Initialize(INITIALIZATION_OFFTHERECORD)); 521 AddGeolocationWatch(false); 522 CheckGeoposition(fake_latitude(), fake_longitude()); 523 } 524 525 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoLeakFromOffTheRecord) { 526 // First, check infobar will be created for incognito profile. 527 ASSERT_TRUE(Initialize(INITIALIZATION_OFFTHERECORD)); 528 AddGeolocationWatch(true); 529 // Response won't be persisted. 530 SetInfoBarResponse(current_url(), true); 531 CheckGeoposition(fake_latitude(), fake_longitude()); 532 // Disables further prompts from this tab. 533 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 534 // Go to the regular profile, infobar will be created. 535 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 536 AddGeolocationWatch(true); 537 SetInfoBarResponse(current_url(), false); 538 CheckStringValueFromJavascript("1", "geoGetLastError()"); 539 } 540 541 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithFreshPosition) { 542 set_html_for_tests("/geolocation/iframes_different_origin.html"); 543 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 544 LoadIFrames(2); 545 LOG(WARNING) << "frames loaded"; 546 547 set_iframe_xpath("//iframe[@id='iframe_0']"); 548 AddGeolocationWatch(true); 549 SetInfoBarResponse(iframe_url(0), true); 550 CheckGeoposition(fake_latitude(), fake_longitude()); 551 // Disables further prompts from this iframe. 552 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 553 554 // Test second iframe from a different origin with a cached geoposition will 555 // create the infobar. 556 set_iframe_xpath("//iframe[@id='iframe_1']"); 557 AddGeolocationWatch(true); 558 559 // Back to the first frame, enable navigation and refresh geoposition. 560 set_iframe_xpath("//iframe[@id='iframe_0']"); 561 CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)"); 562 double fresh_position_latitude = 3.17; 563 double fresh_position_longitude = 4.23; 564 content::WindowedNotificationObserver observer( 565 content::NOTIFICATION_LOAD_STOP, 566 content::Source<NavigationController>( 567 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 568 GetController())); 569 NotifyGeoposition(fresh_position_latitude, fresh_position_longitude); 570 observer.Wait(); 571 CheckGeoposition(fresh_position_latitude, fresh_position_longitude); 572 573 // Disable navigation for this frame. 574 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 575 576 // Now go ahead an authorize the second frame. 577 set_iframe_xpath("//iframe[@id='iframe_1']"); 578 // Infobar was displayed, allow access and check there's no error code. 579 SetInfoBarResponse(iframe_url(1), true); 580 LOG(WARNING) << "Checking position..."; 581 CheckGeoposition(fresh_position_latitude, fresh_position_longitude); 582 LOG(WARNING) << "...done."; 583 } 584 585 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, 586 IFramesWithCachedPosition) { 587 set_html_for_tests("/geolocation/iframes_different_origin.html"); 588 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 589 LoadIFrames(2); 590 591 set_iframe_xpath("//iframe[@id='iframe_0']"); 592 AddGeolocationWatch(true); 593 SetInfoBarResponse(iframe_url(0), true); 594 CheckGeoposition(fake_latitude(), fake_longitude()); 595 596 // Refresh geoposition, but let's not yet create the watch on the second frame 597 // so that it'll fetch from cache. 598 double cached_position_latitude = 5.67; 599 double cached_position_lognitude = 8.09; 600 content::WindowedNotificationObserver observer( 601 content::NOTIFICATION_LOAD_STOP, 602 content::Source<NavigationController>( 603 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 604 GetController())); 605 NotifyGeoposition(cached_position_latitude, cached_position_lognitude); 606 observer.Wait(); 607 CheckGeoposition(cached_position_latitude, cached_position_lognitude); 608 609 // Disable navigation for this frame. 610 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 611 612 // Now go ahead an authorize the second frame. 613 set_iframe_xpath("//iframe[@id='iframe_1']"); 614 AddGeolocationWatch(true); 615 // WebKit will use its cache, but we also broadcast a position shortly 616 // afterwards. We're only interested in the first navigation for the success 617 // callback from the cached position. 618 CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)"); 619 SetInfoBarResponse(iframe_url(1), true); 620 CheckGeoposition(cached_position_latitude, cached_position_lognitude); 621 } 622 623 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, CancelPermissionForFrame) { 624 set_html_for_tests("/geolocation/iframes_different_origin.html"); 625 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 626 LoadIFrames(2); 627 LOG(WARNING) << "frames loaded"; 628 629 set_iframe_xpath("//iframe[@id='iframe_0']"); 630 AddGeolocationWatch(true); 631 SetInfoBarResponse(iframe_url(0), true); 632 CheckGeoposition(fake_latitude(), fake_longitude()); 633 // Disables further prompts from this iframe. 634 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 635 636 // Test second iframe from a different origin with a cached geoposition will 637 // create the infobar. 638 set_iframe_xpath("//iframe[@id='iframe_1']"); 639 AddGeolocationWatch(true); 640 641 InfoBarService* infobar_service = InfoBarService::FromWebContents( 642 current_browser()->tab_strip_model()->GetActiveWebContents()); 643 size_t num_infobars_before_cancel = infobar_service->infobar_count(); 644 // Change the iframe, and ensure the infobar is gone. 645 IFrameLoader change_iframe_1(current_browser(), 1, current_url()); 646 size_t num_infobars_after_cancel = infobar_service->infobar_count(); 647 EXPECT_EQ(num_infobars_before_cancel, num_infobars_after_cancel + 1); 648 } 649 650 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) { 651 // Tests that an invalid URL (e.g. from a popup window) is rejected 652 // correctly. Also acts as a regression test for http://crbug.com/40478 653 set_html_for_tests("/geolocation/invalid_request_url.html"); 654 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 655 WebContents* original_tab = 656 current_browser()->tab_strip_model()->GetActiveWebContents(); 657 CheckStringValueFromJavascript("1", "requestGeolocationFromInvalidUrl()"); 658 CheckStringValueFromJavascriptForTab("1", "isAlive()", original_tab); 659 } 660 661 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfoBarBeforeStart) { 662 // See http://crbug.com/42789 663 set_html_for_tests("/geolocation/iframes_different_origin.html"); 664 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 665 LoadIFrames(2); 666 LOG(WARNING) << "frames loaded"; 667 668 // Access navigator.geolocation, but ensure it won't request permission. 669 set_iframe_xpath("//iframe[@id='iframe_1']"); 670 CheckStringValueFromJavascript("object", "geoAccessNavigatorGeolocation()"); 671 672 set_iframe_xpath("//iframe[@id='iframe_0']"); 673 AddGeolocationWatch(true); 674 SetInfoBarResponse(iframe_url(0), true); 675 CheckGeoposition(fake_latitude(), fake_longitude()); 676 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 677 678 // Permission should be requested after adding a watch. 679 set_iframe_xpath("//iframe[@id='iframe_1']"); 680 AddGeolocationWatch(true); 681 SetInfoBarResponse(iframe_url(1), true); 682 CheckGeoposition(fake_latitude(), fake_longitude()); 683 } 684 685 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TwoWatchesInOneFrame) { 686 set_html_for_tests("/geolocation/two_watches.html"); 687 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 688 // First, set the JavaScript to navigate when it receives |final_position|. 689 double final_position_latitude = 3.17; 690 double final_position_longitude = 4.23; 691 std::string script = base::StringPrintf( 692 "window.domAutomationController.send(geoSetFinalPosition(%f, %f))", 693 final_position_latitude, final_position_longitude); 694 std::string js_result; 695 EXPECT_TRUE(content::ExecuteScriptAndExtractString( 696 current_browser()->tab_strip_model()->GetActiveWebContents(), script, 697 &js_result)); 698 EXPECT_EQ(js_result, "ok"); 699 700 // Send a position which both geolocation watches will receive. 701 AddGeolocationWatch(true); 702 SetInfoBarResponse(current_url(), true); 703 CheckGeoposition(fake_latitude(), fake_longitude()); 704 705 // The second watch will now have cancelled. Ensure an update still makes 706 // its way through to the first watcher. 707 content::WindowedNotificationObserver observer( 708 content::NOTIFICATION_LOAD_STOP, 709 content::Source<NavigationController>( 710 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 711 GetController())); 712 NotifyGeoposition(final_position_latitude, final_position_longitude); 713 observer.Wait(); 714 CheckGeoposition(final_position_latitude, final_position_longitude); 715 } 716 717 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TabDestroyed) { 718 set_html_for_tests("/geolocation/tab_destroyed.html"); 719 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 720 LoadIFrames(3); 721 722 set_iframe_xpath("//iframe[@id='iframe_0']"); 723 AddGeolocationWatch(true); 724 725 set_iframe_xpath("//iframe[@id='iframe_1']"); 726 AddGeolocationWatch(false); 727 728 set_iframe_xpath("//iframe[@id='iframe_2']"); 729 AddGeolocationWatch(false); 730 731 std::string script = 732 "window.domAutomationController.send(window.close());"; 733 bool result = content::ExecuteScript( 734 current_browser()->tab_strip_model()->GetActiveWebContents(), script); 735 EXPECT_EQ(result, true); 736 } 737