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