Chromium Code Reviews| 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 cfab72949f7efe7eb83b529aaa595cb1c9bba8ec..33b2897ca6a7b89a0c76bfb6357419c36384cdce 100644 |
| --- a/content/browser/frame_host/navigation_handle_impl_browsertest.cc |
| +++ b/content/browser/frame_host/navigation_handle_impl_browsertest.cc |
| @@ -140,6 +140,9 @@ class TestNavigationThrottle : public NavigationThrottle { |
| ~TestNavigationThrottle() override {} |
| void Resume() { navigation_handle()->Resume(); } |
| + void Cancel(NavigationThrottle::ThrottleCheckResult result) { |
| + navigation_handle()->CancelDeferredNavigation(result); |
| + } |
| RequestContextType request_context_type() { return request_context_type_; } |
| @@ -187,21 +190,23 @@ class TestNavigationThrottle : public NavigationThrottle { |
| RequestContextType request_context_type_ = REQUEST_CONTEXT_TYPE_UNSPECIFIED; |
| }; |
| -// Install a TestNavigationThrottle on all following requests and allows waiting |
| -// for various NavigationThrottle related events. Waiting works only for the |
| -// immediately next navigation. New instances are needed to wait for further |
| -// navigations. |
| +// Installs a TestNavigationThrottle either on all following requests or on |
| +// requests with an expected starting URL, and allows waiting for various |
| +// NavigationThrottle related events. Waiting works only for the immediately |
| +// next navigation. New instances are needed to wait for further navigations. |
| class TestNavigationThrottleInstaller : public WebContentsObserver { |
| public: |
| TestNavigationThrottleInstaller( |
| WebContents* web_contents, |
| NavigationThrottle::ThrottleCheckResult will_start_result, |
| NavigationThrottle::ThrottleCheckResult will_redirect_result, |
| - NavigationThrottle::ThrottleCheckResult will_process_result) |
| + NavigationThrottle::ThrottleCheckResult will_process_result, |
| + const GURL& expected_start_url = GURL()) |
| : WebContentsObserver(web_contents), |
| will_start_result_(will_start_result), |
| will_redirect_result_(will_redirect_result), |
| will_process_result_(will_process_result), |
| + expected_start_url_(expected_start_url), |
| weak_factory_(this) {} |
| ~TestNavigationThrottleInstaller() override {} |
| @@ -231,14 +236,45 @@ class TestNavigationThrottleInstaller : public WebContentsObserver { |
| will_process_loop_runner_ = nullptr; |
| } |
| + void Continue(NavigationThrottle::ThrottleCheckResult result) { |
| + ASSERT_NE(NavigationThrottle::DEFER, result); |
| + if (result == NavigationThrottle::PROCEED) |
| + navigation_throttle()->Resume(); |
| + else |
| + navigation_throttle()->Cancel(result); |
| + } |
| + |
| int will_start_called() { return will_start_called_; } |
| int will_redirect_called() { return will_redirect_called_; } |
| int will_process_called() { return will_process_called_; } |
| int install_count() { return install_count_; } |
| + protected: |
| + virtual void DidCallWillStartRequest() { |
| + will_start_called_++; |
| + if (will_start_loop_runner_) |
| + will_start_loop_runner_->Quit(); |
| + } |
| + |
| + virtual void DidCallWillRedirectRequest() { |
| + will_redirect_called_++; |
| + if (will_redirect_loop_runner_) |
| + will_redirect_loop_runner_->Quit(); |
| + } |
| + |
| + virtual void DidCallWillProcessResponse() { |
| + will_process_called_++; |
| + if (will_process_loop_runner_) |
| + will_process_loop_runner_->Quit(); |
| + } |
| + |
| private: |
| void DidStartNavigation(NavigationHandle* handle) override { |
| + if (!expected_start_url_.is_empty() && |
| + handle->GetURL() != expected_start_url_) |
| + return; |
| + |
| std::unique_ptr<NavigationThrottle> throttle(new TestNavigationThrottle( |
| handle, will_start_result_, will_redirect_result_, will_process_result_, |
| base::Bind(&TestNavigationThrottleInstaller::DidCallWillStartRequest, |
| @@ -260,24 +296,6 @@ class TestNavigationThrottleInstaller : public WebContentsObserver { |
| 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_; |
| @@ -289,12 +307,56 @@ class TestNavigationThrottleInstaller : public WebContentsObserver { |
| scoped_refptr<MessageLoopRunner> will_start_loop_runner_; |
| scoped_refptr<MessageLoopRunner> will_redirect_loop_runner_; |
| scoped_refptr<MessageLoopRunner> will_process_loop_runner_; |
| + GURL expected_start_url_; |
| // The throttle installer can be deleted before all tasks posted by its |
| // throttles are run, so it must be referenced via weak pointers. |
| base::WeakPtrFactory<TestNavigationThrottleInstaller> weak_factory_; |
| }; |
| +// Same as above, but installs NavigationThrottles that do not directly return |
| +// the pre-programmed check results, but first DEFER the navigation at each |
| +// stage and then resume/cancel asynchronously. |
| +class TestDeferringNavigationThrottleInstaller |
| + : public TestNavigationThrottleInstaller { |
| + public: |
| + TestDeferringNavigationThrottleInstaller( |
| + WebContents* web_contents, |
| + NavigationThrottle::ThrottleCheckResult will_start_result, |
| + NavigationThrottle::ThrottleCheckResult will_redirect_result, |
| + NavigationThrottle::ThrottleCheckResult will_process_result, |
| + GURL expected_start_url = GURL()) |
| + : TestNavigationThrottleInstaller(web_contents, |
| + NavigationThrottle::DEFER, |
| + NavigationThrottle::DEFER, |
| + NavigationThrottle::DEFER, |
| + expected_start_url), |
| + will_start_deferred_result_(will_start_result), |
| + will_redirect_deferred_result_(will_redirect_result), |
| + will_process_deferred_result_(will_process_result) {} |
| + |
| + protected: |
| + void DidCallWillStartRequest() override { |
| + TestNavigationThrottleInstaller::DidCallWillStartRequest(); |
| + Continue(will_start_deferred_result_); |
| + } |
| + |
| + void DidCallWillRedirectRequest() override { |
| + TestNavigationThrottleInstaller::DidCallWillStartRequest(); |
| + Continue(will_redirect_deferred_result_); |
| + } |
| + |
| + void DidCallWillProcessResponse() override { |
| + TestNavigationThrottleInstaller::DidCallWillStartRequest(); |
| + Continue(will_process_deferred_result_); |
| + } |
| + |
| + private: |
| + NavigationThrottle::ThrottleCheckResult will_start_deferred_result_; |
| + NavigationThrottle::ThrottleCheckResult will_redirect_deferred_result_; |
| + NavigationThrottle::ThrottleCheckResult will_process_deferred_result_; |
| +}; |
| + |
| // Records all navigation start URLs from the WebContents. |
| class NavigationStartUrlRecorder : public WebContentsObserver { |
| public: |
| @@ -311,6 +373,17 @@ class NavigationStartUrlRecorder : public WebContentsObserver { |
| std::vector<GURL> urls_; |
| }; |
| +bool IsChildFrameCollapsed(Shell* shell, const std::string& element_id) { |
| + const char kScript[] = |
| + "window.domAutomationController.send(" |
| + " document.getElementById(\"%s\").clientWidth" |
| + ");"; |
| + int client_width = 0; |
| + EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| + shell, base::StringPrintf(kScript, element_id.c_str()), &client_width)); |
| + return !client_width; |
| +} |
| + |
| } // namespace |
| class NavigationHandleImplBrowserTest : public ContentBrowserTest { |
| @@ -719,6 +792,106 @@ IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, ThrottleDefer) { |
| GURL(embedded_test_server()->GetURL("bar.com", "/title2.html"))); |
| } |
| +// Ensure that a NavigationThrottle can block the navigation and collapse the |
| +// frame owner both on request start as well as after a redirect. Plus, ensure |
| +// that the frame is restored on the subsequent non-error-page navigation. |
| +IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, |
| + ThrottleBlockAndCollapse) { |
| + const char kChildFrameId[] = "child0"; |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/frame_tree/page_with_one_frame.html")); |
| + GURL blocked_subframe_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross-site/baz.com/title1.html")); |
| + GURL allowed_subframe_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross-site/baz.com/title2.html")); |
| + GURL allowed_subframe_final_url( |
| + embedded_test_server()->GetURL("baz.com", "/title2.html")); |
| + |
| + // Exercise both synchronous and deferred throttle check results, and both on |
| + // WillStartRequest and on WillRedirectRequest. |
| + const struct { |
| + NavigationThrottle::ThrottleCheckResult will_start_result; |
| + NavigationThrottle::ThrottleCheckResult will_redirect_result; |
| + bool deferred_block; |
| + } kTestCases[] = { |
| + {NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE, |
| + NavigationThrottle::PROCEED, false}, |
| + {NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE, |
| + NavigationThrottle::PROCEED, true}, |
| + {NavigationThrottle::PROCEED, |
| + NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE, false}, |
| + {NavigationThrottle::PROCEED, |
| + NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE, true}, |
| + }; |
| + |
| + for (const auto& test_case : kTestCases) { |
| + SCOPED_TRACE(::testing::Message() << test_case.will_start_result << ", " |
| + << test_case.will_redirect_result << ", " |
| + << test_case.deferred_block); |
| + |
| + if (!IsBrowserSideNavigationEnabled() && |
| + test_case.will_redirect_result == |
| + NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE) { |
| + continue; |
| + } |
| + |
| + std::unique_ptr<TestNavigationThrottleInstaller> |
| + subframe_throttle_installer; |
| + if (test_case.deferred_block) { |
| + subframe_throttle_installer.reset( |
| + new TestDeferringNavigationThrottleInstaller( |
| + shell()->web_contents(), test_case.will_start_result, |
| + test_case.will_redirect_result, NavigationThrottle::PROCEED, |
| + blocked_subframe_url)); |
| + } else { |
| + subframe_throttle_installer.reset(new TestNavigationThrottleInstaller( |
| + shell()->web_contents(), test_case.will_start_result, |
| + test_case.will_redirect_result, NavigationThrottle::PROCEED, |
| + blocked_subframe_url)); |
| + } |
| + |
| + { |
| + SCOPED_TRACE("Initial navigation blocked on main frame load."); |
| + NavigationHandleObserver subframe_observer(shell()->web_contents(), |
| + blocked_subframe_url); |
| + |
| + ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| + EXPECT_TRUE(subframe_observer.is_error()); |
| + EXPECT_TRUE(subframe_observer.has_committed()); |
| + EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, subframe_observer.net_error_code()); |
| + EXPECT_TRUE(IsChildFrameCollapsed(shell(), kChildFrameId)); |
|
alexmos
2017/04/11 06:00:29
Could we also check that the corresponding FrameTr
engedy
2017/04/11 08:06:17
Sure. Done.
|
| + } |
| + |
| + { |
| + SCOPED_TRACE("Subsequent subframe navigation is allowed."); |
| + NavigationHandleObserver subframe_observer(shell()->web_contents(), |
| + allowed_subframe_url); |
| + |
| + ASSERT_TRUE(NavigateIframeToURL(shell()->web_contents(), kChildFrameId, |
| + allowed_subframe_url)); |
| + EXPECT_TRUE(subframe_observer.has_committed()); |
| + EXPECT_FALSE(subframe_observer.is_error()); |
| + EXPECT_EQ(allowed_subframe_final_url, |
| + subframe_observer.last_committed_url()); |
| + EXPECT_FALSE(IsChildFrameCollapsed(shell(), kChildFrameId)); |
| + } |
| + |
| + { |
| + SCOPED_TRACE("Subsequent subframe navigation is blocked."); |
| + NavigationHandleObserver subframe_observer(shell()->web_contents(), |
| + blocked_subframe_url); |
| + |
| + ASSERT_TRUE(NavigateIframeToURL(shell()->web_contents(), kChildFrameId, |
| + blocked_subframe_url)); |
| + |
| + EXPECT_TRUE(subframe_observer.has_committed()); |
| + EXPECT_TRUE(subframe_observer.is_error()); |
| + EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, subframe_observer.net_error_code()); |
| + EXPECT_TRUE(IsChildFrameCollapsed(shell(), kChildFrameId)); |
| + } |
| + } |
| +} |
| + |
| // Checks that the RequestContextType value is properly set. |
| IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, |
| VerifyRequestContextTypeForFrameTree) { |
| @@ -742,7 +915,8 @@ IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, |
| EXPECT_TRUE(main_manager.WaitForRequestStart()); |
| // For each navigation a new throttle should have been installed. |
| EXPECT_EQ(1, installer.install_count()); |
| - // Checks the only URL recorded so far is the one expected for the main frame. |
| + // Checks the only URL recorded so far is the one expected for the main |
| + // frame. |
|
alexmos
2017/04/11 06:00:29
nit: unnecessary churn?
engedy
2017/04/11 08:06:17
Looks like it, undone.
|
| EXPECT_EQ(main_url, url_recorder.urls().back()); |
| EXPECT_EQ(1ul, url_recorder.urls().size()); |
| // Checks the main frame RequestContextType. |