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 base::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 InfoBar* infobar() { return infobar_; } 145 146 private: 147 content::NotificationRegistrar registrar_; 148 bool wait_for_infobar_; 149 InfoBar* 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<InfoBar::AddedDetails>(details).ptr(); 187 ASSERT_FALSE(infobar_->delegate()->GetIcon().IsEmpty()); 188 ASSERT_TRUE(infobar_->delegate()->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 infobar, 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 // Initializes the test server and navigates to the initial url. 268 bool Initialize(InitializationOptions options) WARN_UNUSED_RESULT; 269 270 // Loads the specified number of iframes. 271 void LoadIFrames(int number_iframes); 272 273 // Start watching for geolocation notifications. If |wait_for_infobar| is 274 // true, wait for the infobar to be displayed. Otherwise wait for a javascript 275 // response. 276 void AddGeolocationWatch(bool wait_for_infobar); 277 278 // Checks that no errors have been received in javascript, and checks that the 279 // position most recently received in javascript matches |latitude| and 280 // |longitude|. 281 void CheckGeoposition(double latitude, double longitude); 282 283 // For |requesting_url| if |allowed| is true accept the infobar. Otherwise 284 // cancel it. 285 void SetInfoBarResponse(const GURL& requesting_url, bool allowed); 286 287 // Executes |function| in |web_contents| and checks that the return value 288 // matches |expected|. 289 void CheckStringValueFromJavascriptForTab(const std::string& expected, 290 const std::string& function, 291 WebContents* web_contents); 292 293 // Executes |function| and checks that the return value matches |expected|. 294 void CheckStringValueFromJavascript(const std::string& expected, 295 const std::string& function); 296 297 // Sets a new position and sends a notification with the new position. 298 void NotifyGeoposition(double latitude, double longitude); 299 300 private: 301 InfoBar* infobar_; 302 Browser* current_browser_; 303 // path element of a URL referencing the html content for this test. 304 std::string html_for_tests_; 305 // This member defines the iframe (or top-level page, if empty) where the 306 // javascript calls will run. 307 std::string iframe_xpath_; 308 // The current url for the top level page. 309 GURL current_url_; 310 // If not empty, the GURLs for the iframes loaded by LoadIFrames(). 311 std::vector<GURL> iframe_urls_; 312 double fake_latitude_; 313 double fake_longitude_; 314 315 DISALLOW_COPY_AND_ASSIGN(GeolocationBrowserTest); 316 }; 317 318 GeolocationBrowserTest::GeolocationBrowserTest() 319 : infobar_(NULL), 320 current_browser_(NULL), 321 html_for_tests_("/geolocation/simple.html"), 322 fake_latitude_(1.23), 323 fake_longitude_(4.56) { 324 } 325 326 GeolocationBrowserTest::~GeolocationBrowserTest() { 327 } 328 329 void GeolocationBrowserTest::SetUpOnMainThread() { 330 ui_test_utils::OverrideGeolocation(fake_latitude_, fake_longitude_); 331 } 332 333 void GeolocationBrowserTest::TearDownInProcessBrowserTestFixture() { 334 LOG(WARNING) << "TearDownInProcessBrowserTestFixture. Test Finished."; 335 } 336 337 bool GeolocationBrowserTest::Initialize(InitializationOptions options) { 338 if (!embedded_test_server()->Started() && 339 !embedded_test_server()->InitializeAndWaitUntilReady()) { 340 ADD_FAILURE() << "Test server failed to start."; 341 return false; 342 } 343 344 current_url_ = embedded_test_server()->GetURL(html_for_tests_); 345 LOG(WARNING) << "before navigate"; 346 if (options == INITIALIZATION_OFFTHERECORD) { 347 current_browser_ = ui_test_utils::OpenURLOffTheRecord( 348 browser()->profile(), current_url_); 349 } else { 350 current_browser_ = browser(); 351 if (options == INITIALIZATION_NEWTAB) 352 chrome::NewTab(current_browser_); 353 ui_test_utils::NavigateToURL(current_browser_, current_url_); 354 } 355 LOG(WARNING) << "after navigate"; 356 357 EXPECT_TRUE(current_browser_); 358 return !!current_browser_; 359 } 360 361 void GeolocationBrowserTest::LoadIFrames(int number_iframes) { 362 // Limit to 3 iframes. 363 DCHECK_LT(0, number_iframes); 364 DCHECK_LE(number_iframes, 3); 365 iframe_urls_.resize(number_iframes); 366 for (int i = 0; i < number_iframes; ++i) { 367 IFrameLoader loader(current_browser_, i, GURL()); 368 iframe_urls_[i] = loader.iframe_url(); 369 } 370 } 371 372 void GeolocationBrowserTest::AddGeolocationWatch(bool wait_for_infobar) { 373 GeolocationNotificationObserver notification_observer(wait_for_infobar); 374 notification_observer.AddWatchAndWaitForNotification( 375 current_browser_->tab_strip_model()->GetActiveWebContents()-> 376 GetRenderViewHost(), 377 iframe_xpath()); 378 if (wait_for_infobar) { 379 EXPECT_TRUE(notification_observer.has_infobar()); 380 infobar_ = notification_observer.infobar(); 381 } 382 } 383 384 void GeolocationBrowserTest::CheckGeoposition(double latitude, 385 double longitude) { 386 // Checks we have no error. 387 CheckStringValueFromJavascript("0", "geoGetLastError()"); 388 CheckStringValueFromJavascript(base::DoubleToString(latitude), 389 "geoGetLastPositionLatitude()"); 390 CheckStringValueFromJavascript(base::DoubleToString(longitude), 391 "geoGetLastPositionLongitude()"); 392 } 393 394 void GeolocationBrowserTest::SetInfoBarResponse(const GURL& requesting_url, 395 bool allowed) { 396 WebContents* web_contents = 397 current_browser_->tab_strip_model()->GetActiveWebContents(); 398 TabSpecificContentSettings* content_settings = 399 TabSpecificContentSettings::FromWebContents(web_contents); 400 const ContentSettingsUsagesState& usages_state = 401 content_settings->geolocation_usages_state(); 402 size_t state_map_size = usages_state.state_map().size(); 403 ASSERT_TRUE(infobar_); 404 LOG(WARNING) << "will set infobar response"; 405 { 406 content::WindowedNotificationObserver observer( 407 content::NOTIFICATION_LOAD_STOP, 408 content::Source<NavigationController>(&web_contents->GetController())); 409 if (allowed) 410 infobar_->delegate()->AsConfirmInfoBarDelegate()->Accept(); 411 else 412 infobar_->delegate()->AsConfirmInfoBarDelegate()->Cancel(); 413 observer.Wait(); 414 } 415 416 InfoBarService::FromWebContents(web_contents)->RemoveInfoBar(infobar_); 417 LOG(WARNING) << "infobar response set"; 418 infobar_ = NULL; 419 EXPECT_GT(usages_state.state_map().size(), state_map_size); 420 GURL requesting_origin(requesting_url.GetOrigin()); 421 EXPECT_EQ(1U, usages_state.state_map().count(requesting_origin)); 422 ContentSetting expected_setting = 423 allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; 424 EXPECT_EQ(expected_setting, 425 usages_state.state_map().find(requesting_origin)->second); 426 } 427 428 void GeolocationBrowserTest::CheckStringValueFromJavascriptForTab( 429 const std::string& expected, 430 const std::string& function, 431 WebContents* web_contents) { 432 std::string script(base::StringPrintf( 433 "window.domAutomationController.send(%s)", function.c_str())); 434 std::string result; 435 ASSERT_TRUE(content::ExecuteScriptInFrameAndExtractString( 436 web_contents, iframe_xpath_, script, &result)); 437 EXPECT_EQ(expected, result); 438 } 439 440 void GeolocationBrowserTest::CheckStringValueFromJavascript( 441 const std::string& expected, 442 const std::string& function) { 443 CheckStringValueFromJavascriptForTab( 444 expected, function, 445 current_browser_->tab_strip_model()->GetActiveWebContents()); 446 } 447 448 void GeolocationBrowserTest::NotifyGeoposition(double latitude, 449 double longitude) { 450 fake_latitude_ = latitude; 451 fake_longitude_ = longitude; 452 ui_test_utils::OverrideGeolocation(latitude, longitude); 453 LOG(WARNING) << "MockLocationProvider listeners updated"; 454 } 455 456 457 // Tests ---------------------------------------------------------------------- 458 459 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DisplaysPermissionBar) { 460 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 461 AddGeolocationWatch(true); 462 } 463 464 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, Geoposition) { 465 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 466 AddGeolocationWatch(true); 467 SetInfoBarResponse(current_url(), true); 468 CheckGeoposition(fake_latitude(), fake_longitude()); 469 } 470 471 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, 472 ErrorOnPermissionDenied) { 473 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 474 AddGeolocationWatch(true); 475 // Infobar was displayed, deny access and check for error code. 476 SetInfoBarResponse(current_url(), false); 477 CheckStringValueFromJavascript("1", "geoGetLastError()"); 478 } 479 480 // See http://crbug.com/308358 481 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfobarForSecondTab) { 482 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 483 AddGeolocationWatch(true); 484 SetInfoBarResponse(current_url(), true); 485 // Disables further prompts from this tab. 486 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 487 488 // Checks infobar will not be created a second tab. 489 ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB)); 490 AddGeolocationWatch(false); 491 CheckGeoposition(fake_latitude(), fake_longitude()); 492 } 493 494 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForDeniedOrigin) { 495 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 496 current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( 497 ContentSettingsPattern::FromURLNoWildcard(current_url()), 498 ContentSettingsPattern::FromURLNoWildcard(current_url()), 499 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_BLOCK); 500 AddGeolocationWatch(false); 501 // Checks we have an error for this denied origin. 502 CheckStringValueFromJavascript("1", "geoGetLastError()"); 503 // Checks infobar will not be created a second tab. 504 ASSERT_TRUE(Initialize(INITIALIZATION_NEWTAB)); 505 AddGeolocationWatch(false); 506 CheckStringValueFromJavascript("1", "geoGetLastError()"); 507 } 508 509 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForAllowedOrigin) { 510 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 511 current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting( 512 ContentSettingsPattern::FromURLNoWildcard(current_url()), 513 ContentSettingsPattern::FromURLNoWildcard(current_url()), 514 CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_ALLOW); 515 // Checks no infobar will be created and there's no error callback. 516 AddGeolocationWatch(false); 517 CheckGeoposition(fake_latitude(), fake_longitude()); 518 } 519 520 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForOffTheRecord) { 521 // First, check infobar will be created for regular profile 522 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 523 AddGeolocationWatch(true); 524 // Response will be persisted 525 SetInfoBarResponse(current_url(), true); 526 CheckGeoposition(fake_latitude(), fake_longitude()); 527 // Disables further prompts from this tab. 528 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 529 // Go incognito, and checks no infobar will be created. 530 ASSERT_TRUE(Initialize(INITIALIZATION_OFFTHERECORD)); 531 AddGeolocationWatch(false); 532 CheckGeoposition(fake_latitude(), fake_longitude()); 533 } 534 535 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoLeakFromOffTheRecord) { 536 // First, check infobar will be created for incognito profile. 537 ASSERT_TRUE(Initialize(INITIALIZATION_OFFTHERECORD)); 538 AddGeolocationWatch(true); 539 // Response won't be persisted. 540 SetInfoBarResponse(current_url(), true); 541 CheckGeoposition(fake_latitude(), fake_longitude()); 542 // Disables further prompts from this tab. 543 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 544 // Go to the regular profile, infobar will be created. 545 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 546 AddGeolocationWatch(true); 547 SetInfoBarResponse(current_url(), false); 548 CheckStringValueFromJavascript("1", "geoGetLastError()"); 549 } 550 551 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithFreshPosition) { 552 set_html_for_tests("/geolocation/iframes_different_origin.html"); 553 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 554 LoadIFrames(2); 555 LOG(WARNING) << "frames loaded"; 556 557 set_iframe_xpath("//iframe[@id='iframe_0']"); 558 AddGeolocationWatch(true); 559 SetInfoBarResponse(iframe_url(0), true); 560 CheckGeoposition(fake_latitude(), fake_longitude()); 561 // Disables further prompts from this iframe. 562 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 563 564 // Test second iframe from a different origin with a cached geoposition will 565 // create the infobar. 566 set_iframe_xpath("//iframe[@id='iframe_1']"); 567 AddGeolocationWatch(true); 568 569 // Back to the first frame, enable navigation and refresh geoposition. 570 set_iframe_xpath("//iframe[@id='iframe_0']"); 571 CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)"); 572 double fresh_position_latitude = 3.17; 573 double fresh_position_longitude = 4.23; 574 content::WindowedNotificationObserver observer( 575 content::NOTIFICATION_LOAD_STOP, 576 content::Source<NavigationController>( 577 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 578 GetController())); 579 NotifyGeoposition(fresh_position_latitude, fresh_position_longitude); 580 observer.Wait(); 581 CheckGeoposition(fresh_position_latitude, fresh_position_longitude); 582 583 // Disable navigation for this frame. 584 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 585 586 // Now go ahead an authorize the second frame. 587 set_iframe_xpath("//iframe[@id='iframe_1']"); 588 // Infobar was displayed, allow access and check there's no error code. 589 SetInfoBarResponse(iframe_url(1), true); 590 LOG(WARNING) << "Checking position..."; 591 CheckGeoposition(fresh_position_latitude, fresh_position_longitude); 592 LOG(WARNING) << "...done."; 593 } 594 595 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, 596 IFramesWithCachedPosition) { 597 set_html_for_tests("/geolocation/iframes_different_origin.html"); 598 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 599 LoadIFrames(2); 600 601 set_iframe_xpath("//iframe[@id='iframe_0']"); 602 AddGeolocationWatch(true); 603 SetInfoBarResponse(iframe_url(0), true); 604 CheckGeoposition(fake_latitude(), fake_longitude()); 605 606 // Refresh geoposition, but let's not yet create the watch on the second frame 607 // so that it'll fetch from cache. 608 double cached_position_latitude = 5.67; 609 double cached_position_lognitude = 8.09; 610 content::WindowedNotificationObserver observer( 611 content::NOTIFICATION_LOAD_STOP, 612 content::Source<NavigationController>( 613 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 614 GetController())); 615 NotifyGeoposition(cached_position_latitude, cached_position_lognitude); 616 observer.Wait(); 617 CheckGeoposition(cached_position_latitude, cached_position_lognitude); 618 619 // Disable navigation for this frame. 620 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 621 622 // Now go ahead an authorize the second frame. 623 set_iframe_xpath("//iframe[@id='iframe_1']"); 624 AddGeolocationWatch(true); 625 // WebKit will use its cache, but we also broadcast a position shortly 626 // afterwards. We're only interested in the first navigation for the success 627 // callback from the cached position. 628 CheckStringValueFromJavascript("1", "geoSetMaxNavigateCount(1)"); 629 SetInfoBarResponse(iframe_url(1), true); 630 CheckGeoposition(cached_position_latitude, cached_position_lognitude); 631 } 632 633 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, CancelPermissionForFrame) { 634 set_html_for_tests("/geolocation/iframes_different_origin.html"); 635 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 636 LoadIFrames(2); 637 LOG(WARNING) << "frames loaded"; 638 639 set_iframe_xpath("//iframe[@id='iframe_0']"); 640 AddGeolocationWatch(true); 641 SetInfoBarResponse(iframe_url(0), true); 642 CheckGeoposition(fake_latitude(), fake_longitude()); 643 // Disables further prompts from this iframe. 644 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 645 646 // Test second iframe from a different origin with a cached geoposition will 647 // create the infobar. 648 set_iframe_xpath("//iframe[@id='iframe_1']"); 649 AddGeolocationWatch(true); 650 651 InfoBarService* infobar_service = InfoBarService::FromWebContents( 652 current_browser()->tab_strip_model()->GetActiveWebContents()); 653 size_t num_infobars_before_cancel = infobar_service->infobar_count(); 654 // Change the iframe, and ensure the infobar is gone. 655 IFrameLoader change_iframe_1(current_browser(), 1, current_url()); 656 size_t num_infobars_after_cancel = infobar_service->infobar_count(); 657 EXPECT_EQ(num_infobars_before_cancel, num_infobars_after_cancel + 1); 658 } 659 660 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) { 661 // Tests that an invalid URL (e.g. from a popup window) is rejected 662 // correctly. Also acts as a regression test for http://crbug.com/40478 663 set_html_for_tests("/geolocation/invalid_request_url.html"); 664 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 665 WebContents* original_tab = 666 current_browser()->tab_strip_model()->GetActiveWebContents(); 667 CheckStringValueFromJavascript("1", "requestGeolocationFromInvalidUrl()"); 668 CheckStringValueFromJavascriptForTab("1", "isAlive()", original_tab); 669 } 670 671 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfoBarBeforeStart) { 672 // See http://crbug.com/42789 673 set_html_for_tests("/geolocation/iframes_different_origin.html"); 674 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 675 LoadIFrames(2); 676 LOG(WARNING) << "frames loaded"; 677 678 // Access navigator.geolocation, but ensure it won't request permission. 679 set_iframe_xpath("//iframe[@id='iframe_1']"); 680 CheckStringValueFromJavascript("object", "geoAccessNavigatorGeolocation()"); 681 682 set_iframe_xpath("//iframe[@id='iframe_0']"); 683 AddGeolocationWatch(true); 684 SetInfoBarResponse(iframe_url(0), true); 685 CheckGeoposition(fake_latitude(), fake_longitude()); 686 CheckStringValueFromJavascript("0", "geoSetMaxNavigateCount(0)"); 687 688 // Permission should be requested after adding a watch. 689 set_iframe_xpath("//iframe[@id='iframe_1']"); 690 AddGeolocationWatch(true); 691 SetInfoBarResponse(iframe_url(1), true); 692 CheckGeoposition(fake_latitude(), fake_longitude()); 693 } 694 695 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TwoWatchesInOneFrame) { 696 set_html_for_tests("/geolocation/two_watches.html"); 697 ASSERT_TRUE(Initialize(INITIALIZATION_NONE)); 698 // First, set the JavaScript to navigate when it receives |final_position|. 699 double final_position_latitude = 3.17; 700 double final_position_longitude = 4.23; 701 std::string script = base::StringPrintf( 702 "window.domAutomationController.send(geoSetFinalPosition(%f, %f))", 703 final_position_latitude, final_position_longitude); 704 std::string js_result; 705 EXPECT_TRUE(content::ExecuteScriptAndExtractString( 706 current_browser()->tab_strip_model()->GetActiveWebContents(), script, 707 &js_result)); 708 EXPECT_EQ(js_result, "ok"); 709 710 // Send a position which both geolocation watches will receive. 711 AddGeolocationWatch(true); 712 SetInfoBarResponse(current_url(), true); 713 CheckGeoposition(fake_latitude(), fake_longitude()); 714 715 // The second watch will now have cancelled. Ensure an update still makes 716 // its way through to the first watcher. 717 content::WindowedNotificationObserver observer( 718 content::NOTIFICATION_LOAD_STOP, 719 content::Source<NavigationController>( 720 ¤t_browser()->tab_strip_model()->GetActiveWebContents()-> 721 GetController())); 722 NotifyGeoposition(final_position_latitude, final_position_longitude); 723 observer.Wait(); 724 CheckGeoposition(final_position_latitude, final_position_longitude); 725 } 726 727 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TabDestroyed) { 728 set_html_for_tests("/geolocation/tab_destroyed.html"); 729 ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES)); 730 LoadIFrames(3); 731 732 set_iframe_xpath("//iframe[@id='iframe_0']"); 733 AddGeolocationWatch(true); 734 735 set_iframe_xpath("//iframe[@id='iframe_1']"); 736 AddGeolocationWatch(false); 737 738 set_iframe_xpath("//iframe[@id='iframe_2']"); 739 AddGeolocationWatch(false); 740 741 std::string script = 742 "window.domAutomationController.send(window.close());"; 743 bool result = content::ExecuteScript( 744 current_browser()->tab_strip_model()->GetActiveWebContents(), script); 745 EXPECT_EQ(result, true); 746 } 747