Index: content/browser/site_per_process_browsertest.cc |
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc |
index f800b101c2b34ee5aebe7609f4365d817c63ae78..416b0dcdc1ad7e1fac14ed4d6a6cde7f0d3c2246 100644 |
--- a/content/browser/site_per_process_browsertest.cc |
+++ b/content/browser/site_per_process_browsertest.cc |
@@ -4,32 +4,21 @@ |
#include "base/command_line.h" |
#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
#include "content/browser/frame_host/frame_tree.h" |
-#include "content/browser/loader/resource_dispatcher_host_impl.h" |
#include "content/browser/renderer_host/render_view_host_impl.h" |
#include "content/browser/web_contents/web_contents_impl.h" |
-#include "content/public/browser/navigation_entry.h" |
#include "content/public/browser/notification_observer.h" |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_types.h" |
-#include "content/public/browser/resource_dispatcher_host_delegate.h" |
-#include "content/public/browser/resource_throttle.h" |
#include "content/public/browser/web_contents_observer.h" |
#include "content/public/common/content_switches.h" |
-#include "content/public/common/url_constants.h" |
#include "content/public/test/browser_test_utils.h" |
-#include "content/public/test/test_navigation_observer.h" |
#include "content/public/test/test_utils.h" |
#include "content/shell/browser/shell.h" |
-#include "content/shell/browser/shell_content_browser_client.h" |
-#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h" |
#include "content/test/content_browser_test.h" |
#include "content/test/content_browser_test_utils.h" |
-#include "net/base/escape.h" |
#include "net/dns/mock_host_resolver.h" |
-#include "net/url_request/url_request.h" |
-#include "net/url_request/url_request_status.h" |
+#include "url/gurl.h" |
namespace content { |
@@ -165,171 +154,9 @@ void RedirectNotificationObserver::Observe( |
running_ = false; |
} |
-// Tracks a single request for a specified URL, and allows waiting until the |
-// request is destroyed, and then inspecting whether it completed successfully. |
-class TrackingResourceDispatcherHostDelegate |
- : public ShellResourceDispatcherHostDelegate { |
- public: |
- TrackingResourceDispatcherHostDelegate() : throttle_created_(false) { |
- } |
- |
- virtual void RequestBeginning( |
- net::URLRequest* request, |
- ResourceContext* resource_context, |
- appcache::AppCacheService* appcache_service, |
- ResourceType::Type resource_type, |
- int child_id, |
- int route_id, |
- ScopedVector<ResourceThrottle>* throttles) OVERRIDE { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- ShellResourceDispatcherHostDelegate::RequestBeginning( |
- request, resource_context, appcache_service, resource_type, child_id, |
- route_id, throttles); |
- // Expect only a single request for the tracked url. |
- ASSERT_FALSE(throttle_created_); |
- // If this is a request for the tracked URL, add a throttle to track it. |
- if (request->url() == tracked_url_) |
- throttles->push_back(new TrackingThrottle(request, this)); |
- } |
- |
- // Starts tracking a URL. The request for previously tracked URL, if any, |
- // must have been made and deleted before calling this function. |
- void SetTrackedURL(const GURL& tracked_url) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- // Should not currently be tracking any URL. |
- ASSERT_FALSE(run_loop_); |
- |
- // Create a RunLoop that will be stopped once the request for the tracked |
- // URL has been destroyed, to allow tracking the URL while also waiting for |
- // other events. |
- run_loop_.reset(new base::RunLoop()); |
- |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind( |
- &TrackingResourceDispatcherHostDelegate::SetTrackedURLOnIOThread, |
- base::Unretained(this), |
- tracked_url)); |
- } |
- |
- // Waits until the tracked URL has been requests, and the request for it has |
- // been destroyed. |
- bool WaitForTrackedURLAndGetCompleted() { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- run_loop_->Run(); |
- run_loop_.reset(); |
- return tracked_request_completed_; |
- } |
- |
- private: |
- // ResourceThrottle attached to request for the tracked URL. On destruction, |
- // passes the final URLRequestStatus back to the delegate. |
- class TrackingThrottle : public ResourceThrottle { |
- public: |
- TrackingThrottle(net::URLRequest* request, |
- TrackingResourceDispatcherHostDelegate* tracker) |
- : request_(request), tracker_(tracker) { |
- } |
- |
- virtual ~TrackingThrottle() { |
- // If the request is deleted without being cancelled, its status will |
- // indicate it succeeded, so have to check if the request is still pending |
- // as well. |
- tracker_->OnTrackedRequestDestroyed( |
- !request_->is_pending() && request_->status().is_success()); |
- } |
- |
- // ResourceThrottle implementation: |
- virtual const char* GetNameForLogging() const OVERRIDE { |
- return "TrackingThrottle"; |
- } |
- |
- private: |
- net::URLRequest* request_; |
- TrackingResourceDispatcherHostDelegate* tracker_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TrackingThrottle); |
- }; |
- |
- void SetTrackedURLOnIOThread(const GURL& tracked_url) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- throttle_created_ = false; |
- tracked_url_ = tracked_url; |
- } |
- |
- void OnTrackedRequestDestroyed(bool completed) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- tracked_request_completed_ = completed; |
- tracked_url_ = GURL(); |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, run_loop_->QuitClosure()); |
- } |
- |
- // These live on the IO thread. |
- GURL tracked_url_; |
- bool throttle_created_; |
- |
- // This is created and destroyed on the UI thread, but stopped on the IO |
- // thread. |
- scoped_ptr<base::RunLoop> run_loop_; |
- |
- // Set on the IO thread while |run_loop_| is non-NULL, read on the UI thread |
- // after deleting run_loop_. |
- bool tracked_request_completed_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TrackingResourceDispatcherHostDelegate); |
-}; |
- |
-// WebContentsDelegate that fails to open a URL when there's a request that |
-// needs to be transferred between renderers. |
-class NoTransferRequestDelegate : public WebContentsDelegate { |
- public: |
- NoTransferRequestDelegate() {} |
- |
- virtual WebContents* OpenURLFromTab(WebContents* source, |
- const OpenURLParams& params) OVERRIDE { |
- bool is_transfer = |
- (params.transferred_global_request_id != GlobalRequestID()); |
- if (is_transfer) |
- return NULL; |
- NavigationController::LoadURLParams load_url_params(params.url); |
- load_url_params.referrer = params.referrer; |
- load_url_params.frame_tree_node_id = params.frame_tree_node_id; |
- load_url_params.transition_type = params.transition; |
- load_url_params.extra_headers = params.extra_headers; |
- load_url_params.should_replace_current_entry = |
- params.should_replace_current_entry; |
- load_url_params.is_renderer_initiated = true; |
- source->GetController().LoadURLWithParams(load_url_params); |
- return source; |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(NoTransferRequestDelegate); |
-}; |
- |
class SitePerProcessBrowserTest : public ContentBrowserTest { |
public: |
- SitePerProcessBrowserTest() : old_delegate_(NULL) { |
- } |
- |
- // ContentBrowserTest implementation: |
- virtual void SetUpOnMainThread() OVERRIDE { |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind( |
- &SitePerProcessBrowserTest::InjectResourceDisptcherHostDelegate, |
- base::Unretained(this))); |
- } |
- |
- virtual void TearDownOnMainThread() OVERRIDE { |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind( |
- &SitePerProcessBrowserTest::RestoreResourceDisptcherHostDelegate, |
- base::Unretained(this))); |
- } |
+ SitePerProcessBrowserTest() {} |
protected: |
// Start at a data URL so each extra navigation creates a navigation entry. |
@@ -364,48 +191,12 @@ class SitePerProcessBrowserTest : public ContentBrowserTest { |
return result; |
} |
- void NavigateToURLContentInitiated(Shell* window, |
- const GURL& url, |
- bool should_replace_current_entry, |
- bool should_wait_for_navigation) { |
- std::string script; |
- if (should_replace_current_entry) |
- script = base::StringPrintf("location.replace('%s')", url.spec().c_str()); |
- else |
- script = base::StringPrintf("location.href = '%s'", url.spec().c_str()); |
- TestNavigationObserver load_observer(shell()->web_contents(), 1); |
- bool result = ExecuteScript(window->web_contents(), script); |
- EXPECT_TRUE(result); |
- if (should_wait_for_navigation) |
- load_observer.Wait(); |
- } |
- |
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
command_line->AppendSwitch(switches::kSitePerProcess); |
// TODO(creis): Remove this when GTK is no longer a supported platform. |
command_line->AppendSwitch(switches::kForceCompositingMode); |
} |
- |
- void InjectResourceDisptcherHostDelegate() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- old_delegate_ = ResourceDispatcherHostImpl::Get()->delegate(); |
- ResourceDispatcherHostImpl::Get()->SetDelegate(&tracking_delegate_); |
- } |
- |
- void RestoreResourceDisptcherHostDelegate() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- ResourceDispatcherHostImpl::Get()->SetDelegate(old_delegate_); |
- old_delegate_ = NULL; |
- } |
- |
- TrackingResourceDispatcherHostDelegate& tracking_delegate() { |
- return tracking_delegate_; |
- } |
- |
- private: |
- TrackingResourceDispatcherHostDelegate tracking_delegate_; |
- ResourceDispatcherHostDelegate* old_delegate_; |
}; |
// Ensure that we can complete a cross-process subframe navigation. |
@@ -724,221 +515,4 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
} |
} |
-// Tests that the |should_replace_current_entry| flag persists correctly across |
-// request transfers that began with a cross-process navigation. |
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
- ReplaceEntryCrossProcessThenTransfer) { |
- const NavigationController& controller = |
- shell()->web_contents()->GetController(); |
- host_resolver()->AddRule("*", "127.0.0.1"); |
- ASSERT_TRUE(test_server()->Start()); |
- |
- // These must all stay in scope with replace_host. |
- GURL::Replacements replace_host; |
- std::string a_com("A.com"); |
- std::string b_com("B.com"); |
- |
- // Navigate to a starting URL, so there is a history entry to replace. |
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); |
- NavigateToURL(shell(), url1); |
- |
- // Force all future navigations to transfer. Note that this includes same-site |
- // navigiations which may cause double process swaps (via OpenURL and then via |
- // transfer). This test intentionally exercises that case. |
- ShellContentBrowserClient::SetSwapProcessesForRedirect(true); |
- |
- // Navigate to a page on A.com with entry replacement. This navigation is |
- // cross-site, so the renderer will send it to the browser via OpenURL to give |
- // to a new process. It will then be transferred into yet another process due |
- // to the call above. |
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); |
- replace_host.SetHostStr(a_com); |
- url2 = url2.ReplaceComponents(replace_host); |
- // Used to make sure the request for url2 succeeds, and there was only one of |
- // them. |
- tracking_delegate().SetTrackedURL(url2); |
- NavigateToURLContentInitiated(shell(), url2, true, true); |
- |
- // There should be one history entry. url2 should have replaced url1. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(1, controller.GetEntryCount()); |
- EXPECT_EQ(0, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); |
- // Make sure the request succeeded. |
- EXPECT_TRUE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); |
- |
- // Now navigate as before to a page on B.com, but normally (without |
- // replacement). This will still perform a double process-swap as above, via |
- // OpenURL and then transfer. |
- GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3"); |
- replace_host.SetHostStr(b_com); |
- url3 = url3.ReplaceComponents(replace_host); |
- // Used to make sure the request for url3 succeeds, and there was only one of |
- // them. |
- tracking_delegate().SetTrackedURL(url3); |
- NavigateToURLContentInitiated(shell(), url3, false, true); |
- |
- // There should be two history entries. url2 should have replaced url1. url2 |
- // should not have replaced url3. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(2, controller.GetEntryCount()); |
- EXPECT_EQ(1, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); |
- EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL()); |
- |
- // Make sure the request succeeded. |
- EXPECT_TRUE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); |
-} |
- |
-// Tests that the |should_replace_current_entry| flag persists correctly across |
-// request transfers that began with a content-initiated in-process |
-// navigation. This test is the same as the test above, except transfering from |
-// in-process. |
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
- ReplaceEntryInProcessThenTranfers) { |
- const NavigationController& controller = |
- shell()->web_contents()->GetController(); |
- ASSERT_TRUE(test_server()->Start()); |
- |
- // Navigate to a starting URL, so there is a history entry to replace. |
- GURL url = test_server()->GetURL("files/site_isolation/blank.html?1"); |
- NavigateToURL(shell(), url); |
- |
- // Force all future navigations to transfer. Note that this includes same-site |
- // navigiations which may cause double process swaps (via OpenURL and then via |
- // transfer). All navigations in this test are same-site, so it only swaps |
- // processes via request transfer. |
- ShellContentBrowserClient::SetSwapProcessesForRedirect(true); |
- |
- // Navigate in-process with entry replacement. It will then be transferred |
- // into a new one due to the call above. |
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); |
- NavigateToURLContentInitiated(shell(), url2, true, true); |
- |
- // There should be one history entry. url2 should have replaced url1. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(1, controller.GetEntryCount()); |
- EXPECT_EQ(0, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); |
- |
- // Now navigate as before, but without replacement. |
- GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3"); |
- NavigateToURLContentInitiated(shell(), url3, false, true); |
- |
- // There should be two history entries. url2 should have replaced url1. url2 |
- // should not have replaced url3. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(2, controller.GetEntryCount()); |
- EXPECT_EQ(1, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); |
- EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL()); |
-} |
- |
-// Tests that the |should_replace_current_entry| flag persists correctly across |
-// request transfers that cross processes twice from renderer policy. |
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
- ReplaceEntryCrossProcessTwice) { |
- const NavigationController& controller = |
- shell()->web_contents()->GetController(); |
- host_resolver()->AddRule("*", "127.0.0.1"); |
- ASSERT_TRUE(test_server()->Start()); |
- |
- // These must all stay in scope with replace_host. |
- GURL::Replacements replace_host; |
- std::string a_com("A.com"); |
- std::string b_com("B.com"); |
- |
- // Navigate to a starting URL, so there is a history entry to replace. |
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); |
- NavigateToURL(shell(), url1); |
- |
- // Navigate to a page on A.com which redirects to B.com with entry |
- // replacement. This will switch processes via OpenURL twice. First to A.com, |
- // and second in response to the server redirect to B.com. The second swap is |
- // also renderer-initiated via OpenURL because decidePolicyForNavigation is |
- // currently applied on redirects. |
- GURL url2b = test_server()->GetURL("files/site_isolation/blank.html?2"); |
- replace_host.SetHostStr(b_com); |
- url2b = url2b.ReplaceComponents(replace_host); |
- GURL url2a = test_server()->GetURL( |
- "server-redirect?" + net::EscapeQueryParamValue(url2b.spec(), false)); |
- replace_host.SetHostStr(a_com); |
- url2a = url2a.ReplaceComponents(replace_host); |
- NavigateToURLContentInitiated(shell(), url2a, true, true); |
- |
- // There should be one history entry. url2b should have replaced url1. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(1, controller.GetEntryCount()); |
- EXPECT_EQ(0, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2b, controller.GetEntryAtIndex(0)->GetURL()); |
- |
- // Now repeat without replacement. |
- GURL url3b = test_server()->GetURL("files/site_isolation/blank.html?3"); |
- replace_host.SetHostStr(b_com); |
- url3b = url3b.ReplaceComponents(replace_host); |
- GURL url3a = test_server()->GetURL( |
- "server-redirect?" + net::EscapeQueryParamValue(url3b.spec(), false)); |
- replace_host.SetHostStr(a_com); |
- url3a = url3a.ReplaceComponents(replace_host); |
- NavigateToURLContentInitiated(shell(), url3a, false, true); |
- |
- // There should be two history entries. url2b should have replaced url1. url2b |
- // should not have replaced url3b. |
- EXPECT_TRUE(controller.GetPendingEntry() == NULL); |
- EXPECT_EQ(2, controller.GetEntryCount()); |
- EXPECT_EQ(1, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url2b, controller.GetEntryAtIndex(0)->GetURL()); |
- EXPECT_EQ(url3b, controller.GetEntryAtIndex(1)->GetURL()); |
-} |
- |
-// Tests that the request is destroyed when a cross process navigation is |
-// cancelled. |
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NoLeakOnCrossSiteCancel) { |
- const NavigationController& controller = |
- shell()->web_contents()->GetController(); |
- host_resolver()->AddRule("*", "127.0.0.1"); |
- ASSERT_TRUE(test_server()->Start()); |
- |
- // These must all stay in scope with replace_host. |
- GURL::Replacements replace_host; |
- std::string a_com("A.com"); |
- std::string b_com("B.com"); |
- |
- // Navigate to a starting URL, so there is a history entry to replace. |
- GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1"); |
- NavigateToURL(shell(), url1); |
- |
- // Force all future navigations to transfer. |
- ShellContentBrowserClient::SetSwapProcessesForRedirect(true); |
- |
- NoTransferRequestDelegate no_transfer_request_delegate; |
- WebContentsDelegate* old_delegate = shell()->web_contents()->GetDelegate(); |
- shell()->web_contents()->SetDelegate(&no_transfer_request_delegate); |
- |
- // Navigate to a page on A.com with entry replacement. This navigation is |
- // cross-site, so the renderer will send it to the browser via OpenURL to give |
- // to a new process. It will then be transferred into yet another process due |
- // to the call above. |
- GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2"); |
- replace_host.SetHostStr(a_com); |
- url2 = url2.ReplaceComponents(replace_host); |
- // Used to make sure the second request is cancelled, and there is only one |
- // request for url2. |
- tracking_delegate().SetTrackedURL(url2); |
- |
- // Don't wait for the navigation to complete, since that never happens in |
- // this case. |
- NavigateToURLContentInitiated(shell(), url2, false, false); |
- |
- // There should be one history entry, with url1. |
- EXPECT_EQ(1, controller.GetEntryCount()); |
- EXPECT_EQ(0, controller.GetCurrentEntryIndex()); |
- EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL()); |
- |
- // Make sure the request for url2 did not complete. |
- EXPECT_FALSE(tracking_delegate().WaitForTrackedURLAndGetCompleted()); |
- |
- shell()->web_contents()->SetDelegate(old_delegate); |
-} |
- |
} // namespace content |