blob: 6b2eba35006494a85935d3edf65677295698cbec [file] [log] [blame]
// 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(base::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(
)->GetPendingTransitionRequest(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