Home | History | Annotate | Download | only in history
      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 
     27 namespace {
     28 
     29 class 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
     41 TEST_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.
     61 TEST_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
     94 TEST_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 
    144 TEST_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(&current_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, &current_path));
    188   ASSERT_TRUE(file_util::AbsolutePath(&current_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
    196 TEST_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.
    228 TEST_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.
    248 TEST_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.
    269 TEST_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
    294 TEST_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