Index: content/browser/frame_host/navigation_handle_impl_browsertest.cc |
diff --git a/content/browser/frame_host/navigation_handle_impl_browsertest.cc b/content/browser/frame_host/navigation_handle_impl_browsertest.cc |
index 86c6e9dd1f5f04b0a87fcc148251249180635cad..7630a743531944c57f5e163b93b87247835f3954 100644 |
--- a/content/browser/frame_host/navigation_handle_impl_browsertest.cc |
+++ b/content/browser/frame_host/navigation_handle_impl_browsertest.cc |
@@ -9,6 +9,8 @@ |
#include "content/public/test/browser_test_utils.h" |
#include "content/public/test/content_browser_test.h" |
#include "content/public/test/content_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 "net/dns/mock_host_resolver.h" |
#include "ui/base/page_transition_types.h" |
@@ -111,6 +113,157 @@ class NavigationHandleObserver : public WebContentsObserver { |
GURL last_committed_url_; |
}; |
+// A test NavigationThrottle that will return pre-determined checks and run |
+// callbacks when the various NavigationThrottle methods are called. |
+class TestNavigationThrottle : public NavigationThrottle { |
+ public: |
+ TestNavigationThrottle( |
+ NavigationHandle* handle, |
+ NavigationThrottle::ThrottleCheckResult will_start_result, |
+ NavigationThrottle::ThrottleCheckResult will_redirect_result, |
+ NavigationThrottle::ThrottleCheckResult will_process_result, |
+ base::Closure did_call_will_start, |
+ base::Closure did_call_will_redirect, |
+ base::Closure did_call_will_process) |
+ : NavigationThrottle(handle), |
+ will_start_result_(will_start_result), |
+ will_redirect_result_(will_redirect_result), |
+ will_process_result_(will_process_result), |
+ did_call_will_start_(did_call_will_start), |
+ did_call_will_redirect_(did_call_will_redirect), |
+ did_call_will_process_(did_call_will_process) {} |
+ ~TestNavigationThrottle() override {} |
+ |
+ void Resume() { navigation_handle()->Resume(); } |
+ |
+ private: |
+ // NavigationThrottle implementation. |
+ NavigationThrottle::ThrottleCheckResult WillStartRequest() override { |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, did_call_will_start_); |
+ return will_start_result_; |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override { |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ did_call_will_redirect_); |
+ return will_redirect_result_; |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult WillProcessResponse() override { |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ did_call_will_process_); |
+ return will_process_result_; |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult will_start_result_; |
+ NavigationThrottle::ThrottleCheckResult will_redirect_result_; |
+ NavigationThrottle::ThrottleCheckResult will_process_result_; |
+ base::Closure did_call_will_start_; |
+ base::Closure did_call_will_redirect_; |
+ base::Closure did_call_will_process_; |
+}; |
+ |
+// Install a TestNavigationThrottle on all requests and allows waiting for |
+// various NavigationThrottle related events. |
+class TestNavigationThrottleInstaller : public WebContentsObserver { |
+ public: |
+ TestNavigationThrottleInstaller( |
+ WebContents* web_contents, |
+ NavigationThrottle::ThrottleCheckResult will_start_result, |
+ NavigationThrottle::ThrottleCheckResult will_redirect_result, |
+ NavigationThrottle::ThrottleCheckResult will_process_result) |
+ : WebContentsObserver(web_contents), |
+ will_start_result_(will_start_result), |
+ will_redirect_result_(will_redirect_result), |
+ will_process_result_(will_process_result), |
+ will_start_called_(0), |
+ will_redirect_called_(0), |
+ will_process_called_(0), |
+ navigation_throttle_(nullptr) {} |
+ ~TestNavigationThrottleInstaller() override{}; |
+ |
+ TestNavigationThrottle* navigation_throttle() { return navigation_throttle_; } |
+ |
+ void WaitForThrottleWillStart() { |
+ if (will_start_called_) |
+ return; |
+ will_start_loop_runner_ = new MessageLoopRunner(); |
+ will_start_loop_runner_->Run(); |
+ will_start_loop_runner_ = nullptr; |
+ } |
+ |
+ void WaitForThrottleWillRedirect() { |
+ if (will_redirect_called_) |
+ return; |
+ will_redirect_loop_runner_ = new MessageLoopRunner(); |
+ will_redirect_loop_runner_->Run(); |
+ will_redirect_loop_runner_ = nullptr; |
+ } |
+ |
+ void WaitForThrottleWillProcess() { |
+ if (will_process_called_) |
+ return; |
+ will_process_loop_runner_ = new MessageLoopRunner(); |
+ will_process_loop_runner_->Run(); |
+ will_process_loop_runner_ = nullptr; |
+ } |
+ |
+ int will_start_called() { return will_start_called_; } |
+ int will_redirect_called() { return will_redirect_called_; } |
+ int will_process_called() { return will_process_called_; } |
+ |
+ private: |
+ void DidStartNavigation(NavigationHandle* handle) override { |
+ scoped_ptr<NavigationThrottle> throttle(new TestNavigationThrottle( |
+ handle, will_start_result_, will_redirect_result_, will_process_result_, |
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillStartRequest, |
+ base::Unretained(this)), |
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillRedirectRequest, |
+ base::Unretained(this)), |
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillProcessResponse, |
+ base::Unretained(this)))); |
+ navigation_throttle_ = static_cast<TestNavigationThrottle*>(throttle.get()); |
+ handle->RegisterThrottleForTesting(std::move(throttle)); |
+ } |
+ |
+ void DidFinishNavigation(NavigationHandle* handle) override { |
+ if (!navigation_throttle_) |
+ return; |
+ |
+ if (handle == navigation_throttle_->navigation_handle()) |
+ navigation_throttle_ = nullptr; |
+ } |
+ |
+ void DidCallWillStartRequest() { |
+ will_start_called_++; |
+ if (will_start_loop_runner_) |
+ will_start_loop_runner_->Quit(); |
+ } |
+ |
+ void DidCallWillRedirectRequest() { |
+ will_redirect_called_++; |
+ if (will_redirect_loop_runner_) |
+ will_redirect_loop_runner_->Quit(); |
+ } |
+ |
+ void DidCallWillProcessResponse() { |
+ will_process_called_++; |
+ if (will_process_loop_runner_) |
+ will_process_loop_runner_->Quit(); |
+ } |
+ |
+ NavigationThrottle::ThrottleCheckResult will_start_result_; |
+ NavigationThrottle::ThrottleCheckResult will_redirect_result_; |
+ NavigationThrottle::ThrottleCheckResult will_process_result_; |
+ int will_start_called_; |
+ int will_redirect_called_; |
+ int will_process_called_; |
+ TestNavigationThrottle* navigation_throttle_; |
+ scoped_refptr<MessageLoopRunner> will_start_loop_runner_; |
+ scoped_refptr<MessageLoopRunner> will_redirect_loop_runner_; |
+ scoped_refptr<MessageLoopRunner> will_process_loop_runner_; |
+}; |
+ |
} // namespace |
class NavigationHandleImplBrowserTest : public ContentBrowserTest { |
@@ -269,4 +422,139 @@ IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifySynchronous) { |
EXPECT_TRUE(observer.is_synchronous()); |
} |
+// Ensure that a NavigationThrottle can cancel the navigation at navigation |
+// start. |
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, ThrottleCancelStart) { |
+ GURL start_url(embedded_test_server()->GetURL("/title1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), start_url)); |
+ |
+ GURL redirect_url( |
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html")); |
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url); |
+ TestNavigationThrottleInstaller installer( |
+ shell()->web_contents(), NavigationThrottle::CANCEL, |
+ NavigationThrottle::PROCEED, NavigationThrottle::PROCEED); |
+ |
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url)); |
+ |
+ EXPECT_FALSE(observer.has_committed()); |
+ EXPECT_TRUE(observer.is_error()); |
+ |
+ // The navigation should have been canceled before being redirected. |
+ EXPECT_FALSE(observer.was_redirected()); |
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url); |
+} |
+ |
+// Ensure that a NavigationThrottle can cancel the navigation when a navigation |
+// is redirected. |
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, |
+ ThrottleCancelRedirect) { |
+ GURL start_url(embedded_test_server()->GetURL("/title1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), start_url)); |
+ |
+ // A navigation with a redirect should be canceled. |
+ { |
+ GURL redirect_url( |
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html")); |
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url); |
+ TestNavigationThrottleInstaller installer( |
+ shell()->web_contents(), NavigationThrottle::PROCEED, |
+ NavigationThrottle::CANCEL, NavigationThrottle::PROCEED); |
+ |
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url)); |
+ |
+ EXPECT_FALSE(observer.has_committed()); |
+ EXPECT_TRUE(observer.is_error()); |
+ EXPECT_TRUE(observer.was_redirected()); |
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url); |
+ } |
+ |
+ // A navigation without redirects should be successful. |
+ { |
+ GURL no_redirect_url(embedded_test_server()->GetURL("/title2.html")); |
+ NavigationHandleObserver observer(shell()->web_contents(), no_redirect_url); |
+ TestNavigationThrottleInstaller installer( |
+ shell()->web_contents(), NavigationThrottle::PROCEED, |
+ NavigationThrottle::CANCEL, NavigationThrottle::PROCEED); |
+ |
+ EXPECT_TRUE(NavigateToURL(shell(), no_redirect_url)); |
+ |
+ EXPECT_TRUE(observer.has_committed()); |
+ EXPECT_FALSE(observer.is_error()); |
+ EXPECT_FALSE(observer.was_redirected()); |
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), no_redirect_url); |
+ } |
+} |
+ |
+// Ensure that a NavigationThrottle can cancel the navigation when the response |
+// is received. |
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, |
+ ThrottleCancelResponse) { |
+ GURL start_url(embedded_test_server()->GetURL("/title1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), start_url)); |
+ |
+ GURL redirect_url( |
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html")); |
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url); |
+ TestNavigationThrottleInstaller installer( |
+ shell()->web_contents(), NavigationThrottle::PROCEED, |
+ NavigationThrottle::PROCEED, NavigationThrottle::CANCEL); |
+ |
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url)); |
+ |
+ EXPECT_FALSE(observer.has_committed()); |
+ EXPECT_TRUE(observer.is_error()); |
+ // The navigation should have been redirected first, and then canceled when |
+ // the response arrived. |
+ EXPECT_TRUE(observer.was_redirected()); |
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url); |
+} |
+ |
+// Ensure that a NavigationThrottle can defer and resume the navigation at |
+// navigation start, navigation redirect and response received. |
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, ThrottleDefer) { |
+ GURL start_url(embedded_test_server()->GetURL("/title1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), start_url)); |
+ |
+ GURL redirect_url( |
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html")); |
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1); |
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url); |
+ TestNavigationThrottleInstaller installer( |
+ shell()->web_contents(), NavigationThrottle::DEFER, |
+ NavigationThrottle::DEFER, NavigationThrottle::DEFER); |
+ |
+ shell()->LoadURL(redirect_url); |
+ |
+ // Wait for WillStartRequest. |
+ installer.WaitForThrottleWillStart(); |
+ EXPECT_EQ(1, installer.will_start_called()); |
+ EXPECT_EQ(0, installer.will_redirect_called()); |
+ EXPECT_EQ(0, installer.will_process_called()); |
+ installer.navigation_throttle()->Resume(); |
+ |
+ // Wait for WillRedirectRequest. |
+ installer.WaitForThrottleWillRedirect(); |
+ EXPECT_EQ(1, installer.will_start_called()); |
+ EXPECT_EQ(1, installer.will_redirect_called()); |
+ EXPECT_EQ(0, installer.will_process_called()); |
+ installer.navigation_throttle()->Resume(); |
+ |
+ // Wait for WillProcessResponse. |
+ installer.WaitForThrottleWillProcess(); |
+ EXPECT_EQ(1, installer.will_start_called()); |
+ EXPECT_EQ(1, installer.will_redirect_called()); |
+ EXPECT_EQ(1, installer.will_process_called()); |
+ installer.navigation_throttle()->Resume(); |
+ |
+ // Wait for the end of the navigation. |
+ navigation_observer.Wait(); |
+ |
+ EXPECT_TRUE(observer.has_committed()); |
+ EXPECT_TRUE(observer.was_redirected()); |
+ EXPECT_FALSE(observer.is_error()); |
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), |
+ GURL(embedded_test_server()->GetURL("bar.com", "/title2.html"))); |
+} |
+ |
} // namespace content |