1 // Copyright 2016 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 "base/bind.h"
6 #include "base/callback_helpers.h"
7 #include "base/feature_list.h"
8 #include "base/files/file_path.h"
9 #include "base/macros.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/test/bind.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "build/build_config.h"
16 #include "net/base/features.h"
17 #include "net/base/isolation_info.h"
18 #include "net/base/load_timing_info.h"
19 #include "net/base/network_delegate.h"
20 #include "net/base/network_isolation_key.h"
21 #include "net/cert/ct_policy_enforcer.h"
22 #include "net/cert/ct_policy_status.h"
23 #include "net/cert/mock_cert_verifier.h"
24 #include "net/dns/mapped_host_resolver.h"
25 #include "net/dns/mock_host_resolver.h"
26 #include "net/log/net_log_event_type.h"
27 #include "net/log/test_net_log.h"
28 #include "net/log/test_net_log_util.h"
29 #include "net/quic/crypto/proof_source_chromium.h"
30 #include "net/quic/quic_context.h"
31 #include "net/test/cert_test_util.h"
32 #include "net/test/gtest_util.h"
33 #include "net/test/test_data_directory.h"
34 #include "net/test/test_with_task_environment.h"
35 #include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
36 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
37 #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
38 #include "net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h"
39 #include "net/tools/quic/quic_simple_server.h"
40 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
41 #include "net/url_request/url_request.h"
42 #include "net/url_request/url_request_test_util.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 #include "url/gurl.h"
46
47 namespace net {
48
49 namespace {
50
51 // This must match the certificate used (quic-chain.pem and quic-leaf-cert.key).
52 const char kTestServerHost[] = "test.example.com";
53 // Used as a simple response from the server.
54 const char kHelloPath[] = "/hello.txt";
55 const char kHelloBodyValue[] = "Hello from QUIC Server";
56 const int kHelloStatus = 200;
57
58 // Used as a simple pushed response from the server.
59 const char kKittenPath[] = "/kitten-1.jpg";
60 const char kKittenBodyValue[] = "Kitten image";
61
62 // Used as a simple pushed response from the server.
63 const char kFaviconPath[] = "/favicon.ico";
64 const char kFaviconBodyValue[] = "Favion";
65
66 // Used as a simple pushed response from the server.
67 const char kIndexPath[] = "/index2.html";
68 const char kIndexBodyValue[] = "Hello from QUIC Server";
69 const int kIndexStatus = 200;
70
71 class MockCTPolicyEnforcerNonCompliant : public CTPolicyEnforcer {
72 public:
73 MockCTPolicyEnforcerNonCompliant() = default;
74 ~MockCTPolicyEnforcerNonCompliant() override = default;
75
CheckCompliance(X509Certificate * cert,const ct::SCTList & verified_scts,const NetLogWithSource & net_log)76 ct::CTPolicyCompliance CheckCompliance(
77 X509Certificate* cert,
78 const ct::SCTList& verified_scts,
79 const NetLogWithSource& net_log) override {
80 return ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS;
81 }
82 };
83
84 // An ExpectCTReporter that records the number of times OnExpectCTFailed() was
85 // called.
86 class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter {
87 public:
88 MockExpectCTReporter() = default;
89 ~MockExpectCTReporter() override = default;
90
OnExpectCTFailed(const HostPortPair & host_port_pair,const GURL & report_uri,base::Time expiration,const X509Certificate * validated_certificate_chain,const X509Certificate * served_certificate_chain,const SignedCertificateTimestampAndStatusList & signed_certificate_timestamps,const NetworkIsolationKey & network_isolation_key)91 void OnExpectCTFailed(
92 const HostPortPair& host_port_pair,
93 const GURL& report_uri,
94 base::Time expiration,
95 const X509Certificate* validated_certificate_chain,
96 const X509Certificate* served_certificate_chain,
97 const SignedCertificateTimestampAndStatusList&
98 signed_certificate_timestamps,
99 const NetworkIsolationKey& network_isolation_key) override {
100 num_failures_++;
101 report_uri_ = report_uri;
102 network_isolation_key_ = network_isolation_key;
103 }
104
num_failures() const105 int num_failures() const { return num_failures_; }
report_uri() const106 const GURL& report_uri() const { return report_uri_; }
network_isolation_key() const107 const NetworkIsolationKey& network_isolation_key() const {
108 return network_isolation_key_;
109 }
110
111 private:
112 int num_failures_ = 0;
113
114 GURL report_uri_;
115 NetworkIsolationKey network_isolation_key_;
116 };
117
118 class URLRequestQuicTest
119 : public TestWithTaskEnvironment,
120 public ::testing::WithParamInterface<quic::ParsedQuicVersion> {
121 protected:
URLRequestQuicTest()122 URLRequestQuicTest() : context_(new TestURLRequestContext(true)) {
123 QuicEnableVersion(version());
124 StartQuicServer(version());
125
126 std::unique_ptr<HttpNetworkSession::Params> params(
127 new HttpNetworkSession::Params);
128 CertVerifyResult verify_result;
129 verify_result.verified_cert = ImportCertFromFile(
130 GetTestCertsDirectory(), "quic-chain.pem");
131 cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
132 kTestServerHost, verify_result, OK);
133 // To simplify the test, and avoid the race with the HTTP request, we force
134 // QUIC for these requests.
135 context_->set_quic_context(&quic_context_);
136 quic_context_.params()->supported_versions = {version()};
137 quic_context_.params()->origins_to_force_quic_on.insert(
138 HostPortPair(kTestServerHost, 443));
139 params->enable_quic = true;
140 params->enable_server_push_cancellation = true;
141 context_->set_host_resolver(host_resolver_.get());
142 context_->set_http_network_session_params(std::move(params));
143 context_->set_cert_verifier(&cert_verifier_);
144 context_->set_net_log(&net_log_);
145 transport_security_state_.SetExpectCTReporter(&expect_ct_reporter_);
146 context_->set_transport_security_state(&transport_security_state_);
147 }
148
TearDown()149 void TearDown() override {
150 if (server_) {
151 server_->Shutdown();
152 // If possible, deliver the conncetion close packet to the client before
153 // destruct the TestURLRequestContext.
154 base::RunLoop().RunUntilIdle();
155 }
156 }
157
158 // Sets a NetworkDelegate to use for |context_|. Must be done before Init().
SetNetworkDelegate(NetworkDelegate * network_delegate)159 void SetNetworkDelegate(NetworkDelegate* network_delegate) {
160 context_->set_network_delegate(network_delegate);
161 }
162
163 // Can be used to modify |context_|. Only safe to modify before Init() is
164 // called.
context()165 TestURLRequestContext* context() { return context_.get(); }
166
167 // Initializes the TestURLRequestContext |context_|.
Init()168 void Init() { context_->Init(); }
169
CreateRequest(const GURL & url,RequestPriority priority,URLRequest::Delegate * delegate)170 std::unique_ptr<URLRequest> CreateRequest(const GURL& url,
171 RequestPriority priority,
172 URLRequest::Delegate* delegate) {
173 return context_->CreateRequest(url, priority, delegate,
174 TRAFFIC_ANNOTATION_FOR_TESTS);
175 }
176
GetRstErrorCountReceivedByServer(quic::QuicRstStreamErrorCode error_code) const177 unsigned int GetRstErrorCountReceivedByServer(
178 quic::QuicRstStreamErrorCode error_code) const {
179 return (static_cast<quic::QuicSimpleDispatcher*>(server_->dispatcher()))
180 ->GetRstErrorCount(error_code);
181 }
182
FindPushUrlSource(const std::vector<NetLogEntry> & entries,const std::string & push_url)183 static const NetLogSource FindPushUrlSource(
184 const std::vector<NetLogEntry>& entries,
185 const std::string& push_url) {
186 std::string entry_push_url;
187 for (const auto& entry : entries) {
188 if (entry.phase == NetLogEventPhase::BEGIN &&
189 entry.source.type ==
190 NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION) {
191 auto entry_push_url =
192 GetOptionalStringValueFromParams(entry, "push_url");
193 if (entry_push_url && *entry_push_url == push_url) {
194 return entry.source;
195 }
196 }
197 }
198 return NetLogSource();
199 }
200
FindEndBySource(const std::vector<NetLogEntry> & entries,const NetLogSource & source)201 static const NetLogEntry* FindEndBySource(
202 const std::vector<NetLogEntry>& entries,
203 const NetLogSource& source) {
204 for (const auto& entry : entries) {
205 if (entry.phase == NetLogEventPhase::END &&
206 entry.source.type == source.type && entry.source.id == source.id)
207 return &entry;
208 }
209 return nullptr;
210 }
211
version()212 quic::ParsedQuicVersion version() { return GetParam(); }
213
expect_ct_reporter()214 MockExpectCTReporter* expect_ct_reporter() { return &expect_ct_reporter_; }
215
transport_security_state()216 TransportSecurityState* transport_security_state() {
217 return &transport_security_state_;
218 }
219
220 protected:
221 // Returns a fully-qualified URL for |path| on the test server.
UrlFromPath(base::StringPiece path)222 std::string UrlFromPath(base::StringPiece path) {
223 return std::string("https://") + std::string(kTestServerHost) +
224 std::string(path);
225 }
226
227 RecordingTestNetLog net_log_;
228
229 private:
StartQuicServer(quic::ParsedQuicVersion version)230 void StartQuicServer(quic::ParsedQuicVersion version) {
231 // Set up in-memory cache.
232
233 // Add the simply hello response.
234 memory_cache_backend_.AddSimpleResponse(kTestServerHost, kHelloPath,
235 kHelloStatus, kHelloBodyValue);
236
237 // Now set up index so that it pushes kitten and favicon.
238 quic::QuicBackendResponse::ServerPushInfo push_info1(
239 quic::QuicUrl(UrlFromPath(kKittenPath)), spdy::Http2HeaderBlock(),
240 spdy::kV3LowestPriority, kKittenBodyValue);
241 quic::QuicBackendResponse::ServerPushInfo push_info2(
242 quic::QuicUrl(UrlFromPath(kFaviconPath)), spdy::Http2HeaderBlock(),
243 spdy::kV3LowestPriority, kFaviconBodyValue);
244 memory_cache_backend_.AddSimpleResponseWithServerPushResources(
245 kTestServerHost, kIndexPath, kIndexStatus, kIndexBodyValue,
246 {push_info1, push_info2});
247 quic::QuicConfig config;
248 // Set up server certs.
249 std::unique_ptr<net::ProofSourceChromium> proof_source(
250 new net::ProofSourceChromium());
251 base::FilePath directory = GetTestCertsDirectory();
252 CHECK(proof_source->Initialize(
253 directory.Append(FILE_PATH_LITERAL("quic-chain.pem")),
254 directory.Append(FILE_PATH_LITERAL("quic-leaf-cert.key")),
255 base::FilePath()));
256 server_.reset(new QuicSimpleServer(
257 quic::test::crypto_test_utils::ProofSourceForTesting(), config,
258 quic::QuicCryptoServerConfig::ConfigOptions(), {version},
259 &memory_cache_backend_));
260 int rv =
261 server_->Listen(net::IPEndPoint(net::IPAddress::IPv4AllZeros(), 0));
262 EXPECT_GE(rv, 0) << "Quic server fails to start";
263
264 std::unique_ptr<MockHostResolver> resolver(new MockHostResolver());
265 resolver->rules()->AddRule("test.example.com", "127.0.0.1");
266 host_resolver_.reset(new MappedHostResolver(std::move(resolver)));
267 // Use a mapped host resolver so that request for test.example.com
268 // reach the server running on localhost.
269 std::string map_rule =
270 "MAP test.example.com test.example.com:" +
271 base::NumberToString(server_->server_address().port());
272 EXPECT_TRUE(host_resolver_->AddRuleFromString(map_rule));
273 }
274
ServerPushCacheDirectory()275 std::string ServerPushCacheDirectory() {
276 base::FilePath path;
277 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
278 path = path.AppendASCII("net").AppendASCII("data").AppendASCII(
279 "quic_http_response_cache_data_with_push");
280 // The file path is known to be an ascii string.
281 return path.MaybeAsASCII();
282 }
283
284 MockExpectCTReporter expect_ct_reporter_;
285 TransportSecurityState transport_security_state_;
286
287 std::unique_ptr<MappedHostResolver> host_resolver_;
288 std::unique_ptr<QuicSimpleServer> server_;
289 std::unique_ptr<TestURLRequestContext> context_;
290 QuicContext quic_context_;
291 quic::QuicMemoryCacheBackend memory_cache_backend_;
292 MockCertVerifier cert_verifier_;
293 QuicFlagSaver flags_; // Save/restore all QUIC flag values.
294 };
295
296 // A URLRequest::Delegate that checks LoadTimingInfo when response headers are
297 // received.
298 class CheckLoadTimingDelegate : public TestDelegate {
299 public:
CheckLoadTimingDelegate(bool session_reused)300 CheckLoadTimingDelegate(bool session_reused)
301 : session_reused_(session_reused) {}
OnResponseStarted(URLRequest * request,int error)302 void OnResponseStarted(URLRequest* request, int error) override {
303 TestDelegate::OnResponseStarted(request, error);
304 LoadTimingInfo load_timing_info;
305 request->GetLoadTimingInfo(&load_timing_info);
306 assertLoadTimingValid(load_timing_info, session_reused_);
307 }
308
309 private:
assertLoadTimingValid(const LoadTimingInfo & load_timing_info,bool session_reused)310 void assertLoadTimingValid(const LoadTimingInfo& load_timing_info,
311 bool session_reused) {
312 EXPECT_EQ(session_reused, load_timing_info.socket_reused);
313
314 // If |session_reused| is true, these fields should all be null, non-null
315 // otherwise.
316 EXPECT_EQ(session_reused,
317 load_timing_info.connect_timing.connect_start.is_null());
318 EXPECT_EQ(session_reused,
319 load_timing_info.connect_timing.connect_end.is_null());
320 EXPECT_EQ(session_reused,
321 load_timing_info.connect_timing.ssl_start.is_null());
322 EXPECT_EQ(session_reused,
323 load_timing_info.connect_timing.ssl_end.is_null());
324 EXPECT_EQ(load_timing_info.connect_timing.connect_start,
325 load_timing_info.connect_timing.ssl_start);
326 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
327 load_timing_info.connect_timing.ssl_end);
328 EXPECT_EQ(session_reused,
329 load_timing_info.connect_timing.dns_start.is_null());
330 EXPECT_EQ(session_reused,
331 load_timing_info.connect_timing.dns_end.is_null());
332 }
333
334 bool session_reused_;
335
336 DISALLOW_COPY_AND_ASSIGN(CheckLoadTimingDelegate);
337 };
338
339 // A TestNetworkDelegate that invokes |all_requests_completed_callback| when
340 // |num_expected_requests| requests are completed.
341 class WaitForCompletionNetworkDelegate : public net::TestNetworkDelegate {
342 public:
WaitForCompletionNetworkDelegate(base::OnceClosure all_requests_completed_callback,size_t num_expected_requests)343 WaitForCompletionNetworkDelegate(
344 base::OnceClosure all_requests_completed_callback,
345 size_t num_expected_requests)
346 : all_requests_completed_callback_(
347 std::move(all_requests_completed_callback)),
348 num_expected_requests_(num_expected_requests) {}
349
OnCompleted(URLRequest * request,bool started,int net_error)350 void OnCompleted(URLRequest* request, bool started, int net_error) override {
351 net::TestNetworkDelegate::OnCompleted(request, started, net_error);
352 num_expected_requests_--;
353 if (num_expected_requests_ == 0)
354 std::move(all_requests_completed_callback_).Run();
355 }
356
357 private:
358 base::OnceClosure all_requests_completed_callback_;
359 size_t num_expected_requests_;
360 DISALLOW_COPY_AND_ASSIGN(WaitForCompletionNetworkDelegate);
361 };
362
363 } // namespace
364
365 // Used by ::testing::PrintToStringParamName().
PrintToString(const quic::ParsedQuicVersion & v)366 std::string PrintToString(const quic::ParsedQuicVersion& v) {
367 return quic::ParsedQuicVersionToString(v);
368 }
369
370 INSTANTIATE_TEST_SUITE_P(Version,
371 URLRequestQuicTest,
372 ::testing::ValuesIn(quic::AllSupportedVersions()),
373 ::testing::PrintToStringParamName());
374
TEST_P(URLRequestQuicTest,TestGetRequest)375 TEST_P(URLRequestQuicTest, TestGetRequest) {
376 Init();
377 CheckLoadTimingDelegate delegate(false);
378 std::unique_ptr<URLRequest> request =
379 CreateRequest(GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate);
380
381 request->Start();
382 ASSERT_TRUE(request->is_pending());
383 delegate.RunUntilComplete();
384
385 EXPECT_EQ(OK, delegate.request_status());
386 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
387 EXPECT_TRUE(request->ssl_info().is_valid());
388 }
389
TEST_P(URLRequestQuicTest,CancelPushIfCached_SomeCached)390 TEST_P(URLRequestQuicTest, CancelPushIfCached_SomeCached) {
391 if (VersionUsesHttp3(version().transport_version)) {
392 Init();
393 return;
394 }
395
396 // Skip test if "split cache" is enabled while "partition connections" is
397 // disabled, as it breaks push.
398 if (base::FeatureList::IsEnabled(
399 net::features::kSplitCacheByNetworkIsolationKey) &&
400 !base::FeatureList::IsEnabled(
401 net::features::kPartitionConnectionsByNetworkIsolationKey)) {
402 return;
403 }
404
405 const url::Origin kOrigin1 =
406 url::Origin::Create(GURL("http://www.example.com"));
407 const IsolationInfo kTestIsolationInfo =
408 IsolationInfo::CreateForInternalRequest(kOrigin1);
409
410 Init();
411
412 // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
413 // cache.
414 CheckLoadTimingDelegate delegate_0(false);
415 std::unique_ptr<URLRequest> request_0 = CreateRequest(
416 GURL(UrlFromPath(kKittenPath)), DEFAULT_PRIORITY, &delegate_0);
417
418 request_0->set_isolation_info(kTestIsolationInfo);
419 request_0->Start();
420 ASSERT_TRUE(request_0->is_pending());
421
422 // Spin the message loop until the client receives the response for the first
423 // request.
424 delegate_0.RunUntilComplete();
425 EXPECT_EQ(OK, delegate_0.request_status());
426
427 // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
428 // Should cancel push for /kitten-1.jpg.
429 CheckLoadTimingDelegate delegate(true);
430 std::unique_ptr<URLRequest> request =
431 CreateRequest(GURL(UrlFromPath(kIndexPath)), DEFAULT_PRIORITY, &delegate);
432
433 request->set_isolation_info(kTestIsolationInfo);
434 request->Start();
435 ASSERT_TRUE(request->is_pending());
436
437 // Spin the message loop until the client receives the response for the second
438 // request.
439 delegate.RunUntilComplete();
440 EXPECT_EQ(OK, delegate.request_status());
441 // Wait until all QUIC events are process, some of which happen
442 // asynchronously.
443 base::RunLoop().RunUntilIdle();
444
445 // Extract net logs on client side to verify push lookup transactions.
446 auto entries = net_log_.GetEntriesWithType(
447 NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
448
449 ASSERT_EQ(4u, entries.size());
450
451 std::string value;
452 std::string push_url_1 = UrlFromPath(kKittenPath);
453 std::string push_url_2 = UrlFromPath(kFaviconPath);
454
455 const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
456 EXPECT_TRUE(source_1.IsValid());
457
458 // No net error code for this lookup transaction, the push is found.
459 const NetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
460 EXPECT_FALSE(end_entry_1->HasParams());
461 EXPECT_FALSE(GetOptionalNetErrorCodeFromParams(*end_entry_1));
462
463 const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
464 EXPECT_TRUE(source_2.IsValid());
465 EXPECT_NE(source_1.id, source_2.id);
466
467 // Net error code -400 is found for this lookup transaction, the push is not
468 // found in the cache.
469 const NetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
470 EXPECT_TRUE(end_entry_2->HasParams());
471 EXPECT_EQ(-400, GetNetErrorCodeFromParams(*end_entry_2));
472
473 #if !defined(OS_FUCHSIA) && !defined(OS_IOS) && !defined(OS_APPLE)
474 // TODO(crbug.com/813631): Make this work on Fuchsia.
475 // TODO(crbug.com/1032568): Make this work on iOS.
476 // TODO(crbug.com/1128459): Turn this on for ARM mac.
477
478 // Wait until the server has processed all errors which is
479 // happening asynchronously
480 base::RunLoop().RunUntilIdle();
481 // Verify the reset error count received on the server side.
482 EXPECT_LE(1u, GetRstErrorCountReceivedByServer(quic::QUIC_STREAM_CANCELLED));
483 #endif
484 }
485
TEST_P(URLRequestQuicTest,CancelPushIfCached_AllCached)486 TEST_P(URLRequestQuicTest, CancelPushIfCached_AllCached) {
487 if (VersionUsesHttp3(version().transport_version)) {
488 Init();
489 return;
490 }
491
492 // Skip test if "split cache" is enabled while "partition connections" is
493 // disabled, as it breaks push.
494 if (base::FeatureList::IsEnabled(
495 net::features::kSplitCacheByNetworkIsolationKey) &&
496 !base::FeatureList::IsEnabled(
497 net::features::kPartitionConnectionsByNetworkIsolationKey)) {
498 return;
499 }
500
501 const url::Origin kOrigin1 =
502 url::Origin::Create(GURL("http://www.example.com"));
503 const IsolationInfo kTestIsolationInfo =
504 IsolationInfo::CreateForInternalRequest(kOrigin1);
505
506 Init();
507
508 // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
509 // cache.
510 CheckLoadTimingDelegate delegate_0(false);
511 std::unique_ptr<URLRequest> request_0 = CreateRequest(
512 GURL(UrlFromPath(kKittenPath)), DEFAULT_PRIORITY, &delegate_0);
513
514 request_0->set_isolation_info(kTestIsolationInfo);
515 request_0->Start();
516 ASSERT_TRUE(request_0->is_pending());
517
518 // Spin the message loop until the client receives the response for the first
519 // request.
520 delegate_0.RunUntilComplete();
521 EXPECT_EQ(OK, delegate_0.request_status());
522
523 // Send a request to the pushed url: /favicon.ico to pull the resource into
524 // cache.
525 CheckLoadTimingDelegate delegate_1(true);
526 std::unique_ptr<URLRequest> request_1 = CreateRequest(
527 GURL(UrlFromPath(kFaviconPath)), DEFAULT_PRIORITY, &delegate_1);
528
529 request_1->set_isolation_info(kTestIsolationInfo);
530 request_1->Start();
531 ASSERT_TRUE(request_1->is_pending());
532
533 // Spin the message loop until the client receives the response for the second
534 // request.
535 delegate_1.RunUntilComplete();
536 EXPECT_EQ(OK, delegate_1.request_status());
537
538 // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
539 // Should cancel push for both pushed resources, since they're already cached.
540 CheckLoadTimingDelegate delegate(true);
541 std::unique_ptr<URLRequest> request =
542 CreateRequest(GURL(UrlFromPath(kIndexPath)), DEFAULT_PRIORITY, &delegate);
543
544 request->set_isolation_info(kTestIsolationInfo);
545 request->Start();
546 ASSERT_TRUE(request->is_pending());
547
548 // Spin the message loop until the client receives the response for the third
549 // request.
550 delegate.RunUntilComplete();
551 EXPECT_EQ(OK, delegate.request_status());
552 // Wait until all QUIC events are process, some of which happen
553 // asynchronously.
554 base::RunLoop().RunUntilIdle();
555
556 // Extract net logs on client side to verify push lookup transactions.
557 auto entries = net_log_.GetEntriesWithType(
558 NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
559
560 ASSERT_EQ(4u, entries.size());
561
562 std::string value;
563 std::string push_url_1 = UrlFromPath(kKittenPath);
564 std::string push_url_2 = UrlFromPath(kFaviconPath);
565
566 const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
567 EXPECT_TRUE(source_1.IsValid());
568
569 // No net error code for this lookup transaction, the push is found.
570 const NetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
571 EXPECT_FALSE(end_entry_1->HasParams());
572 EXPECT_FALSE(GetOptionalNetErrorCodeFromParams(*end_entry_1));
573
574 const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
575 EXPECT_TRUE(source_1.IsValid());
576 EXPECT_NE(source_1.id, source_2.id);
577
578 // No net error code for this lookup transaction, the push is found.
579 const NetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
580 EXPECT_FALSE(end_entry_2->HasParams());
581 EXPECT_FALSE(GetOptionalNetErrorCodeFromParams(*end_entry_2));
582
583 #if !defined(OS_FUCHSIA) && !defined(OS_APPLE)
584 // TODO(crbug.com/813631): Make this work on Fuchsia.
585 // TODO(crbug.com/1032568): Make this work on iOS.
586 // TODO(crbug.com/1087378): Flaky on Mac.
587 // Verify the reset error count received on the server side.
588 EXPECT_LE(2u, GetRstErrorCountReceivedByServer(quic::QUIC_STREAM_CANCELLED));
589 #endif
590 }
591
TEST_P(URLRequestQuicTest,DoNotCancelPushIfNotFoundInCache)592 TEST_P(URLRequestQuicTest, DoNotCancelPushIfNotFoundInCache) {
593 if (VersionUsesHttp3(version().transport_version)) {
594 Init();
595 return;
596 }
597
598 Init();
599
600 // Send a request to /index2.hmtl which pushes /kitten-1.jpg and /favicon.ico
601 // and shouldn't cancel any since neither is in cache.
602 CheckLoadTimingDelegate delegate(false);
603 std::string url = UrlFromPath(kIndexPath);
604 std::unique_ptr<URLRequest> request =
605 CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
606
607 request->Start();
608 ASSERT_TRUE(request->is_pending());
609
610 // Spin the message loop until the client receives response.
611 delegate.RunUntilComplete();
612 EXPECT_EQ(OK, delegate.request_status());
613
614 // Extract net logs on client side to verify push lookup transactions.
615 auto entries = net_log_.GetEntriesWithType(
616 NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
617
618 ASSERT_EQ(4u, entries.size());
619
620 std::string value;
621 std::string push_url_1 = UrlFromPath(kKittenPath);
622 std::string push_url_2 = UrlFromPath(kFaviconPath);
623
624 const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
625 EXPECT_TRUE(source_1.IsValid());
626 const NetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
627 EXPECT_TRUE(end_entry_1->HasParams());
628 EXPECT_EQ(-400, GetNetErrorCodeFromParams(*end_entry_1));
629
630 const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
631 EXPECT_TRUE(source_2.IsValid());
632 EXPECT_NE(source_1.id, source_2.id);
633 const NetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
634 EXPECT_TRUE(end_entry_2->HasParams());
635 EXPECT_EQ(-400, GetNetErrorCodeFromParams(*end_entry_2));
636
637 // Verify the reset error count received on the server side.
638 EXPECT_EQ(0u, GetRstErrorCountReceivedByServer(quic::QUIC_STREAM_CANCELLED));
639 }
640
641 // Tests that if two requests use the same QUIC session, the second request
642 // should not have |LoadTimingInfo::connect_timing|.
TEST_P(URLRequestQuicTest,TestTwoRequests)643 TEST_P(URLRequestQuicTest, TestTwoRequests) {
644 base::RunLoop run_loop;
645 WaitForCompletionNetworkDelegate network_delegate(
646 run_loop.QuitClosure(), /*num_expected_requests=*/2);
647 SetNetworkDelegate(&network_delegate);
648 Init();
649 CheckLoadTimingDelegate delegate(false);
650 delegate.set_on_complete(base::DoNothing());
651 std::unique_ptr<URLRequest> request =
652 CreateRequest(GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate);
653
654 CheckLoadTimingDelegate delegate2(true);
655 delegate2.set_on_complete(base::DoNothing());
656 std::unique_ptr<URLRequest> request2 = CreateRequest(
657 GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate2);
658 request->Start();
659 request2->Start();
660 ASSERT_TRUE(request->is_pending());
661 ASSERT_TRUE(request2->is_pending());
662 run_loop.Run();
663
664 EXPECT_EQ(OK, delegate.request_status());
665 EXPECT_EQ(OK, delegate2.request_status());
666 EXPECT_EQ(kHelloBodyValue, delegate.data_received());
667 EXPECT_EQ(kHelloBodyValue, delegate2.data_received());
668 }
669
TEST_P(URLRequestQuicTest,RequestHeadersCallback)670 TEST_P(URLRequestQuicTest, RequestHeadersCallback) {
671 Init();
672 HttpRawRequestHeaders raw_headers;
673 TestDelegate delegate;
674 TestURLRequestContext context;
675 HttpRequestHeaders extra_headers;
676 extra_headers.SetHeader("X-Foo", "bar");
677
678 std::unique_ptr<URLRequest> request =
679 CreateRequest(GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate);
680
681 request->SetExtraRequestHeaders(extra_headers);
682 request->SetRequestHeadersCallback(
683 base::BindLambdaForTesting([&](HttpRawRequestHeaders raw_headers) {
684 // This should be invoked before the request is completed, or any bytes
685 // are read.
686 EXPECT_FALSE(delegate.response_completed());
687 EXPECT_FALSE(delegate.bytes_received());
688
689 EXPECT_FALSE(raw_headers.headers().empty());
690 std::string value;
691 EXPECT_TRUE(raw_headers.FindHeaderForTest("x-foo", &value));
692 EXPECT_EQ("bar", value);
693 EXPECT_TRUE(raw_headers.FindHeaderForTest("accept-encoding", &value));
694 EXPECT_EQ("gzip, deflate", value);
695 EXPECT_TRUE(raw_headers.FindHeaderForTest(":path", &value));
696 EXPECT_EQ("/hello.txt", value);
697 EXPECT_TRUE(raw_headers.FindHeaderForTest(":authority", &value));
698 EXPECT_EQ("test.example.com", value);
699 EXPECT_TRUE(raw_headers.request_line().empty());
700 }));
701 request->Start();
702 ASSERT_TRUE(request->is_pending());
703 delegate.RunUntilComplete();
704 EXPECT_EQ(OK, delegate.request_status());
705 }
706
707 // Tests that if there's an Expect-CT failure at the QUIC layer, a report is
708 // generated.
TEST_P(URLRequestQuicTest,ExpectCT)709 TEST_P(URLRequestQuicTest, ExpectCT) {
710 TransportSecurityState::SetRequireCTForTesting(true);
711 base::test::ScopedFeatureList feature_list;
712 feature_list.InitWithFeatures(
713 // enabled_features
714 {features::kPartitionConnectionsByNetworkIsolationKey,
715 features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
716 features::kPartitionSSLSessionsByNetworkIsolationKey},
717 // disabled_features
718 {});
719
720 MockCTPolicyEnforcerNonCompliant ct_enforcer;
721 context()->set_ct_policy_enforcer(&ct_enforcer);
722 Init();
723
724 GURL report_uri("https://report.test/");
725 IsolationInfo isolation_info = IsolationInfo::CreateTransient();
726 transport_security_state()->AddExpectCT(
727 kTestServerHost, base::Time::Now() + base::TimeDelta::FromDays(1),
728 true /* enforce */, report_uri, isolation_info.network_isolation_key());
729
730 base::RunLoop run_loop;
731 TestDelegate delegate;
732 std::unique_ptr<URLRequest> request =
733 CreateRequest(GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate);
734 request->set_isolation_info(isolation_info);
735 request->Start();
736 delegate.RunUntilComplete();
737
738 EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate.request_status());
739 ASSERT_EQ(1, expect_ct_reporter()->num_failures());
740 EXPECT_EQ(report_uri, expect_ct_reporter()->report_uri());
741 EXPECT_EQ(isolation_info.network_isolation_key(),
742 expect_ct_reporter()->network_isolation_key());
743 }
744
745 } // namespace net
746