OLD | NEW |
| (Empty) |
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 <set> | |
6 | |
7 #include "base/json/json_reader.h" | |
8 #include "base/memory/ref_counted.h" | |
9 #include "base/path_service.h" | |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "base/values.h" | |
12 #include "content/browser/renderer_host/render_view_host_impl.h" | |
13 #include "content/browser/site_instance_impl.h" | |
14 #include "content/browser/web_contents/web_contents_impl.h" | |
15 #include "content/common/content_constants_internal.h" | |
16 #include "content/public/browser/navigation_controller.h" | |
17 #include "content/public/browser/navigation_entry.h" | |
18 #include "content/public/browser/notification_details.h" | |
19 #include "content/public/browser/notification_observer.h" | |
20 #include "content/public/browser/notification_registrar.h" | |
21 #include "content/public/browser/notification_types.h" | |
22 #include "content/public/browser/render_process_host.h" | |
23 #include "content/public/browser/web_contents.h" | |
24 #include "content/public/browser/web_contents_observer.h" | |
25 #include "content/public/common/url_constants.h" | |
26 #include "content/public/test/browser_test_utils.h" | |
27 #include "content/public/test/test_navigation_observer.h" | |
28 #include "content/public/test/test_utils.h" | |
29 #include "content/shell/browser/shell.h" | |
30 #include "content/test/content_browser_test.h" | |
31 #include "content/test/content_browser_test_utils.h" | |
32 #include "net/base/net_util.h" | |
33 #include "net/test/spawned_test_server/spawned_test_server.h" | |
34 | |
35 namespace content { | |
36 | |
37 class RenderViewHostManagerTest : public ContentBrowserTest { | |
38 public: | |
39 RenderViewHostManagerTest() {} | |
40 | |
41 static bool GetFilePathWithHostAndPortReplacement( | |
42 const std::string& original_file_path, | |
43 const net::HostPortPair& host_port_pair, | |
44 std::string* replacement_path) { | |
45 std::vector<net::SpawnedTestServer::StringPair> replacement_text; | |
46 replacement_text.push_back( | |
47 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); | |
48 return net::SpawnedTestServer::GetFilePathWithReplacements( | |
49 original_file_path, replacement_text, replacement_path); | |
50 } | |
51 }; | |
52 | |
53 // Web pages should not have script access to the swapped out page. | |
54 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
55 DISABLED_NoScriptAccessAfterSwapOut) { | |
56 // Start two servers with different sites. | |
57 ASSERT_TRUE(test_server()->Start()); | |
58 net::SpawnedTestServer https_server( | |
59 net::SpawnedTestServer::TYPE_HTTPS, | |
60 net::SpawnedTestServer::kLocalhost, | |
61 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
62 ASSERT_TRUE(https_server.Start()); | |
63 | |
64 // Load a page with links that open in a new window. | |
65 std::string replacement_path; | |
66 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
67 "files/click-noreferrer-links.html", | |
68 https_server.host_port_pair(), | |
69 &replacement_path)); | |
70 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
71 | |
72 // Get the original SiteInstance for later comparison. | |
73 scoped_refptr<SiteInstance> orig_site_instance( | |
74 shell()->web_contents()->GetSiteInstance()); | |
75 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
76 | |
77 // Open a same-site link in a new window. | |
78 ShellAddedObserver new_shell_observer; | |
79 bool success = false; | |
80 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
81 shell()->web_contents(), | |
82 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
83 &success)); | |
84 EXPECT_TRUE(success); | |
85 Shell* new_shell = new_shell_observer.GetShell(); | |
86 | |
87 // Wait for the navigation in the new window to finish, if it hasn't. | |
88 WaitForLoadStop(new_shell->web_contents()); | |
89 EXPECT_EQ("/files/navigate_opener.html", | |
90 new_shell->web_contents()->GetLastCommittedURL().path()); | |
91 | |
92 // Should have the same SiteInstance. | |
93 scoped_refptr<SiteInstance> blank_site_instance( | |
94 new_shell->web_contents()->GetSiteInstance()); | |
95 EXPECT_EQ(orig_site_instance, blank_site_instance); | |
96 | |
97 // We should have access to the opened window's location. | |
98 success = false; | |
99 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
100 shell()->web_contents(), | |
101 "window.domAutomationController.send(testScriptAccessToWindow());", | |
102 &success)); | |
103 EXPECT_TRUE(success); | |
104 | |
105 // Now navigate the new window to a different site. | |
106 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
107 scoped_refptr<SiteInstance> new_site_instance( | |
108 new_shell->web_contents()->GetSiteInstance()); | |
109 EXPECT_NE(orig_site_instance, new_site_instance); | |
110 | |
111 // We should no longer have script access to the opened window's location. | |
112 success = false; | |
113 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
114 shell()->web_contents(), | |
115 "window.domAutomationController.send(testScriptAccessToWindow());", | |
116 &success)); | |
117 EXPECT_FALSE(success); | |
118 } | |
119 | |
120 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer | |
121 // and target=_blank should create a new SiteInstance. | |
122 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
123 SwapProcessWithRelNoreferrerAndTargetBlank) { | |
124 // Start two servers with different sites. | |
125 ASSERT_TRUE(test_server()->Start()); | |
126 net::SpawnedTestServer https_server( | |
127 net::SpawnedTestServer::TYPE_HTTPS, | |
128 net::SpawnedTestServer::kLocalhost, | |
129 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
130 ASSERT_TRUE(https_server.Start()); | |
131 | |
132 // Load a page with links that open in a new window. | |
133 std::string replacement_path; | |
134 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
135 "files/click-noreferrer-links.html", | |
136 https_server.host_port_pair(), | |
137 &replacement_path)); | |
138 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
139 | |
140 // Get the original SiteInstance for later comparison. | |
141 scoped_refptr<SiteInstance> orig_site_instance( | |
142 shell()->web_contents()->GetSiteInstance()); | |
143 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
144 | |
145 // Test clicking a rel=noreferrer + target=blank link. | |
146 ShellAddedObserver new_shell_observer; | |
147 bool success = false; | |
148 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
149 shell()->web_contents(), | |
150 "window.domAutomationController.send(clickNoRefTargetBlankLink());", | |
151 &success)); | |
152 EXPECT_TRUE(success); | |
153 | |
154 // Wait for the window to open. | |
155 Shell* new_shell = new_shell_observer.GetShell(); | |
156 | |
157 EXPECT_EQ("/files/title2.html", | |
158 new_shell->web_contents()->GetVisibleURL().path()); | |
159 | |
160 // Wait for the cross-site transition in the new tab to finish. | |
161 WaitForLoadStop(new_shell->web_contents()); | |
162 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( | |
163 new_shell->web_contents()); | |
164 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()-> | |
165 pending_render_view_host()); | |
166 | |
167 // Should have a new SiteInstance. | |
168 scoped_refptr<SiteInstance> noref_blank_site_instance( | |
169 new_shell->web_contents()->GetSiteInstance()); | |
170 EXPECT_NE(orig_site_instance, noref_blank_site_instance); | |
171 } | |
172 | |
173 // As of crbug.com/69267, we create a new BrowsingInstance (and SiteInstance) | |
174 // for rel=noreferrer links in new windows, even to same site pages and named | |
175 // targets. | |
176 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
177 SwapProcessWithSameSiteRelNoreferrer) { | |
178 // Start two servers with different sites. | |
179 ASSERT_TRUE(test_server()->Start()); | |
180 net::SpawnedTestServer https_server( | |
181 net::SpawnedTestServer::TYPE_HTTPS, | |
182 net::SpawnedTestServer::kLocalhost, | |
183 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
184 ASSERT_TRUE(https_server.Start()); | |
185 | |
186 // Load a page with links that open in a new window. | |
187 std::string replacement_path; | |
188 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
189 "files/click-noreferrer-links.html", | |
190 https_server.host_port_pair(), | |
191 &replacement_path)); | |
192 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
193 | |
194 // Get the original SiteInstance for later comparison. | |
195 scoped_refptr<SiteInstance> orig_site_instance( | |
196 shell()->web_contents()->GetSiteInstance()); | |
197 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
198 | |
199 // Test clicking a same-site rel=noreferrer + target=foo link. | |
200 ShellAddedObserver new_shell_observer; | |
201 bool success = false; | |
202 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
203 shell()->web_contents(), | |
204 "window.domAutomationController.send(clickSameSiteNoRefTargetedLink());", | |
205 &success)); | |
206 EXPECT_TRUE(success); | |
207 | |
208 // Wait for the window to open. | |
209 Shell* new_shell = new_shell_observer.GetShell(); | |
210 | |
211 // Opens in new window. | |
212 EXPECT_EQ("/files/title2.html", | |
213 new_shell->web_contents()->GetVisibleURL().path()); | |
214 | |
215 // Wait for the cross-site transition in the new tab to finish. | |
216 WaitForLoadStop(new_shell->web_contents()); | |
217 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( | |
218 new_shell->web_contents()); | |
219 EXPECT_FALSE(web_contents->GetRenderManagerForTesting()-> | |
220 pending_render_view_host()); | |
221 | |
222 // Should have a new SiteInstance (in a new BrowsingInstance). | |
223 scoped_refptr<SiteInstance> noref_blank_site_instance( | |
224 new_shell->web_contents()->GetSiteInstance()); | |
225 EXPECT_NE(orig_site_instance, noref_blank_site_instance); | |
226 } | |
227 | |
228 // Test for crbug.com/24447. Following a cross-site link with just | |
229 // target=_blank should not create a new SiteInstance. | |
230 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
231 DontSwapProcessWithOnlyTargetBlank) { | |
232 // Start two servers with different sites. | |
233 ASSERT_TRUE(test_server()->Start()); | |
234 net::SpawnedTestServer https_server( | |
235 net::SpawnedTestServer::TYPE_HTTPS, | |
236 net::SpawnedTestServer::kLocalhost, | |
237 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
238 ASSERT_TRUE(https_server.Start()); | |
239 | |
240 // Load a page with links that open in a new window. | |
241 std::string replacement_path; | |
242 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
243 "files/click-noreferrer-links.html", | |
244 https_server.host_port_pair(), | |
245 &replacement_path)); | |
246 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
247 | |
248 // Get the original SiteInstance for later comparison. | |
249 scoped_refptr<SiteInstance> orig_site_instance( | |
250 shell()->web_contents()->GetSiteInstance()); | |
251 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
252 | |
253 // Test clicking a target=blank link. | |
254 ShellAddedObserver new_shell_observer; | |
255 bool success = false; | |
256 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
257 shell()->web_contents(), | |
258 "window.domAutomationController.send(clickTargetBlankLink());", | |
259 &success)); | |
260 EXPECT_TRUE(success); | |
261 | |
262 // Wait for the window to open. | |
263 Shell* new_shell = new_shell_observer.GetShell(); | |
264 | |
265 // Wait for the cross-site transition in the new tab to finish. | |
266 WaitForLoadStop(new_shell->web_contents()); | |
267 EXPECT_EQ("/files/title2.html", | |
268 new_shell->web_contents()->GetLastCommittedURL().path()); | |
269 | |
270 // Should have the same SiteInstance. | |
271 scoped_refptr<SiteInstance> blank_site_instance( | |
272 new_shell->web_contents()->GetSiteInstance()); | |
273 EXPECT_EQ(orig_site_instance, blank_site_instance); | |
274 } | |
275 | |
276 // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer | |
277 // and no target=_blank should not create a new SiteInstance. | |
278 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
279 DontSwapProcessWithOnlyRelNoreferrer) { | |
280 // Start two servers with different sites. | |
281 ASSERT_TRUE(test_server()->Start()); | |
282 net::SpawnedTestServer https_server( | |
283 net::SpawnedTestServer::TYPE_HTTPS, | |
284 net::SpawnedTestServer::kLocalhost, | |
285 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
286 ASSERT_TRUE(https_server.Start()); | |
287 | |
288 // Load a page with links that open in a new window. | |
289 std::string replacement_path; | |
290 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
291 "files/click-noreferrer-links.html", | |
292 https_server.host_port_pair(), | |
293 &replacement_path)); | |
294 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
295 | |
296 // Get the original SiteInstance for later comparison. | |
297 scoped_refptr<SiteInstance> orig_site_instance( | |
298 shell()->web_contents()->GetSiteInstance()); | |
299 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
300 | |
301 // Test clicking a rel=noreferrer link. | |
302 bool success = false; | |
303 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
304 shell()->web_contents(), | |
305 "window.domAutomationController.send(clickNoRefLink());", | |
306 &success)); | |
307 EXPECT_TRUE(success); | |
308 | |
309 // Wait for the cross-site transition in the current tab to finish. | |
310 WaitForLoadStop(shell()->web_contents()); | |
311 | |
312 // Opens in same window. | |
313 EXPECT_EQ(1u, Shell::windows().size()); | |
314 EXPECT_EQ("/files/title2.html", | |
315 shell()->web_contents()->GetLastCommittedURL().path()); | |
316 | |
317 // Should have the same SiteInstance. | |
318 scoped_refptr<SiteInstance> noref_site_instance( | |
319 shell()->web_contents()->GetSiteInstance()); | |
320 EXPECT_EQ(orig_site_instance, noref_site_instance); | |
321 } | |
322 | |
323 // Test for crbug.com/116192. Targeted links should still work after the | |
324 // named target window has swapped processes. | |
325 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
326 AllowTargetedNavigationsAfterSwap) { | |
327 // Start two servers with different sites. | |
328 ASSERT_TRUE(test_server()->Start()); | |
329 net::SpawnedTestServer https_server( | |
330 net::SpawnedTestServer::TYPE_HTTPS, | |
331 net::SpawnedTestServer::kLocalhost, | |
332 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
333 ASSERT_TRUE(https_server.Start()); | |
334 | |
335 // Load a page with links that open in a new window. | |
336 std::string replacement_path; | |
337 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
338 "files/click-noreferrer-links.html", | |
339 https_server.host_port_pair(), | |
340 &replacement_path)); | |
341 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
342 | |
343 // Get the original SiteInstance for later comparison. | |
344 scoped_refptr<SiteInstance> orig_site_instance( | |
345 shell()->web_contents()->GetSiteInstance()); | |
346 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
347 | |
348 // Test clicking a target=foo link. | |
349 ShellAddedObserver new_shell_observer; | |
350 bool success = false; | |
351 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
352 shell()->web_contents(), | |
353 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
354 &success)); | |
355 EXPECT_TRUE(success); | |
356 Shell* new_shell = new_shell_observer.GetShell(); | |
357 | |
358 // Wait for the navigation in the new tab to finish, if it hasn't. | |
359 WaitForLoadStop(new_shell->web_contents()); | |
360 EXPECT_EQ("/files/navigate_opener.html", | |
361 new_shell->web_contents()->GetLastCommittedURL().path()); | |
362 | |
363 // Should have the same SiteInstance. | |
364 scoped_refptr<SiteInstance> blank_site_instance( | |
365 new_shell->web_contents()->GetSiteInstance()); | |
366 EXPECT_EQ(orig_site_instance, blank_site_instance); | |
367 | |
368 // Now navigate the new tab to a different site. | |
369 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
370 scoped_refptr<SiteInstance> new_site_instance( | |
371 new_shell->web_contents()->GetSiteInstance()); | |
372 EXPECT_NE(orig_site_instance, new_site_instance); | |
373 | |
374 // Clicking the original link in the first tab should cause us to swap back. | |
375 TestNavigationObserver navigation_observer(new_shell->web_contents()); | |
376 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
377 shell()->web_contents(), | |
378 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
379 &success)); | |
380 EXPECT_TRUE(success); | |
381 navigation_observer.Wait(); | |
382 | |
383 // Should have swapped back and shown the new window again. | |
384 scoped_refptr<SiteInstance> revisit_site_instance( | |
385 new_shell->web_contents()->GetSiteInstance()); | |
386 EXPECT_EQ(orig_site_instance, revisit_site_instance); | |
387 | |
388 // If it navigates away to another process, the original window should | |
389 // still be able to close it (using a cross-process close message). | |
390 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
391 EXPECT_EQ(new_site_instance, | |
392 new_shell->web_contents()->GetSiteInstance()); | |
393 WebContentsDestroyedWatcher close_watcher(new_shell->web_contents()); | |
394 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
395 shell()->web_contents(), | |
396 "window.domAutomationController.send(testCloseWindow());", | |
397 &success)); | |
398 EXPECT_TRUE(success); | |
399 close_watcher.Wait(); | |
400 } | |
401 | |
402 // Test that setting the opener to null in a window affects cross-process | |
403 // navigations, including those to existing entries. http://crbug.com/156669. | |
404 // Flaky on windows: http://crbug.com/291249 | |
405 #if defined(OS_WIN) | |
406 #define MAYBE_DisownOpener DISABLED_DisownOpener | |
407 #else | |
408 #define MAYBE_DisownOpener DisownOpener | |
409 #endif | |
410 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, MAYBE_DisownOpener) { | |
411 // Start two servers with different sites. | |
412 ASSERT_TRUE(test_server()->Start()); | |
413 net::SpawnedTestServer https_server( | |
414 net::SpawnedTestServer::TYPE_HTTPS, | |
415 net::SpawnedTestServer::kLocalhost, | |
416 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
417 ASSERT_TRUE(https_server.Start()); | |
418 | |
419 // Load a page with links that open in a new window. | |
420 std::string replacement_path; | |
421 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
422 "files/click-noreferrer-links.html", | |
423 https_server.host_port_pair(), | |
424 &replacement_path)); | |
425 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
426 | |
427 // Get the original SiteInstance for later comparison. | |
428 scoped_refptr<SiteInstance> orig_site_instance( | |
429 shell()->web_contents()->GetSiteInstance()); | |
430 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
431 | |
432 // Test clicking a target=_blank link. | |
433 ShellAddedObserver new_shell_observer; | |
434 bool success = false; | |
435 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
436 shell()->web_contents(), | |
437 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", | |
438 &success)); | |
439 EXPECT_TRUE(success); | |
440 Shell* new_shell = new_shell_observer.GetShell(); | |
441 | |
442 // Wait for the navigation in the new tab to finish, if it hasn't. | |
443 WaitForLoadStop(new_shell->web_contents()); | |
444 EXPECT_EQ("/files/title2.html", | |
445 new_shell->web_contents()->GetLastCommittedURL().path()); | |
446 | |
447 // Should have the same SiteInstance. | |
448 scoped_refptr<SiteInstance> blank_site_instance( | |
449 new_shell->web_contents()->GetSiteInstance()); | |
450 EXPECT_EQ(orig_site_instance, blank_site_instance); | |
451 | |
452 // Now navigate the new tab to a different site. | |
453 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
454 scoped_refptr<SiteInstance> new_site_instance( | |
455 new_shell->web_contents()->GetSiteInstance()); | |
456 EXPECT_NE(orig_site_instance, new_site_instance); | |
457 | |
458 // Now disown the opener. | |
459 EXPECT_TRUE(ExecuteScript(new_shell->web_contents(), | |
460 "window.opener = null;")); | |
461 | |
462 // Go back and ensure the opener is still null. | |
463 { | |
464 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); | |
465 new_shell->web_contents()->GetController().GoBack(); | |
466 back_nav_load_observer.Wait(); | |
467 } | |
468 success = false; | |
469 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
470 new_shell->web_contents(), | |
471 "window.domAutomationController.send(window.opener == null);", | |
472 &success)); | |
473 EXPECT_TRUE(success); | |
474 | |
475 // Now navigate forward again (creating a new process) and check opener. | |
476 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
477 success = false; | |
478 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
479 new_shell->web_contents(), | |
480 "window.domAutomationController.send(window.opener == null);", | |
481 &success)); | |
482 EXPECT_TRUE(success); | |
483 } | |
484 | |
485 // Test that subframes can disown their openers. http://crbug.com/225528. | |
486 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, DisownSubframeOpener) { | |
487 const GURL frame_url("data:text/html,<iframe name=\"foo\"></iframe>"); | |
488 NavigateToURL(shell(), frame_url); | |
489 | |
490 // Give the frame an opener using window.open. | |
491 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), | |
492 "window.open('about:blank','foo');")); | |
493 | |
494 // Now disown the frame's opener. Shouldn't crash. | |
495 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), | |
496 "window.frames[0].opener = null;")); | |
497 } | |
498 | |
499 // Test for crbug.com/99202. PostMessage calls should still work after | |
500 // navigating the source and target windows to different sites. | |
501 // Specifically: | |
502 // 1) Create 3 windows (opener, "foo", and _blank) and send "foo" cross-process. | |
503 // 2) Fail to post a message from "foo" to opener with the wrong target origin. | |
504 // 3) Post a message from "foo" to opener, which replies back to "foo". | |
505 // 4) Post a message from _blank to "foo". | |
506 // 5) Post a message from "foo" to a subframe of opener, which replies back. | |
507 // 6) Post a message from _blank to a subframe of "foo". | |
508 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
509 SupportCrossProcessPostMessage) { | |
510 // Start two servers with different sites. | |
511 ASSERT_TRUE(test_server()->Start()); | |
512 net::SpawnedTestServer https_server( | |
513 net::SpawnedTestServer::TYPE_HTTPS, | |
514 net::SpawnedTestServer::kLocalhost, | |
515 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
516 ASSERT_TRUE(https_server.Start()); | |
517 | |
518 // Load a page with links that open in a new window. | |
519 std::string replacement_path; | |
520 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
521 "files/click-noreferrer-links.html", | |
522 https_server.host_port_pair(), | |
523 &replacement_path)); | |
524 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
525 | |
526 // Get the original SiteInstance and RVHM for later comparison. | |
527 WebContents* opener_contents = shell()->web_contents(); | |
528 scoped_refptr<SiteInstance> orig_site_instance( | |
529 opener_contents->GetSiteInstance()); | |
530 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
531 RenderViewHostManager* opener_manager = static_cast<WebContentsImpl*>( | |
532 opener_contents)->GetRenderManagerForTesting(); | |
533 | |
534 // 1) Open two more windows, one named. These initially have openers but no | |
535 // reference to each other. We will later post a message between them. | |
536 | |
537 // First, a named target=foo window. | |
538 ShellAddedObserver new_shell_observer; | |
539 bool success = false; | |
540 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
541 opener_contents, | |
542 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
543 &success)); | |
544 EXPECT_TRUE(success); | |
545 Shell* new_shell = new_shell_observer.GetShell(); | |
546 | |
547 // Wait for the navigation in the new window to finish, if it hasn't, then | |
548 // send it to post_message.html on a different site. | |
549 WebContents* foo_contents = new_shell->web_contents(); | |
550 WaitForLoadStop(foo_contents); | |
551 EXPECT_EQ("/files/navigate_opener.html", | |
552 foo_contents->GetLastCommittedURL().path()); | |
553 NavigateToURL(new_shell, https_server.GetURL("files/post_message.html")); | |
554 scoped_refptr<SiteInstance> foo_site_instance( | |
555 foo_contents->GetSiteInstance()); | |
556 EXPECT_NE(orig_site_instance, foo_site_instance); | |
557 | |
558 // Second, a target=_blank window. | |
559 ShellAddedObserver new_shell_observer2; | |
560 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
561 shell()->web_contents(), | |
562 "window.domAutomationController.send(clickSameSiteTargetBlankLink());", | |
563 &success)); | |
564 EXPECT_TRUE(success); | |
565 | |
566 // Wait for the navigation in the new window to finish, if it hasn't, then | |
567 // send it to post_message.html on the original site. | |
568 Shell* new_shell2 = new_shell_observer2.GetShell(); | |
569 WebContents* new_contents = new_shell2->web_contents(); | |
570 WaitForLoadStop(new_contents); | |
571 EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path()); | |
572 NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html")); | |
573 EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance()); | |
574 RenderViewHostManager* new_manager = | |
575 static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting(); | |
576 | |
577 // We now have three windows. The opener should have a swapped out RVH | |
578 // for the new SiteInstance, but the _blank window should not. | |
579 EXPECT_EQ(3u, Shell::windows().size()); | |
580 EXPECT_TRUE( | |
581 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); | |
582 EXPECT_FALSE( | |
583 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); | |
584 | |
585 // 2) Fail to post a message from the foo window to the opener if the target | |
586 // origin is wrong. We won't see an error, but we can check for the right | |
587 // number of received messages below. | |
588 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
589 foo_contents, | |
590 "window.domAutomationController.send(postToOpener('msg'," | |
591 " 'http://google.com'));", | |
592 &success)); | |
593 EXPECT_TRUE(success); | |
594 ASSERT_FALSE( | |
595 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); | |
596 | |
597 // 3) Post a message from the foo window to the opener. The opener will | |
598 // reply, causing the foo window to update its own title. | |
599 base::string16 expected_title = ASCIIToUTF16("msg"); | |
600 TitleWatcher title_watcher(foo_contents, expected_title); | |
601 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
602 foo_contents, | |
603 "window.domAutomationController.send(postToOpener('msg','*'));", | |
604 &success)); | |
605 EXPECT_TRUE(success); | |
606 ASSERT_FALSE( | |
607 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); | |
608 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); | |
609 | |
610 // We should have received only 1 message in the opener and "foo" tabs, | |
611 // and updated the title. | |
612 int opener_received_messages = 0; | |
613 EXPECT_TRUE(ExecuteScriptAndExtractInt( | |
614 opener_contents, | |
615 "window.domAutomationController.send(window.receivedMessages);", | |
616 &opener_received_messages)); | |
617 int foo_received_messages = 0; | |
618 EXPECT_TRUE(ExecuteScriptAndExtractInt( | |
619 foo_contents, | |
620 "window.domAutomationController.send(window.receivedMessages);", | |
621 &foo_received_messages)); | |
622 EXPECT_EQ(1, foo_received_messages); | |
623 EXPECT_EQ(1, opener_received_messages); | |
624 EXPECT_EQ(ASCIIToUTF16("msg"), foo_contents->GetTitle()); | |
625 | |
626 // 4) Now post a message from the _blank window to the foo window. The | |
627 // foo window will update its title and will not reply. | |
628 expected_title = ASCIIToUTF16("msg2"); | |
629 TitleWatcher title_watcher2(foo_contents, expected_title); | |
630 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
631 new_contents, | |
632 "window.domAutomationController.send(postToFoo('msg2'));", | |
633 &success)); | |
634 EXPECT_TRUE(success); | |
635 ASSERT_EQ(expected_title, title_watcher2.WaitAndGetTitle()); | |
636 | |
637 // This postMessage should have created a swapped out RVH for the new | |
638 // SiteInstance in the target=_blank window. | |
639 EXPECT_TRUE( | |
640 new_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); | |
641 | |
642 // TODO(nasko): Test subframe targeting of postMessage once | |
643 // http://crbug.com/153701 is fixed. | |
644 } | |
645 | |
646 // Test for crbug.com/278336. MessagePorts should work cross-process. I.e., | |
647 // messages which contain Transferables and get intercepted by | |
648 // RenderViewImpl::willCheckAndDispatchMessageEvent (because the RenderView is | |
649 // swapped out) should work. | |
650 // Specifically: | |
651 // 1) Create 2 windows (opener and "foo") and send "foo" cross-process. | |
652 // 2) Post a message containing a message port from opener to "foo". | |
653 // 3) Post a message from "foo" back to opener via the passed message port. | |
654 // The test will be enabled when the feature implementation lands. | |
655 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
656 SupportCrossProcessPostMessageWithMessagePort) { | |
657 // Start two servers with different sites. | |
658 ASSERT_TRUE(test_server()->Start()); | |
659 net::SpawnedTestServer https_server( | |
660 net::SpawnedTestServer::TYPE_HTTPS, | |
661 net::SpawnedTestServer::kLocalhost, | |
662 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
663 ASSERT_TRUE(https_server.Start()); | |
664 | |
665 // Load a page with links that open in a new window. | |
666 std::string replacement_path; | |
667 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
668 "files/click-noreferrer-links.html", | |
669 https_server.host_port_pair(), | |
670 &replacement_path)); | |
671 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
672 | |
673 // Get the original SiteInstance and RVHM for later comparison. | |
674 WebContents* opener_contents = shell()->web_contents(); | |
675 scoped_refptr<SiteInstance> orig_site_instance( | |
676 opener_contents->GetSiteInstance()); | |
677 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
678 RenderViewHostManager* opener_manager = static_cast<WebContentsImpl*>( | |
679 opener_contents)->GetRenderManagerForTesting(); | |
680 | |
681 // 1) Open a named target=foo window. We will later post a message between the | |
682 // opener and the new window. | |
683 ShellAddedObserver new_shell_observer; | |
684 bool success = false; | |
685 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
686 opener_contents, | |
687 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
688 &success)); | |
689 EXPECT_TRUE(success); | |
690 Shell* new_shell = new_shell_observer.GetShell(); | |
691 | |
692 // Wait for the navigation in the new window to finish, if it hasn't, then | |
693 // send it to post_message.html on a different site. | |
694 WebContents* foo_contents = new_shell->web_contents(); | |
695 WaitForLoadStop(foo_contents); | |
696 EXPECT_EQ("/files/navigate_opener.html", | |
697 foo_contents->GetLastCommittedURL().path()); | |
698 NavigateToURL( | |
699 new_shell, | |
700 https_server.GetURL("files/post_message.html")); | |
701 scoped_refptr<SiteInstance> foo_site_instance( | |
702 foo_contents->GetSiteInstance()); | |
703 EXPECT_NE(orig_site_instance, foo_site_instance); | |
704 | |
705 // We now have two windows. The opener should have a swapped out RVH | |
706 // for the new SiteInstance. | |
707 EXPECT_EQ(2u, Shell::windows().size()); | |
708 EXPECT_TRUE( | |
709 opener_manager->GetSwappedOutRenderViewHost(foo_site_instance.get())); | |
710 | |
711 // 2) Post a message containing a MessagePort from opener to the the foo | |
712 // window. The foo window will reply via the passed port, causing the opener | |
713 // to update its own title. | |
714 WindowedNotificationObserver title_observer( | |
715 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED, | |
716 Source<WebContents>(opener_contents)); | |
717 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
718 opener_contents, | |
719 "window.domAutomationController.send(postWithPortToFoo());", | |
720 &success)); | |
721 EXPECT_TRUE(success); | |
722 ASSERT_FALSE( | |
723 opener_manager->GetSwappedOutRenderViewHost(orig_site_instance.get())); | |
724 title_observer.Wait(); | |
725 | |
726 // Check message counts. | |
727 int opener_received_messages_via_port = 0; | |
728 EXPECT_TRUE(ExecuteScriptAndExtractInt( | |
729 opener_contents, | |
730 "window.domAutomationController.send(window.receivedMessagesViaPort);", | |
731 &opener_received_messages_via_port)); | |
732 int foo_received_messages = 0; | |
733 EXPECT_TRUE(ExecuteScriptAndExtractInt( | |
734 foo_contents, | |
735 "window.domAutomationController.send(window.receivedMessages);", | |
736 &foo_received_messages)); | |
737 int foo_received_messages_with_port = 0; | |
738 EXPECT_TRUE(ExecuteScriptAndExtractInt( | |
739 foo_contents, | |
740 "window.domAutomationController.send(window.receivedMessagesWithPort);", | |
741 &foo_received_messages_with_port)); | |
742 EXPECT_EQ(1, foo_received_messages); | |
743 EXPECT_EQ(1, foo_received_messages_with_port); | |
744 EXPECT_EQ(1, opener_received_messages_via_port); | |
745 EXPECT_EQ(ASCIIToUTF16("msg-with-port"), foo_contents->GetTitle()); | |
746 EXPECT_EQ(ASCIIToUTF16("msg-back-via-port"), opener_contents->GetTitle()); | |
747 } | |
748 | |
749 // Test for crbug.com/116192. Navigations to a window's opener should | |
750 // still work after a process swap. | |
751 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
752 AllowTargetedNavigationsInOpenerAfterSwap) { | |
753 // Start two servers with different sites. | |
754 ASSERT_TRUE(test_server()->Start()); | |
755 net::SpawnedTestServer https_server( | |
756 net::SpawnedTestServer::TYPE_HTTPS, | |
757 net::SpawnedTestServer::kLocalhost, | |
758 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
759 ASSERT_TRUE(https_server.Start()); | |
760 | |
761 // Load a page with links that open in a new window. | |
762 std::string replacement_path; | |
763 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
764 "files/click-noreferrer-links.html", | |
765 https_server.host_port_pair(), | |
766 &replacement_path)); | |
767 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
768 | |
769 // Get the original tab and SiteInstance for later comparison. | |
770 WebContents* orig_contents = shell()->web_contents(); | |
771 scoped_refptr<SiteInstance> orig_site_instance( | |
772 orig_contents->GetSiteInstance()); | |
773 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
774 | |
775 // Test clicking a target=foo link. | |
776 ShellAddedObserver new_shell_observer; | |
777 bool success = false; | |
778 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
779 orig_contents, | |
780 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
781 &success)); | |
782 EXPECT_TRUE(success); | |
783 Shell* new_shell = new_shell_observer.GetShell(); | |
784 | |
785 // Wait for the navigation in the new window to finish, if it hasn't. | |
786 WaitForLoadStop(new_shell->web_contents()); | |
787 EXPECT_EQ("/files/navigate_opener.html", | |
788 new_shell->web_contents()->GetLastCommittedURL().path()); | |
789 | |
790 // Should have the same SiteInstance. | |
791 scoped_refptr<SiteInstance> blank_site_instance( | |
792 new_shell->web_contents()->GetSiteInstance()); | |
793 EXPECT_EQ(orig_site_instance, blank_site_instance); | |
794 | |
795 // Now navigate the original (opener) tab to a different site. | |
796 NavigateToURL(shell(), https_server.GetURL("files/title1.html")); | |
797 scoped_refptr<SiteInstance> new_site_instance( | |
798 shell()->web_contents()->GetSiteInstance()); | |
799 EXPECT_NE(orig_site_instance, new_site_instance); | |
800 | |
801 // The opened tab should be able to navigate the opener back to its process. | |
802 TestNavigationObserver navigation_observer(orig_contents); | |
803 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
804 new_shell->web_contents(), | |
805 "window.domAutomationController.send(navigateOpener());", | |
806 &success)); | |
807 EXPECT_TRUE(success); | |
808 navigation_observer.Wait(); | |
809 | |
810 // Should have swapped back into this process. | |
811 scoped_refptr<SiteInstance> revisit_site_instance( | |
812 shell()->web_contents()->GetSiteInstance()); | |
813 EXPECT_EQ(orig_site_instance, revisit_site_instance); | |
814 } | |
815 | |
816 // Test that opening a new window in the same SiteInstance and then navigating | |
817 // both windows to a different SiteInstance allows the first process to exit. | |
818 // See http://crbug.com/126333. | |
819 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
820 ProcessExitWithSwappedOutViews) { | |
821 // Start two servers with different sites. | |
822 ASSERT_TRUE(test_server()->Start()); | |
823 net::SpawnedTestServer https_server( | |
824 net::SpawnedTestServer::TYPE_HTTPS, | |
825 net::SpawnedTestServer::kLocalhost, | |
826 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
827 ASSERT_TRUE(https_server.Start()); | |
828 | |
829 // Load a page with links that open in a new window. | |
830 std::string replacement_path; | |
831 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
832 "files/click-noreferrer-links.html", | |
833 https_server.host_port_pair(), | |
834 &replacement_path)); | |
835 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
836 | |
837 // Get the original SiteInstance for later comparison. | |
838 scoped_refptr<SiteInstance> orig_site_instance( | |
839 shell()->web_contents()->GetSiteInstance()); | |
840 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
841 | |
842 // Test clicking a target=foo link. | |
843 ShellAddedObserver new_shell_observer; | |
844 bool success = false; | |
845 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
846 shell()->web_contents(), | |
847 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
848 &success)); | |
849 EXPECT_TRUE(success); | |
850 Shell* new_shell = new_shell_observer.GetShell(); | |
851 | |
852 // Wait for the navigation in the new window to finish, if it hasn't. | |
853 WaitForLoadStop(new_shell->web_contents()); | |
854 EXPECT_EQ("/files/navigate_opener.html", | |
855 new_shell->web_contents()->GetLastCommittedURL().path()); | |
856 | |
857 // Should have the same SiteInstance. | |
858 scoped_refptr<SiteInstance> opened_site_instance( | |
859 new_shell->web_contents()->GetSiteInstance()); | |
860 EXPECT_EQ(orig_site_instance, opened_site_instance); | |
861 | |
862 // Now navigate the opened window to a different site. | |
863 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
864 scoped_refptr<SiteInstance> new_site_instance( | |
865 new_shell->web_contents()->GetSiteInstance()); | |
866 EXPECT_NE(orig_site_instance, new_site_instance); | |
867 | |
868 // The original process should still be alive, since it is still used in the | |
869 // first window. | |
870 RenderProcessHost* orig_process = orig_site_instance->GetProcess(); | |
871 EXPECT_TRUE(orig_process->HasConnection()); | |
872 | |
873 // Navigate the first window to a different site as well. The original | |
874 // process should exit, since all of its views are now swapped out. | |
875 WindowedNotificationObserver exit_observer( | |
876 NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
877 Source<RenderProcessHost>(orig_process)); | |
878 NavigateToURL(shell(), https_server.GetURL("files/title1.html")); | |
879 exit_observer.Wait(); | |
880 scoped_refptr<SiteInstance> new_site_instance2( | |
881 shell()->web_contents()->GetSiteInstance()); | |
882 EXPECT_EQ(new_site_instance, new_site_instance2); | |
883 } | |
884 | |
885 // Test for crbug.com/76666. A cross-site navigation that fails with a 204 | |
886 // error should not make us ignore future renderer-initiated navigations. | |
887 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, ClickLinkAfter204Error) { | |
888 // Start two servers with different sites. | |
889 ASSERT_TRUE(test_server()->Start()); | |
890 net::SpawnedTestServer https_server( | |
891 net::SpawnedTestServer::TYPE_HTTPS, | |
892 net::SpawnedTestServer::kLocalhost, | |
893 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
894 ASSERT_TRUE(https_server.Start()); | |
895 | |
896 // Load a page with links that open in a new window. | |
897 // The links will point to the HTTPS server. | |
898 std::string replacement_path; | |
899 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
900 "files/click-noreferrer-links.html", | |
901 https_server.host_port_pair(), | |
902 &replacement_path)); | |
903 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
904 | |
905 // Get the original SiteInstance for later comparison. | |
906 scoped_refptr<SiteInstance> orig_site_instance( | |
907 shell()->web_contents()->GetSiteInstance()); | |
908 EXPECT_TRUE(orig_site_instance.get() != NULL); | |
909 | |
910 // Load a cross-site page that fails with a 204 error. | |
911 NavigateToURL(shell(), https_server.GetURL("nocontent")); | |
912 | |
913 // We should still be looking at the normal page. The typed URL will | |
914 // still be visible until the user clears it manually, but the last | |
915 // committed URL will be the previous page. | |
916 scoped_refptr<SiteInstance> post_nav_site_instance( | |
917 shell()->web_contents()->GetSiteInstance()); | |
918 EXPECT_EQ(orig_site_instance, post_nav_site_instance); | |
919 EXPECT_EQ("/nocontent", | |
920 shell()->web_contents()->GetVisibleURL().path()); | |
921 EXPECT_EQ("/files/click-noreferrer-links.html", | |
922 shell()->web_contents()->GetController(). | |
923 GetLastCommittedEntry()->GetVirtualURL().path()); | |
924 | |
925 // Renderer-initiated navigations should work. | |
926 bool success = false; | |
927 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
928 shell()->web_contents(), | |
929 "window.domAutomationController.send(clickNoRefLink());", | |
930 &success)); | |
931 EXPECT_TRUE(success); | |
932 | |
933 // Wait for the cross-site transition in the current tab to finish. | |
934 WaitForLoadStop(shell()->web_contents()); | |
935 | |
936 // Opens in same tab. | |
937 EXPECT_EQ(1u, Shell::windows().size()); | |
938 EXPECT_EQ("/files/title2.html", | |
939 shell()->web_contents()->GetLastCommittedURL().path()); | |
940 | |
941 // Should have the same SiteInstance. | |
942 scoped_refptr<SiteInstance> noref_site_instance( | |
943 shell()->web_contents()->GetSiteInstance()); | |
944 EXPECT_EQ(orig_site_instance, noref_site_instance); | |
945 } | |
946 | |
947 // Test for crbug.com/9682. We should show the URL for a pending renderer- | |
948 // initiated navigation in a new tab, until the content of the initial | |
949 // about:blank page is modified by another window. At that point, we should | |
950 // revert to showing about:blank to prevent a URL spoof. | |
951 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, ShowLoadingURLUntilSpoof) { | |
952 ASSERT_TRUE(test_server()->Start()); | |
953 | |
954 // Load a page that can open a URL that won't commit in a new window. | |
955 NavigateToURL( | |
956 shell(), test_server()->GetURL("files/click-nocontent-link.html")); | |
957 WebContents* orig_contents = shell()->web_contents(); | |
958 | |
959 // Click a /nocontent link that opens in a new window but never commits. | |
960 ShellAddedObserver new_shell_observer; | |
961 bool success = false; | |
962 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
963 orig_contents, | |
964 "window.domAutomationController.send(clickNoContentTargetedLink());", | |
965 &success)); | |
966 EXPECT_TRUE(success); | |
967 | |
968 // Wait for the window to open. | |
969 Shell* new_shell = new_shell_observer.GetShell(); | |
970 | |
971 // Ensure the destination URL is visible, because it is considered the | |
972 // initial navigation. | |
973 WebContents* contents = new_shell->web_contents(); | |
974 EXPECT_TRUE(contents->GetController().IsInitialNavigation()); | |
975 EXPECT_EQ("/nocontent", | |
976 contents->GetController().GetVisibleEntry()->GetURL().path()); | |
977 | |
978 // Now modify the contents of the new window from the opener. This will also | |
979 // modify the title of the document to give us something to listen for. | |
980 base::string16 expected_title = ASCIIToUTF16("Modified Title"); | |
981 TitleWatcher title_watcher(contents, expected_title); | |
982 success = false; | |
983 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
984 orig_contents, | |
985 "window.domAutomationController.send(modifyNewWindow());", | |
986 &success)); | |
987 EXPECT_TRUE(success); | |
988 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); | |
989 | |
990 // At this point, we should no longer be showing the destination URL. | |
991 // The visible entry should be null, resulting in about:blank in the address | |
992 // bar. | |
993 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); | |
994 } | |
995 | |
996 // Test for crbug.com/9682. We should not show the URL for a pending renderer- | |
997 // initiated navigation in a new tab if it is not the initial navigation. In | |
998 // this case, the renderer will not notify us of a modification, so we cannot | |
999 // show the pending URL without allowing a spoof. | |
1000 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
1001 DontShowLoadingURLIfNotInitialNav) { | |
1002 ASSERT_TRUE(test_server()->Start()); | |
1003 | |
1004 // Load a page that can open a URL that won't commit in a new window. | |
1005 NavigateToURL( | |
1006 shell(), test_server()->GetURL("files/click-nocontent-link.html")); | |
1007 WebContents* orig_contents = shell()->web_contents(); | |
1008 | |
1009 // Click a /nocontent link that opens in a new window but never commits. | |
1010 // By using an onclick handler that first creates the window, the slow | |
1011 // navigation is not considered an initial navigation. | |
1012 ShellAddedObserver new_shell_observer; | |
1013 bool success = false; | |
1014 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1015 orig_contents, | |
1016 "window.domAutomationController.send(" | |
1017 "clickNoContentScriptedTargetedLink());", | |
1018 &success)); | |
1019 EXPECT_TRUE(success); | |
1020 | |
1021 // Wait for the window to open. | |
1022 Shell* new_shell = new_shell_observer.GetShell(); | |
1023 | |
1024 // Ensure the destination URL is not visible, because it is not the initial | |
1025 // navigation. | |
1026 WebContents* contents = new_shell->web_contents(); | |
1027 EXPECT_FALSE(contents->GetController().IsInitialNavigation()); | |
1028 EXPECT_FALSE(contents->GetController().GetVisibleEntry()); | |
1029 } | |
1030 | |
1031 // Test for http://crbug.com/93427. Ensure that cross-site navigations | |
1032 // do not cause back/forward navigations to be considered stale by the | |
1033 // renderer. | |
1034 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, BackForwardNotStale) { | |
1035 NavigateToURL(shell(), GURL(kAboutBlankURL)); | |
1036 | |
1037 // Start two servers with different sites. | |
1038 ASSERT_TRUE(test_server()->Start()); | |
1039 net::SpawnedTestServer https_server( | |
1040 net::SpawnedTestServer::TYPE_HTTPS, | |
1041 net::SpawnedTestServer::kLocalhost, | |
1042 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
1043 ASSERT_TRUE(https_server.Start()); | |
1044 | |
1045 // Visit a page on first site. | |
1046 std::string replacement_path_a1; | |
1047 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
1048 "files/title1.html", | |
1049 test_server()->host_port_pair(), | |
1050 &replacement_path_a1)); | |
1051 NavigateToURL(shell(), test_server()->GetURL(replacement_path_a1)); | |
1052 | |
1053 // Visit three pages on second site. | |
1054 std::string replacement_path_b1; | |
1055 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
1056 "files/title1.html", | |
1057 https_server.host_port_pair(), | |
1058 &replacement_path_b1)); | |
1059 NavigateToURL(shell(), https_server.GetURL(replacement_path_b1)); | |
1060 std::string replacement_path_b2; | |
1061 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
1062 "files/title2.html", | |
1063 https_server.host_port_pair(), | |
1064 &replacement_path_b2)); | |
1065 NavigateToURL(shell(), https_server.GetURL(replacement_path_b2)); | |
1066 std::string replacement_path_b3; | |
1067 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
1068 "files/title3.html", | |
1069 https_server.host_port_pair(), | |
1070 &replacement_path_b3)); | |
1071 NavigateToURL(shell(), https_server.GetURL(replacement_path_b3)); | |
1072 | |
1073 // History is now [blank, A1, B1, B2, *B3]. | |
1074 WebContents* contents = shell()->web_contents(); | |
1075 EXPECT_EQ(5, contents->GetController().GetEntryCount()); | |
1076 | |
1077 // Open another window in same process to keep this process alive. | |
1078 Shell* new_shell = CreateBrowser(); | |
1079 NavigateToURL(new_shell, https_server.GetURL(replacement_path_b1)); | |
1080 | |
1081 // Go back three times to first site. | |
1082 { | |
1083 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); | |
1084 shell()->web_contents()->GetController().GoBack(); | |
1085 back_nav_load_observer.Wait(); | |
1086 } | |
1087 { | |
1088 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); | |
1089 shell()->web_contents()->GetController().GoBack(); | |
1090 back_nav_load_observer.Wait(); | |
1091 } | |
1092 { | |
1093 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); | |
1094 shell()->web_contents()->GetController().GoBack(); | |
1095 back_nav_load_observer.Wait(); | |
1096 } | |
1097 | |
1098 // Now go forward twice to B2. Shouldn't be left spinning. | |
1099 { | |
1100 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); | |
1101 shell()->web_contents()->GetController().GoForward(); | |
1102 forward_nav_load_observer.Wait(); | |
1103 } | |
1104 { | |
1105 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); | |
1106 shell()->web_contents()->GetController().GoForward(); | |
1107 forward_nav_load_observer.Wait(); | |
1108 } | |
1109 | |
1110 // Go back twice to first site. | |
1111 { | |
1112 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); | |
1113 shell()->web_contents()->GetController().GoBack(); | |
1114 back_nav_load_observer.Wait(); | |
1115 } | |
1116 { | |
1117 TestNavigationObserver back_nav_load_observer(shell()->web_contents()); | |
1118 shell()->web_contents()->GetController().GoBack(); | |
1119 back_nav_load_observer.Wait(); | |
1120 } | |
1121 | |
1122 // Now go forward directly to B3. Shouldn't be left spinning. | |
1123 { | |
1124 TestNavigationObserver forward_nav_load_observer(shell()->web_contents()); | |
1125 shell()->web_contents()->GetController().GoToIndex(4); | |
1126 forward_nav_load_observer.Wait(); | |
1127 } | |
1128 } | |
1129 | |
1130 // Test for http://crbug.com/130016. | |
1131 // Swapping out a render view should update its visiblity state. | |
1132 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
1133 SwappedOutViewHasCorrectVisibilityState) { | |
1134 // Start two servers with different sites. | |
1135 ASSERT_TRUE(test_server()->Start()); | |
1136 net::SpawnedTestServer https_server( | |
1137 net::SpawnedTestServer::TYPE_HTTPS, | |
1138 net::SpawnedTestServer::kLocalhost, | |
1139 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
1140 ASSERT_TRUE(https_server.Start()); | |
1141 | |
1142 // Load a page with links that open in a new window. | |
1143 std::string replacement_path; | |
1144 ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( | |
1145 "files/click-noreferrer-links.html", | |
1146 https_server.host_port_pair(), | |
1147 &replacement_path)); | |
1148 NavigateToURL(shell(), test_server()->GetURL(replacement_path)); | |
1149 | |
1150 // Open a same-site link in a new widnow. | |
1151 ShellAddedObserver new_shell_observer; | |
1152 bool success = false; | |
1153 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1154 shell()->web_contents(), | |
1155 "window.domAutomationController.send(clickSameSiteTargetedLink());", | |
1156 &success)); | |
1157 EXPECT_TRUE(success); | |
1158 Shell* new_shell = new_shell_observer.GetShell(); | |
1159 | |
1160 // Wait for the navigation in the new tab to finish, if it hasn't. | |
1161 WaitForLoadStop(new_shell->web_contents()); | |
1162 EXPECT_EQ("/files/navigate_opener.html", | |
1163 new_shell->web_contents()->GetLastCommittedURL().path()); | |
1164 | |
1165 RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost(); | |
1166 | |
1167 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1168 rvh, | |
1169 "window.domAutomationController.send(" | |
1170 " document.visibilityState == 'visible');", | |
1171 &success)); | |
1172 EXPECT_TRUE(success); | |
1173 | |
1174 // Now navigate the new window to a different site. This should swap out the | |
1175 // tab's existing RenderView, causing it become hidden. | |
1176 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
1177 | |
1178 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1179 rvh, | |
1180 "window.domAutomationController.send(" | |
1181 " document.visibilityState == 'hidden');", | |
1182 &success)); | |
1183 EXPECT_TRUE(success); | |
1184 | |
1185 // Going back should make the previously swapped-out view to become visible | |
1186 // again. | |
1187 { | |
1188 TestNavigationObserver back_nav_load_observer(new_shell->web_contents()); | |
1189 new_shell->web_contents()->GetController().GoBack(); | |
1190 back_nav_load_observer.Wait(); | |
1191 } | |
1192 | |
1193 EXPECT_EQ("/files/navigate_opener.html", | |
1194 new_shell->web_contents()->GetLastCommittedURL().path()); | |
1195 | |
1196 EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost()); | |
1197 | |
1198 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1199 rvh, | |
1200 "window.domAutomationController.send(" | |
1201 " document.visibilityState == 'visible');", | |
1202 &success)); | |
1203 EXPECT_TRUE(success); | |
1204 } | |
1205 | |
1206 // This class ensures that all the given RenderViewHosts have properly been | |
1207 // shutdown. | |
1208 class RenderViewHostDestructionObserver : public WebContentsObserver { | |
1209 public: | |
1210 explicit RenderViewHostDestructionObserver(WebContents* web_contents) | |
1211 : WebContentsObserver(web_contents) {} | |
1212 virtual ~RenderViewHostDestructionObserver() {} | |
1213 void EnsureRVHGetsDestructed(RenderViewHost* rvh) { | |
1214 watched_render_view_hosts_.insert(rvh); | |
1215 } | |
1216 size_t GetNumberOfWatchedRenderViewHosts() const { | |
1217 return watched_render_view_hosts_.size(); | |
1218 } | |
1219 | |
1220 private: | |
1221 // WebContentsObserver implementation: | |
1222 virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE { | |
1223 watched_render_view_hosts_.erase(rvh); | |
1224 } | |
1225 | |
1226 std::set<RenderViewHost*> watched_render_view_hosts_; | |
1227 }; | |
1228 | |
1229 // Test for crbug.com/90867. Make sure we don't leak render view hosts since | |
1230 // they may cause crashes or memory corruptions when trying to call dead | |
1231 // delegate_. This test also verifies crbug.com/117420 and crbug.com/143255 to | |
1232 // ensure that a separate SiteInstance is created when navigating to view-source | |
1233 // URLs, regardless of current URL. | |
1234 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, LeakingRenderViewHosts) { | |
1235 // Start two servers with different sites. | |
1236 ASSERT_TRUE(test_server()->Start()); | |
1237 net::SpawnedTestServer https_server( | |
1238 net::SpawnedTestServer::TYPE_HTTPS, | |
1239 net::SpawnedTestServer::kLocalhost, | |
1240 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
1241 ASSERT_TRUE(https_server.Start()); | |
1242 | |
1243 // Observe the created render_view_host's to make sure they will not leak. | |
1244 RenderViewHostDestructionObserver rvh_observers(shell()->web_contents()); | |
1245 | |
1246 GURL navigated_url(test_server()->GetURL("files/title2.html")); | |
1247 GURL view_source_url(kViewSourceScheme + std::string(":") + | |
1248 navigated_url.spec()); | |
1249 | |
1250 // Let's ensure that when we start with a blank window, navigating away to a | |
1251 // view-source URL, we create a new SiteInstance. | |
1252 RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost(); | |
1253 SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance(); | |
1254 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL()); | |
1255 EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL()); | |
1256 rvh_observers.EnsureRVHGetsDestructed(blank_rvh); | |
1257 | |
1258 // Now navigate to the view-source URL and ensure we got a different | |
1259 // SiteInstance and RenderViewHost. | |
1260 NavigateToURL(shell(), view_source_url); | |
1261 EXPECT_NE(blank_rvh, shell()->web_contents()->GetRenderViewHost()); | |
1262 EXPECT_NE(blank_site_instance, shell()->web_contents()-> | |
1263 GetRenderViewHost()->GetSiteInstance()); | |
1264 rvh_observers.EnsureRVHGetsDestructed( | |
1265 shell()->web_contents()->GetRenderViewHost()); | |
1266 | |
1267 // Load a random page and then navigate to view-source: of it. | |
1268 // This used to cause two RVH instances for the same SiteInstance, which | |
1269 // was a problem. This is no longer the case. | |
1270 NavigateToURL(shell(), navigated_url); | |
1271 SiteInstance* site_instance1 = shell()->web_contents()-> | |
1272 GetRenderViewHost()->GetSiteInstance(); | |
1273 rvh_observers.EnsureRVHGetsDestructed( | |
1274 shell()->web_contents()->GetRenderViewHost()); | |
1275 | |
1276 NavigateToURL(shell(), view_source_url); | |
1277 rvh_observers.EnsureRVHGetsDestructed( | |
1278 shell()->web_contents()->GetRenderViewHost()); | |
1279 SiteInstance* site_instance2 = shell()->web_contents()-> | |
1280 GetRenderViewHost()->GetSiteInstance(); | |
1281 | |
1282 // Ensure that view-source navigations force a new SiteInstance. | |
1283 EXPECT_NE(site_instance1, site_instance2); | |
1284 | |
1285 // Now navigate to a different instance so that we swap out again. | |
1286 NavigateToURL(shell(), https_server.GetURL("files/title2.html")); | |
1287 rvh_observers.EnsureRVHGetsDestructed( | |
1288 shell()->web_contents()->GetRenderViewHost()); | |
1289 | |
1290 // This used to leak a render view host. | |
1291 shell()->Close(); | |
1292 | |
1293 RunAllPendingInMessageLoop(); // Needed on ChromeOS. | |
1294 | |
1295 EXPECT_EQ(0U, rvh_observers.GetNumberOfWatchedRenderViewHosts()); | |
1296 } | |
1297 | |
1298 // Test for crbug.com/143155. Frame tree updates during unload should not | |
1299 // interrupt the intended navigation and show swappedout:// instead. | |
1300 // Specifically: | |
1301 // 1) Open 2 tabs in an HTTP SiteInstance, with a subframe in the opener. | |
1302 // 2) Send the second tab to a different HTTPS SiteInstance. | |
1303 // This creates a swapped out opener for the first tab in the HTTPS process. | |
1304 // 3) Navigate the first tab to the HTTPS SiteInstance, and have the first | |
1305 // tab's unload handler remove its frame. | |
1306 // This used to cause an update to the frame tree of the swapped out RV, | |
1307 // just as it was navigating to a real page. That pre-empted the real | |
1308 // navigation and visibly sent the tab to swappedout://. | |
1309 IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, | |
1310 DontPreemptNavigationWithFrameTreeUpdate) { | |
1311 // Start two servers with different sites. | |
1312 ASSERT_TRUE(test_server()->Start()); | |
1313 net::SpawnedTestServer https_server( | |
1314 net::SpawnedTestServer::TYPE_HTTPS, | |
1315 net::SpawnedTestServer::kLocalhost, | |
1316 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); | |
1317 ASSERT_TRUE(https_server.Start()); | |
1318 | |
1319 // 1. Load a page that deletes its iframe during unload. | |
1320 NavigateToURL(shell(), | |
1321 test_server()->GetURL("files/remove_frame_on_unload.html")); | |
1322 | |
1323 // Get the original SiteInstance for later comparison. | |
1324 scoped_refptr<SiteInstance> orig_site_instance( | |
1325 shell()->web_contents()->GetSiteInstance()); | |
1326 | |
1327 // Open a same-site page in a new window. | |
1328 ShellAddedObserver new_shell_observer; | |
1329 bool success = false; | |
1330 EXPECT_TRUE(ExecuteScriptAndExtractBool( | |
1331 shell()->web_contents(), | |
1332 "window.domAutomationController.send(openWindow());", | |
1333 &success)); | |
1334 EXPECT_TRUE(success); | |
1335 Shell* new_shell = new_shell_observer.GetShell(); | |
1336 | |
1337 // Wait for the navigation in the new window to finish, if it hasn't. | |
1338 WaitForLoadStop(new_shell->web_contents()); | |
1339 EXPECT_EQ("/files/title1.html", | |
1340 new_shell->web_contents()->GetLastCommittedURL().path()); | |
1341 | |
1342 // Should have the same SiteInstance. | |
1343 EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance()); | |
1344 | |
1345 // 2. Send the second tab to a different process. | |
1346 NavigateToURL(new_shell, https_server.GetURL("files/title1.html")); | |
1347 scoped_refptr<SiteInstance> new_site_instance( | |
1348 new_shell->web_contents()->GetSiteInstance()); | |
1349 EXPECT_NE(orig_site_instance, new_site_instance); | |
1350 | |
1351 // 3. Send the first tab to the second tab's process. | |
1352 NavigateToURL(shell(), https_server.GetURL("files/title1.html")); | |
1353 | |
1354 // Make sure it ends up at the right page. | |
1355 WaitForLoadStop(shell()->web_contents()); | |
1356 EXPECT_EQ(https_server.GetURL("files/title1.html"), | |
1357 shell()->web_contents()->GetLastCommittedURL()); | |
1358 EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance()); | |
1359 } | |
1360 | |
1361 } // namespace content | |
OLD | NEW |