| // Copyright 2019 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/files/file_path.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/synchronization/lock.h" |
| #include "base/test/bind.h" |
| #include "base/thread_annotations.h" |
| #include "build/build_config.h" |
| #include "components/network_session_configurator/common/network_switches.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "weblayer/browser/tab_impl.h" |
| #include "weblayer/shell/browser/shell.h" |
| #include "weblayer/test/weblayer_browser_test.h" |
| #include "weblayer/test/weblayer_browser_test_utils.h" |
| |
| namespace weblayer { |
| namespace { |
| const char kPrefetchPage[] = "/simple_prefetch.html"; |
| const char kRedirectPrefetchPage[] = "/redirect_prefetch.html"; |
| const char kRedirectPrefetchUrl[] = "/redirect"; |
| const char kRedirectedPrefetchUrl[] = "/redirected"; |
| const char kPrefetchTarget[] = "/prefetch_target.lnk"; |
| } // namespace |
| |
| class PrefetchBrowserTest : public WebLayerBrowserTest { |
| public: |
| void SetUpOnMainThread() override { |
| // The test makes requests to google.com which we want to redirect to the |
| // test server. |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| |
| embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( |
| &PrefetchBrowserTest::MonitorRequest, base::Unretained(this))); |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // Set a dummy variation ID to send X-Client-Data header to Google hosts |
| // in RedirectedPrefetch test. |
| command_line->AppendSwitchASCII("force-variation-ids", "42"); |
| // Need to ignore cert errors to use a HTTPS server for the test domains. |
| command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
| } |
| |
| bool RunPrefetchExperiment(GURL url, const std::u16string expected_title) { |
| content::TitleWatcher title_watcher( |
| static_cast<TabImpl*>(shell()->tab())->web_contents(), expected_title); |
| NavigateAndWaitForCompletion(url, shell()); |
| return expected_title == title_watcher.WaitAndGetTitle(); |
| } |
| |
| protected: |
| bool prefetch_target_request_seen_ = false; |
| base::Lock lock_; |
| |
| // |requests_| is accessed on the UI thread by the test body and on the IO |
| // thread by the test server's request handler, so must be guarded by a lock |
| // to avoid data races. |
| std::vector<net::test_server::HttpRequest> requests_ GUARDED_BY(lock_); |
| |
| private: |
| void MonitorRequest(const net::test_server::HttpRequest& request) { |
| if (request.relative_url == std::string(kPrefetchTarget)) { |
| prefetch_target_request_seen_ = true; |
| } |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, PrefetchWorks) { |
| // Set real NetworkChangeNotifier singleton aside. |
| std::unique_ptr<net::NetworkChangeNotifier::DisableForTest> disable_for_test( |
| new net::NetworkChangeNotifier::DisableForTest); |
| ASSERT_FALSE(prefetch_target_request_seen_); |
| EXPECT_TRUE(RunPrefetchExperiment( |
| embedded_test_server()->GetURL(kPrefetchPage), u"link onload")); |
| EXPECT_TRUE(prefetch_target_request_seen_); |
| } |
| |
| // https://crbug.com/922362: When the prefetched request is redirected, DCHECKs |
| // in PrefetchURLLoader::FollowRedirect() failed due to "X-Client-Data" in |
| // removed_headers. Verify that it no longer does. |
| IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, RedirectedPrefetch) { |
| net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server.RegisterRequestHandler(base::BindLambdaForTesting( |
| [this](const net::test_server::HttpRequest& request) |
| -> std::unique_ptr<net::test_server::HttpResponse> { |
| auto response = std::make_unique<net::test_server::BasicHttpResponse>(); |
| base::AutoLock auto_lock(lock_); |
| if (request.relative_url == std::string(kRedirectPrefetchPage)) { |
| requests_.push_back(request); |
| response->set_content_type("text/html"); |
| response->set_content( |
| base::StringPrintf("<link rel=\"prefetch\" href=\"%s\" " |
| "onload=\"document.title='done'\">", |
| kRedirectPrefetchUrl)); |
| return response; |
| } else if (request.relative_url == std::string(kRedirectPrefetchUrl)) { |
| requests_.push_back(request); |
| response->set_code(net::HTTP_MOVED_PERMANENTLY); |
| response->AddCustomHeader( |
| "Location", base::StringPrintf("https://example.com:%s%s", |
| request.GetURL().port().c_str(), |
| kRedirectedPrefetchUrl)); |
| return response; |
| } else if (request.relative_url == |
| std::string(kRedirectedPrefetchUrl)) { |
| requests_.push_back(request); |
| return response; |
| } |
| return nullptr; |
| })); |
| |
| https_server.ServeFilesFromSourceDirectory( |
| base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); |
| { |
| base::AutoLock auto_lock(lock_); |
| requests_.clear(); |
| } |
| ASSERT_TRUE(https_server.Start()); |
| |
| GURL url = https_server.GetURL("www.google.com", kRedirectPrefetchPage); |
| EXPECT_TRUE(RunPrefetchExperiment(url, u"done")); |
| { |
| base::AutoLock auto_lock(lock_); |
| ASSERT_EQ(3U, requests_.size()); |
| EXPECT_EQ(base::StringPrintf("www.google.com:%u", https_server.port()), |
| requests_[0].headers["Host"]); |
| EXPECT_EQ(kRedirectPrefetchPage, requests_[0].relative_url); |
| } |
| } |
| |
| } // namespace weblayer |