blob: 5bb4a80c240160cd18b7731ea6219de9398b21ff [file] [log] [blame]
// 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/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