// 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(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 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 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 { auto response = std::make_unique(); 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("", 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