transport_connect_job_unittest.cc 51 KB

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