Index: content/browser/frame_host/navigator_impl_unittest.cc |
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc |
index b304ba177af50b2d108ac6c548040bb738d9c5ad..cf4eb5b4c70b01180383c6ed8b27efbdeab5081e 100644 |
--- a/content/browser/frame_host/navigator_impl_unittest.cc |
+++ b/content/browser/frame_host/navigator_impl_unittest.cc |
@@ -5,7 +5,6 @@ |
#include "base/command_line.h" |
#include "base/test/histogram_tester.h" |
#include "base/time/time.h" |
-#include "content/browser/frame_host/navigation_before_commit_info.h" |
#include "content/browser/frame_host/navigation_controller_impl.h" |
#include "content/browser/frame_host/navigation_entry_impl.h" |
#include "content/browser/frame_host/navigation_request.h" |
@@ -13,21 +12,125 @@ |
#include "content/browser/frame_host/navigator.h" |
#include "content/browser/frame_host/navigator_impl.h" |
#include "content/browser/frame_host/render_frame_host_manager.h" |
+#include "content/browser/loader/navigation_url_loader.h" |
+#include "content/browser/loader/navigation_url_loader_factory.h" |
#include "content/browser/site_instance_impl.h" |
#include "content/common/navigation_params.h" |
+#include "content/public/browser/stream_handle.h" |
#include "content/public/common/content_switches.h" |
#include "content/public/common/url_constants.h" |
#include "content/public/common/url_utils.h" |
#include "content/test/test_render_frame_host.h" |
#include "content/test/test_web_contents.h" |
#include "net/base/load_flags.h" |
+#include "net/url_request/redirect_info.h" |
#include "ui/base/page_transition_types.h" |
namespace content { |
+namespace { |
+ |
+class TestNavigationURLLoader : public NavigationURLLoader { |
+ public: |
+ TestNavigationURLLoader(const CommonNavigationParams& common_params, |
+ scoped_ptr<NavigationRequestInfo> request_info, |
+ NavigationURLLoader::Delegate* delegate) |
+ : common_params_(common_params), |
+ request_info_(request_info.Pass()), |
+ delegate_(delegate) { |
+ } |
+ |
+ virtual ~TestNavigationURLLoader() { |
+ // Record the number of times a loader was canceled before ResponseStarted |
+ // or RequestFailed was returned. |
+ if (delegate_) |
+ cancel_count_++; |
+ } |
+ |
+ // NavigationURLLoader implementation. |
+ virtual void FollowRedirect() OVERRIDE { |
+ redirect_count_++; |
+ } |
+ |
+ const CommonNavigationParams& common_params() const { return common_params_; } |
+ NavigationRequestInfo* request_info() const { return request_info_.get(); } |
+ |
+ void CallOnRequestRedirected(const net::RedirectInfo& redirect_info, |
+ ResourceResponse* response) { |
+ delegate_->OnRequestRedirected(redirect_info, response); |
+ } |
+ |
+ void CallOnResponseStarted(ResourceResponse* response, |
+ scoped_ptr<StreamHandle> body) { |
+ delegate_->OnResponseStarted(response, body.Pass()); |
+ delegate_ = NULL; |
+ } |
+ |
+ static int redirect_count() { return redirect_count_; } |
+ static int cancel_count() { return cancel_count_; } |
+ |
+ private: |
+ static int redirect_count_; |
+ static int cancel_count_; |
+ |
+ CommonNavigationParams common_params_; |
+ scoped_ptr<NavigationRequestInfo> request_info_; |
+ NavigationURLLoader::Delegate* delegate_; |
+}; |
+ |
+int TestNavigationURLLoader::redirect_count_ = 0; |
+int TestNavigationURLLoader::cancel_count_ = 0; |
+ |
+class TestNavigationURLLoaderFactory : public NavigationURLLoaderFactory { |
+ public: |
+ // NavigationURLLoaderFactory implementation. |
+ virtual scoped_ptr<NavigationURLLoader> CreateLoader( |
+ BrowserContext* browser_context, |
+ int64 frame_tree_node_id, |
+ const CommonNavigationParams& common_params, |
+ scoped_ptr<NavigationRequestInfo> request_info, |
+ ResourceRequestBody* request_body, |
+ NavigationURLLoader::Delegate* delegate) OVERRIDE { |
+ return scoped_ptr<NavigationURLLoader>(new TestNavigationURLLoader( |
+ common_params, request_info.Pass(), delegate)); |
+ } |
+}; |
+ |
+// Mocked out stream handle to call OnResponseStarted with. |
+class TestStreamHandle : public StreamHandle { |
+ public: |
+ TestStreamHandle() : url_("test:stream") {} |
+ |
+ virtual const GURL& GetURL() OVERRIDE { |
+ return url_; |
+ } |
+ |
+ virtual void AddCloseListener(const base::Closure& callback) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ private: |
+ GURL url_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestStreamHandle); |
+}; |
+ |
+} |
+ |
class NavigatorTest |
: public RenderViewHostImplTestHarness { |
public: |
+ virtual void SetUp() OVERRIDE { |
+ RenderViewHostImplTestHarness::SetUp(); |
+ loader_factory_.reset(new TestNavigationURLLoaderFactory); |
+ NavigationURLLoader::SetFactoryForTesting(loader_factory_.get()); |
+ } |
+ |
+ virtual void TearDown() OVERRIDE { |
+ NavigationURLLoader::SetFactoryForTesting(NULL); |
+ loader_factory_.reset(); |
+ RenderViewHostImplTestHarness::TearDown(); |
+ } |
+ |
NavigationRequest* GetNavigationRequestForFrameTreeNode( |
FrameTreeNode* frame_tree_node) const { |
NavigatorImpl* navigator = |
@@ -36,6 +139,11 @@ class NavigatorTest |
frame_tree_node->frame_tree_node_id()); |
} |
+ TestNavigationURLLoader* GetLoaderForNavigationRequest( |
+ NavigationRequest* request) const { |
+ return static_cast<TestNavigationURLLoader*>(request->loader_for_testing()); |
+ } |
+ |
void EnableBrowserSideNavigation() { |
CommandLine::ForCurrentProcess()->AppendSwitch( |
switches::kEnableBrowserSideNavigation); |
@@ -66,6 +174,9 @@ class NavigatorTest |
static_cast<NavigatorImpl*>(node->navigator())->RequestNavigation( |
node, *entry, reload_type, base::TimeTicks::Now()); |
} |
+ |
+ private: |
+ scoped_ptr<TestNavigationURLLoaderFactory> loader_factory_; |
}; |
// PlzNavigate: Test that a proper NavigationRequest is created by |
@@ -76,7 +187,6 @@ TEST_F(NavigatorTest, BrowserSideNavigationBeginNavigation) { |
const GURL kUrl1("http://www.google.com/"); |
const GURL kUrl2("http://www.chromium.org/"); |
const GURL kUrl3("http://www.gmail.com/"); |
- const int64 kFirstNavRequestID = 1; |
EnableBrowserSideNavigation(); |
contents()->NavigateAndCommit(kUrl1); |
@@ -88,37 +198,38 @@ TEST_F(NavigatorTest, BrowserSideNavigationBeginNavigation) { |
FrameTreeNode* subframe_node = subframe_rfh->frame_tree_node(); |
SendRequestNavigation(subframe_rfh->frame_tree_node(), kUrl2); |
- // Simulate a BeginNavigation IPC on the subframe. |
- subframe_rfh->SendBeginNavigationWithURL(kUrl2); |
+ // There is no previous renderer, so BeginNavigation is handled already. |
NavigationRequest* subframe_request = |
GetNavigationRequestForFrameTreeNode(subframe_node); |
+ TestNavigationURLLoader* subframe_loader = |
+ GetLoaderForNavigationRequest(subframe_request); |
ASSERT_TRUE(subframe_request); |
EXPECT_EQ(kUrl2, subframe_request->common_params().url); |
+ EXPECT_EQ(kUrl2, subframe_loader->common_params().url); |
// First party for cookies url should be that of the main frame. |
- EXPECT_EQ(kUrl1, subframe_request->info_for_test()->first_party_for_cookies); |
- EXPECT_FALSE(subframe_request->info_for_test()->is_main_frame); |
- EXPECT_TRUE(subframe_request->info_for_test()->parent_is_main_frame); |
- EXPECT_EQ(kFirstNavRequestID + 1, subframe_request->navigation_request_id()); |
+ EXPECT_EQ(kUrl1, subframe_loader->request_info()->first_party_for_cookies); |
+ EXPECT_FALSE(subframe_loader->request_info()->is_main_frame); |
+ EXPECT_TRUE(subframe_loader->request_info()->parent_is_main_frame); |
FrameTreeNode* main_frame_node = |
contents()->GetMainFrame()->frame_tree_node(); |
SendRequestNavigation(main_frame_node, kUrl3); |
- // Simulate a BeginNavigation IPC on the main frame. |
- contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl3); |
+ // There is no previous renderer, so BeginNavigation is handled already. |
NavigationRequest* main_request = |
GetNavigationRequestForFrameTreeNode(main_frame_node); |
+ TestNavigationURLLoader* main_loader = |
+ GetLoaderForNavigationRequest(main_request); |
ASSERT_TRUE(main_request); |
EXPECT_EQ(kUrl3, main_request->common_params().url); |
- EXPECT_EQ(kUrl3, main_request->info_for_test()->first_party_for_cookies); |
- EXPECT_TRUE(main_request->info_for_test()->is_main_frame); |
- EXPECT_FALSE(main_request->info_for_test()->parent_is_main_frame); |
- EXPECT_EQ(kFirstNavRequestID + 2, main_request->navigation_request_id()); |
+ EXPECT_EQ(kUrl3, main_loader->common_params().url); |
+ EXPECT_EQ(kUrl3, main_loader->request_info()->first_party_for_cookies); |
+ EXPECT_TRUE(main_loader->request_info()->is_main_frame); |
+ EXPECT_FALSE(main_loader->request_info()->parent_is_main_frame); |
} |
// PlzNavigate: Test that RequestNavigation creates a NavigationRequest and that |
// RenderFrameHost is not modified when the navigation commits. |
-TEST_F(NavigatorTest, |
- BrowserSideNavigationRequestNavigationNoLiveRenderer) { |
+TEST_F(NavigatorTest, BrowserSideNavigationRequestNavigationNoLiveRenderer) { |
const GURL kUrl("http://www.google.com/"); |
EnableBrowserSideNavigation(); |
@@ -130,11 +241,11 @@ TEST_F(NavigatorTest, |
EXPECT_TRUE(main_request != NULL); |
RenderFrameHostImpl* rfh = main_test_rfh(); |
- // Now commit the same url. |
- NavigationBeforeCommitInfo commit_info; |
- commit_info.navigation_url = kUrl; |
- commit_info.navigation_request_id = main_request->navigation_request_id(); |
- node->navigator()->CommitNavigation(node, commit_info); |
+ // Now return the response without any redirects. This will cause the |
+ // navigation to commit at the same URL. |
+ scoped_refptr<ResourceResponse> response(new ResourceResponse); |
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted( |
+ response.get(), scoped_ptr<StreamHandle>(new TestStreamHandle)); |
main_request = GetNavigationRequestForFrameTreeNode(node); |
// The main RFH should not have been changed, and the renderer should have |
@@ -146,40 +257,80 @@ TEST_F(NavigatorTest, |
// PlzNavigate: Test that a new RenderFrameHost is created when doing a cross |
// site navigation. |
-TEST_F(NavigatorTest, |
- BrowserSideNavigationCrossSiteNavigation) { |
+TEST_F(NavigatorTest, BrowserSideNavigationCrossSiteNavigation) { |
const GURL kUrl1("http://www.chromium.org/"); |
const GURL kUrl2("http://www.google.com/"); |
- EnableBrowserSideNavigation(); |
contents()->NavigateAndCommit(kUrl1); |
RenderFrameHostImpl* rfh = main_test_rfh(); |
EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh->rfh_state()); |
FrameTreeNode* node = main_test_rfh()->frame_tree_node(); |
+ EnableBrowserSideNavigation(); |
+ |
// Navigate to a different site. |
SendRequestNavigation(node, kUrl2); |
main_test_rfh()->SendBeginNavigationWithURL(kUrl2); |
NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node); |
ASSERT_TRUE(main_request); |
- NavigationBeforeCommitInfo commit_info; |
- commit_info.navigation_url = kUrl2; |
- commit_info.navigation_request_id = main_request->navigation_request_id(); |
- node->navigator()->CommitNavigation(node, commit_info); |
- EXPECT_NE(main_test_rfh(), rfh); |
- EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive()); |
- EXPECT_TRUE(main_test_rfh()->render_view_host()->IsRenderViewLive()); |
+ scoped_refptr<ResourceResponse> response(new ResourceResponse); |
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted( |
+ response.get(), scoped_ptr<StreamHandle>(new TestStreamHandle)); |
+ RenderFrameHostImpl* pending_rfh = |
+ node->render_manager()->pending_frame_host(); |
+ ASSERT_TRUE(pending_rfh); |
+ EXPECT_NE(pending_rfh, rfh); |
+ EXPECT_TRUE(pending_rfh->IsRenderFrameLive()); |
+ EXPECT_TRUE(pending_rfh->render_view_host()->IsRenderViewLive()); |
} |
-// PlzNavigate: Test that a navigation commit is ignored if another request has |
-// been issued in the meantime. |
-// TODO(carlosk): add checks to assert that the cancel call was sent to |
-// ResourceDispatcherHost in the IO thread by extending |
-// ResourceDispatcherHostDelegate (like in cross_site_transfer_browsertest.cc |
-// and plugin_browsertest.cc). |
-TEST_F(NavigatorTest, |
- BrowserSideNavigationIgnoreStaleNavigationCommit) { |
+// PlzNavigate: Test that redirects are followed. |
+TEST_F(NavigatorTest, BrowserSideNavigationRedirectCrossSite) { |
+ const GURL kUrl1("http://www.chromium.org/"); |
+ const GURL kUrl2("http://www.google.com/"); |
+ |
+ contents()->NavigateAndCommit(kUrl1); |
+ RenderFrameHostImpl* rfh = main_test_rfh(); |
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh->rfh_state()); |
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node(); |
+ |
+ EnableBrowserSideNavigation(); |
+ |
+ // Navigate to a URL on the same site. |
+ SendRequestNavigation(node, kUrl1); |
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl1); |
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node); |
+ ASSERT_TRUE(main_request); |
+ |
+ // It then redirects to another site. |
+ net::RedirectInfo redirect_info; |
+ redirect_info.status_code = 302; |
+ redirect_info.new_method = "GET"; |
+ redirect_info.new_url = kUrl2; |
+ redirect_info.new_first_party_for_cookies = kUrl2; |
+ scoped_refptr<ResourceResponse> response(new ResourceResponse); |
+ GetLoaderForNavigationRequest(main_request)->CallOnRequestRedirected( |
+ redirect_info, response.get()); |
+ |
+ // The redirect should have been followed. |
+ EXPECT_EQ(1, TestNavigationURLLoader::redirect_count()); |
+ |
+ // Then it commits. |
+ response = new ResourceResponse; |
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted( |
+ response.get(), scoped_ptr<StreamHandle>(new TestStreamHandle)); |
+ RenderFrameHostImpl* pending_rfh = |
+ node->render_manager()->pending_frame_host(); |
+ ASSERT_TRUE(pending_rfh); |
+ EXPECT_NE(pending_rfh, rfh); |
+ EXPECT_TRUE(pending_rfh->IsRenderFrameLive()); |
+ EXPECT_TRUE(pending_rfh->render_view_host()->IsRenderViewLive()); |
+} |
+ |
+// PlzNavigate: Test that a navigation is cancelled if another request has been |
+// issued in the meantime. |
+TEST_F(NavigatorTest, BrowserSideNavigationReplacePendingNavigation) { |
const GURL kUrl0("http://www.wikipedia.org/"); |
const GURL kUrl0_site = SiteInstance::GetSiteForURL(browser_context(), kUrl0); |
const GURL kUrl1("http://www.chromium.org/"); |
@@ -197,32 +348,28 @@ TEST_F(NavigatorTest, |
main_test_rfh()->SendBeginNavigationWithURL(kUrl1); |
NavigationRequest* request1 = GetNavigationRequestForFrameTreeNode(node); |
ASSERT_TRUE(request1); |
- int64 request_id1 = request1->navigation_request_id(); |
+ int cancel_count = TestNavigationURLLoader::cancel_count(); |
// Request navigation to the 2nd URL and gather more data. |
- SendRequestNavigation(node, kUrl2); |
+ SendRequestNavigation(main_test_rfh()->frame_tree_node(), kUrl2); |
main_test_rfh()->SendBeginNavigationWithURL(kUrl2); |
NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node); |
ASSERT_TRUE(request2); |
- int64 request_id2 = request2->navigation_request_id(); |
- EXPECT_NE(request_id1, request_id2); |
- |
- // Confirms that a stale commit is ignored by the Navigator. |
- NavigationBeforeCommitInfo nbc_info; |
- nbc_info.navigation_url = kUrl1; |
- nbc_info.navigation_request_id = request_id1; |
- node->navigator()->CommitNavigation(node, nbc_info); |
- EXPECT_FALSE(node->render_manager()->pending_frame_host()); |
- EXPECT_EQ(kUrl0_site, main_test_rfh()->GetSiteInstance()->GetSiteURL()); |
+ |
+ // Confirm that the first request got canceled. |
+ EXPECT_EQ(cancel_count + 1, TestNavigationURLLoader::cancel_count()); |
// Confirms that a valid, request-matching commit is correctly processed. |
- nbc_info.navigation_url = kUrl2; |
- nbc_info.navigation_request_id = request_id2; |
- node->navigator()->CommitNavigation(node, nbc_info); |
+ scoped_refptr<ResourceResponse> response(new ResourceResponse); |
+ GetLoaderForNavigationRequest(request2)->CallOnResponseStarted( |
+ response.get(), scoped_ptr<StreamHandle>(new TestStreamHandle)); |
RenderFrameHostImpl* pending_rfh = |
node->render_manager()->pending_frame_host(); |
ASSERT_TRUE(pending_rfh); |
EXPECT_EQ(kUrl2_site, pending_rfh->GetSiteInstance()->GetSiteURL()); |
+ |
+ // The loader should not have been canceled. |
+ EXPECT_EQ(cancel_count + 1, TestNavigationURLLoader::cancel_count()); |
} |
// PlzNavigate: Tests that the navigation histograms are correctly tracked both |