xref: /aosp_15_r20/external/cronet/net/socket/transport_connect_job_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 The Chromium Authors
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 "net/socket/transport_connect_job.h"
6 
7 #include <memory>
8 #include <string>
9 #include <vector>
10 
11 #include "base/memory/ref_counted.h"
12 #include "base/test/scoped_feature_list.h"
13 #include "base/test/task_environment.h"
14 #include "net/base/address_family.h"
15 #include "net/base/features.h"
16 #include "net/base/host_port_pair.h"
17 #include "net/base/ip_address.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/net_errors.h"
20 #include "net/cert/mock_cert_verifier.h"
21 #include "net/dns/mock_host_resolver.h"
22 #include "net/dns/public/secure_dns_policy.h"
23 #include "net/http/transport_security_state.h"
24 #include "net/log/net_log.h"
25 #include "net/socket/connect_job_test_util.h"
26 #include "net/socket/connection_attempts.h"
27 #include "net/socket/ssl_client_socket.h"
28 #include "net/socket/stream_socket.h"
29 #include "net/socket/transport_client_socket_pool_test_util.h"
30 #include "net/ssl/ssl_config_service.h"
31 #include "net/ssl/test_ssl_config_service.h"
32 #include "net/test/gtest_util.h"
33 #include "net/test/test_with_task_environment.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "url/scheme_host_port.h"
36 #include "url/url_constants.h"
37 
38 namespace net {
39 namespace {
40 
41 const char kHostName[] = "unresolvable.host.name";
42 
ParseIP(const std::string & ip)43 IPAddress ParseIP(const std::string& ip) {
44   IPAddress address;
45   CHECK(address.AssignFromIPLiteral(ip));
46   return address;
47 }
48 
49 class TransportConnectJobTest : public WithTaskEnvironment,
50                                 public testing::Test {
51  public:
TransportConnectJobTest()52   TransportConnectJobTest()
53       : WithTaskEnvironment(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
54         client_socket_factory_(NetLog::Get()),
55         common_connect_job_params_(
56             &client_socket_factory_,
57             &host_resolver_,
58             /*http_auth_cache=*/nullptr,
59             /*http_auth_handler_factory=*/nullptr,
60             /*spdy_session_pool=*/nullptr,
61             /*quic_supported_versions=*/nullptr,
62             /*quic_session_pool=*/nullptr,
63             /*proxy_delegate=*/nullptr,
64             /*http_user_agent_settings=*/nullptr,
65             &ssl_client_context_,
66             /*socket_performance_watcher_factory=*/nullptr,
67             /*network_quality_estimator=*/nullptr,
68             NetLog::Get(),
69             /*websocket_endpoint_lock_manager=*/nullptr,
70             /*http_server_properties=*/nullptr,
71             /*alpn_protos=*/nullptr,
72             /*application_settings=*/nullptr,
73             /*ignore_certificate_errors=*/nullptr,
74             /*early_data_enabled=*/nullptr) {}
75 
76   ~TransportConnectJobTest() override = default;
77 
DefaultParams()78   static scoped_refptr<TransportSocketParams> DefaultParams() {
79     return base::MakeRefCounted<TransportSocketParams>(
80         url::SchemeHostPort(url::kHttpScheme, kHostName, 80),
81         NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
82         OnHostResolutionCallback(),
83         /*supported_alpns=*/base::flat_set<std::string>());
84   }
85 
DefaultHttpsParams()86   static scoped_refptr<TransportSocketParams> DefaultHttpsParams() {
87     return base::MakeRefCounted<TransportSocketParams>(
88         url::SchemeHostPort(url::kHttpsScheme, kHostName, 443),
89         NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
90         OnHostResolutionCallback(),
91         /*supported_alpns=*/base::flat_set<std::string>{"h2", "http/1.1"});
92   }
93 
94  protected:
95   MockHostResolver host_resolver_{/*default_result=*/MockHostResolverBase::
96                                       RuleResolver::GetLocalhostResult()};
97   MockTransportClientSocketFactory client_socket_factory_;
98   TestSSLConfigService ssl_config_service_{SSLContextConfig{}};
99   MockCertVerifier cert_verifier_;
100   TransportSecurityState transport_security_state_;
101   SSLClientContext ssl_client_context_{&ssl_config_service_, &cert_verifier_,
102                                        &transport_security_state_,
103                                        /*ssl_client_session_cache=*/nullptr,
104                                        /*sct_auditing_delegate=*/nullptr};
105   const CommonConnectJobParams common_connect_job_params_;
106 };
107 
TEST_F(TransportConnectJobTest,HostResolutionFailure)108 TEST_F(TransportConnectJobTest, HostResolutionFailure) {
109   host_resolver_.rules()->AddSimulatedTimeoutFailure(kHostName);
110 
111   //  Check sync and async failures.
112   for (bool host_resolution_synchronous : {false, true}) {
113     host_resolver_.set_synchronous_mode(host_resolution_synchronous);
114     TestConnectJobDelegate test_delegate;
115     TransportConnectJob transport_connect_job(
116         DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
117         DefaultParams(), &test_delegate, nullptr /* net_log */);
118     test_delegate.StartJobExpectingResult(&transport_connect_job,
119                                           ERR_NAME_NOT_RESOLVED,
120                                           host_resolution_synchronous);
121     EXPECT_THAT(transport_connect_job.GetResolveErrorInfo().error,
122                 test::IsError(ERR_DNS_TIMED_OUT));
123   }
124 }
125 
TEST_F(TransportConnectJobTest,ConnectionFailure)126 TEST_F(TransportConnectJobTest, ConnectionFailure) {
127   for (bool host_resolution_synchronous : {false, true}) {
128     for (bool connection_synchronous : {false, true}) {
129       host_resolver_.set_synchronous_mode(host_resolution_synchronous);
130       client_socket_factory_.set_default_client_socket_type(
131           connection_synchronous
132               ? MockTransportClientSocketFactory::Type::kFailing
133               : MockTransportClientSocketFactory::Type::kPendingFailing);
134       TestConnectJobDelegate test_delegate;
135       TransportConnectJob transport_connect_job(
136           DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
137           DefaultParams(), &test_delegate, nullptr /* net_log */);
138       test_delegate.StartJobExpectingResult(
139           &transport_connect_job, ERR_CONNECTION_FAILED,
140           host_resolution_synchronous && connection_synchronous);
141     }
142   }
143 }
144 
TEST_F(TransportConnectJobTest,HostResolutionTimeout)145 TEST_F(TransportConnectJobTest, HostResolutionTimeout) {
146   const base::TimeDelta kTinyTime = base::Microseconds(1);
147 
148   // Make request hang.
149   host_resolver_.set_ondemand_mode(true);
150 
151   TestConnectJobDelegate test_delegate;
152   TransportConnectJob transport_connect_job(
153       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
154       DefaultParams(), &test_delegate, nullptr /* net_log */);
155   ASSERT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
156 
157   // Right up until just before expiration, the job does not time out.
158   FastForwardBy(TransportConnectJob::ConnectionTimeout() - kTinyTime);
159   EXPECT_FALSE(test_delegate.has_result());
160 
161   // But at the exact time of expiration, the job fails.
162   FastForwardBy(kTinyTime);
163   EXPECT_TRUE(test_delegate.has_result());
164   EXPECT_THAT(test_delegate.WaitForResult(), test::IsError(ERR_TIMED_OUT));
165 }
166 
TEST_F(TransportConnectJobTest,ConnectionTimeout)167 TEST_F(TransportConnectJobTest, ConnectionTimeout) {
168   const base::TimeDelta kTinyTime = base::Microseconds(1);
169 
170   // Half the timeout time. In the async case, spend half the time waiting on
171   // host resolution, half on connecting.
172   const base::TimeDelta kFirstHalfOfTimeout =
173       TransportConnectJob::ConnectionTimeout() / 2;
174 
175   const base::TimeDelta kSecondHalfOfTimeout =
176       TransportConnectJob::ConnectionTimeout() - kFirstHalfOfTimeout;
177   ASSERT_LE(kTinyTime, kSecondHalfOfTimeout);
178 
179   // Make connection attempts hang.
180   client_socket_factory_.set_default_client_socket_type(
181       MockTransportClientSocketFactory::Type::kStalled);
182 
183   for (bool host_resolution_synchronous : {false, true}) {
184     host_resolver_.set_ondemand_mode(!host_resolution_synchronous);
185     TestConnectJobDelegate test_delegate;
186     TransportConnectJob transport_connect_job(
187         DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
188         DefaultParams(), &test_delegate, nullptr /* net_log */);
189     EXPECT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
190 
191     // After half the timeout, connection does not timeout.
192     FastForwardBy(kFirstHalfOfTimeout);
193     EXPECT_FALSE(test_delegate.has_result());
194 
195     // In the async case, the host resolution completes now.
196     if (!host_resolution_synchronous) {
197       host_resolver_.ResolveOnlyRequestNow();
198     }
199 
200     // After (almost) the second half of timeout, just before the full timeout
201     // period, the ConnectJob is still live.
202     FastForwardBy(kSecondHalfOfTimeout - kTinyTime);
203     EXPECT_FALSE(test_delegate.has_result());
204 
205     // But at the exact timeout time, the job fails.
206     FastForwardBy(kTinyTime);
207     EXPECT_TRUE(test_delegate.has_result());
208     EXPECT_THAT(test_delegate.WaitForResult(), test::IsError(ERR_TIMED_OUT));
209   }
210 }
211 
TEST_F(TransportConnectJobTest,ConnectionSuccess)212 TEST_F(TransportConnectJobTest, ConnectionSuccess) {
213   for (bool host_resolution_synchronous : {false, true}) {
214     for (bool connection_synchronous : {false, true}) {
215       host_resolver_.set_synchronous_mode(host_resolution_synchronous);
216       client_socket_factory_.set_default_client_socket_type(
217           connection_synchronous
218               ? MockTransportClientSocketFactory::Type::kSynchronous
219               : MockTransportClientSocketFactory::Type::kPending);
220       TestConnectJobDelegate test_delegate;
221       TransportConnectJob transport_connect_job(
222           DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
223           DefaultParams(), &test_delegate, nullptr /* net_log */);
224       test_delegate.StartJobExpectingResult(
225           &transport_connect_job, OK,
226           host_resolution_synchronous && connection_synchronous);
227     }
228   }
229 }
230 
TEST_F(TransportConnectJobTest,LoadState)231 TEST_F(TransportConnectJobTest, LoadState) {
232   client_socket_factory_.set_default_client_socket_type(
233       MockTransportClientSocketFactory::Type::kStalled);
234   host_resolver_.set_ondemand_mode(true);
235   host_resolver_.rules()->AddIPLiteralRule(kHostName, "1:abcd::3:4:ff,1.1.1.1",
236                                            std::string());
237 
238   TestConnectJobDelegate test_delegate;
239   TransportConnectJob transport_connect_job(
240       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
241       DefaultParams(), &test_delegate, /*net_log=*/nullptr);
242   EXPECT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
243 
244   // The job is initially waiting on DNS.
245   EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_RESOLVING_HOST);
246 
247   // Complete DNS. It is now waiting on a TCP connection.
248   host_resolver_.ResolveOnlyRequestNow();
249   RunUntilIdle();
250   EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_CONNECTING);
251 
252   // Wait for the IPv4 job to start. The job is still waiting on a TCP
253   // connection.
254   FastForwardBy(TransportConnectJob::kIPv6FallbackTime +
255                 base::Milliseconds(50));
256   EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_CONNECTING);
257 }
258 
259 // TODO(crbug.com/1206799): Set up `host_resolver_` to require the expected
260 // scheme.
TEST_F(TransportConnectJobTest,HandlesHttpsEndpoint)261 TEST_F(TransportConnectJobTest, HandlesHttpsEndpoint) {
262   TestConnectJobDelegate test_delegate;
263   TransportConnectJob transport_connect_job(
264       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
265       base::MakeRefCounted<TransportSocketParams>(
266           url::SchemeHostPort(url::kHttpsScheme, kHostName, 80),
267           NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
268           OnHostResolutionCallback(),
269           /*supported_alpns=*/base::flat_set<std::string>{"h2", "http/1.1"}),
270       &test_delegate, nullptr /* net_log */);
271   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
272                                         false /* expect_sync_result */);
273 }
274 
275 // TODO(crbug.com/1206799): Set up `host_resolver_` to require the expected
276 // lack of scheme.
TEST_F(TransportConnectJobTest,HandlesNonStandardEndpoint)277 TEST_F(TransportConnectJobTest, HandlesNonStandardEndpoint) {
278   TestConnectJobDelegate test_delegate;
279   TransportConnectJob transport_connect_job(
280       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
281       base::MakeRefCounted<TransportSocketParams>(
282           HostPortPair(kHostName, 80), NetworkAnonymizationKey(),
283           SecureDnsPolicy::kAllow, OnHostResolutionCallback(),
284           /*supported_alpns=*/base::flat_set<std::string>()),
285       &test_delegate, nullptr /* net_log */);
286   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
287                                         false /* expect_sync_result */);
288 }
289 
TEST_F(TransportConnectJobTest,SecureDnsPolicy)290 TEST_F(TransportConnectJobTest, SecureDnsPolicy) {
291   for (auto secure_dns_policy :
292        {SecureDnsPolicy::kAllow, SecureDnsPolicy::kDisable}) {
293     TestConnectJobDelegate test_delegate;
294     TransportConnectJob transport_connect_job(
295         DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
296         base::MakeRefCounted<TransportSocketParams>(
297             url::SchemeHostPort(url::kHttpScheme, kHostName, 80),
298             NetworkAnonymizationKey(), secure_dns_policy,
299             OnHostResolutionCallback(),
300             /*supported_alpns=*/base::flat_set<std::string>{}),
301         &test_delegate, nullptr /* net_log */);
302     test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
303                                           false /* expect_sync_result */);
304     EXPECT_EQ(secure_dns_policy, host_resolver_.last_secure_dns_policy());
305   }
306 }
307 
308 // Test the case of the IPv6 address stalling, and falling back to the IPv4
309 // socket which finishes first.
TEST_F(TransportConnectJobTest,IPv6FallbackSocketIPv4FinishesFirst)310 TEST_F(TransportConnectJobTest, IPv6FallbackSocketIPv4FinishesFirst) {
311   MockTransportClientSocketFactory::Rule rules[] = {
312       // The first IPv6 attempt fails.
313       MockTransportClientSocketFactory::Rule(
314           MockTransportClientSocketFactory::Type::kFailing,
315           std::vector{IPEndPoint(ParseIP("1:abcd::3:4:ff"), 80)}),
316       // The second IPv6 attempt stalls.
317       MockTransportClientSocketFactory::Rule(
318           MockTransportClientSocketFactory::Type::kStalled,
319           std::vector{IPEndPoint(ParseIP("2:abcd::3:4:ff"), 80)}),
320       // After a timeout, we try the IPv4 address.
321       MockTransportClientSocketFactory::Rule(
322           MockTransportClientSocketFactory::Type::kPending,
323           std::vector{IPEndPoint(ParseIP("2.2.2.2"), 80)})};
324 
325   client_socket_factory_.SetRules(rules);
326 
327   // Resolve an AddressList with two IPv6 addresses and then a IPv4 address.
328   host_resolver_.rules()->AddIPLiteralRule(
329       kHostName, "1:abcd::3:4:ff,2:abcd::3:4:ff,2.2.2.2", std::string());
330 
331   TestConnectJobDelegate test_delegate;
332   TransportConnectJob transport_connect_job(
333       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
334       DefaultParams(), &test_delegate, nullptr /* net_log */);
335   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
336                                         false /* expect_sync_result */);
337 
338   IPEndPoint endpoint;
339   test_delegate.socket()->GetLocalAddress(&endpoint);
340   EXPECT_TRUE(endpoint.address().IsIPv4());
341 
342   // Check that the failed connection attempt is collected.
343   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
344   ASSERT_EQ(1u, attempts.size());
345   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
346   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1:abcd::3:4:ff"), 80));
347 
348   EXPECT_EQ(3, client_socket_factory_.allocation_count());
349 }
350 
351 // Test the case of the IPv6 address being slow, thus falling back to trying to
352 // connect to the IPv4 address, but having the connect to the IPv6 address
353 // finish first.
TEST_F(TransportConnectJobTest,IPv6FallbackSocketIPv6FinishesFirst)354 TEST_F(TransportConnectJobTest, IPv6FallbackSocketIPv6FinishesFirst) {
355   MockTransportClientSocketFactory::Rule rules[] = {
356       // The first IPv6 attempt ultimately succeeds, but is delayed.
357       MockTransportClientSocketFactory::Rule(
358           MockTransportClientSocketFactory::Type::kDelayed,
359           std::vector{IPEndPoint(ParseIP("2:abcd::3:4:ff"), 80)}),
360       // The first IPv4 attempt fails.
361       MockTransportClientSocketFactory::Rule(
362           MockTransportClientSocketFactory::Type::kFailing,
363           std::vector{IPEndPoint(ParseIP("2.2.2.2"), 80)}),
364       // The second IPv4 attempt stalls.
365       MockTransportClientSocketFactory::Rule(
366           MockTransportClientSocketFactory::Type::kStalled,
367           std::vector{IPEndPoint(ParseIP("3.3.3.3"), 80)})};
368 
369   client_socket_factory_.SetRules(rules);
370   client_socket_factory_.set_delay(TransportConnectJob::kIPv6FallbackTime +
371                                    base::Milliseconds(50));
372 
373   // Resolve an AddressList with a IPv6 address first and then a IPv4 address.
374   host_resolver_.rules()->AddIPLiteralRule(
375       kHostName, "2:abcd::3:4:ff,2.2.2.2,3.3.3.3", std::string());
376 
377   TestConnectJobDelegate test_delegate;
378   TransportConnectJob transport_connect_job(
379       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
380       DefaultParams(), &test_delegate, nullptr /* net_log */);
381   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
382                                         false /* expect_sync_result */);
383 
384   IPEndPoint endpoint;
385   test_delegate.socket()->GetLocalAddress(&endpoint);
386   EXPECT_TRUE(endpoint.address().IsIPv6());
387 
388   // Check that the failed connection attempt on the fallback socket is
389   // collected.
390   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
391   ASSERT_EQ(1u, attempts.size());
392   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
393   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("2.2.2.2"), 80));
394 
395   EXPECT_EQ(3, client_socket_factory_.allocation_count());
396 }
397 
TEST_F(TransportConnectJobTest,IPv6NoIPv4AddressesToFallbackTo)398 TEST_F(TransportConnectJobTest, IPv6NoIPv4AddressesToFallbackTo) {
399   client_socket_factory_.set_default_client_socket_type(
400       MockTransportClientSocketFactory::Type::kDelayed);
401 
402   // Resolve an AddressList with only IPv6 addresses.
403   host_resolver_.rules()->AddIPLiteralRule(
404       kHostName, "2:abcd::3:4:ff,3:abcd::3:4:ff", std::string());
405 
406   TestConnectJobDelegate test_delegate;
407   TransportConnectJob transport_connect_job(
408       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
409       DefaultParams(), &test_delegate, nullptr /* net_log */);
410   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
411                                         false /* expect_sync_result */);
412 
413   IPEndPoint endpoint;
414   test_delegate.socket()->GetLocalAddress(&endpoint);
415   EXPECT_TRUE(endpoint.address().IsIPv6());
416   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
417   EXPECT_EQ(0u, attempts.size());
418   EXPECT_EQ(1, client_socket_factory_.allocation_count());
419 }
420 
TEST_F(TransportConnectJobTest,IPv4HasNoFallback)421 TEST_F(TransportConnectJobTest, IPv4HasNoFallback) {
422   client_socket_factory_.set_default_client_socket_type(
423       MockTransportClientSocketFactory::Type::kDelayed);
424 
425   // Resolve an AddressList with only IPv4 addresses.
426   host_resolver_.rules()->AddIPLiteralRule(kHostName, "1.1.1.1", std::string());
427 
428   TestConnectJobDelegate test_delegate;
429   TransportConnectJob transport_connect_job(
430       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
431       DefaultParams(), &test_delegate, nullptr /* net_log */);
432   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
433                                         false /* expect_sync_result */);
434 
435   IPEndPoint endpoint;
436   test_delegate.socket()->GetLocalAddress(&endpoint);
437   EXPECT_TRUE(endpoint.address().IsIPv4());
438   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
439   EXPECT_EQ(0u, attempts.size());
440   EXPECT_EQ(1, client_socket_factory_.allocation_count());
441 }
442 
TEST_F(TransportConnectJobTest,DnsAliases)443 TEST_F(TransportConnectJobTest, DnsAliases) {
444   host_resolver_.set_synchronous_mode(true);
445   client_socket_factory_.set_default_client_socket_type(
446       MockTransportClientSocketFactory::Type::kSynchronous);
447 
448   // Resolve an AddressList with DNS aliases.
449   std::vector<std::string> aliases({"alias1", "alias2", kHostName});
450   host_resolver_.rules()->AddIPLiteralRuleWithDnsAliases(kHostName, "2.2.2.2",
451                                                          std::move(aliases));
452 
453   TestConnectJobDelegate test_delegate;
454   TransportConnectJob transport_connect_job(
455       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
456       DefaultParams(), &test_delegate, nullptr /* net_log */);
457 
458   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
459                                         true /* expect_sync_result */);
460 
461   // Verify that the elements of the alias list are those from the
462   // parameter vector.
463   EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
464               testing::ElementsAre("alias1", "alias2", kHostName));
465 }
466 
TEST_F(TransportConnectJobTest,NoAdditionalDnsAliases)467 TEST_F(TransportConnectJobTest, NoAdditionalDnsAliases) {
468   host_resolver_.set_synchronous_mode(true);
469   client_socket_factory_.set_default_client_socket_type(
470       MockTransportClientSocketFactory::Type::kSynchronous);
471 
472   // Resolve an AddressList without additional DNS aliases. (The parameter
473   // is an empty vector.)
474   std::vector<std::string> aliases;
475   host_resolver_.rules()->AddIPLiteralRuleWithDnsAliases(kHostName, "2.2.2.2",
476                                                          std::move(aliases));
477 
478   TestConnectJobDelegate test_delegate;
479   TransportConnectJob transport_connect_job(
480       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
481       DefaultParams(), &test_delegate, nullptr /* net_log */);
482 
483   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
484                                         true /* expect_sync_result */);
485 
486   // Verify that the alias list only contains kHostName.
487   EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
488               testing::ElementsAre(kHostName));
489 }
490 
491 // Test that `TransportConnectJob` will pick up options from
492 // `HostResolverEndpointResult`.
TEST_F(TransportConnectJobTest,EndpointResult)493 TEST_F(TransportConnectJobTest, EndpointResult) {
494   HostResolverEndpointResult endpoint;
495   endpoint.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8443),
496                            IPEndPoint(ParseIP("1.1.1.1"), 8443)};
497   endpoint.metadata.supported_protocol_alpns = {"h2"};
498   host_resolver_.rules()->AddRule(
499       kHostName,
500       MockHostResolverBase::RuleResolver::RuleResult(std::vector{endpoint}));
501 
502   // The first access succeeds.
503   MockTransportClientSocketFactory::Rule rule(
504       MockTransportClientSocketFactory::Type::kSynchronous,
505       std::vector{IPEndPoint(ParseIP("1::"), 8443)});
506   client_socket_factory_.SetRules(base::make_span(&rule, 1u));
507 
508   TestConnectJobDelegate test_delegate;
509   TransportConnectJob transport_connect_job(
510       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
511       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
512   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
513                                         /*expect_sync_result=*/false);
514 
515   IPEndPoint peer_address;
516   test_delegate.socket()->GetPeerAddress(&peer_address);
517   EXPECT_EQ(peer_address, IPEndPoint(ParseIP("1::"), 8443));
518 
519   EXPECT_EQ(1, client_socket_factory_.allocation_count());
520 
521   // There were no failed connection attempts to report.
522   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
523   EXPECT_EQ(0u, attempts.size());
524 }
525 
526 // Test that, given multiple `HostResolverEndpointResult` results,
527 // `TransportConnectJob` tries each in succession.
TEST_F(TransportConnectJobTest,MultipleRoutesFallback)528 TEST_F(TransportConnectJobTest, MultipleRoutesFallback) {
529   std::vector<HostResolverEndpointResult> endpoints(3);
530   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
531                                IPEndPoint(ParseIP("1.1.1.1"), 8441)};
532   endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
533   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
534                                IPEndPoint(ParseIP("2.2.2.2"), 8442)};
535   endpoints[1].metadata.supported_protocol_alpns = {"h3"};
536   endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("4::"), 443),
537                                IPEndPoint(ParseIP("4.4.4.4"), 443)};
538   host_resolver_.rules()->AddRule(
539       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
540 
541   MockTransportClientSocketFactory::Rule rules[] = {
542       // `endpoints[0]`'s addresses each fail.
543       MockTransportClientSocketFactory::Rule(
544           MockTransportClientSocketFactory::Type::kFailing,
545           std::vector{endpoints[0].ip_endpoints[0]}),
546       MockTransportClientSocketFactory::Rule(
547           MockTransportClientSocketFactory::Type::kFailing,
548           std::vector{endpoints[0].ip_endpoints[1]}),
549       // `endpoints[1]` is skipped because the ALPN is not compatible.
550       // `endpoints[2]`'s first address succeeds.
551       MockTransportClientSocketFactory::Rule(
552           MockTransportClientSocketFactory::Type::kSynchronous,
553           std::vector{endpoints[2].ip_endpoints[0]}),
554   };
555 
556   client_socket_factory_.SetRules(rules);
557 
558   TestConnectJobDelegate test_delegate;
559   TransportConnectJob transport_connect_job(
560       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
561       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
562   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
563                                         /*expect_sync_result=*/false);
564 
565   IPEndPoint peer_address;
566   test_delegate.socket()->GetPeerAddress(&peer_address);
567   EXPECT_EQ(peer_address, IPEndPoint(ParseIP("4::"), 443));
568 
569   // Check that failed connection attempts are reported.
570   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
571   ASSERT_EQ(2u, attempts.size());
572   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
573   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
574   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
575   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
576 }
577 
578 // Test that the `HostResolverEndpointResult` fallback works in combination with
579 // the IPv4 fallback.
TEST_F(TransportConnectJobTest,MultipleRoutesIPV4Fallback)580 TEST_F(TransportConnectJobTest, MultipleRoutesIPV4Fallback) {
581   HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
582   endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
583                             IPEndPoint(ParseIP("1.1.1.1"), 8441)};
584   endpoint1.metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
585   endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
586                             IPEndPoint(ParseIP("2.2.2.2"), 8442)};
587   endpoint2.metadata.supported_protocol_alpns = {"h3"};
588   endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443),
589                             IPEndPoint(ParseIP("3.3.3.3"), 443)};
590   host_resolver_.rules()->AddRule(
591       kHostName, MockHostResolverBase::RuleResolver::RuleResult(
592                      std::vector{endpoint1, endpoint2, endpoint3}));
593 
594   MockTransportClientSocketFactory::Rule rules[] = {
595       // `endpoint1`'s IPv6 address fails, but takes long enough that the IPv4
596       // fallback runs.
597       //
598       // TODO(davidben): If the network is such that IPv6 connection attempts
599       // always stall, we will never try `endpoint2`. Should Happy Eyeballs
600       // logic happen before HTTPS RR. Or perhaps we should implement a more
601       // Happy-Eyeballs-v2-like strategy.
602       MockTransportClientSocketFactory::Rule(
603           MockTransportClientSocketFactory::Type::kDelayedFailing,
604           std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
605 
606       // `endpoint1`'s IPv4 address fails immediately.
607       MockTransportClientSocketFactory::Rule(
608           MockTransportClientSocketFactory::Type::kFailing,
609           std::vector{IPEndPoint(ParseIP("1.1.1.1"), 8441)}),
610 
611       // `endpoint2` is skipped because the ALPN is not compatible.
612 
613       // `endpoint3`'s IPv6 address never completes.
614       MockTransportClientSocketFactory::Rule(
615           MockTransportClientSocketFactory::Type::kStalled,
616           std::vector{IPEndPoint(ParseIP("3::"), 443)}),
617       // `endpoint3`'s IPv4 address succeeds.
618       MockTransportClientSocketFactory::Rule(
619           MockTransportClientSocketFactory::Type::kSynchronous,
620           std::vector{IPEndPoint(ParseIP("3.3.3.3"), 443)}),
621   };
622   client_socket_factory_.SetRules(rules);
623   client_socket_factory_.set_delay(TransportConnectJob::kIPv6FallbackTime +
624                                    base::Milliseconds(50));
625 
626   TestConnectJobDelegate test_delegate;
627   TransportConnectJob transport_connect_job(
628       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
629       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
630   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
631                                         /*expect_sync_result=*/false);
632 
633   IPEndPoint peer_address;
634   test_delegate.socket()->GetPeerAddress(&peer_address);
635   EXPECT_EQ(peer_address, IPEndPoint(ParseIP("3.3.3.3"), 443));
636 
637   // Check that failed connection attempts are reported.
638   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
639   ASSERT_EQ(2u, attempts.size());
640   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
641   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
642   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
643   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1::"), 8441));
644 }
645 
646 // Test that `TransportConnectJob` will not continue trying routes given
647 // ERR_NETWORK_IO_SUSPENDED.
TEST_F(TransportConnectJobTest,MultipleRoutesSuspended)648 TEST_F(TransportConnectJobTest, MultipleRoutesSuspended) {
649   std::vector<HostResolverEndpointResult> endpoints(2);
650   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8443)};
651   endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
652   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 443)};
653   host_resolver_.rules()->AddRule(
654       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
655 
656   // The first connect attempt will fail with `ERR_NETWORK_IO_SUSPENDED`.
657   // `TransportConnectJob` should not attempt routes after receiving this error.
658   MockTransportClientSocketFactory::Rule rule(
659       MockTransportClientSocketFactory::Type::kFailing,
660       endpoints[0].ip_endpoints, ERR_NETWORK_IO_SUSPENDED);
661   client_socket_factory_.SetRules(base::make_span(&rule, 1u));
662 
663   TestConnectJobDelegate test_delegate;
664   TransportConnectJob transport_connect_job(
665       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
666       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
667   test_delegate.StartJobExpectingResult(&transport_connect_job,
668                                         ERR_NETWORK_IO_SUSPENDED,
669                                         /*expect_sync_result=*/false);
670 
671   // Check that failed connection attempts are reported.
672   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
673   ASSERT_EQ(1u, attempts.size());
674   EXPECT_THAT(attempts[0].result, test::IsError(ERR_NETWORK_IO_SUSPENDED));
675   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8443));
676 }
677 
678 // Test that, if `HostResolver` supports SVCB for a scheme but the caller didn't
679 // pass in any ALPN protocols, `TransportConnectJob` ignores all protocol
680 // endpoints.
TEST_F(TransportConnectJobTest,NoAlpnProtocols)681 TEST_F(TransportConnectJobTest, NoAlpnProtocols) {
682   std::vector<HostResolverEndpointResult> endpoints(3);
683   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8081),
684                                IPEndPoint(ParseIP("1.1.1.1"), 8081)};
685   endpoints[0].metadata.supported_protocol_alpns = {"foo", "bar"};
686   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8082),
687                                IPEndPoint(ParseIP("2.2.2.2"), 8082)};
688   endpoints[1].metadata.supported_protocol_alpns = {"baz"};
689   endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 80),
690                                IPEndPoint(ParseIP("3.3.3.3"), 80)};
691   host_resolver_.rules()->AddRule(
692       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
693 
694   // `endpoints[2]`'s first address succeeds.
695   MockTransportClientSocketFactory::Rule rule(
696       MockTransportClientSocketFactory::Type::kSynchronous,
697       std::vector{endpoints[2].ip_endpoints[0]});
698   client_socket_factory_.SetRules(base::make_span(&rule, 1u));
699 
700   // Use `DefaultParams()`, an http scheme. That it is http is not very
701   // important, but `url::SchemeHostPort` is difficult to use with unknown
702   // schemes. See https://crbug.com/869291.
703   scoped_refptr<TransportSocketParams> params = DefaultParams();
704   ASSERT_TRUE(params->supported_alpns().empty());
705 
706   TestConnectJobDelegate test_delegate;
707   TransportConnectJob transport_connect_job(
708       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
709       std::move(params), &test_delegate, /*net_log=*/nullptr);
710   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
711                                         /*expect_sync_result=*/false);
712 
713   IPEndPoint peer_address;
714   test_delegate.socket()->GetPeerAddress(&peer_address);
715   EXPECT_EQ(peer_address, IPEndPoint(ParseIP("3::"), 80));
716 }
717 
718 // Test that, given multiple `HostResolverEndpointResult` results,
719 // `TransportConnectJob` reports failure if each one fails.
TEST_F(TransportConnectJobTest,MultipleRoutesAllFailed)720 TEST_F(TransportConnectJobTest, MultipleRoutesAllFailed) {
721   std::vector<HostResolverEndpointResult> endpoints(3);
722   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
723                                IPEndPoint(ParseIP("1.1.1.1"), 8441)};
724   endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
725   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
726                                IPEndPoint(ParseIP("2.2.2.2"), 8442)};
727   endpoints[1].metadata.supported_protocol_alpns = {"h3"};
728   endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 443),
729                                IPEndPoint(ParseIP("3.3.3.3"), 443)};
730   host_resolver_.rules()->AddRule(
731       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
732 
733   MockTransportClientSocketFactory::Rule rules[] = {
734       // `endpoints[0]`'s addresses each fail.
735       MockTransportClientSocketFactory::Rule(
736           MockTransportClientSocketFactory::Type::kFailing,
737           std::vector{endpoints[0].ip_endpoints[0]}),
738       MockTransportClientSocketFactory::Rule(
739           MockTransportClientSocketFactory::Type::kFailing,
740           std::vector{endpoints[0].ip_endpoints[1]}),
741       // `endpoints[1]` is skipped because the ALPN is not compatible.
742       // `endpoints[2]`'s addresses each fail.
743       MockTransportClientSocketFactory::Rule(
744           MockTransportClientSocketFactory::Type::kFailing,
745           std::vector{endpoints[2].ip_endpoints[0]}),
746       MockTransportClientSocketFactory::Rule(
747           MockTransportClientSocketFactory::Type::kFailing,
748           std::vector{endpoints[2].ip_endpoints[1]}),
749   };
750 
751   client_socket_factory_.SetRules(rules);
752 
753   TestConnectJobDelegate test_delegate;
754   TransportConnectJob transport_connect_job(
755       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
756       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
757   test_delegate.StartJobExpectingResult(&transport_connect_job,
758                                         ERR_CONNECTION_FAILED,
759                                         /*expect_sync_result=*/false);
760 
761   // Check that failed connection attempts are reported.
762   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
763   ASSERT_EQ(4u, attempts.size());
764   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
765   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
766   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
767   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
768   EXPECT_THAT(attempts[2].result, test::IsError(ERR_CONNECTION_FAILED));
769   EXPECT_EQ(attempts[2].endpoint, IPEndPoint(ParseIP("3::"), 443));
770   EXPECT_THAT(attempts[3].result, test::IsError(ERR_CONNECTION_FAILED));
771   EXPECT_EQ(attempts[3].endpoint, IPEndPoint(ParseIP("3.3.3.3"), 443));
772 }
773 
774 // Test that `TransportConnectJob` reports failure if all provided routes were
775 // unusable.
TEST_F(TransportConnectJobTest,NoUsableRoutes)776 TEST_F(TransportConnectJobTest, NoUsableRoutes) {
777   std::vector<HostResolverEndpointResult> endpoints(2);
778   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
779                                IPEndPoint(ParseIP("1.1.1.1"), 8441)};
780   endpoints[0].metadata.supported_protocol_alpns = {"h3"};
781   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
782                                IPEndPoint(ParseIP("2.2.2.2"), 8442)};
783   endpoints[1].metadata.supported_protocol_alpns = {"unrecognized-protocol"};
784   host_resolver_.rules()->AddRule(
785       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
786 
787   // `TransportConnectJob` should not create any sockets.
788   client_socket_factory_.set_default_client_socket_type(
789       MockTransportClientSocketFactory::Type::kUnexpected);
790 
791   TestConnectJobDelegate test_delegate;
792   TransportConnectJob transport_connect_job(
793       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
794       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
795   test_delegate.StartJobExpectingResult(&transport_connect_job,
796                                         ERR_NAME_NOT_RESOLVED,
797                                         /*expect_sync_result=*/false);
798 }
799 
800 // Test that, if the last route is unusable, the error from the
801 // previously-attempted route is preserved.
TEST_F(TransportConnectJobTest,LastRouteUnusable)802 TEST_F(TransportConnectJobTest, LastRouteUnusable) {
803   std::vector<HostResolverEndpointResult> endpoints(2);
804   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
805                                IPEndPoint(ParseIP("1.1.1.1"), 8441)};
806   endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
807   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
808                                IPEndPoint(ParseIP("2.2.2.2"), 8442)};
809   endpoints[1].metadata.supported_protocol_alpns = {"h3"};
810   host_resolver_.rules()->AddRule(
811       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
812 
813   MockTransportClientSocketFactory::Rule rules[] = {
814       // `endpoints[0]`'s addresses each fail.
815       MockTransportClientSocketFactory::Rule(
816           MockTransportClientSocketFactory::Type::kFailing,
817           std::vector{endpoints[0].ip_endpoints[0]}),
818       MockTransportClientSocketFactory::Rule(
819           MockTransportClientSocketFactory::Type::kFailing,
820           std::vector{endpoints[0].ip_endpoints[1]}),
821       // `endpoints[1]` is skipped because the ALPN is not compatible.
822   };
823 
824   client_socket_factory_.SetRules(rules);
825 
826   TestConnectJobDelegate test_delegate;
827   TransportConnectJob transport_connect_job(
828       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
829       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
830   test_delegate.StartJobExpectingResult(&transport_connect_job,
831                                         ERR_CONNECTION_FAILED,
832                                         /*expect_sync_result=*/false);
833 
834   // Check that failed connection attempts are reported.
835   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
836   ASSERT_EQ(2u, attempts.size());
837   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
838   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
839   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
840   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
841 }
842 
843 // `GetHostResolverEndpointResult` should surface information about the endpoint
844 // that was actually used.
TEST_F(TransportConnectJobTest,GetHostResolverEndpointResult)845 TEST_F(TransportConnectJobTest, GetHostResolverEndpointResult) {
846   std::vector<HostResolverEndpointResult> endpoints(4);
847   // `endpoints[0]` will be skipped due to ALPN mismatch.
848   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
849   endpoints[0].metadata.supported_protocol_alpns = {"h3"};
850   endpoints[0].metadata.ech_config_list = {1, 2, 3, 4};
851   // `endpoints[1]` will be skipped due to connection failure.
852   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
853   endpoints[1].metadata.supported_protocol_alpns = {"http/1.1"};
854   endpoints[1].metadata.ech_config_list = {5, 6, 7, 8};
855   // `endpoints[2]` will succeed.
856   endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 8443)};
857   endpoints[2].metadata.supported_protocol_alpns = {"http/1.1"};
858   endpoints[2].metadata.ech_config_list = {9, 10, 11, 12};
859   // `endpoints[3]` will be not be tried because `endpoints[2]` will already
860   // have succeeded.
861   endpoints[3].ip_endpoints = {IPEndPoint(ParseIP("4::"), 8444)};
862   endpoints[3].metadata.supported_protocol_alpns = {"http/1.1"};
863   endpoints[3].metadata.ech_config_list = {13, 14, 15, 16};
864   host_resolver_.rules()->AddRule(
865       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
866 
867   MockTransportClientSocketFactory::Rule rules[] = {
868       MockTransportClientSocketFactory::Rule(
869           MockTransportClientSocketFactory::Type::kFailing,
870           std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
871       MockTransportClientSocketFactory::Rule(
872           MockTransportClientSocketFactory::Type::kSynchronous,
873           std::vector{IPEndPoint(ParseIP("3::"), 8443)}),
874   };
875   client_socket_factory_.SetRules(rules);
876 
877   TestConnectJobDelegate test_delegate;
878   TransportConnectJob transport_connect_job(
879       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
880       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
881   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
882                                         /*expect_sync_result=*/false);
883 
884   EXPECT_EQ(transport_connect_job.GetHostResolverEndpointResult(),
885             endpoints[2]);
886 }
887 
888 // If the client and server both support ECH, TransportConnectJob should switch
889 // to SVCB-reliant mode and disable the A/AAAA fallback.
TEST_F(TransportConnectJobTest,SvcbReliantIfEch)890 TEST_F(TransportConnectJobTest, SvcbReliantIfEch) {
891   HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
892   endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
893   endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
894   endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
895   endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
896   endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
897   endpoint2.metadata.ech_config_list = {1, 2, 3, 4};
898   endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
899   // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
900   host_resolver_.rules()->AddRule(
901       kHostName, MockHostResolverBase::RuleResolver::RuleResult(
902                      std::vector{endpoint1, endpoint2, endpoint3}));
903 
904   // `TransportConnectJob` should not try `endpoint3`.
905   MockTransportClientSocketFactory::Rule rules[] = {
906       MockTransportClientSocketFactory::Rule(
907           MockTransportClientSocketFactory::Type::kFailing,
908           std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
909       MockTransportClientSocketFactory::Rule(
910           MockTransportClientSocketFactory::Type::kFailing,
911           std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
912   };
913   client_socket_factory_.SetRules(rules);
914 
915   TestConnectJobDelegate test_delegate;
916   TransportConnectJob transport_connect_job(
917       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
918       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
919   test_delegate.StartJobExpectingResult(&transport_connect_job,
920                                         ERR_CONNECTION_FAILED,
921                                         /*expect_sync_result=*/false);
922 
923   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
924   ASSERT_EQ(2u, attempts.size());
925   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
926   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
927   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
928   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("2::"), 8442));
929 }
930 
931 // SVCB-reliant mode should be disabled for ECH servers when ECH is disabled via
932 // config.
TEST_F(TransportConnectJobTest,SvcbOptionalIfEchDisabledConfig)933 TEST_F(TransportConnectJobTest, SvcbOptionalIfEchDisabledConfig) {
934   SSLContextConfig config;
935   config.ech_enabled = false;
936   ssl_config_service_.UpdateSSLConfigAndNotify(config);
937 
938   HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
939   endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
940   endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
941   endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
942   endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
943   endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
944   endpoint2.metadata.ech_config_list = {1, 2, 3, 4};
945   endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
946   // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
947   host_resolver_.rules()->AddRule(
948       kHostName, MockHostResolverBase::RuleResolver::RuleResult(
949                      std::vector{endpoint1, endpoint2, endpoint3}));
950 
951   // `TransportConnectJob` should try `endpoint3`.
952   MockTransportClientSocketFactory::Rule rules[] = {
953       MockTransportClientSocketFactory::Rule(
954           MockTransportClientSocketFactory::Type::kFailing,
955           std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
956       MockTransportClientSocketFactory::Rule(
957           MockTransportClientSocketFactory::Type::kFailing,
958           std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
959       MockTransportClientSocketFactory::Rule(
960           MockTransportClientSocketFactory::Type::kSynchronous,
961           std::vector{IPEndPoint(ParseIP("3::"), 443)}),
962   };
963   client_socket_factory_.SetRules(rules);
964 
965   TestConnectJobDelegate test_delegate;
966   TransportConnectJob transport_connect_job(
967       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
968       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
969   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
970                                         /*expect_sync_result=*/false);
971 }
972 
973 // SVCB-reliant mode should be disabled if not all SVCB/HTTPS records include
974 // ECH.
TEST_F(TransportConnectJobTest,SvcbOptionalIfEchInconsistent)975 TEST_F(TransportConnectJobTest, SvcbOptionalIfEchInconsistent) {
976   HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
977   endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
978   endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
979   endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
980   endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
981   endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
982   endpoint2.metadata.ech_config_list = {};
983   endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
984   // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
985   host_resolver_.rules()->AddRule(
986       kHostName, MockHostResolverBase::RuleResolver::RuleResult(
987                      std::vector{endpoint1, endpoint2, endpoint3}));
988 
989   // `TransportConnectJob` should try `endpoint3`.
990   MockTransportClientSocketFactory::Rule rules[] = {
991       MockTransportClientSocketFactory::Rule(
992           MockTransportClientSocketFactory::Type::kFailing,
993           std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
994       MockTransportClientSocketFactory::Rule(
995           MockTransportClientSocketFactory::Type::kFailing,
996           std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
997       MockTransportClientSocketFactory::Rule(
998           MockTransportClientSocketFactory::Type::kSynchronous,
999           std::vector{IPEndPoint(ParseIP("3::"), 443)}),
1000   };
1001   client_socket_factory_.SetRules(rules);
1002 
1003   TestConnectJobDelegate test_delegate;
1004   TransportConnectJob transport_connect_job(
1005       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
1006       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
1007   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
1008                                         /*expect_sync_result=*/false);
1009 }
1010 
1011 // Overriding the endpoint results should skip DNS resolution.
TEST_F(TransportConnectJobTest,EndpointResultOverride)1012 TEST_F(TransportConnectJobTest, EndpointResultOverride) {
1013   // Make DNS resolution fail, to confirm we don't use the result.
1014   host_resolver_.rules()->AddRule(kHostName, ERR_FAILED);
1015 
1016   // `TransportConnectJob` should try `endpoint`.
1017   HostResolverEndpointResult endpoint;
1018   endpoint.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
1019   endpoint.metadata.supported_protocol_alpns = {"http/1.1"};
1020   MockTransportClientSocketFactory::Rule rules[] = {
1021       MockTransportClientSocketFactory::Rule(
1022           MockTransportClientSocketFactory::Type::kSynchronous,
1023           endpoint.ip_endpoints),
1024   };
1025   client_socket_factory_.SetRules(rules);
1026 
1027   TransportConnectJob::EndpointResultOverride override(
1028       endpoint, {"alias.example", kHostName});
1029   TestConnectJobDelegate test_delegate;
1030   TransportConnectJob transport_connect_job(
1031       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
1032       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr, override);
1033   test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
1034                                         /*expect_sync_result=*/true);
1035 
1036   // Verify information is reported from the override.
1037   EXPECT_EQ(transport_connect_job.GetHostResolverEndpointResult(), endpoint);
1038   EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
1039               testing::ElementsAre("alias.example", kHostName));
1040 }
1041 
1042 // If two `HostResolverEndpointResult`s share an IP endpoint,
1043 // `TransportConnectJob` should not try to connect a second time.
TEST_F(TransportConnectJobTest,DedupIPEndPoints)1044 TEST_F(TransportConnectJobTest, DedupIPEndPoints) {
1045   std::vector<HostResolverEndpointResult> endpoints(4);
1046   // Some initial IPEndPoints.
1047   endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 443),
1048                                IPEndPoint(ParseIP("1.1.1.1"), 443)};
1049   endpoints[0].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
1050   // Contains a new IPEndPoint, but no common protocols.
1051   endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 443)};
1052   endpoints[1].metadata.supported_protocol_alpns = {"h3"};
1053   // Contains mixture of previously seen and new IPEndPoints, so we should only
1054   // try a subset of them.
1055   endpoints[2].ip_endpoints = {
1056       // Duplicate from `endpoints[0]`, should be filtered out.
1057       IPEndPoint(ParseIP("1::"), 443),
1058       // Same IP but new port. Should be used.
1059       IPEndPoint(ParseIP("1::"), 444),
1060       // Duplicate from `endpoints[1]`, but `endpoints[1]` was dropped, so this
1061       // should be used.
1062       IPEndPoint(ParseIP("2::"), 443),
1063       // Duplicate from `endpoints[0]`, should be filtered out.
1064       IPEndPoint(ParseIP("1.1.1.1"), 443),
1065       // New endpoint. Should be used.
1066       IPEndPoint(ParseIP("2.2.2.2"), 443)};
1067   endpoints[2].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
1068   // Contains only previously seen IPEndPoints, so should be filtered out
1069   // entirely.
1070   endpoints[3].ip_endpoints = {IPEndPoint(ParseIP("1::"), 443),
1071                                IPEndPoint(ParseIP("1::"), 444),
1072                                IPEndPoint(ParseIP("2.2.2.2"), 443)};
1073   endpoints[3].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
1074   host_resolver_.rules()->AddRule(
1075       kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
1076 
1077   MockTransportClientSocketFactory::Rule rules[] = {
1078       // First, try `endpoints[0]`'s addresses.
1079       MockTransportClientSocketFactory::Rule(
1080           MockTransportClientSocketFactory::Type::kFailing,
1081           std::vector{IPEndPoint(ParseIP("1::"), 443)}),
1082       MockTransportClientSocketFactory::Rule(
1083           MockTransportClientSocketFactory::Type::kFailing,
1084           std::vector{IPEndPoint(ParseIP("1.1.1.1"), 443)}),
1085 
1086       // `endpoints[1]` is unusable, so it is ignored, including for purposes of
1087       // duplicate endpoints.
1088 
1089       // Only new IP endpoints from `endpoints[2]` should be considered. Note
1090       // different ports count as different endpoints.
1091       MockTransportClientSocketFactory::Rule(
1092           MockTransportClientSocketFactory::Type::kFailing,
1093           std::vector{IPEndPoint(ParseIP("1::"), 444)}),
1094       MockTransportClientSocketFactory::Rule(
1095           MockTransportClientSocketFactory::Type::kFailing,
1096           std::vector{IPEndPoint(ParseIP("2::"), 443)}),
1097       MockTransportClientSocketFactory::Rule(
1098           MockTransportClientSocketFactory::Type::kFailing,
1099           std::vector{IPEndPoint(ParseIP("2.2.2.2"), 443)}),
1100 
1101       // `endpoints[3]` only contains duplicate IP endpoints and should be
1102       // skipped.
1103   };
1104 
1105   client_socket_factory_.SetRules(rules);
1106 
1107   TestConnectJobDelegate test_delegate;
1108   TransportConnectJob transport_connect_job(
1109       DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
1110       DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
1111   test_delegate.StartJobExpectingResult(&transport_connect_job,
1112                                         ERR_CONNECTION_FAILED,
1113                                         /*expect_sync_result=*/false);
1114 
1115   // Check that failed connection attempts are reported.
1116   ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
1117   ASSERT_EQ(5u, attempts.size());
1118   EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
1119   EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 443));
1120   EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
1121   EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 443));
1122   EXPECT_THAT(attempts[2].result, test::IsError(ERR_CONNECTION_FAILED));
1123   EXPECT_EQ(attempts[2].endpoint, IPEndPoint(ParseIP("1::"), 444));
1124   EXPECT_THAT(attempts[3].result, test::IsError(ERR_CONNECTION_FAILED));
1125   EXPECT_EQ(attempts[3].endpoint, IPEndPoint(ParseIP("2::"), 443));
1126   EXPECT_THAT(attempts[4].result, test::IsError(ERR_CONNECTION_FAILED));
1127   EXPECT_EQ(attempts[4].endpoint, IPEndPoint(ParseIP("2.2.2.2"), 443));
1128 }
1129 
1130 }  // namespace
1131 }  // namespace net
1132