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 <stddef.h>
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/macros.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/test/simple_test_clock.h"
18 #include "base/time/clock.h"
19 #include "build/build_config.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "components/content_settings/browser/page_specific_content_settings.h"
29 #include "components/content_settings/core/browser/host_content_settings_map.h"
30 #include "components/permissions/features.h"
31 #include "components/permissions/permission_request_manager.h"
32 #include "components/permissions/test/permission_request_observer.h"
33 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/render_frame_host.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/test/browser_test.h"
39 #include "content/public/test/browser_test_utils.h"
40 #include "net/base/escape.h"
41 #include "net/test/embedded_test_server/embedded_test_server.h"
42 #include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
43 #include "services/device/public/mojom/geoposition.mojom.h"
44
45 namespace {
46
GetErrorCodePermissionDenied()47 std::string GetErrorCodePermissionDenied() {
48 return base::NumberToString(static_cast<int>(
49 device::mojom::Geoposition::ErrorCode::PERMISSION_DENIED));
50 }
51
RunScript(content::RenderFrameHost * render_frame_host,const std::string & script)52 std::string RunScript(content::RenderFrameHost* render_frame_host,
53 const std::string& script) {
54 std::string result;
55 EXPECT_TRUE(content::ExecuteScriptAndExtractString(render_frame_host, script,
56 &result));
57 return result;
58 }
59
60 // IFrameLoader ---------------------------------------------------------------
61
62 // Used to block until an iframe is loaded via a javascript call.
63 // Note: NavigateToURLBlockUntilNavigationsComplete doesn't seem to work for
64 // multiple embedded iframes, as notifications seem to be 'batched'. Instead, we
65 // load and wait one single frame here by calling a javascript function.
66 class IFrameLoader : public content::NotificationObserver {
67 public:
68 IFrameLoader(Browser* browser, int iframe_id, const GURL& url);
69 ~IFrameLoader() override;
70
71 // content::NotificationObserver:
72 void Observe(int type,
73 const content::NotificationSource& source,
74 const content::NotificationDetails& details) override;
75
iframe_url() const76 const GURL& iframe_url() const { return iframe_url_; }
77
78 private:
79 content::NotificationRegistrar registrar_;
80
81 // If true the navigation has completed.
82 bool navigation_completed_;
83
84 // If true the javascript call has completed.
85 bool javascript_completed_;
86
87 std::string javascript_response_;
88
89 // The URL for the iframe we just loaded.
90 GURL iframe_url_;
91
92 DISALLOW_COPY_AND_ASSIGN(IFrameLoader);
93 };
94
IFrameLoader(Browser * browser,int iframe_id,const GURL & url)95 IFrameLoader::IFrameLoader(Browser* browser, int iframe_id, const GURL& url)
96 : navigation_completed_(false),
97 javascript_completed_(false) {
98 content::WebContents* web_contents =
99 browser->tab_strip_model()->GetActiveWebContents();
100 content::NavigationController* controller = &web_contents->GetController();
101 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
102 content::Source<content::NavigationController>(controller));
103 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
104 content::NotificationService::AllSources());
105 std::string script(base::StringPrintf(
106 "window.domAutomationController.send(addIFrame(%d, \"%s\"));",
107 iframe_id, url.spec().c_str()));
108 web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
109 base::UTF8ToUTF16(script), base::NullCallback());
110 content::RunMessageLoop();
111
112 EXPECT_EQ(base::StringPrintf("\"%d\"", iframe_id), javascript_response_);
113 registrar_.RemoveAll();
114 // Now that we loaded the iframe, let's fetch its src.
115 script = base::StringPrintf(
116 "window.domAutomationController.send(getIFrameSrc(%d))", iframe_id);
117 iframe_url_ = GURL(RunScript(web_contents->GetMainFrame(), script));
118 }
119
~IFrameLoader()120 IFrameLoader::~IFrameLoader() {
121 }
122
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)123 void IFrameLoader::Observe(int type,
124 const content::NotificationSource& source,
125 const content::NotificationDetails& details) {
126 if (type == content::NOTIFICATION_LOAD_STOP) {
127 navigation_completed_ = true;
128 } else if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) {
129 content::Details<std::string> dom_op_result(details);
130 javascript_response_ = *dom_op_result.ptr();
131 javascript_completed_ = true;
132 }
133 if (javascript_completed_ && navigation_completed_)
134 base::RunLoop::QuitCurrentWhenIdleDeprecated();
135 }
136
137 } // namespace
138
139
140 // GeolocationBrowserTest -----------------------------------------------------
141
142 // This is a browser test for Geolocation.
143 // It exercises various integration points from javascript <-> browser:
144 // 1. The user is prompted when a position is requested from an unauthorized
145 // origin.
146 // 2. Denying the request triggers the correct error callback.
147 // 3. Granting permission does not trigger an error, and allows a position to
148 // be passed to javascript.
149 // 4. Permissions persisted in disk are respected.
150 // 5. Incognito profiles don't persist permissions on disk, but they do inherit
151 // them from their regular parent profile.
152 class GeolocationBrowserTest : public InProcessBrowserTest {
153 public:
154 enum InitializationOptions {
155 // The default profile and browser window will be used.
156 INITIALIZATION_DEFAULT,
157
158 // An incognito profile and browser window will be used.
159 INITIALIZATION_OFFTHERECORD,
160
161 // A new tab will be created using the default profile and browser window.
162 INITIALIZATION_NEWTAB,
163 };
164
165 GeolocationBrowserTest();
166 ~GeolocationBrowserTest() override = default;
167
168 // InProcessBrowserTest:
169 void TearDownInProcessBrowserTestFixture() override;
170
current_browser()171 Browser* current_browser() { return current_browser_; }
set_html_for_tests(const std::string & html_for_tests)172 void set_html_for_tests(const std::string& html_for_tests) {
173 html_for_tests_ = html_for_tests;
174 }
current_url() const175 const GURL& current_url() const { return current_url_; }
iframe_url(size_t i) const176 const GURL& iframe_url(size_t i) const { return iframe_urls_[i]; }
fake_latitude() const177 double fake_latitude() const { return fake_latitude_; }
fake_longitude() const178 double fake_longitude() const { return fake_longitude_; }
179
180 // Initializes the test server and navigates to the initial url.
181 void Initialize(InitializationOptions options);
182
183 // Loads two iframes with different origins: http://127.0.0.1 and
184 // http://localhost.
185 void LoadIFrames();
186
187 // Specifies which frame to use for executing JavaScript.
188 void SetFrameForScriptExecution(const std::string& frame_name);
189
190 // Gets the HostContentSettingsMap for the current profile.
191 HostContentSettingsMap* GetHostContentSettingsMap();
192
193 // Calls watchPosition in JavaScript and accepts or denies the resulting
194 // permission request. Returns |true| if the expected behavior happened.
195 bool WatchPositionAndGrantPermission() WARN_UNUSED_RESULT;
196 bool WatchPositionAndDenyPermission() WARN_UNUSED_RESULT;
197
198 // Calls watchPosition in JavaScript and observes whether the permission
199 // request is shown without interacting with it. Callers should set
200 // |request_should_display| to |true| if they expect a request to display.
201 void WatchPositionAndObservePermissionRequest(bool request_should_display);
202
203 // Checks that no errors have been received in JavaScript, and checks that the
204 // position most recently received matches |latitude| and |longitude|.
205 void ExpectPosition(double latitude, double longitude);
206
207 // Executes |function| in |render_frame_host| and checks that the return value
208 // matches |expected|.
209 void ExpectValueFromScriptForFrame(
210 const std::string& expected,
211 const std::string& function,
212 content::RenderFrameHost* render_frame_host);
213
214 // Executes |function| and checks that the return value matches |expected|.
215 void ExpectValueFromScript(const std::string& expected,
216 const std::string& function);
217
218 // Sets a new (second) position and runs all callbacks currently registered
219 // with the Geolocation system. Returns |true| if the new position is updated
220 // successfully in JavaScript.
221 bool SetPositionAndWaitUntilUpdated(double latitude, double longitude);
222
223 // Convenience method to look up the number of queued permission requests.
224 int GetRequestQueueSize(permissions::PermissionRequestManager* manager);
225
226 protected:
227 // The values used for the position override.
228 double fake_latitude_ = 1.23;
229 double fake_longitude_ = 4.56;
230 std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_;
231
232 private:
233 // Calls watchPosition() in JavaScript and accepts or denies the resulting
234 // permission request. Returns the JavaScript response.
235 std::string WatchPositionAndRespondToPermissionRequest(
236 permissions::PermissionRequestManager::AutoResponseType request_response);
237
238 // The current Browser as set in Initialize. May be for an incognito profile.
239 Browser* current_browser_ = nullptr;
240
241 // The path element of a URL referencing the html content for this test.
242 std::string html_for_tests_ = "/geolocation/simple.html";
243
244 // The frame where the JavaScript calls will run.
245 content::RenderFrameHost* render_frame_host_ = nullptr;
246
247 // The current url for the top level page.
248 GURL current_url_;
249
250 // The urls for the iframes loaded by LoadIFrames.
251 std::vector<GURL> iframe_urls_;
252
253
254 DISALLOW_COPY_AND_ASSIGN(GeolocationBrowserTest);
255 };
256
257 // WebContentImpl tries to connect Device Service earlier than
258 // of SetUpOnMainThread(), so create the |geolocation_overrider_| here.
GeolocationBrowserTest()259 GeolocationBrowserTest::GeolocationBrowserTest()
260 : geolocation_overrider_(
261 std::make_unique<device::ScopedGeolocationOverrider>(
262 fake_latitude_,
263 fake_longitude_)) {}
264
TearDownInProcessBrowserTestFixture()265 void GeolocationBrowserTest::TearDownInProcessBrowserTestFixture() {
266 LOG(WARNING) << "TearDownInProcessBrowserTestFixture. Test Finished.";
267 }
268
Initialize(InitializationOptions options)269 void GeolocationBrowserTest::Initialize(InitializationOptions options) {
270 if (!embedded_test_server()->Started() && !embedded_test_server()->Start()) {
271 ADD_FAILURE() << "Test server failed to start.";
272 return;
273 }
274
275 current_url_ = embedded_test_server()->GetURL(html_for_tests_);
276 if (options == INITIALIZATION_OFFTHERECORD) {
277 current_browser_ = OpenURLOffTheRecord(browser()->profile(), current_url_);
278 } else {
279 current_browser_ = browser();
280 if (options == INITIALIZATION_NEWTAB)
281 chrome::NewTab(current_browser_);
282 }
283 ASSERT_TRUE(current_browser_);
284 if (options != INITIALIZATION_OFFTHERECORD)
285 ui_test_utils::NavigateToURL(current_browser_, current_url_);
286
287 // By default the main frame is used for JavaScript execution.
288 SetFrameForScriptExecution("");
289 }
290
LoadIFrames()291 void GeolocationBrowserTest::LoadIFrames() {
292 int number_iframes = 2;
293 iframe_urls_.resize(number_iframes);
294 for (int i = 0; i < number_iframes; ++i) {
295 IFrameLoader loader(current_browser_, i, GURL());
296 iframe_urls_[i] = loader.iframe_url();
297 }
298 }
299
SetFrameForScriptExecution(const std::string & frame_name)300 void GeolocationBrowserTest::SetFrameForScriptExecution(
301 const std::string& frame_name) {
302 content::WebContents* web_contents =
303 current_browser_->tab_strip_model()->GetActiveWebContents();
304 render_frame_host_ = nullptr;
305
306 if (frame_name.empty()) {
307 render_frame_host_ = web_contents->GetMainFrame();
308 } else {
309 render_frame_host_ = content::FrameMatchingPredicate(
310 web_contents,
311 base::BindRepeating(&content::FrameMatchesName, frame_name));
312 }
313 DCHECK(render_frame_host_);
314 }
315
GetHostContentSettingsMap()316 HostContentSettingsMap* GeolocationBrowserTest::GetHostContentSettingsMap() {
317 return HostContentSettingsMapFactory::GetForProfile(
318 current_browser()->profile());
319 }
320
WatchPositionAndGrantPermission()321 bool GeolocationBrowserTest::WatchPositionAndGrantPermission() {
322 std::string result = WatchPositionAndRespondToPermissionRequest(
323 permissions::PermissionRequestManager::ACCEPT_ALL);
324 return "request-callback-success" == result;
325 }
326
WatchPositionAndDenyPermission()327 bool GeolocationBrowserTest::WatchPositionAndDenyPermission() {
328 std::string result = WatchPositionAndRespondToPermissionRequest(
329 permissions::PermissionRequestManager::DENY_ALL);
330 return "request-callback-error" == result;
331 }
332
WatchPositionAndRespondToPermissionRequest(permissions::PermissionRequestManager::AutoResponseType request_response)333 std::string GeolocationBrowserTest::WatchPositionAndRespondToPermissionRequest(
334 permissions::PermissionRequestManager::AutoResponseType request_response) {
335 permissions::PermissionRequestManager::FromWebContents(
336 current_browser_->tab_strip_model()->GetActiveWebContents())
337 ->set_auto_response_for_test(request_response);
338 return RunScript(render_frame_host_, "geoStartWithAsyncResponse()");
339 }
340
WatchPositionAndObservePermissionRequest(bool request_should_display)341 void GeolocationBrowserTest::WatchPositionAndObservePermissionRequest(
342 bool request_should_display) {
343 permissions::PermissionRequestObserver observer(
344 current_browser_->tab_strip_model()->GetActiveWebContents());
345 if (request_should_display) {
346 // Control will return as soon as the API call is made, and then the
347 // observer will wait for the request to display.
348 RunScript(render_frame_host_, "geoStartWithSyncResponse()");
349 observer.Wait();
350 } else {
351 // Control will return once one of the callbacks fires.
352 RunScript(render_frame_host_, "geoStartWithAsyncResponse()");
353 }
354 EXPECT_EQ(request_should_display, observer.request_shown());
355 }
356
ExpectPosition(double latitude,double longitude)357 void GeolocationBrowserTest::ExpectPosition(double latitude, double longitude) {
358 // Checks we have no error.
359 ExpectValueFromScript("0", "geoGetLastError()");
360 ExpectValueFromScript(base::NumberToString(latitude),
361 "geoGetLastPositionLatitude()");
362 ExpectValueFromScript(base::NumberToString(longitude),
363 "geoGetLastPositionLongitude()");
364 }
365
ExpectValueFromScriptForFrame(const std::string & expected,const std::string & function,content::RenderFrameHost * render_frame_host)366 void GeolocationBrowserTest::ExpectValueFromScriptForFrame(
367 const std::string& expected,
368 const std::string& function,
369 content::RenderFrameHost* render_frame_host) {
370 std::string script(base::StringPrintf(
371 "window.domAutomationController.send(%s)", function.c_str()));
372 EXPECT_EQ(expected, RunScript(render_frame_host, script));
373 }
374
ExpectValueFromScript(const std::string & expected,const std::string & function)375 void GeolocationBrowserTest::ExpectValueFromScript(
376 const std::string& expected,
377 const std::string& function) {
378 ExpectValueFromScriptForFrame(expected, function, render_frame_host_);
379 }
380
SetPositionAndWaitUntilUpdated(double latitude,double longitude)381 bool GeolocationBrowserTest::SetPositionAndWaitUntilUpdated(double latitude,
382 double longitude) {
383 content::DOMMessageQueue dom_message_queue;
384
385 fake_latitude_ = latitude;
386 fake_longitude_ = longitude;
387
388 geolocation_overrider_->UpdateLocation(fake_latitude_, fake_longitude_);
389
390 std::string result;
391 if (!dom_message_queue.WaitForMessage(&result))
392 return false;
393 return result == "\"geoposition-updated\"";
394 }
395
GetRequestQueueSize(permissions::PermissionRequestManager * manager)396 int GeolocationBrowserTest::GetRequestQueueSize(
397 permissions::PermissionRequestManager* manager) {
398 return static_cast<int>(manager->Requests().size());
399 }
400
401 // Tests ----------------------------------------------------------------------
402
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,DisplaysPrompt)403 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DisplaysPrompt) {
404 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
405 ASSERT_TRUE(WatchPositionAndGrantPermission());
406
407 EXPECT_EQ(
408 CONTENT_SETTING_ALLOW,
409 GetHostContentSettingsMap()->GetContentSetting(
410 current_url(), current_url(), ContentSettingsType::GEOLOCATION));
411
412 // Ensure a second request doesn't create a prompt in this tab.
413 WatchPositionAndObservePermissionRequest(false);
414 }
415
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,Geoposition)416 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, Geoposition) {
417 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
418 ASSERT_TRUE(WatchPositionAndGrantPermission());
419 ExpectPosition(fake_latitude(), fake_longitude());
420 }
421
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,ErrorOnPermissionDenied)422 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, ErrorOnPermissionDenied) {
423 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
424 EXPECT_TRUE(WatchPositionAndDenyPermission());
425 ExpectValueFromScript(GetErrorCodePermissionDenied(), "geoGetLastError()");
426
427 EXPECT_EQ(
428 CONTENT_SETTING_BLOCK,
429 GetHostContentSettingsMap()->GetContentSetting(
430 current_url(), current_url(), ContentSettingsType::GEOLOCATION));
431
432 // Ensure a second request doesn't create a prompt in this tab.
433 WatchPositionAndObservePermissionRequest(false);
434 }
435
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,NoPromptForSecondTab)436 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoPromptForSecondTab) {
437 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
438 ASSERT_TRUE(WatchPositionAndGrantPermission());
439
440 // Checks request is not needed in a second tab.
441 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_NEWTAB));
442 WatchPositionAndObservePermissionRequest(false);
443 ExpectPosition(fake_latitude(), fake_longitude());
444 }
445
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,NoPromptForDeniedOrigin)446 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoPromptForDeniedOrigin) {
447 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
448 GetHostContentSettingsMap()->SetContentSettingDefaultScope(
449 current_url(), current_url(), ContentSettingsType::GEOLOCATION,
450 CONTENT_SETTING_BLOCK);
451
452 // Check that the request wasn't shown but we get an error for this origin.
453 WatchPositionAndObservePermissionRequest(false);
454 ExpectValueFromScript(GetErrorCodePermissionDenied(), "geoGetLastError()");
455
456 // Checks prompt will not be created a second tab.
457 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_NEWTAB));
458 WatchPositionAndObservePermissionRequest(false);
459 ExpectValueFromScript(GetErrorCodePermissionDenied(), "geoGetLastError()");
460 }
461
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,NoPromptForAllowedOrigin)462 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoPromptForAllowedOrigin) {
463 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
464 GetHostContentSettingsMap()->SetContentSettingDefaultScope(
465 current_url(), current_url(), ContentSettingsType::GEOLOCATION,
466 CONTENT_SETTING_ALLOW);
467 // The request is not shown, there is no error, and the position gets to the
468 // script.
469 WatchPositionAndObservePermissionRequest(false);
470 ExpectPosition(fake_latitude(), fake_longitude());
471 }
472
473 // Crashes on Win only. http://crbug.com/1014506
474 #if defined(OS_WIN)
475 #define MAYBE_PromptForOffTheRecord DISABLED_PromptForOffTheRecord
476 #else
477 #define MAYBE_PromptForOffTheRecord PromptForOffTheRecord
478 #endif
479
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,MAYBE_PromptForOffTheRecord)480 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_PromptForOffTheRecord) {
481 // For a regular profile the user is prompted, and when granted the position
482 // gets to the script.
483 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
484 ASSERT_TRUE(WatchPositionAndGrantPermission());
485 ExpectPosition(fake_latitude(), fake_longitude());
486
487 // The permission from the regular profile is not inherited because it is more
488 // permissive than the initial default for geolocation. This prevents
489 // identifying information to be sent to a server without explicit consent by
490 // the user.
491 // Go incognito, and check that the user is prompted again and when granted,
492 // the position gets to the script.
493 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_OFFTHERECORD));
494 ASSERT_TRUE(WatchPositionAndGrantPermission());
495 ExpectPosition(fake_latitude(), fake_longitude());
496 }
497
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,NoLeakFromOffTheRecord)498 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoLeakFromOffTheRecord) {
499 // The user is prompted in a fresh incognito profile, and when granted the
500 // position gets to the script.
501 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_OFFTHERECORD));
502 ASSERT_TRUE(WatchPositionAndGrantPermission());
503 ExpectPosition(fake_latitude(), fake_longitude());
504
505 // The regular profile knows nothing of what happened in incognito. It is
506 // prompted and when granted the position gets to the script.
507 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
508 ASSERT_TRUE(WatchPositionAndGrantPermission());
509 ExpectPosition(fake_latitude(), fake_longitude());
510 }
511
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,IFramesWithCachedPosition)512 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithCachedPosition) {
513 set_html_for_tests("/geolocation/two_iframes.html");
514 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
515 LoadIFrames();
516
517 // Grant permission in the first frame, the position gets to the script.
518 SetFrameForScriptExecution("iframe_0");
519 ASSERT_TRUE(WatchPositionAndGrantPermission());
520 ExpectPosition(fake_latitude(), fake_longitude());
521
522 // Refresh the position, but let's not yet create the watch on the second
523 // frame so that it'll fetch from cache.
524 double cached_position_latitude = 5.67;
525 double cached_position_lognitude = 8.09;
526 ASSERT_TRUE(SetPositionAndWaitUntilUpdated(cached_position_latitude,
527 cached_position_lognitude));
528 ExpectPosition(cached_position_latitude, cached_position_lognitude);
529
530 // Now check the second frame gets cached values as well.
531 SetFrameForScriptExecution("iframe_1");
532 ASSERT_TRUE(WatchPositionAndGrantPermission());
533 ExpectPosition(cached_position_latitude, cached_position_lognitude);
534 }
535
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,InvalidUrlRequest)536 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) {
537 // Tests that an invalid URL (e.g. from a popup window) is rejected
538 // correctly. Also acts as a regression test for http://crbug.com/40478
539 set_html_for_tests("/geolocation/invalid_request_url.html");
540 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
541
542 content::WebContents* original_tab =
543 current_browser()->tab_strip_model()->GetActiveWebContents();
544 ExpectValueFromScript(GetErrorCodePermissionDenied(),
545 "requestGeolocationFromInvalidUrl()");
546 ExpectValueFromScriptForFrame("1", "isAlive()", original_tab->GetMainFrame());
547 }
548
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,NoPromptBeforeStart)549 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoPromptBeforeStart) {
550 // See http://crbug.com/42789
551 set_html_for_tests("/geolocation/two_iframes.html");
552 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
553 LoadIFrames();
554
555 // In the second iframe, access the navigator.geolocation object, but don't
556 // call any methods yet so it won't request permission yet.
557 SetFrameForScriptExecution("iframe_1");
558 ExpectValueFromScript("object", "geoAccessNavigatorGeolocation()");
559
560 // In the first iframe, call watchPosition, grant permission, and verify that
561 // the position gets to the script.
562 SetFrameForScriptExecution("iframe_0");
563 ASSERT_TRUE(WatchPositionAndGrantPermission());
564 ExpectPosition(fake_latitude(), fake_longitude());
565
566 // Back to the second frame. The user is prompted now (it has a different
567 // origin). When permission is granted the position gets to the script.
568 SetFrameForScriptExecution("iframe_1");
569 ASSERT_TRUE(WatchPositionAndGrantPermission());
570 ExpectPosition(fake_latitude(), fake_longitude());
571 }
572
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,TwoWatchesInOneFrame)573 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TwoWatchesInOneFrame) {
574 set_html_for_tests("/geolocation/two_watches.html");
575 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
576
577 // Tell the script what to expect as the final coordinates.
578 double final_position_latitude = 3.17;
579 double final_position_longitude = 4.23;
580 std::string script =
581 base::StringPrintf("geoSetFinalPosition(%f, %f)", final_position_latitude,
582 final_position_longitude);
583 ExpectValueFromScript("ok", script);
584
585 // Request permission and set two watches for the initial success callback.
586 ASSERT_TRUE(WatchPositionAndGrantPermission());
587 ExpectPosition(fake_latitude(), fake_longitude());
588
589 // The second watch will now have cancelled. Ensure an update still makes
590 // its way through to the first watcher.
591 ASSERT_TRUE(SetPositionAndWaitUntilUpdated(final_position_latitude,
592 final_position_longitude));
593 ExpectPosition(final_position_latitude, final_position_longitude);
594 }
595
596 // TODO(felt): Disabled because the second permission request hangs.
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,DISABLED_PendingChildFrames)597 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_PendingChildFrames) {
598 set_html_for_tests("/geolocation/two_iframes.html");
599 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
600 LoadIFrames();
601
602 SetFrameForScriptExecution("iframe_0");
603 WatchPositionAndObservePermissionRequest(true);
604
605 SetFrameForScriptExecution("iframe_1");
606 WatchPositionAndObservePermissionRequest(true);
607 }
608
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,TabDestroyed)609 IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, TabDestroyed) {
610 ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT));
611 WatchPositionAndObservePermissionRequest(true);
612
613 // TODO(mvanouwerkerk): Can't close a window you did not open. Maybe this was
614 // valid when the test was written, but now it just prints "Scripts may close
615 // only the windows that were opened by it."
616 std::string script = "window.domAutomationController.send(window.close())";
617 ASSERT_TRUE(content::ExecuteScript(
618 current_browser()->tab_strip_model()->GetActiveWebContents(), script));
619 }
620