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