| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "content/browser/loader/cross_site_resource_handler.h" |
| #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| #include "content/browser/loader/resource_request_info_impl.h" |
| #include "content/browser/transition_request_manager.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/common/content_switches.h" |
| #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_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/url_request/url_request.h" |
| |
| namespace content { |
| |
| class TransitionBrowserTest : public ContentBrowserTest { |
| public: |
| TransitionBrowserTest() {} |
| |
| void SetUpCommandLine(CommandLine* command_line) override { |
| command_line->AppendSwitch( |
| switches::kEnableExperimentalWebPlatformFeatures); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TransitionBrowserTest); |
| }; |
| |
| class TransitionBrowserTestObserver |
| : public WebContentsObserver, |
| public ShellResourceDispatcherHostDelegate { |
| public: |
| TransitionBrowserTestObserver(WebContents* web_contents) |
| : WebContentsObserver(web_contents), |
| request_(NULL), |
| did_defer_response_(false), |
| is_transition_request_(false), |
| did_clear_data_(false) { |
| } |
| |
| void RequestBeginning(net::URLRequest* request, |
| ResourceContext* resource_context, |
| AppCacheService* appcache_service, |
| ResourceType resource_type, |
| ScopedVector<ResourceThrottle>* throttles) override { |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| ShellResourceDispatcherHostDelegate::RequestBeginning(request, |
| resource_context, |
| appcache_service, |
| resource_type, |
| throttles); |
| request_ = request; |
| |
| ResourceRequestInfoImpl* info = |
| ResourceRequestInfoImpl::ForRequest(request_); |
| |
| if (is_transition_request_) { |
| TransitionRequestManager::GetInstance( |
| )->AddPendingTransitionRequestDataForTesting( |
| info->GetChildID(), info->GetRenderFrameID()); |
| } |
| } |
| |
| void OnResponseStarted(net::URLRequest* request, |
| ResourceContext* resource_context, |
| ResourceResponse* response, |
| IPC::Sender* sender) override { |
| ResourceRequestInfoImpl* info = |
| ResourceRequestInfoImpl::ForRequest(request_); |
| |
| did_defer_response_ = info->cross_site_handler()->did_defer_for_testing(); |
| } |
| |
| void RequestComplete(net::URLRequest* url_request) override { |
| if (is_transition_request_) { |
| ResourceRequestInfoImpl* info = |
| ResourceRequestInfoImpl::ForRequest(request_); |
| TransitionLayerData transition_data; |
| did_clear_data_ = !TransitionRequestManager::GetInstance( |
| )->HasPendingTransitionRequest(info->GetChildID(), |
| info->GetRenderFrameID(), |
| request_->url(), |
| &transition_data); |
| } |
| } |
| |
| void set_pending_transition_request(bool is_transition_request) { |
| is_transition_request_ = is_transition_request; |
| } |
| |
| bool did_defer_response() const { return did_defer_response_; } |
| bool did_clear_data() const { return did_clear_data_; } |
| |
| private: |
| net::URLRequest* request_; |
| bool did_defer_response_; |
| bool is_transition_request_; |
| bool did_clear_data_; |
| }; |
| |
| // This tests that normal navigations don't defer at first response. |
| IN_PROC_BROWSER_TEST_F(TransitionBrowserTest, |
| NormalNavigationNotDeferred) { |
| // This test shouldn't run in --site-per-process mode, where normal |
| // navigations are also deferred. |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kSitePerProcess)) |
| return; |
| |
| ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| scoped_ptr<TransitionBrowserTestObserver> observer( |
| new TransitionBrowserTestObserver(shell()->web_contents())); |
| |
| ResourceDispatcherHost::Get()->SetDelegate(observer.get()); |
| |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); |
| |
| EXPECT_FALSE(observer->did_defer_response()); |
| } |
| |
| // This tests that when a navigation transition is detected, the response is |
| // deferred. |
| IN_PROC_BROWSER_TEST_F(TransitionBrowserTest, |
| TransitionNavigationIsDeferred) { |
| ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| scoped_ptr<TransitionBrowserTestObserver> observer( |
| new TransitionBrowserTestObserver(shell()->web_contents())); |
| |
| ResourceDispatcherHost::Get()->SetDelegate(observer.get()); |
| observer->set_pending_transition_request(true); |
| |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); |
| |
| EXPECT_TRUE(observer->did_defer_response()); |
| } |
| |
| // This tests that the renderer is reused between the outgoing and transition. |
| IN_PROC_BROWSER_TEST_F(TransitionBrowserTest, |
| TransitionNavigationSharesRenderer) { |
| ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); |
| |
| int outgoing_process_id = |
| shell()->web_contents()->GetRenderProcessHost()->GetID(); |
| |
| WebContents::CreateParams create_params( |
| shell()->web_contents()->GetBrowserContext(), |
| shell()->web_contents()->GetSiteInstance()); |
| scoped_ptr<WebContents> transition_web_contents( |
| WebContents::Create(create_params)); |
| |
| GURL about_blank(url::kAboutBlankURL); |
| NavigationController::LoadURLParams params(about_blank); |
| transition_web_contents->GetController().LoadURLWithParams(params); |
| transition_web_contents->Focus(); |
| |
| WaitForLoadStop(transition_web_contents.get()); |
| |
| int transition_process_id = |
| transition_web_contents->GetRenderProcessHost()->GetID(); |
| |
| EXPECT_EQ(outgoing_process_id, transition_process_id); |
| } |
| |
| // This tests that the transition data is cleared after the transition. |
| IN_PROC_BROWSER_TEST_F(TransitionBrowserTest, |
| TransitionNavigationDataIsCleared) { |
| ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| scoped_ptr<TransitionBrowserTestObserver> observer( |
| new TransitionBrowserTestObserver(shell()->web_contents())); |
| |
| ResourceDispatcherHost::Get()->SetDelegate(observer.get()); |
| observer->set_pending_transition_request(true); |
| |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); |
| WaitForLoadStop(shell()->web_contents()); |
| |
| EXPECT_TRUE(observer->did_clear_data()); |
| } |
| |
| } // namespace content |