1// Copyright (c) 2011 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/file_util.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/memory/scoped_temp_dir.h" 13#include "base/string_util.h" 14#include "base/string16.h" 15#include "base/test/test_timeouts.h" 16#include "base/threading/platform_thread.h" 17#include "base/utf_string_conversions.h" 18#include "chrome/browser/ui/view_ids.h" 19#include "chrome/test/automation/browser_proxy.h" 20#include "chrome/test/automation/tab_proxy.h" 21#include "chrome/test/automation/window_proxy.h" 22#include "chrome/test/ui/ui_test.h" 23#include "net/base/net_util.h" 24#include "net/test/test_server.h" 25#include "ui/base/events.h" 26 27namespace { 28 29class RedirectTest : public UITest { 30 public: 31 RedirectTest() 32 : test_server_(net::TestServer::TYPE_HTTP, 33 FilePath(FILE_PATH_LITERAL("chrome/test/data"))) { 34 } 35 36 protected: 37 net::TestServer test_server_; 38}; 39 40// Tests a single server redirect 41TEST_F(RedirectTest, Server) { 42 ASSERT_TRUE(test_server_.Start()); 43 44 GURL final_url = test_server_.GetURL(std::string()); 45 GURL first_url = test_server_.GetURL( 46 "server-redirect?" + final_url.spec()); 47 48 NavigateToURL(first_url); 49 50 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 51 ASSERT_TRUE(tab_proxy.get()); 52 53 std::vector<GURL> redirects; 54 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 55 56 ASSERT_EQ(1U, redirects.size()); 57 EXPECT_EQ(final_url.spec(), redirects[0].spec()); 58} 59 60// Tests a single client redirect. 61TEST_F(RedirectTest, Client) { 62 ASSERT_TRUE(test_server_.Start()); 63 64 GURL final_url = test_server_.GetURL(std::string()); 65 GURL first_url = test_server_.GetURL( 66 "client-redirect?" + final_url.spec()); 67 68 // The client redirect appears as two page visits in the browser. 69 NavigateToURLBlockUntilNavigationsComplete(first_url, 2); 70 71 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 72 ASSERT_TRUE(tab_proxy.get()); 73 74 std::vector<GURL> redirects; 75 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 76 77 ASSERT_EQ(1U, redirects.size()); 78 EXPECT_EQ(final_url.spec(), redirects[0].spec()); 79 80 // The address bar should display the final URL. 81 GURL tab_url; 82 EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url)); 83 EXPECT_TRUE(final_url == tab_url); 84 85 // Navigate one more time. 86 NavigateToURLBlockUntilNavigationsComplete(first_url, 2); 87 88 // The address bar should still display the final URL. 89 EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url)); 90 EXPECT_TRUE(final_url == tab_url); 91} 92 93// http://code.google.com/p/chromium/issues/detail?id=62772 94TEST_F(RedirectTest, FLAKY_ClientEmptyReferer) { 95 ASSERT_TRUE(test_server_.Start()); 96 97 // Create the file contents, which will do a redirect to the 98 // test server. 99 GURL final_url = test_server_.GetURL(std::string()); 100 ASSERT_TRUE(final_url.is_valid()); 101 std::string file_redirect_contents = StringPrintf( 102 "<html>" 103 "<head></head>" 104 "<body onload=\"document.location='%s'\"></body>" 105 "</html>", 106 final_url.spec().c_str()); 107 108 // Write the contents to a temporary file. 109 ScopedTempDir temp_directory; 110 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); 111 FilePath temp_file; 112 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(), 113 &temp_file)); 114 ASSERT_EQ(static_cast<int>(file_redirect_contents.size()), 115 file_util::WriteFile(temp_file, 116 file_redirect_contents.data(), 117 file_redirect_contents.size())); 118 119 // Navigate to the file through the browser. The client redirect will appear 120 // as two page visits in the browser. 121 GURL first_url = net::FilePathToFileURL(temp_file); 122 NavigateToURLBlockUntilNavigationsComplete(first_url, 2); 123 124 std::vector<GURL> redirects; 125 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 126 ASSERT_TRUE(tab_proxy.get()); 127 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 128 ASSERT_EQ(1U, redirects.size()); 129 EXPECT_EQ(final_url.spec(), redirects[0].spec()); 130} 131 132// Tests to make sure a location change when a pending redirect exists isn't 133// flagged as a redirect. 134#if defined(OS_MACOSX) 135// SimulateOSClick is broken on the Mac: http://crbug.com/45162 136#define MAYBE_ClientCancelled DISABLED_ClientCancelled 137#elif defined(OS_WIN) 138// http://crbug.com/53091 139#define MAYBE_ClientCancelled FAILS_ClientCancelled 140#else 141#define MAYBE_ClientCancelled ClientCancelled 142#endif 143 144TEST_F(RedirectTest, MAYBE_ClientCancelled) { 145 FilePath first_path(test_data_directory_); 146 first_path = first_path.AppendASCII("cancelled_redirect_test.html"); 147 ASSERT_TRUE(file_util::AbsolutePath(&first_path)); 148 GURL first_url = net::FilePathToFileURL(first_path); 149 150 NavigateToURLBlockUntilNavigationsComplete(first_url, 1); 151 152 scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0); 153 ASSERT_TRUE(browser.get()); 154 scoped_refptr<WindowProxy> window = browser->GetWindow(); 155 ASSERT_TRUE(window.get()); 156 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 157 ASSERT_TRUE(tab_proxy.get()); 158 int64 last_nav_time = 0; 159 EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time)); 160 // Simulate a click to force to make a user-initiated location change; 161 // otherwise, a non user-initiated in-page location change will be treated 162 // as client redirect and the redirect will be recoreded, which can cause 163 // this test failed. 164 gfx::Rect tab_view_bounds; 165 ASSERT_TRUE(browser->BringToFront()); 166 ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds, 167 true)); 168 ASSERT_TRUE(window->SimulateOSClick(tab_view_bounds.CenterPoint(), 169 ui::EF_LEFT_BUTTON_DOWN)); 170 EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time)); 171 172 std::vector<GURL> redirects; 173 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 174 175 // There should be no redirects from first_url, because the anchor location 176 // change that occurs should not be flagged as a redirect and the meta-refresh 177 // won't have fired yet. 178 ASSERT_EQ(0U, redirects.size()); 179 GURL current_url; 180 ASSERT_TRUE(tab_proxy->GetCurrentURL(¤t_url)); 181 182 // Need to test final path and ref separately since constructing a file url 183 // containing an anchor using FilePathToFileURL will escape the anchor as 184 // %23, but in current_url the anchor will be '#'. 185 std::string final_ref = "myanchor"; 186 FilePath current_path; 187 ASSERT_TRUE(net::FileURLToFilePath(current_url, ¤t_path)); 188 ASSERT_TRUE(file_util::AbsolutePath(¤t_path)); 189 // Path should remain unchanged. 190 EXPECT_EQ(StringToLowerASCII(first_path.value()), 191 StringToLowerASCII(current_path.value())); 192 EXPECT_EQ(final_ref, current_url.ref()); 193} 194 195// Tests a client->server->server redirect 196TEST_F(RedirectTest, ClientServerServer) { 197 ASSERT_TRUE(test_server_.Start()); 198 199 GURL final_url = test_server_.GetURL(std::string()); 200 GURL next_to_last = test_server_.GetURL( 201 "server-redirect?" + final_url.spec()); 202 GURL second_url = test_server_.GetURL( 203 "server-redirect?" + next_to_last.spec()); 204 GURL first_url = test_server_.GetURL( 205 "client-redirect?" + second_url.spec()); 206 std::vector<GURL> redirects; 207 208 // We need the sleep for the client redirects, because it appears as two 209 // page visits in the browser. 210 NavigateToURL(first_url); 211 212 for (int i = 0; i < 10; ++i) { 213 base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms()); 214 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 215 ASSERT_TRUE(tab_proxy.get()); 216 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 217 if (!redirects.empty()) 218 break; 219 } 220 221 ASSERT_EQ(3U, redirects.size()); 222 EXPECT_EQ(second_url.spec(), redirects[0].spec()); 223 EXPECT_EQ(next_to_last.spec(), redirects[1].spec()); 224 EXPECT_EQ(final_url.spec(), redirects[2].spec()); 225} 226 227// Tests that the "#reference" gets preserved across server redirects. 228TEST_F(RedirectTest, ServerReference) { 229 ASSERT_TRUE(test_server_.Start()); 230 231 const std::string ref("reference"); 232 233 GURL final_url = test_server_.GetURL(std::string()); 234 GURL initial_url = test_server_.GetURL( 235 "server-redirect?" + final_url.spec() + "#" + ref); 236 237 NavigateToURL(initial_url); 238 239 GURL url = GetActiveTabURL(); 240 EXPECT_EQ(ref, url.ref()); 241} 242 243// Test that redirect from http:// to file:// : 244// A) does not crash the browser or confuse the redirect chain, see bug 1080873 245// B) does not take place. 246// 247// Flaky on XP and Vista, http://crbug.com/69390. 248TEST_F(RedirectTest, FLAKY_NoHttpToFile) { 249 ASSERT_TRUE(test_server_.Start()); 250 FilePath test_file(test_data_directory_); 251 test_file = test_file.AppendASCII("http_to_file.html"); 252 GURL file_url = net::FilePathToFileURL(test_file); 253 254 GURL initial_url = test_server_.GetURL( 255 "client-redirect?" + file_url.spec()); 256 257 NavigateToURL(initial_url); 258 // UITest will check for crashes. We make sure the title doesn't match the 259 // title from the file, because the nav should not have taken place. 260 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 261 ASSERT_TRUE(tab_proxy.get()); 262 std::wstring actual_title; 263 ASSERT_TRUE(tab_proxy->GetTabTitle(&actual_title)); 264 EXPECT_NE("File!", WideToUTF8(actual_title)); 265} 266 267// Ensures that non-user initiated location changes (within page) are 268// flagged as client redirects. See bug 1139823. 269TEST_F(RedirectTest, ClientFragments) { 270 ASSERT_TRUE(test_server_.Start()); 271 272 FilePath test_file(test_data_directory_); 273 test_file = test_file.AppendASCII("ref_redirect.html"); 274 GURL first_url = net::FilePathToFileURL(test_file); 275 std::vector<GURL> redirects; 276 277 NavigateToURL(first_url); 278 279 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 280 ASSERT_TRUE(tab_proxy.get()); 281 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 282 EXPECT_EQ(1U, redirects.size()); 283 EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec()); 284} 285 286// TODO(timsteele): This is disabled because our current testserver can't 287// handle multiple requests in parallel, making it hang on the first request 288// to /slow?60. It's unable to serve our second request for files/title2.html 289// until /slow? completes, which doesn't give the desired behavior. We could 290// alternatively load the second page from disk, but we would need to start 291// the browser for this testcase with --process-per-tab, and I don't think 292// we can do this at test-case-level granularity at the moment. 293// http://crbug.com/45056 294TEST_F(RedirectTest, 295 DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) { 296 // We want to initiate a second navigation after the provisional load for 297 // the client redirect destination has started, but before this load is 298 // committed. To achieve this, we tell the browser to load a slow page, 299 // which causes it to start a provisional load, and while it is waiting 300 // for the response (which means it hasn't committed the load for the client 301 // redirect destination page yet), we issue a new navigation request. 302 ASSERT_TRUE(test_server_.Start()); 303 304 GURL final_url = test_server_.GetURL("files/title2.html"); 305 GURL slow = test_server_.GetURL("slow?60"); 306 GURL first_url = test_server_.GetURL( 307 "client-redirect?" + slow.spec()); 308 std::vector<GURL> redirects; 309 310 NavigateToURL(first_url); 311 // We don't sleep here - the first navigation won't have been committed yet 312 // because we told the server to wait a minute. This means the browser has 313 // started it's provisional load for the client redirect destination page but 314 // hasn't completed. Our time is now! 315 NavigateToURL(final_url); 316 317 std::wstring tab_title; 318 std::wstring final_url_title = UTF8ToWide("Title Of Awesomeness"); 319 // Wait till the final page has been loaded. 320 for (int i = 0; i < 10; ++i) { 321 base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms()); 322 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); 323 ASSERT_TRUE(tab_proxy.get()); 324 ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title)); 325 if (tab_title == final_url_title) { 326 ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects)); 327 break; 328 } 329 } 330 331 // Check to make sure the navigation did in fact take place and we are 332 // at the expected page. 333 EXPECT_EQ(final_url_title, tab_title); 334 335 bool final_navigation_not_redirect = true; 336 // Check to make sure our request for files/title2.html doesn't get flagged 337 // as a client redirect from the first (/client-redirect?) page. 338 for (std::vector<GURL>::iterator it = redirects.begin(); 339 it != redirects.end(); ++it) { 340 if (final_url.spec() == it->spec()) { 341 final_navigation_not_redirect = false; 342 break; 343 } 344 } 345 EXPECT_TRUE(final_navigation_not_redirect); 346} 347 348} // namespace 349