1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "base/command_line.h"
7#include "content/browser/loader/cross_site_resource_handler.h"
8#include "content/browser/loader/resource_dispatcher_host_impl.h"
9#include "content/browser/loader/resource_request_info_impl.h"
10#include "content/browser/transition_request_manager.h"
11#include "content/browser/web_contents/web_contents_impl.h"
12#include "content/public/browser/web_contents_observer.h"
13#include "content/public/common/content_switches.h"
14#include "content/public/test/browser_test_utils.h"
15#include "content/public/test/content_browser_test.h"
16#include "content/public/test/content_browser_test_utils.h"
17#include "content/public/test/test_utils.h"
18#include "content/shell/browser/shell.h"
19#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
20#include "net/test/embedded_test_server/embedded_test_server.h"
21#include "net/url_request/url_request.h"
22
23namespace content {
24
25class TransitionBrowserTest : public ContentBrowserTest {
26 public:
27  TransitionBrowserTest() {}
28
29  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
30    command_line->AppendSwitch(
31        switches::kEnableExperimentalWebPlatformFeatures);
32  }
33
34 private:
35  DISALLOW_COPY_AND_ASSIGN(TransitionBrowserTest);
36};
37
38class TransitionBrowserTestObserver
39    : public WebContentsObserver,
40      public ShellResourceDispatcherHostDelegate {
41 public:
42  TransitionBrowserTestObserver(WebContents* web_contents)
43      : WebContentsObserver(web_contents),
44        request_(NULL),
45        did_defer_response_(false),
46        is_transition_request_(false) {
47  }
48
49  virtual void RequestBeginning(
50      net::URLRequest* request,
51      ResourceContext* resource_context,
52      AppCacheService* appcache_service,
53      ResourceType resource_type,
54      ScopedVector<ResourceThrottle>* throttles) OVERRIDE {
55    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
56    ShellResourceDispatcherHostDelegate::RequestBeginning(request,
57                                                          resource_context,
58                                                          appcache_service,
59                                                          resource_type,
60                                                          throttles);
61    request_ = request;
62
63    ResourceRequestInfoImpl* info =
64        ResourceRequestInfoImpl::ForRequest(request_);
65
66    if (is_transition_request_) {
67      TransitionRequestManager::GetInstance()->AddPendingTransitionRequestData(
68          info->GetChildID(), info->GetRenderFrameID(), "*", "", "");
69    }
70  }
71
72  virtual void OnResponseStarted(
73      net::URLRequest* request,
74      ResourceContext* resource_context,
75      ResourceResponse* response,
76      IPC::Sender* sender) OVERRIDE {
77    ResourceRequestInfoImpl* info =
78        ResourceRequestInfoImpl::ForRequest(request_);
79
80    did_defer_response_ = info->cross_site_handler()->did_defer_for_testing();
81  }
82
83  void set_pending_transition_request(bool is_transition_request) {
84    is_transition_request_ = is_transition_request;
85  }
86
87  bool did_defer_response() const { return did_defer_response_; }
88
89 private:
90  net::URLRequest* request_;
91  bool did_defer_response_;
92  bool is_transition_request_;
93};
94
95// This tests that normal navigations don't defer at first response.
96IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
97                       NormalNavigationNotDeferred) {
98  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
99  scoped_ptr<TransitionBrowserTestObserver> observer(
100      new TransitionBrowserTestObserver(shell()->web_contents()));
101
102  ResourceDispatcherHost::Get()->SetDelegate(observer.get());
103
104  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
105
106  EXPECT_FALSE(observer->did_defer_response());
107}
108
109// This tests that when a navigation transition is detected, the response is
110// deferred.
111IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
112                       TransitionNavigationIsDeferred) {
113  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
114  scoped_ptr<TransitionBrowserTestObserver> observer(
115      new TransitionBrowserTestObserver(shell()->web_contents()));
116
117  ResourceDispatcherHost::Get()->SetDelegate(observer.get());
118  observer->set_pending_transition_request(true);
119
120  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
121
122  EXPECT_TRUE(observer->did_defer_response());
123}
124
125// This tests that the renderer is reused between the outgoing and transition.
126IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
127                       TransitionNavigationSharesRenderer) {
128  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
129
130  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
131
132  int outgoing_process_id =
133      shell()->web_contents()->GetRenderProcessHost()->GetID();
134
135  WebContents::CreateParams create_params(
136      shell()->web_contents()->GetBrowserContext(),
137      shell()->web_contents()->GetSiteInstance());
138  scoped_ptr<WebContents> transition_web_contents(
139      WebContents::Create(create_params));
140
141  GURL about_blank(url::kAboutBlankURL);
142  NavigationController::LoadURLParams params(about_blank);
143  transition_web_contents->GetController().LoadURLWithParams(params);
144  transition_web_contents->Focus();
145
146  WaitForLoadStop(transition_web_contents.get());
147
148  int transition_process_id =
149      transition_web_contents->GetRenderProcessHost()->GetID();
150
151  EXPECT_EQ(outgoing_process_id, transition_process_id);
152}
153
154}  // namespace content
155