blob: 4e47416ff01ccd8a96e7ab4381952a84d9fa6aae [file] [log] [blame]
Matt Falkenhagen7b2877d2020-06-19 07:59:211// Copyright 2020 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 "chrome/browser/predictors/prefetch_manager.h"
6
7#include <map>
8#include <vector>
9
10#include "base/containers/flat_map.h"
11#include "base/containers/flat_set.h"
12#include "base/format_macros.h"
13#include "base/memory/weak_ptr.h"
14#include "base/run_loop.h"
15#include "base/strings/stringprintf.h"
Guido Urdanetaef4e91942020-11-09 15:06:2416#include "base/test/bind.h"
Matt Falkenhagen7b2877d2020-06-19 07:59:2117#include "base/test/scoped_feature_list.h"
18#include "chrome/browser/predictors/loading_test_util.h"
19#include "chrome/browser/predictors/predictors_features.h"
Matt Falkenhagen2e2085f2020-08-13 03:14:2420#include "chrome/browser/predictors/predictors_switches.h"
Matt Falkenhagen7b2877d2020-06-19 07:59:2121#include "chrome/test/base/testing_profile.h"
Matt Falkenhagen7811fd42020-06-24 22:42:4122#include "content/public/browser/content_browser_client.h"
23#include "content/public/browser/navigation_ui_data.h"
24#include "content/public/common/content_client.h"
Matt Falkenhagen7b2877d2020-06-19 07:59:2125#include "content/public/test/browser_task_environment.h"
26#include "content/public/test/url_loader_interceptor.h"
27#include "mojo/public/cpp/bindings/pending_remote.h"
28#include "mojo/public/cpp/bindings/remote.h"
29#include "net/base/load_flags.h"
30#include "net/base/network_isolation_key.h"
31#include "net/test/embedded_test_server/controllable_http_response.h"
32#include "net/test/embedded_test_server/embedded_test_server.h"
Matt Falkenhagen38bdc492020-06-29 03:05:4933#include "services/network/public/mojom/fetch_api.mojom.h"
Matt Falkenhagen7b2877d2020-06-19 07:59:2134#include "testing/gtest/include/gtest/gtest.h"
Matt Falkenhagen7811fd42020-06-24 22:42:4135#include "third_party/blink/public/common/loader/url_loader_throttle.h"
Matt Falkenhagen38bdc492020-06-29 03:05:4936#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
Matt Falkenhagen7b2877d2020-06-19 07:59:2137#include "url/origin.h"
38
39namespace predictors {
40
41namespace {
42
Sophie Chang01e95d92020-07-16 20:46:2043using ::testing::UnorderedElementsAreArray;
44
Matt Falkenhagen7b2877d2020-06-19 07:59:2145class FakePrefetchManagerDelegate
46 : public PrefetchManager::Delegate,
47 public base::SupportsWeakPtr<FakePrefetchManagerDelegate> {
48 public:
Sophie Chang01e95d92020-07-16 20:46:2049 void PrefetchInitiated(const GURL& url, const GURL& prefetch_url) override {
50 prefetched_urls_for_main_frame_url_[url].insert(prefetch_url);
51 }
52
Matt Falkenhagen7b2877d2020-06-19 07:59:2153 void PrefetchFinished(std::unique_ptr<PrefetchStats> stats) override {
54 finished_urls_.insert(stats->url);
55 auto iter = done_callbacks_.find(stats->url);
56 if (iter == done_callbacks_.end())
57 return;
58 auto callback = std::move(iter->second);
59 done_callbacks_.erase(iter);
60 std::move(callback).Run();
61 }
62
63 void WaitForPrefetchFinished(const GURL& url) {
64 if (finished_urls_.find(url) != finished_urls_.end())
65 return;
66 base::RunLoop loop;
67 DCHECK(done_callbacks_.find(url) == done_callbacks_.end());
68 done_callbacks_[url] = loop.QuitClosure();
69 loop.Run();
70 }
71
Sophie Chang01e95d92020-07-16 20:46:2072 base::flat_set<GURL> GetPrefetchedURLsForURL(const GURL& url) const {
73 auto it = prefetched_urls_for_main_frame_url_.find(url);
74 if (it == prefetched_urls_for_main_frame_url_.end())
75 return {};
76 return it->second;
77 }
78
79 void ClearPrefetchedURLs() { prefetched_urls_for_main_frame_url_ = {}; }
80
Matt Falkenhagen7b2877d2020-06-19 07:59:2181 private:
Sophie Chang01e95d92020-07-16 20:46:2082 base::flat_map<GURL, base::flat_set<GURL>>
83 prefetched_urls_for_main_frame_url_;
Matt Falkenhagen7b2877d2020-06-19 07:59:2184 base::flat_set<GURL> finished_urls_;
85 base::flat_map<GURL, base::OnceClosure> done_callbacks_;
86};
87
88// Creates a NetworkIsolationKey for a main frame navigation to URL.
89net::NetworkIsolationKey CreateNetworkIsolationKey(const GURL& main_frame_url) {
90 url::Origin origin = url::Origin::Create(main_frame_url);
91 return net::NetworkIsolationKey(origin, origin);
92}
93
Matt Falkenhagen38bdc492020-06-29 03:05:4994PrefetchRequest CreateScriptRequest(const GURL& url,
95 const GURL& main_frame_url) {
96 return PrefetchRequest(url, CreateNetworkIsolationKey(main_frame_url),
97 network::mojom::RequestDestination::kScript);
98}
99
Matt Falkenhagen7b2877d2020-06-19 07:59:21100} // namespace
101
102// A test fixture for the PrefetchManager.
103class PrefetchManagerTest : public testing::Test {
104 public:
105 PrefetchManagerTest();
106 ~PrefetchManagerTest() override = default;
107
108 PrefetchManagerTest(const PrefetchManagerTest&) = delete;
109 PrefetchManagerTest& operator=(const PrefetchManagerTest&) = delete;
110
111 protected:
112 size_t GetQueuedJobsCount() const {
113 return prefetch_manager_->queued_jobs_.size();
114 }
115
116 base::test::ScopedFeatureList features_;
117 // IO_MAINLOOP is needed for the EmbeddedTestServer.
118 content::BrowserTaskEnvironment task_environment_{
119 content::BrowserTaskEnvironment::IO_MAINLOOP};
120 std::unique_ptr<TestingProfile> profile_;
121 std::unique_ptr<FakePrefetchManagerDelegate> fake_delegate_;
122 std::unique_ptr<PrefetchManager> prefetch_manager_;
123};
124
125PrefetchManagerTest::PrefetchManagerTest()
126 : profile_(std::make_unique<TestingProfile>()),
127 fake_delegate_(std::make_unique<FakePrefetchManagerDelegate>()),
128 prefetch_manager_(
129 std::make_unique<PrefetchManager>(fake_delegate_->AsWeakPtr(),
130 profile_.get())) {
131 features_.InitAndEnableFeature(features::kLoadingPredictorPrefetch);
Matt Falkenhagen2e2085f2020-08-13 03:14:24132 base::CommandLine::ForCurrentProcess()->AppendSwitch(
133 switches::kLoadingPredictorAllowLocalRequestForTesting);
Matt Falkenhagen7b2877d2020-06-19 07:59:21134}
135
136// Tests prefetching a single URL.
137TEST_F(PrefetchManagerTest, OneMainFrameUrlOnePrefetch) {
138 GURL main_frame_url("https://abc.invalid");
139 GURL subresource_url("https://xyz.invalid/script.js");
Matt Falkenhagen38bdc492020-06-29 03:05:49140 PrefetchRequest request =
141 CreateScriptRequest(subresource_url, main_frame_url);
Matt Falkenhagen7b2877d2020-06-19 07:59:21142
143 base::RunLoop loop;
144 content::URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
145 [&](content::URLLoaderInterceptor::RequestParams* params) -> bool {
146 network::ResourceRequest& request = params->url_request;
147 EXPECT_EQ(request.url, subresource_url);
148 EXPECT_TRUE(request.load_flags & net::LOAD_PREFETCH);
149
Hiroki Nakagawab443c4b72020-07-31 08:30:16150 EXPECT_EQ(request.referrer_policy, net::ReferrerPolicy::NO_REFERRER);
Matt Falkenhagen38bdc492020-06-29 03:05:49151 EXPECT_EQ(request.destination,
152 network::mojom::RequestDestination::kScript);
153 EXPECT_EQ(
154 static_cast<blink::mojom::ResourceType>(request.resource_type),
155 blink::mojom::ResourceType::kScript);
156
157 EXPECT_EQ(request.mode, network::mojom::RequestMode::kNoCors);
158
Matt Falkenhagen7b2877d2020-06-19 07:59:21159 std::string purpose;
160 EXPECT_TRUE(request.headers.GetHeader("Purpose", &purpose));
161 EXPECT_EQ(purpose, "prefetch");
162
163 loop.Quit();
164 return false;
165 }));
166 prefetch_manager_->Start(main_frame_url, {request});
167 loop.Run();
168
Sophie Chang01e95d92020-07-16 20:46:20169 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
170 UnorderedElementsAreArray({subresource_url}));
171
Matt Falkenhagen7b2877d2020-06-19 07:59:21172 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
173}
174
175// Tests prefetching multiple URLs.
176TEST_F(PrefetchManagerTest, OneMainFrameUrlMultiplePrefetch) {
177 net::test_server::EmbeddedTestServer test_server;
178 std::vector<std::string> paths;
179 std::vector<PrefetchRequest> requests;
180 std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>>
181 responses;
182
183 GURL main_frame_url("https://abc.invalid");
184
185 // Set up prefetches one more than the inflight limit.
186
187 // The ControllableHttpResponses must be made before the test server
188 // is started.
Sophie Chang45203ab2020-07-27 18:46:30189 for (size_t i = 0; i < features::GetMaxInflightPrefetches() + 1; i++) {
Matt Falkenhagen7b2877d2020-06-19 07:59:21190 std::string path = base::StringPrintf("/script%" PRIuS ".js", i);
191 paths.push_back(path);
192 responses.push_back(
193 std::make_unique<net::test_server::ControllableHttpResponse>(
194 &test_server, path));
195 }
196
197 // Start the server.
198 auto test_server_handle = test_server.StartAndReturnHandle();
199 ASSERT_TRUE(test_server_handle);
200
201 // The request URLs can only be constructed after the server is started.
202 for (size_t i = 0; i < responses.size(); i++) {
203 GURL url = test_server.GetURL(paths[i]);
Matt Falkenhagen38bdc492020-06-29 03:05:49204 requests.push_back(CreateScriptRequest(url, main_frame_url));
Matt Falkenhagen7b2877d2020-06-19 07:59:21205 }
206
207 // Start the prefetching.
208 prefetch_manager_->Start(main_frame_url, std::move(requests));
209
210 // Wait for requests up to the inflight limit.
Sophie Chang01e95d92020-07-16 20:46:20211 std::vector<GURL> prefetched_urls;
212 for (size_t i = 0; i < responses.size() - 1; i++) {
213 prefetched_urls.push_back(test_server.GetURL(paths[i]));
Matt Falkenhagen7b2877d2020-06-19 07:59:21214 responses[i]->WaitForRequest();
Sophie Chang01e95d92020-07-16 20:46:20215 }
216
217 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
218 UnorderedElementsAreArray(prefetched_urls));
Matt Falkenhagen7b2877d2020-06-19 07:59:21219
220 // Verify there is a queued job. Pump the run loop just to give the manager a
221 // chance to incorrectly start the queued job and fail the expectation.
222 base::RunLoop().RunUntilIdle();
223 EXPECT_EQ(GetQueuedJobsCount(), 1u);
224
Sophie Chang01e95d92020-07-16 20:46:20225 fake_delegate_->ClearPrefetchedURLs();
226
Matt Falkenhagen7b2877d2020-06-19 07:59:21227 // Finish one request.
228 responses.front()->Send("hi");
229 responses.front()->Done();
230
231 // Wait for the queued job to start.
232 responses.back()->WaitForRequest();
233 EXPECT_EQ(GetQueuedJobsCount(), 0u);
234
Sophie Chang01e95d92020-07-16 20:46:20235 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
236 UnorderedElementsAreArray({test_server.GetURL(paths.back())}));
237
Matt Falkenhagen7b2877d2020-06-19 07:59:21238 // Finish all requests.
239 for (size_t i = 1; i < responses.size(); i++) {
240 responses[i]->Send("hi");
241 responses[i]->Done();
242 }
243 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
244}
245
246// Tests prefetching multiple URLs for multiple main frames.
247TEST_F(PrefetchManagerTest, MultipleMainFrameUrlMultiplePrefetch) {
248 net::test_server::EmbeddedTestServer test_server;
249 std::vector<std::string> paths;
250 std::vector<PrefetchRequest> requests;
251 std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>>
252 responses;
253
254 GURL main_frame_url("https://abc.invalid");
255 GURL main_frame_url2("https://def.invalid");
256
257 // Set up prefetches one more than the inflight limit.
Sophie Chang45203ab2020-07-27 18:46:30258 size_t count = features::GetMaxInflightPrefetches();
Matt Falkenhagen7b2877d2020-06-19 07:59:21259
260 // The ControllableHttpResponses must be made before the test server
261 // is started.
262 for (size_t i = 0; i < count + 1; i++) {
263 std::string path = base::StringPrintf("/script%" PRIuS ".js", i);
264 paths.push_back(path);
265 responses.push_back(
266 std::make_unique<net::test_server::ControllableHttpResponse>(
267 &test_server, path));
268 }
269
270 // Start the server.
271 auto test_server_handle = test_server.StartAndReturnHandle();
272 ASSERT_TRUE(test_server_handle);
273
274 // The request URLs can only be constructed after the server is started.
Sophie Chang01e95d92020-07-16 20:46:20275 std::vector<GURL> expected_prefetch_requests_for_main_frame_url;
276 for (size_t i = 0; i < count - 1; i++) {
Matt Falkenhagen7b2877d2020-06-19 07:59:21277 GURL url = test_server.GetURL(paths[i]);
Matt Falkenhagen38bdc492020-06-29 03:05:49278 requests.push_back(CreateScriptRequest(url, main_frame_url));
Sophie Chang01e95d92020-07-16 20:46:20279 expected_prefetch_requests_for_main_frame_url.push_back(url);
Matt Falkenhagen7b2877d2020-06-19 07:59:21280 }
Sophie Chang01e95d92020-07-16 20:46:20281 std::vector<GURL> expected_prefetch_requests_for_main_frame_url2;
282 for (size_t i = count - 1; i < count + 1; i++) {
283 GURL url = test_server.GetURL(paths[i]);
Matt Falkenhagen38bdc492020-06-29 03:05:49284 requests.push_back(CreateScriptRequest(url, main_frame_url2));
Sophie Chang01e95d92020-07-16 20:46:20285 expected_prefetch_requests_for_main_frame_url2.push_back(url);
Matt Falkenhagen7b2877d2020-06-19 07:59:21286 }
287
288 // Start the prefetching.
289 prefetch_manager_->Start(main_frame_url,
290 std::vector<PrefetchRequest>(
291 requests.begin(), requests.begin() + count - 1));
292 prefetch_manager_->Start(main_frame_url2,
293 std::vector<PrefetchRequest>(
294 requests.begin() + count - 1, requests.end()));
295
296 // Wait for requests up to the inflight limit.
297 for (size_t i = 0; i < responses.size() - 1; i++)
298 responses[i]->WaitForRequest();
299
300 // Verify there is a queued job. Pump the run loop just to give the manager a
301 // chance to incorrectly start the queued job and fail the expectation.
302 base::RunLoop().RunUntilIdle();
303 EXPECT_EQ(GetQueuedJobsCount(), 1u);
304
Sophie Chang01e95d92020-07-16 20:46:20305 EXPECT_THAT(
306 fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
307 UnorderedElementsAreArray(expected_prefetch_requests_for_main_frame_url));
308 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url2),
309 UnorderedElementsAreArray(
310 {expected_prefetch_requests_for_main_frame_url2.front()}));
311
312 fake_delegate_->ClearPrefetchedURLs();
313
Matt Falkenhagen7b2877d2020-06-19 07:59:21314 // Finish one request.
315 responses.front()->Send("hi");
316 responses.front()->Done();
317
318 // Wait for the queued job to start.
319 responses.back()->WaitForRequest();
320 EXPECT_EQ(GetQueuedJobsCount(), 0u);
321
Sophie Chang01e95d92020-07-16 20:46:20322 // We don't expect any more requests for |main_frame_url| to be initiated and
323 // we expect the last request for |main_frame_url2| to go out.
324 EXPECT_TRUE(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url).empty());
325 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url2),
326 UnorderedElementsAreArray(
327 {expected_prefetch_requests_for_main_frame_url2.back()}));
328
Matt Falkenhagen7b2877d2020-06-19 07:59:21329 // Finish all requests.
330 for (size_t i = 1; i < responses.size(); i++) {
331 responses[i]->Send("hi");
332 responses[i]->Done();
333 }
334 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
335 fake_delegate_->WaitForPrefetchFinished(main_frame_url2);
336}
337
Matt Falkenhagenc2d27dc2020-06-23 05:21:07338TEST_F(PrefetchManagerTest, Stop) {
339 net::test_server::EmbeddedTestServer test_server;
340
341 // Set up prefetches (limit + 1 for URL1, and 1 for URL2)
Sophie Chang45203ab2020-07-27 18:46:30342 size_t limit = features::GetMaxInflightPrefetches();
Matt Falkenhagenc2d27dc2020-06-23 05:21:07343
344 GURL main_frame_url("https://abc.invalid");
345 std::vector<std::string> paths;
346 std::vector<PrefetchRequest> requests;
347 std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>>
348 responses;
349
350 GURL main_frame_url2("https://def.invalid");
351 std::string path2;
352 std::unique_ptr<net::test_server::ControllableHttpResponse> response2;
353
354 // The ControllableHttpResponses must be made before the test server
355 // is started.
356 for (size_t i = 0; i < limit; i++) {
357 std::string path = base::StringPrintf("/script%" PRIuS ".js", i);
358 paths.push_back(path);
359 responses.push_back(
360 std::make_unique<net::test_server::ControllableHttpResponse>(
361 &test_server, path));
362 }
363
364 path2 = base::StringPrintf("/script%" PRIuS ".js", limit);
365 response2 = std::make_unique<net::test_server::ControllableHttpResponse>(
366 &test_server, path2);
367
368 // Verify we don't see a request after Stop().
369 test_server.RegisterRequestMonitor(base::BindLambdaForTesting(
370 [&](const net::test_server::HttpRequest& request) {
371 EXPECT_NE(request.relative_url, "/should_be_cancelled");
372 }));
373
374 // Start the server.
375 auto test_server_handle = test_server.StartAndReturnHandle();
376 ASSERT_TRUE(test_server_handle);
377
378 // The request URLs can only be constructed after the server is started.
Sophie Chang01e95d92020-07-16 20:46:20379 std::vector<GURL> expected_prefetch_requests;
Matt Falkenhagenc2d27dc2020-06-23 05:21:07380 for (size_t i = 0; i < limit; i++) {
381 GURL url = test_server.GetURL(paths[i]);
Matt Falkenhagen38bdc492020-06-29 03:05:49382 requests.push_back(CreateScriptRequest(url, main_frame_url));
Sophie Chang01e95d92020-07-16 20:46:20383 expected_prefetch_requests.push_back(url);
Matt Falkenhagenc2d27dc2020-06-23 05:21:07384 }
385 // This request should never be seen.
Matt Falkenhagen38bdc492020-06-29 03:05:49386 requests.push_back(CreateScriptRequest(
387 test_server.GetURL("/should_be_cancelled"), main_frame_url));
Matt Falkenhagenc2d27dc2020-06-23 05:21:07388
389 // The request from the second navigation.
Matt Falkenhagen38bdc492020-06-29 03:05:49390 PrefetchRequest request2 =
391 CreateScriptRequest(test_server.GetURL(path2), main_frame_url2);
Matt Falkenhagenc2d27dc2020-06-23 05:21:07392
393 // Start URL1, URL2.
394 prefetch_manager_->Start(main_frame_url, requests);
395 prefetch_manager_->Start(main_frame_url2, {request2});
396
397 // Wait for |limit| requests from URL1.
398 for (auto& response : responses)
399 response->WaitForRequest();
400
401 // Call stop on URL1.
402 prefetch_manager_->Stop(main_frame_url);
403
404 // Let URL1 requests finish. This finishes URL1 without
405 // the limit + 1 request being sent.
406 for (auto& response : responses) {
407 response->Send("hi");
408 response->Done();
409 }
410 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
411
Sophie Chang01e95d92020-07-16 20:46:20412 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
413 UnorderedElementsAreArray(expected_prefetch_requests));
414
Matt Falkenhagenc2d27dc2020-06-23 05:21:07415 // The request for URL2 should be requested.
416 response2->WaitForRequest();
417 response2->Send("hi");
418 response2->Done();
419
420 fake_delegate_->WaitForPrefetchFinished(main_frame_url2);
Sophie Chang01e95d92020-07-16 20:46:20421
422 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url2),
423 UnorderedElementsAreArray({test_server.GetURL(path2)}));
Matt Falkenhagenc2d27dc2020-06-23 05:21:07424}
425
426TEST_F(PrefetchManagerTest, StopAndStart) {
427 net::test_server::EmbeddedTestServer test_server;
428
429 // Set up prefetches (limit + 1).
Sophie Chang45203ab2020-07-27 18:46:30430 size_t limit = features::GetMaxInflightPrefetches();
Matt Falkenhagenc2d27dc2020-06-23 05:21:07431
432 GURL main_frame_url("https://abc.invalid");
433 std::vector<std::string> paths;
434 std::vector<PrefetchRequest> requests;
435 std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>>
436 responses;
437 std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>>
438 responses2;
439
440 // The ControllableHttpResponses must be made before the test server
441 // is started.
442 for (size_t i = 0; i < limit; i++) {
443 std::string path = base::StringPrintf("/script%" PRIuS ".js", i);
444 paths.push_back(path);
445 responses.push_back(
446 std::make_unique<net::test_server::ControllableHttpResponse>(
447 &test_server, path));
448 responses2.push_back(
449 std::make_unique<net::test_server::ControllableHttpResponse>(
450 &test_server, path));
451 }
452
453 // Verify we don't see a request after Stop().
454 test_server.RegisterRequestMonitor(base::BindLambdaForTesting(
455 [&](const net::test_server::HttpRequest& request) {
456 EXPECT_NE(request.relative_url, "/should_be_cancelled");
457 }));
458
459 // Start the server.
460 auto test_server_handle = test_server.StartAndReturnHandle();
461 ASSERT_TRUE(test_server_handle);
462
463 // The request URLs can only be constructed after the server is started.
Sophie Chang01e95d92020-07-16 20:46:20464 std::vector<GURL> expected_prefetch_requests;
Matt Falkenhagenc2d27dc2020-06-23 05:21:07465 for (size_t i = 0; i < limit; i++) {
466 GURL url = test_server.GetURL(paths[i]);
Matt Falkenhagen38bdc492020-06-29 03:05:49467 requests.push_back(CreateScriptRequest(url, main_frame_url));
Sophie Chang01e95d92020-07-16 20:46:20468 expected_prefetch_requests.push_back(url);
Matt Falkenhagenc2d27dc2020-06-23 05:21:07469 }
470 // This request should never be seen.
Matt Falkenhagen38bdc492020-06-29 03:05:49471 requests.push_back(CreateScriptRequest(
472 test_server.GetURL("/should_be_cancelled"), main_frame_url));
Matt Falkenhagenc2d27dc2020-06-23 05:21:07473
474 // Start.
475 prefetch_manager_->Start(main_frame_url, requests);
476
477 // Wait for |limit| requests from URL1.
478 for (auto& response : responses) {
479 response->WaitForRequest();
480 }
Sophie Chang01e95d92020-07-16 20:46:20481 EXPECT_THAT(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url),
482 UnorderedElementsAreArray(expected_prefetch_requests));
Matt Falkenhagenc2d27dc2020-06-23 05:21:07483
484 // Call stop.
485 prefetch_manager_->Stop(main_frame_url);
486
Sophie Chang01e95d92020-07-16 20:46:20487 fake_delegate_->ClearPrefetchedURLs();
488
Matt Falkenhagenc2d27dc2020-06-23 05:21:07489 // Call start again. These requests will be coalesced
490 // with the stopped info, and will just be dropped.
491 prefetch_manager_->Start(main_frame_url, requests);
492
493 // Let the inflight requests finish. This finishes the
494 // info without the limit + 1 request or requests
495 // added after Stop() being sent.
496 for (auto& response : responses) {
497 response->Send("hi");
498 response->Done();
499 }
500 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
501
Sophie Chang01e95d92020-07-16 20:46:20502 // We don't expect any additional requests to be started.
503 EXPECT_TRUE(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url).empty());
504
Matt Falkenhagenc2d27dc2020-06-23 05:21:07505 // Restart requests. These requests will work as normal.
506 prefetch_manager_->Start(main_frame_url, requests);
507 for (auto& response : responses2) {
508 response->WaitForRequest();
509 response->Send("hi");
510 response->Done();
511 }
512
513 fake_delegate_->WaitForPrefetchFinished(main_frame_url);
Sophie Chang01e95d92020-07-16 20:46:20514
515 // Prefetches should have been initiated with the second start.
516 EXPECT_FALSE(fake_delegate_->GetPrefetchedURLsForURL(main_frame_url).empty());
Matt Falkenhagenc2d27dc2020-06-23 05:21:07517}
518
Matt Falkenhagen7811fd42020-06-24 22:42:41519class HeaderInjectingThrottle : public blink::URLLoaderThrottle {
520 public:
521 HeaderInjectingThrottle() = default;
522 ~HeaderInjectingThrottle() override = default;
523
524 HeaderInjectingThrottle(const HeaderInjectingThrottle&) = delete;
525 HeaderInjectingThrottle& operator=(const HeaderInjectingThrottle&) = delete;
526
527 void WillStartRequest(network::ResourceRequest* request,
528 bool* defer) override {
529 request->headers.SetHeader("x-injected", "injected value");
530 }
531};
532
533class ThrottlingContentBrowserClient : public content::ContentBrowserClient {
534 public:
535 ThrottlingContentBrowserClient() = default;
536 ~ThrottlingContentBrowserClient() override = default;
537
538 ThrottlingContentBrowserClient(const ThrottlingContentBrowserClient&) =
539 delete;
540 ThrottlingContentBrowserClient& operator=(
541 const ThrottlingContentBrowserClient&) = delete;
542
543 // ContentBrowserClient overrides:
544 std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
545 CreateURLLoaderThrottles(
546 const network::ResourceRequest& request,
547 content::BrowserContext* browser_context,
548 const base::RepeatingCallback<content::WebContents*()>& wc_getter,
549 content::NavigationUIData* navigation_ui_data,
550 int frame_tree_node_id) override {
551 std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
552 throttles.emplace_back(std::make_unique<HeaderInjectingThrottle>());
553 return throttles;
554 }
555};
556
557// Test that prefetches go through URLLoaderThrottles.
558TEST_F(PrefetchManagerTest, Throttles) {
559 // Add a throttle which injects a header.
560 ThrottlingContentBrowserClient content_browser_client;
561 auto* old_content_browser_client =
562 content::SetBrowserClientForTesting(&content_browser_client);
563
564 net::test_server::EmbeddedTestServer test_server;
565 net::test_server::ControllableHttpResponse response(&test_server,
566 "/prefetch");
567
568 // Start the server.
569 auto test_server_handle = test_server.StartAndReturnHandle();
570 ASSERT_TRUE(test_server_handle);
571
572 GURL main_frame_url("https://abc.invalid");
573 GURL prefetch_url = test_server.GetURL("/prefetch");
Matt Falkenhagen38bdc492020-06-29 03:05:49574 PrefetchRequest request = CreateScriptRequest(prefetch_url, main_frame_url);
Matt Falkenhagen7811fd42020-06-24 22:42:41575
576 prefetch_manager_->Start(main_frame_url, {request});
577
578 response.WaitForRequest();
579 const net::test_server::HttpRequest* actual_request = response.http_request();
580 auto iter = actual_request->headers.find("x-injected");
581 ASSERT_TRUE(iter != actual_request->headers.end());
582 EXPECT_EQ(iter->second, "injected value");
583
584 content::SetBrowserClientForTesting(old_content_browser_client);
585}
586
Matt Falkenhagen7b2877d2020-06-19 07:59:21587} // namespace predictors