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