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