- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / redirect_browsertest.cc
1 // Copyright (c) 2012 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 // Navigates the browser to server and client redirect pages and makes sure
6 // that the correct redirects are reflected in the history database. Errors
7 // here might indicate that WebKit changed the calls our glue layer gets in
8 // the case of redirects. It may also mean problems with the history system.
9
10 #include "base/bind.h"
11 #include "base/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/test/test_timeouts.h"
19 #include "base/threading/platform_thread.h"
20 #include "chrome/browser/history/history_service.h"
21 #include "chrome/browser/history/history_service_factory.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/browser/ui/view_ids.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/test_navigation_observer.h"
31 #include "net/base/net_util.h"
32 #include "net/test/spawned_test_server/spawned_test_server.h"
33 #include "ui/events/event_constants.h"
34
35 class RedirectTest : public InProcessBrowserTest {
36  public:
37   RedirectTest() {}
38
39   std::vector<GURL> GetRedirects(const GURL& url) {
40     HistoryService* history_service =
41         HistoryServiceFactory::GetForProfile(browser()->profile(),
42                                              Profile::EXPLICIT_ACCESS);
43
44     // Schedule a history query for redirects. The response will be sent
45     // asynchronously from the callback the history system uses to notify us
46     // that it's done: OnRedirectQueryComplete.
47     std::vector<GURL> rv;
48     history_service->QueryRedirectsFrom(
49         url, &consumer_,
50         base::Bind(&RedirectTest::OnRedirectQueryComplete,
51                    base::Unretained(this), &rv));
52     content::RunMessageLoop();
53     return rv;
54   }
55
56  protected:
57   void OnRedirectQueryComplete(
58       std::vector<GURL>* rv,
59       HistoryService::Handle request_handle,
60       GURL from_url,
61       bool success,
62       history::RedirectList* redirects) {
63     for (size_t i = 0; i < redirects->size(); ++i)
64       rv->push_back(redirects->at(i));
65     base::MessageLoop::current()->PostTask(FROM_HERE,
66                                            base::MessageLoop::QuitClosure());
67   }
68
69   // Consumer for asynchronous history queries.
70   CancelableRequestConsumer consumer_;
71 };
72
73 // Tests a single server redirect
74 IN_PROC_BROWSER_TEST_F(RedirectTest, Server) {
75   ASSERT_TRUE(test_server()->Start());
76   GURL final_url = test_server()->GetURL(std::string());
77   GURL first_url = test_server()->GetURL(
78       "server-redirect?" + final_url.spec());
79
80   ui_test_utils::NavigateToURL(browser(), first_url);
81
82   std::vector<GURL> redirects = GetRedirects(first_url);
83
84   ASSERT_EQ(1U, redirects.size());
85   EXPECT_EQ(final_url.spec(), redirects[0].spec());
86 }
87
88 // Tests a single client redirect.
89 IN_PROC_BROWSER_TEST_F(RedirectTest, Client) {
90   ASSERT_TRUE(test_server()->Start());
91
92   GURL final_url = test_server()->GetURL(std::string());
93   GURL first_url = test_server()->GetURL(
94       "client-redirect?" + final_url.spec());
95
96   // The client redirect appears as two page visits in the browser.
97   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
98       browser(), first_url, 2);
99
100   std::vector<GURL> redirects = GetRedirects(first_url);
101
102   ASSERT_EQ(1U, redirects.size());
103   EXPECT_EQ(final_url.spec(), redirects[0].spec());
104
105   // The address bar should display the final URL.
106   EXPECT_EQ(final_url,
107             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
108
109   // Navigate one more time.
110   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
111       browser(), first_url, 2);
112
113   // The address bar should still display the final URL.
114   EXPECT_EQ(final_url,
115             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
116 }
117
118 // http://code.google.com/p/chromium/issues/detail?id=62772
119 IN_PROC_BROWSER_TEST_F(RedirectTest, ClientEmptyReferer) {
120   ASSERT_TRUE(test_server()->Start());
121
122   // Create the file contents, which will do a redirect to the
123   // test server.
124   GURL final_url = test_server()->GetURL(std::string());
125   ASSERT_TRUE(final_url.is_valid());
126   std::string file_redirect_contents = base::StringPrintf(
127       "<html>"
128       "<head></head>"
129       "<body onload=\"document.location='%s'\"></body>"
130       "</html>",
131       final_url.spec().c_str());
132
133   // Write the contents to a temporary file.
134   base::ScopedTempDir temp_directory;
135   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
136   base::FilePath temp_file;
137   ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
138                                                   &temp_file));
139   ASSERT_EQ(static_cast<int>(file_redirect_contents.size()),
140             file_util::WriteFile(temp_file,
141                                  file_redirect_contents.data(),
142                                  file_redirect_contents.size()));
143
144   // Navigate to the file through the browser. The client redirect will appear
145   // as two page visits in the browser.
146   GURL first_url = net::FilePathToFileURL(temp_file);
147   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
148       browser(), first_url, 2);
149
150   std::vector<GURL> redirects = GetRedirects(first_url);
151   ASSERT_EQ(1U, redirects.size());
152   EXPECT_EQ(final_url.spec(), redirects[0].spec());
153 }
154
155 // Tests to make sure a location change when a pending redirect exists isn't
156 // flagged as a redirect.
157 IN_PROC_BROWSER_TEST_F(RedirectTest, ClientCancelled) {
158   GURL first_url = ui_test_utils::GetTestUrl(
159       base::FilePath(),
160       base::FilePath().AppendASCII("cancelled_redirect_test.html"));
161   ui_test_utils::NavigateToURL(browser(), first_url);
162
163   content::WebContents* web_contents =
164       browser()->tab_strip_model()->GetActiveWebContents();
165   content::TestNavigationObserver navigation_observer(web_contents);
166
167   // Simulate a click to force to make a user-initiated location change;
168   // otherwise, a non user-initiated in-page location change will be treated
169   // as client redirect and the redirect will be recoreded, which can cause
170   // this test failed.
171   content::SimulateMouseClick(web_contents, 0,
172       WebKit::WebMouseEvent::ButtonLeft);
173   navigation_observer.Wait();
174
175   std::vector<GURL> redirects = GetRedirects(first_url);
176
177   // There should be no redirects from first_url, because the anchor location
178   // change that occurs should not be flagged as a redirect and the meta-refresh
179   // won't have fired yet.
180   ASSERT_EQ(0U, redirects.size());
181   EXPECT_EQ("myanchor", web_contents->GetURL().ref());
182 }
183
184 // Tests a client->server->server redirect
185 IN_PROC_BROWSER_TEST_F(RedirectTest, ClientServerServer) {
186   ASSERT_TRUE(test_server()->Start());
187
188   GURL final_url = test_server()->GetURL(std::string());
189   GURL next_to_last = test_server()->GetURL(
190       "server-redirect?" + final_url.spec());
191   GURL second_url = test_server()->GetURL(
192       "server-redirect?" + next_to_last.spec());
193   GURL first_url = test_server()->GetURL(
194       "client-redirect?" + second_url.spec());
195
196   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
197       browser(), first_url, 2);
198
199   std::vector<GURL> redirects = GetRedirects(first_url);
200   ASSERT_EQ(3U, redirects.size());
201   EXPECT_EQ(second_url.spec(), redirects[0].spec());
202   EXPECT_EQ(next_to_last.spec(), redirects[1].spec());
203   EXPECT_EQ(final_url.spec(), redirects[2].spec());
204 }
205
206 // Tests that the "#reference" gets preserved across server redirects.
207 IN_PROC_BROWSER_TEST_F(RedirectTest, ServerReference) {
208   ASSERT_TRUE(test_server()->Start());
209
210   const std::string ref("reference");
211
212   GURL final_url = test_server()->GetURL(std::string());
213   GURL initial_url = test_server()->GetURL(
214       "server-redirect?" + final_url.spec() + "#" + ref);
215
216   ui_test_utils::NavigateToURL(browser(), initial_url);
217
218   EXPECT_EQ(ref,
219             browser()->tab_strip_model()->GetActiveWebContents()->
220                 GetURL().ref());
221 }
222
223 // Test that redirect from http:// to file:// :
224 // A) does not crash the browser or confuse the redirect chain, see bug 1080873
225 // B) does not take place.
226 //
227 // Flaky on XP and Vista, http://crbug.com/69390.
228 IN_PROC_BROWSER_TEST_F(RedirectTest, NoHttpToFile) {
229   ASSERT_TRUE(test_server()->Start());
230   GURL file_url = ui_test_utils::GetTestUrl(
231       base::FilePath(), base::FilePath().AppendASCII("http_to_file.html"));
232
233   GURL initial_url = test_server()->GetURL(
234       "client-redirect?" + file_url.spec());
235
236   ui_test_utils::NavigateToURL(browser(), initial_url);
237   // We make sure the title doesn't match the title from the file, because the
238   // nav should not have taken place.
239   EXPECT_NE(ASCIIToUTF16("File!"),
240             browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
241 }
242
243 // Ensures that non-user initiated location changes (within page) are
244 // flagged as client redirects. See bug 1139823.
245 IN_PROC_BROWSER_TEST_F(RedirectTest, ClientFragments) {
246   ASSERT_TRUE(test_server()->Start());
247   GURL first_url = ui_test_utils::GetTestUrl(
248       base::FilePath(), base::FilePath().AppendASCII("ref_redirect.html"));
249   ui_test_utils::NavigateToURL(browser(), first_url);
250   std::vector<GURL> redirects = GetRedirects(first_url);
251   EXPECT_EQ(1U, redirects.size());
252   EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
253 }
254
255 // TODO(timsteele): This is disabled because our current testserver can't
256 // handle multiple requests in parallel, making it hang on the first request
257 // to /slow?60. It's unable to serve our second request for files/title2.html
258 // until /slow? completes, which doesn't give the desired behavior. We could
259 // alternatively load the second page from disk, but we would need to start
260 // the browser for this testcase with --process-per-tab, and I don't think
261 // we can do this at test-case-level granularity at the moment.
262 // http://crbug.com/45056
263 IN_PROC_BROWSER_TEST_F(RedirectTest,
264        DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
265   // We want to initiate a second navigation after the provisional load for
266   // the client redirect destination has started, but before this load is
267   // committed. To achieve this, we tell the browser to load a slow page,
268   // which causes it to start a provisional load, and while it is waiting
269   // for the response (which means it hasn't committed the load for the client
270   // redirect destination page yet), we issue a new navigation request.
271   ASSERT_TRUE(test_server()->Start());
272
273   GURL final_url = test_server()->GetURL("files/title2.html");
274   GURL slow = test_server()->GetURL("slow?60");
275   GURL first_url = test_server()->GetURL(
276       "client-redirect?" + slow.spec());
277
278   content::WebContents* web_contents =
279       browser()->tab_strip_model()->GetActiveWebContents();
280   content::TestNavigationObserver observer(web_contents, 2);
281
282   ui_test_utils::NavigateToURLWithDisposition(
283       browser(), first_url, CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
284   // We don't sleep here - the first navigation won't have been committed yet
285   // because we told the server to wait a minute. This means the browser has
286   // started it's provisional load for the client redirect destination page but
287   // hasn't completed. Our time is now!
288   ui_test_utils::NavigateToURLWithDisposition(
289       browser(), final_url, CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
290   observer.Wait();
291
292   // Check to make sure the navigation did in fact take place and we are
293   // at the expected page.
294   EXPECT_EQ(ASCIIToUTF16("Title Of Awesomeness"),
295             browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
296
297   bool final_navigation_not_redirect = true;
298   std::vector<GURL> redirects = GetRedirects(first_url);
299   // Check to make sure our request for files/title2.html doesn't get flagged
300   // as a client redirect from the first (/client-redirect?) page.
301   for (std::vector<GURL>::iterator it = redirects.begin();
302        it != redirects.end(); ++it) {
303     if (final_url.spec() == it->spec()) {
304       final_navigation_not_redirect = false;
305       break;
306     }
307   }
308   EXPECT_TRUE(final_navigation_not_redirect);
309 }