OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
6 #include "base/strings/stringprintf.h" | 6 #include "base/strings/stringprintf.h" |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "content/browser/frame_host/frame_tree.h" | 7 #include "content/browser/frame_host/frame_tree.h" |
9 #include "content/browser/loader/resource_dispatcher_host_impl.h" | |
10 #include "content/browser/renderer_host/render_view_host_impl.h" | 8 #include "content/browser/renderer_host/render_view_host_impl.h" |
11 #include "content/browser/web_contents/web_contents_impl.h" | 9 #include "content/browser/web_contents/web_contents_impl.h" |
12 #include "content/public/browser/navigation_entry.h" | |
13 #include "content/public/browser/notification_observer.h" | 10 #include "content/public/browser/notification_observer.h" |
14 #include "content/public/browser/notification_service.h" | 11 #include "content/public/browser/notification_service.h" |
15 #include "content/public/browser/notification_types.h" | 12 #include "content/public/browser/notification_types.h" |
16 #include "content/public/browser/resource_dispatcher_host_delegate.h" | |
17 #include "content/public/browser/resource_throttle.h" | |
18 #include "content/public/browser/web_contents_observer.h" | 13 #include "content/public/browser/web_contents_observer.h" |
19 #include "content/public/common/content_switches.h" | 14 #include "content/public/common/content_switches.h" |
20 #include "content/public/common/url_constants.h" | |
21 #include "content/public/test/browser_test_utils.h" | 15 #include "content/public/test/browser_test_utils.h" |
22 #include "content/public/test/test_navigation_observer.h" | |
23 #include "content/public/test/test_utils.h" | 16 #include "content/public/test/test_utils.h" |
24 #include "content/shell/browser/shell.h" | 17 #include "content/shell/browser/shell.h" |
25 #include "content/shell/browser/shell_content_browser_client.h" | |
26 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h" | |
27 #include "content/test/content_browser_test.h" | 18 #include "content/test/content_browser_test.h" |
28 #include "content/test/content_browser_test_utils.h" | 19 #include "content/test/content_browser_test_utils.h" |
29 #include "net/base/escape.h" | |
30 #include "net/dns/mock_host_resolver.h" | 20 #include "net/dns/mock_host_resolver.h" |
31 #include "net/url_request/url_request.h" | 21 #include "url/gurl.h" |
32 #include "net/url_request/url_request_status.h" | |
33 | 22 |
34 namespace content { | 23 namespace content { |
35 | 24 |
36 class SitePerProcessWebContentsObserver: public WebContentsObserver { | 25 class SitePerProcessWebContentsObserver: public WebContentsObserver { |
37 public: | 26 public: |
38 explicit SitePerProcessWebContentsObserver(WebContents* web_contents) | 27 explicit SitePerProcessWebContentsObserver(WebContents* web_contents) |
39 : WebContentsObserver(web_contents), | 28 : WebContentsObserver(web_contents), |
40 navigation_succeeded_(false) {} | 29 navigation_succeeded_(false) {} |
41 virtual ~SitePerProcessWebContentsObserver() {} | 30 virtual ~SitePerProcessWebContentsObserver() {} |
42 | 31 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 details_ = details; | 147 details_ = details; |
159 seen_twice_ = seen_; | 148 seen_twice_ = seen_; |
160 seen_ = true; | 149 seen_ = true; |
161 if (!running_) | 150 if (!running_) |
162 return; | 151 return; |
163 | 152 |
164 message_loop_runner_->Quit(); | 153 message_loop_runner_->Quit(); |
165 running_ = false; | 154 running_ = false; |
166 } | 155 } |
167 | 156 |
168 // Tracks a single request for a specified URL, and allows waiting until the | |
169 // request is destroyed, and then inspecting whether it completed successfully. | |
170 class TrackingResourceDispatcherHostDelegate | |
171 : public ShellResourceDispatcherHostDelegate { | |
172 public: | |
173 TrackingResourceDispatcherHostDelegate() : throttle_created_(false) { | |
174 } | |
175 | |
176 virtual void RequestBeginning( | |
177 net::URLRequest* request, | |
178 ResourceContext* resource_context, | |
179 appcache::AppCacheService* appcache_service, | |
180 ResourceType::Type resource_type, | |
181 int child_id, | |
182 int route_id, | |
183 ScopedVector<ResourceThrottle>* throttles) OVERRIDE { | |
184 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
185 ShellResourceDispatcherHostDelegate::RequestBeginning( | |
186 request, resource_context, appcache_service, resource_type, child_id, | |
187 route_id, throttles); | |
188 // Expect only a single request for the tracked url. | |
189 ASSERT_FALSE(throttle_created_); | |
190 // If this is a request for the tracked URL, add a throttle to track it. | |
191 if (request->url() == tracked_url_) | |
192 throttles->push_back(new TrackingThrottle(request, this)); | |
193 } | |
194 | |
195 // Starts tracking a URL. The request for previously tracked URL, if any, | |
196 // must have been made and deleted before calling this function. | |
197 void SetTrackedURL(const GURL& tracked_url) { | |
198 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
199 // Should not currently be tracking any URL. | |
200 ASSERT_FALSE(run_loop_); | |
201 | |
202 // Create a RunLoop that will be stopped once the request for the tracked | |
203 // URL has been destroyed, to allow tracking the URL while also waiting for | |
204 // other events. | |
205 run_loop_.reset(new base::RunLoop()); | |
206 | |
207 BrowserThread::PostTask( | |
208 BrowserThread::IO, FROM_HERE, | |
209 base::Bind( | |
210 &TrackingResourceDispatcherHostDelegate::SetTrackedURLOnIOThread, | |
211 base::Unretained(this), | |
212 tracked_url)); | |
213 } | |
214 | |
215 // Waits until the tracked URL has been requests, and the request for it has | |
216 // been destroyed. | |
217 bool WaitForTrackedURLAndGetCompleted() { | |
218 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
219 run_loop_->Run(); | |
220 run_loop_.reset(); | |
221 return tracked_request_completed_; | |
222 } | |
223 | |
224 private: | |
225 // ResourceThrottle attached to request for the tracked URL. On destruction, | |
226 // passes the final URLRequestStatus back to the delegate. | |
227 class TrackingThrottle : public ResourceThrottle { | |
228 public: | |
229 TrackingThrottle(net::URLRequest* request, | |
230 TrackingResourceDispatcherHostDelegate* tracker) | |
231 : request_(request), tracker_(tracker) { | |
232 } | |
233 | |
234 virtual ~TrackingThrottle() { | |
235 // If the request is deleted without being cancelled, its status will | |
236 // indicate it succeeded, so have to check if the request is still pending | |
237 // as well. | |
238 tracker_->OnTrackedRequestDestroyed( | |
239 !request_->is_pending() && request_->status().is_success()); | |
240 } | |
241 | |
242 // ResourceThrottle implementation: | |
243 virtual const char* GetNameForLogging() const OVERRIDE { | |
244 return "TrackingThrottle"; | |
245 } | |
246 | |
247 private: | |
248 net::URLRequest* request_; | |
249 TrackingResourceDispatcherHostDelegate* tracker_; | |
250 | |
251 DISALLOW_COPY_AND_ASSIGN(TrackingThrottle); | |
252 }; | |
253 | |
254 void SetTrackedURLOnIOThread(const GURL& tracked_url) { | |
255 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
256 throttle_created_ = false; | |
257 tracked_url_ = tracked_url; | |
258 } | |
259 | |
260 void OnTrackedRequestDestroyed(bool completed) { | |
261 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
262 tracked_request_completed_ = completed; | |
263 tracked_url_ = GURL(); | |
264 | |
265 BrowserThread::PostTask( | |
266 BrowserThread::UI, FROM_HERE, run_loop_->QuitClosure()); | |
267 } | |
268 | |
269 // These live on the IO thread. | |
270 GURL tracked_url_; | |
271 bool throttle_created_; | |
272 | |
273 // This is created and destroyed on the UI thread, but stopped on the IO | |
274 // thread. | |
275 scoped_ptr<base::RunLoop> run_loop_; | |
276 | |
277 // Set on the IO thread while |run_loop_| is non-NULL, read on the UI thread | |
278 // after deleting run_loop_. | |
279 bool tracked_request_completed_; | |
280 | |
281 DISALLOW_COPY_AND_ASSIGN(TrackingResourceDispatcherHostDelegate); | |
282 }; | |
283 | |
284 // WebContentsDelegate that fails to open a URL when there's a request that | |
285 // needs to be transferred between renderers. | |
286 class NoTransferRequestDelegate : public WebContentsDelegate { | |
287 public: | |
288 NoTransferRequestDelegate() {} | |
289 | |
290 virtual WebContents* OpenURLFromTab(WebContents* source, | |
291 const OpenURLParams& params) OVERRIDE { | |
292 bool is_transfer = | |
293 (params.transferred_global_request_id != GlobalRequestID()); | |
294 if (is_transfer) | |
295 return NULL; | |
296 NavigationController::LoadURLParams load_url_params(params.url); | |
297 load_url_params.referrer = params.referrer; | |
298 load_url_params.frame_tree_node_id = params.frame_tree_node_id; | |
299 load_url_params.transition_type = params.transition; | |
300 load_url_params.extra_headers = params.extra_headers; | |
301 load_url_params.should_replace_current_entry = | |
302 params.should_replace_current_entry; | |
303 load_url_params.is_renderer_initiated = true; | |
304 source->GetController().LoadURLWithParams(load_url_params); | |
305 return source; | |
306 } | |
307 | |
308 private: | |
309 DISALLOW_COPY_AND_ASSIGN(NoTransferRequestDelegate); | |
310 }; | |
311 | |
312 class SitePerProcessBrowserTest : public ContentBrowserTest { | 157 class SitePerProcessBrowserTest : public ContentBrowserTest { |
313 public: | 158 public: |
314 SitePerProcessBrowserTest() : old_delegate_(NULL) { | 159 SitePerProcessBrowserTest() {} |
315 } | |
316 | |
317 // ContentBrowserTest implementation: | |
318 virtual void SetUpOnMainThread() OVERRIDE { | |
319 BrowserThread::PostTask( | |
320 BrowserThread::IO, FROM_HERE, | |
321 base::Bind( | |
322 &SitePerProcessBrowserTest::InjectResourceDisptcherHostDelegate, | |
323 base::Unretained(this))); | |
324 } | |
325 | |
326 virtual void TearDownOnMainThread() OVERRIDE { | |
327 BrowserThread::PostTask( | |
328 BrowserThread::IO, FROM_HERE, | |
329 base::Bind( | |
330 &SitePerProcessBrowserTest::RestoreResourceDisptcherHostDelegate, | |
331 base::Unretained(this))); | |
332 } | |
333 | 160 |
334 protected: | 161 protected: |
335 // Start at a data URL so each extra navigation creates a navigation entry. | 162 // Start at a data URL so each extra navigation creates a navigation entry. |
336 // (The first navigation will silently be classified as AUTO_SUBFRAME.) | 163 // (The first navigation will silently be classified as AUTO_SUBFRAME.) |
337 // TODO(creis): This won't be necessary when we can wait for LOAD_STOP. | 164 // TODO(creis): This won't be necessary when we can wait for LOAD_STOP. |
338 void StartFrameAtDataURL() { | 165 void StartFrameAtDataURL() { |
339 std::string data_url_script = | 166 std::string data_url_script = |
340 "var iframes = document.getElementById('test');iframes.src=" | 167 "var iframes = document.getElementById('test');iframes.src=" |
341 "'data:text/html,dataurl';"; | 168 "'data:text/html,dataurl';"; |
342 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script)); | 169 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script)); |
(...skipping 14 matching lines...) Expand all Loading... |
357 iframe_id.c_str(), url.spec().c_str()); | 184 iframe_id.c_str(), url.spec().c_str()); |
358 WindowedNotificationObserver load_observer( | 185 WindowedNotificationObserver load_observer( |
359 NOTIFICATION_NAV_ENTRY_COMMITTED, | 186 NOTIFICATION_NAV_ENTRY_COMMITTED, |
360 Source<NavigationController>( | 187 Source<NavigationController>( |
361 &window->web_contents()->GetController())); | 188 &window->web_contents()->GetController())); |
362 bool result = ExecuteScript(window->web_contents(), script); | 189 bool result = ExecuteScript(window->web_contents(), script); |
363 load_observer.Wait(); | 190 load_observer.Wait(); |
364 return result; | 191 return result; |
365 } | 192 } |
366 | 193 |
367 void NavigateToURLContentInitiated(Shell* window, | |
368 const GURL& url, | |
369 bool should_replace_current_entry, | |
370 bool should_wait_for_navigation) { | |
371 std::string script; | |
372 if (should_replace_current_entry) | |
373 script = base::StringPrintf("location.replace('%s')", url.spec().c_str()); | |
374 else | |
375 script = base::StringPrintf("location.href = '%s'", url.spec().c_str()); | |
376 TestNavigationObserver load_observer(shell()->web_contents(), 1); | |
377 bool result = ExecuteScript(window->web_contents(), script); | |
378 EXPECT_TRUE(result); | |
379 if (should_wait_for_navigation) | |
380 load_observer.Wait(); | |
381 } | |
382 | |
383 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | 194 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
384 command_line->AppendSwitch(switches::kSitePerProcess); | 195 command_line->AppendSwitch(switches::kSitePerProcess); |
385 | 196 |
386 // TODO(creis): Remove this when GTK is no longer a supported platform. | 197 // TODO(creis): Remove this when GTK is no longer a supported platform. |
387 command_line->AppendSwitch(switches::kForceCompositingMode); | 198 command_line->AppendSwitch(switches::kForceCompositingMode); |
388 } | 199 } |
389 | |
390 void InjectResourceDisptcherHostDelegate() { | |
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
392 old_delegate_ = ResourceDispatcherHostImpl::Get()->delegate(); | |
393 ResourceDispatcherHostImpl::Get()->SetDelegate(&tracking_delegate_); | |
394 } | |
395 | |
396 void RestoreResourceDisptcherHostDelegate() { | |
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
398 ResourceDispatcherHostImpl::Get()->SetDelegate(old_delegate_); | |
399 old_delegate_ = NULL; | |
400 } | |
401 | |
402 TrackingResourceDispatcherHostDelegate& tracking_delegate() { | |
403 return tracking_delegate_; | |
404 } | |
405 | |
406 private: | |
407 TrackingResourceDispatcherHostDelegate tracking_delegate_; | |
408 ResourceDispatcherHostDelegate* old_delegate_; | |
409 }; | 200 }; |
410 | 201 |
411 // Ensure that we can complete a cross-process subframe navigation. | 202 // Ensure that we can complete a cross-process subframe navigation. |
412 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) { | 203 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) { |
413 host_resolver()->AddRule("*", "127.0.0.1"); | 204 host_resolver()->AddRule("*", "127.0.0.1"); |
414 ASSERT_TRUE(test_server()->Start()); | 205 ASSERT_TRUE(test_server()->Start()); |
415 GURL main_url(test_server()->GetURL("files/site_per_process_main.html")); | 206 GURL main_url(test_server()->GetURL("files/site_per_process_main.html")); |
416 NavigateToURL(shell(), main_url); | 207 NavigateToURL(shell(), main_url); |
417 | 208 |
418 StartFrameAtDataURL(); | 209 StartFrameAtDataURL(); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 GURL server_redirect_http_url(test_server()->GetURL( | 508 GURL server_redirect_http_url(test_server()->GetURL( |
718 "server-redirect?" + client_redirect_http_url.spec())); | 509 "server-redirect?" + client_redirect_http_url.spec())); |
719 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test")); | 510 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test")); |
720 | 511 |
721 // DidFailProvisionalLoad when navigating to client_redirect_http_url. | 512 // DidFailProvisionalLoad when navigating to client_redirect_http_url. |
722 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url); | 513 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url); |
723 EXPECT_FALSE(observer.navigation_succeeded()); | 514 EXPECT_FALSE(observer.navigation_succeeded()); |
724 } | 515 } |
725 } | 516 } |
726 | 517 |
727 // Tests that the |should_replace_current_entry| flag persists correctly across | |
728 // request transfers that began with a cross-process navigation. | |
729 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, | |
730 ReplaceEntryCrossProcessThenTransfer) { | |
731 const NavigationController& controller = | |
732 shell()->web_contents()->GetController(); | |
733 host_resolver()->AddRule("*", "127.0.0.1"); | |
734 ASSERT_TRUE(test_server()->Start()); | |
735 | |
736 // These must all stay in scope with replace_host. | |
737 GURL::Replacements replace_host; | |
738 std::string a_com("A.com"); | |
739 std::string b_com("B.com"); | |
740 | |
741 // Navigate to a starting URL, so there is a history entry to replace. | |
742 GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); | |
743 NavigateToURL(shell(), url1); | |
744 | |
745 // Force all future navigations to transfer. Note that this includes same-site | |
746 // navigiations which may cause double process swaps (via OpenURL and then via | |
747 // transfer). This test intentionally exercises that case. | |
748 ShellContentBrowserClient::SetSwapProcessesForRedirect(true); | |
749 | |
750 // Navigate to a page on A.com with entry replacement. This navigation is | |
751 // cross-site, so the renderer will send it to the browser via OpenURL to give | |
752 // to a new process. It will then be transferred into yet another process due | |
753 // to the call above. | |
754 GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); | |
755 replace_host.SetHostStr(a_com); | |
756 url2 = url2.ReplaceComponents(replace_host); | |
757 // Used to make sure the request for url2 succeeds, and there was only one of | |
758 // them. | |
759 tracking_delegate().SetTrackedURL(url2); | |
760 NavigateToURLContentInitiated(shell(), url2, true, true); | |
761 | |
762 // There should be one history entry. url2 should have replaced url1. | |
763 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
764 EXPECT_EQ(1, controller.GetEntryCount()); | |
765 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
766 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); | |
767 // Make sure the request succeeded. | |
768 EXPECT_TRUE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); | |
769 | |
770 // Now navigate as before to a page on B.com, but normally (without | |
771 // replacement). This will still perform a double process-swap as above, via | |
772 // OpenURL and then transfer. | |
773 GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3"); | |
774 replace_host.SetHostStr(b_com); | |
775 url3 = url3.ReplaceComponents(replace_host); | |
776 // Used to make sure the request for url3 succeeds, and there was only one of | |
777 // them. | |
778 tracking_delegate().SetTrackedURL(url3); | |
779 NavigateToURLContentInitiated(shell(), url3, false, true); | |
780 | |
781 // There should be two history entries. url2 should have replaced url1. url2 | |
782 // should not have replaced url3. | |
783 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
784 EXPECT_EQ(2, controller.GetEntryCount()); | |
785 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
786 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); | |
787 EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL()); | |
788 | |
789 // Make sure the request succeeded. | |
790 EXPECT_TRUE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); | |
791 } | |
792 | |
793 // Tests that the |should_replace_current_entry| flag persists correctly across | |
794 // request transfers that began with a content-initiated in-process | |
795 // navigation. This test is the same as the test above, except transfering from | |
796 // in-process. | |
797 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, | |
798 ReplaceEntryInProcessThenTranfers) { | |
799 const NavigationController& controller = | |
800 shell()->web_contents()->GetController(); | |
801 ASSERT_TRUE(test_server()->Start()); | |
802 | |
803 // Navigate to a starting URL, so there is a history entry to replace. | |
804 GURL url = test_server()->GetURL("files/site_isolation/blank.html?1"); | |
805 NavigateToURL(shell(), url); | |
806 | |
807 // Force all future navigations to transfer. Note that this includes same-site | |
808 // navigiations which may cause double process swaps (via OpenURL and then via | |
809 // transfer). All navigations in this test are same-site, so it only swaps | |
810 // processes via request transfer. | |
811 ShellContentBrowserClient::SetSwapProcessesForRedirect(true); | |
812 | |
813 // Navigate in-process with entry replacement. It will then be transferred | |
814 // into a new one due to the call above. | |
815 GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); | |
816 NavigateToURLContentInitiated(shell(), url2, true, true); | |
817 | |
818 // There should be one history entry. url2 should have replaced url1. | |
819 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
820 EXPECT_EQ(1, controller.GetEntryCount()); | |
821 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
822 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); | |
823 | |
824 // Now navigate as before, but without replacement. | |
825 GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3"); | |
826 NavigateToURLContentInitiated(shell(), url3, false, true); | |
827 | |
828 // There should be two history entries. url2 should have replaced url1. url2 | |
829 // should not have replaced url3. | |
830 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
831 EXPECT_EQ(2, controller.GetEntryCount()); | |
832 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
833 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); | |
834 EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL()); | |
835 } | |
836 | |
837 // Tests that the |should_replace_current_entry| flag persists correctly across | |
838 // request transfers that cross processes twice from renderer policy. | |
839 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, | |
840 ReplaceEntryCrossProcessTwice) { | |
841 const NavigationController& controller = | |
842 shell()->web_contents()->GetController(); | |
843 host_resolver()->AddRule("*", "127.0.0.1"); | |
844 ASSERT_TRUE(test_server()->Start()); | |
845 | |
846 // These must all stay in scope with replace_host. | |
847 GURL::Replacements replace_host; | |
848 std::string a_com("A.com"); | |
849 std::string b_com("B.com"); | |
850 | |
851 // Navigate to a starting URL, so there is a history entry to replace. | |
852 GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); | |
853 NavigateToURL(shell(), url1); | |
854 | |
855 // Navigate to a page on A.com which redirects to B.com with entry | |
856 // replacement. This will switch processes via OpenURL twice. First to A.com, | |
857 // and second in response to the server redirect to B.com. The second swap is | |
858 // also renderer-initiated via OpenURL because decidePolicyForNavigation is | |
859 // currently applied on redirects. | |
860 GURL url2b = test_server()->GetURL("files/site_isolation/blank.html?2"); | |
861 replace_host.SetHostStr(b_com); | |
862 url2b = url2b.ReplaceComponents(replace_host); | |
863 GURL url2a = test_server()->GetURL( | |
864 "server-redirect?" + net::EscapeQueryParamValue(url2b.spec(), false)); | |
865 replace_host.SetHostStr(a_com); | |
866 url2a = url2a.ReplaceComponents(replace_host); | |
867 NavigateToURLContentInitiated(shell(), url2a, true, true); | |
868 | |
869 // There should be one history entry. url2b should have replaced url1. | |
870 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
871 EXPECT_EQ(1, controller.GetEntryCount()); | |
872 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
873 EXPECT_EQ(url2b, controller.GetEntryAtIndex(0)->GetURL()); | |
874 | |
875 // Now repeat without replacement. | |
876 GURL url3b = test_server()->GetURL("files/site_isolation/blank.html?3"); | |
877 replace_host.SetHostStr(b_com); | |
878 url3b = url3b.ReplaceComponents(replace_host); | |
879 GURL url3a = test_server()->GetURL( | |
880 "server-redirect?" + net::EscapeQueryParamValue(url3b.spec(), false)); | |
881 replace_host.SetHostStr(a_com); | |
882 url3a = url3a.ReplaceComponents(replace_host); | |
883 NavigateToURLContentInitiated(shell(), url3a, false, true); | |
884 | |
885 // There should be two history entries. url2b should have replaced url1. url2b | |
886 // should not have replaced url3b. | |
887 EXPECT_TRUE(controller.GetPendingEntry() == NULL); | |
888 EXPECT_EQ(2, controller.GetEntryCount()); | |
889 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
890 EXPECT_EQ(url2b, controller.GetEntryAtIndex(0)->GetURL()); | |
891 EXPECT_EQ(url3b, controller.GetEntryAtIndex(1)->GetURL()); | |
892 } | |
893 | |
894 // Tests that the request is destroyed when a cross process navigation is | |
895 // cancelled. | |
896 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NoLeakOnCrossSiteCancel) { | |
897 const NavigationController& controller = | |
898 shell()->web_contents()->GetController(); | |
899 host_resolver()->AddRule("*", "127.0.0.1"); | |
900 ASSERT_TRUE(test_server()->Start()); | |
901 | |
902 // These must all stay in scope with replace_host. | |
903 GURL::Replacements replace_host; | |
904 std::string a_com("A.com"); | |
905 std::string b_com("B.com"); | |
906 | |
907 // Navigate to a starting URL, so there is a history entry to replace. | |
908 GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); | |
909 NavigateToURL(shell(), url1); | |
910 | |
911 // Force all future navigations to transfer. | |
912 ShellContentBrowserClient::SetSwapProcessesForRedirect(true); | |
913 | |
914 NoTransferRequestDelegate no_transfer_request_delegate; | |
915 WebContentsDelegate* old_delegate = shell()->web_contents()->GetDelegate(); | |
916 shell()->web_contents()->SetDelegate(&no_transfer_request_delegate); | |
917 | |
918 // Navigate to a page on A.com with entry replacement. This navigation is | |
919 // cross-site, so the renderer will send it to the browser via OpenURL to give | |
920 // to a new process. It will then be transferred into yet another process due | |
921 // to the call above. | |
922 GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); | |
923 replace_host.SetHostStr(a_com); | |
924 url2 = url2.ReplaceComponents(replace_host); | |
925 // Used to make sure the second request is cancelled, and there is only one | |
926 // request for url2. | |
927 tracking_delegate().SetTrackedURL(url2); | |
928 | |
929 // Don't wait for the navigation to complete, since that never happens in | |
930 // this case. | |
931 NavigateToURLContentInitiated(shell(), url2, false, false); | |
932 | |
933 // There should be one history entry, with url1. | |
934 EXPECT_EQ(1, controller.GetEntryCount()); | |
935 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
936 EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL()); | |
937 | |
938 // Make sure the request for url2 did not complete. | |
939 EXPECT_FALSE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); | |
940 | |
941 shell()->web_contents()->SetDelegate(old_delegate); | |
942 } | |
943 | |
944 } // namespace content | 518 } // namespace content |
OLD | NEW |