1 // Copyright 2019 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 #include "content/browser/loader/prefetch_browsertest_base.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/task/post_task.h"
11 #include "content/browser/loader/prefetch_url_loader_service.h"
12 #include "content/browser/storage_partition_impl.h"
13 #include "content/browser/web_package/signed_exchange_handler.h"
14 #include "content/browser/web_package/signed_exchange_loader.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/browser_task_traits.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/test/browser_test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "net/test/embedded_test_server/embedded_test_server.h"
22 #include "net/test/embedded_test_server/http_request.h"
23
24 namespace content {
25
26 PrefetchBrowserTestBase::ResponseEntry::ResponseEntry() = default;
27
ResponseEntry(const std::string & content,const std::string & content_type,const std::vector<std::pair<std::string,std::string>> & headers,net::HttpStatusCode code)28 PrefetchBrowserTestBase::ResponseEntry::ResponseEntry(
29 const std::string& content,
30 const std::string& content_type,
31 const std::vector<std::pair<std::string, std::string>>& headers,
32 net::HttpStatusCode code)
33 : content(content),
34 content_type(content_type),
35 headers(headers),
36 code(code) {}
37
38 PrefetchBrowserTestBase::ResponseEntry::ResponseEntry(ResponseEntry&& other) =
39 default;
40
41 PrefetchBrowserTestBase::ResponseEntry::~ResponseEntry() = default;
42
43 PrefetchBrowserTestBase::ResponseEntry& PrefetchBrowserTestBase::ResponseEntry::
44 operator=(ResponseEntry&& other) = default;
45
46 PrefetchBrowserTestBase::ScopedSignedExchangeHandlerFactory::
ScopedSignedExchangeHandlerFactory(SignedExchangeHandlerFactory * factory)47 ScopedSignedExchangeHandlerFactory(SignedExchangeHandlerFactory* factory) {
48 SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(factory);
49 }
50
51 PrefetchBrowserTestBase::ScopedSignedExchangeHandlerFactory::
~ScopedSignedExchangeHandlerFactory()52 ~ScopedSignedExchangeHandlerFactory() {
53 SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(nullptr);
54 }
55
56 PrefetchBrowserTestBase::PrefetchBrowserTestBase() = default;
57 PrefetchBrowserTestBase::~PrefetchBrowserTestBase() = default;
58
SetUpOnMainThread()59 void PrefetchBrowserTestBase::SetUpOnMainThread() {
60 ContentBrowserTest::SetUpOnMainThread();
61 StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
62 BrowserContext::GetDefaultStoragePartition(
63 shell()->web_contents()->GetBrowserContext()));
64 partition->GetPrefetchURLLoaderService()
65 ->RegisterPrefetchLoaderCallbackForTest(base::BindRepeating(
66 &PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled,
67 base::Unretained(this)));
68 }
69
RegisterResponse(const std::string & url,ResponseEntry && entry)70 void PrefetchBrowserTestBase::RegisterResponse(const std::string& url,
71 ResponseEntry&& entry) {
72 response_map_[url] = std::move(entry);
73 }
74
75 std::unique_ptr<net::test_server::HttpResponse>
ServeResponses(const net::test_server::HttpRequest & request)76 PrefetchBrowserTestBase::ServeResponses(
77 const net::test_server::HttpRequest& request) {
78 auto found = response_map_.find(request.relative_url);
79 if (found != response_map_.end()) {
80 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
81 response->set_code(found->second.code);
82 response->set_content(found->second.content);
83 response->set_content_type(found->second.content_type);
84 for (const auto& header : found->second.headers) {
85 response->AddCustomHeader(header.first, header.second);
86 }
87 return std::move(response);
88 }
89 return nullptr;
90 }
91
OnPrefetchURLLoaderCalled()92 void PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled() {
93 DCHECK_CURRENTLY_ON(BrowserThread::UI);
94 base::AutoLock lock(lock_);
95 prefetch_url_loader_called_++;
96 }
97
GetPrefetchURLLoaderCallCount()98 int PrefetchBrowserTestBase::GetPrefetchURLLoaderCallCount() {
99 DCHECK_CURRENTLY_ON(BrowserThread::UI);
100 base::AutoLock lock(lock_);
101 return prefetch_url_loader_called_;
102 }
103
RegisterRequestHandler(net::EmbeddedTestServer * test_server)104 void PrefetchBrowserTestBase::RegisterRequestHandler(
105 net::EmbeddedTestServer* test_server) {
106 test_server->RegisterRequestHandler(base::BindRepeating(
107 &PrefetchBrowserTestBase::ServeResponses, base::Unretained(this)));
108 }
109
NavigateToURLAndWaitTitle(const GURL & url,const std::string & title)110 void PrefetchBrowserTestBase::NavigateToURLAndWaitTitle(
111 const GURL& url,
112 const std::string& title) {
113 base::string16 title16 = base::ASCIIToUTF16(title);
114 TitleWatcher title_watcher(shell()->web_contents(), title16);
115 // Execute the JavaScript code to triger the followup navigation from the
116 // current page.
117 EXPECT_TRUE(ExecuteScript(
118 shell()->web_contents(),
119 base::StringPrintf("location.href = '%s';", url.spec().c_str())));
120 EXPECT_EQ(title16, title_watcher.WaitAndGetTitle());
121 }
122
WaitUntilLoaded(const GURL & url)123 void PrefetchBrowserTestBase::WaitUntilLoaded(const GURL& url) {
124 bool result = false;
125 ASSERT_TRUE(
126 ExecuteScriptAndExtractBool(shell()->web_contents(),
127 base::StringPrintf(R"(
128 new Promise((resolve) => {
129 const url = '%s';
130 if (performance.getEntriesByName(url).length > 0) {
131 resolve();
132 return;
133 }
134 new PerformanceObserver((list) => {
135 if (list.getEntriesByName(url).length > 0) {
136 resolve();
137 }
138 }).observe({ entryTypes: ['resource'] });
139 }).then(() => {
140 window.domAutomationController.send(true);
141 }))",
142 url.spec().c_str()),
143 &result));
144 ASSERT_TRUE(result);
145 }
146
147 // static
148 scoped_refptr<PrefetchBrowserTestBase::RequestCounter>
CreateAndMonitor(net::EmbeddedTestServer * test_server,const std::string & path,base::RunLoop * waiter)149 PrefetchBrowserTestBase::RequestCounter::CreateAndMonitor(
150 net::EmbeddedTestServer* test_server,
151 const std::string& path,
152 base::RunLoop* waiter) {
153 auto counter = base::MakeRefCounted<RequestCounter>(path, waiter);
154 test_server->RegisterRequestMonitor(
155 base::BindRepeating(&RequestCounter::OnRequest, counter));
156 return counter;
157 }
158
RequestCounter(const std::string & path,base::RunLoop * waiter)159 PrefetchBrowserTestBase::RequestCounter::RequestCounter(const std::string& path,
160 base::RunLoop* waiter)
161 : waiter_closure_(waiter ? waiter->QuitClosure() : base::OnceClosure()),
162 path_(path) {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI);
164 }
165
166 PrefetchBrowserTestBase::RequestCounter::~RequestCounter() = default;
167
GetRequestCount()168 int PrefetchBrowserTestBase::RequestCounter::GetRequestCount() {
169 base::AutoLock lock(lock_);
170 return request_count_;
171 }
172
OnRequest(const net::test_server::HttpRequest & request)173 void PrefetchBrowserTestBase::RequestCounter::OnRequest(
174 const net::test_server::HttpRequest& request) {
175 if (request.relative_url != path_)
176 return;
177 base::AutoLock lock(lock_);
178 ++request_count_;
179 if (waiter_closure_)
180 std::move(waiter_closure_).Run();
181 }
182
183 } // namespace content
184