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