123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/socket/transport_connect_job.h"
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/memory/ref_counted.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/task_environment.h"
- #include "net/base/address_family.h"
- #include "net/base/address_list.h"
- #include "net/base/features.h"
- #include "net/base/host_port_pair.h"
- #include "net/base/ip_address.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/net_errors.h"
- #include "net/base/test_completion_callback.h"
- #include "net/dns/mock_host_resolver.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/log/net_log.h"
- #include "net/socket/connect_job_test_util.h"
- #include "net/socket/connection_attempts.h"
- #include "net/socket/stream_socket.h"
- #include "net/socket/transport_client_socket_pool_test_util.h"
- #include "net/test/gtest_util.h"
- #include "net/test/test_with_task_environment.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "url/scheme_host_port.h"
- #include "url/url_constants.h"
- namespace net {
- namespace {
- const char kHostName[] = "unresolvable.host.name";
- IPAddress ParseIP(const std::string& ip) {
- IPAddress address;
- CHECK(address.AssignFromIPLiteral(ip));
- return address;
- }
- class TransportConnectJobTest : public WithTaskEnvironment,
- public testing::Test {
- public:
- TransportConnectJobTest()
- : WithTaskEnvironment(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
- client_socket_factory_(NetLog::Get()),
- common_connect_job_params_(
- &client_socket_factory_,
- &host_resolver_,
- nullptr /* http_auth_cache */,
- nullptr /* http_auth_handler_factory */,
- nullptr /* spdy_session_pool */,
- nullptr /* quic_supported_versions */,
- nullptr /* quic_stream_factory */,
- nullptr /* proxy_delegate */,
- nullptr /* http_user_agent_settings */,
- nullptr /* ssl_client_context */,
- nullptr /* socket_performance_watcher_factory */,
- nullptr /* network_quality_estimator */,
- NetLog::Get(),
- nullptr /* websocket_endpoint_lock_manager */) {}
- ~TransportConnectJobTest() override = default;
- static scoped_refptr<TransportSocketParams> DefaultParams() {
- return base::MakeRefCounted<TransportSocketParams>(
- url::SchemeHostPort(url::kHttpScheme, kHostName, 80),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow,
- OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>());
- }
- static scoped_refptr<TransportSocketParams> DefaultHttpsParams() {
- return base::MakeRefCounted<TransportSocketParams>(
- url::SchemeHostPort(url::kHttpsScheme, kHostName, 443),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow,
- OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>{"h2", "http/1.1"});
- }
- protected:
- MockHostResolver host_resolver_{/*default_result=*/MockHostResolverBase::
- RuleResolver::GetLocalhostResult()};
- MockTransportClientSocketFactory client_socket_factory_;
- const CommonConnectJobParams common_connect_job_params_;
- };
- TEST_F(TransportConnectJobTest, HostResolutionFailure) {
- host_resolver_.rules()->AddSimulatedTimeoutFailure(kHostName);
- // Check sync and async failures.
- for (bool host_resolution_synchronous : {false, true}) {
- host_resolver_.set_synchronous_mode(host_resolution_synchronous);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_NAME_NOT_RESOLVED,
- host_resolution_synchronous);
- EXPECT_THAT(transport_connect_job.GetResolveErrorInfo().error,
- test::IsError(ERR_DNS_TIMED_OUT));
- }
- }
- TEST_F(TransportConnectJobTest, ConnectionFailure) {
- for (bool host_resolution_synchronous : {false, true}) {
- for (bool connection_synchronous : {false, true}) {
- host_resolver_.set_synchronous_mode(host_resolution_synchronous);
- client_socket_factory_.set_default_client_socket_type(
- connection_synchronous
- ? MockTransportClientSocketFactory::Type::kFailing
- : MockTransportClientSocketFactory::Type::kPendingFailing);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(
- &transport_connect_job, ERR_CONNECTION_FAILED,
- host_resolution_synchronous && connection_synchronous);
- }
- }
- }
- TEST_F(TransportConnectJobTest, HostResolutionTimeout) {
- const base::TimeDelta kTinyTime = base::Microseconds(1);
- // Make request hang.
- host_resolver_.set_ondemand_mode(true);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- ASSERT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
- // Right up until just before expiration, the job does not time out.
- FastForwardBy(TransportConnectJob::ConnectionTimeout() - kTinyTime);
- EXPECT_FALSE(test_delegate.has_result());
- // But at the exact time of expiration, the job fails.
- FastForwardBy(kTinyTime);
- EXPECT_TRUE(test_delegate.has_result());
- EXPECT_THAT(test_delegate.WaitForResult(), test::IsError(ERR_TIMED_OUT));
- }
- TEST_F(TransportConnectJobTest, ConnectionTimeout) {
- const base::TimeDelta kTinyTime = base::Microseconds(1);
- // Half the timeout time. In the async case, spend half the time waiting on
- // host resolution, half on connecting.
- const base::TimeDelta kFirstHalfOfTimeout =
- TransportConnectJob::ConnectionTimeout() / 2;
- const base::TimeDelta kSecondHalfOfTimeout =
- TransportConnectJob::ConnectionTimeout() - kFirstHalfOfTimeout;
- ASSERT_LE(kTinyTime, kSecondHalfOfTimeout);
- // Make connection attempts hang.
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kStalled);
- for (bool host_resolution_synchronous : {false, true}) {
- host_resolver_.set_ondemand_mode(!host_resolution_synchronous);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- EXPECT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
- // After half the timeout, connection does not timeout.
- FastForwardBy(kFirstHalfOfTimeout);
- EXPECT_FALSE(test_delegate.has_result());
- // In the async case, the host resolution completes now.
- if (!host_resolution_synchronous)
- host_resolver_.ResolveOnlyRequestNow();
- // After (almost) the second half of timeout, just before the full timeout
- // period, the ConnectJob is still live.
- FastForwardBy(kSecondHalfOfTimeout - kTinyTime);
- EXPECT_FALSE(test_delegate.has_result());
- // But at the exact timeout time, the job fails.
- FastForwardBy(kTinyTime);
- EXPECT_TRUE(test_delegate.has_result());
- EXPECT_THAT(test_delegate.WaitForResult(), test::IsError(ERR_TIMED_OUT));
- }
- }
- TEST_F(TransportConnectJobTest, ConnectionSuccess) {
- for (bool host_resolution_synchronous : {false, true}) {
- for (bool connection_synchronous : {false, true}) {
- host_resolver_.set_synchronous_mode(host_resolution_synchronous);
- client_socket_factory_.set_default_client_socket_type(
- connection_synchronous
- ? MockTransportClientSocketFactory::Type::kSynchronous
- : MockTransportClientSocketFactory::Type::kPending);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(
- &transport_connect_job, OK,
- host_resolution_synchronous && connection_synchronous);
- }
- }
- }
- TEST_F(TransportConnectJobTest, LoadState) {
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kStalled);
- host_resolver_.set_ondemand_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(kHostName, "1:abcd::3:4:ff,1.1.1.1",
- std::string());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, /*net_log=*/nullptr);
- EXPECT_THAT(transport_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
- // The job is initially waiting on DNS.
- EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_RESOLVING_HOST);
- // Complete DNS. It is now waiting on a TCP connection.
- host_resolver_.ResolveOnlyRequestNow();
- RunUntilIdle();
- EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_CONNECTING);
- // Wait for the IPv4 job to start. The job is still waiting on a TCP
- // connection.
- FastForwardBy(TransportConnectJob::kIPv6FallbackTime +
- base::Milliseconds(50));
- EXPECT_EQ(transport_connect_job.GetLoadState(), LOAD_STATE_CONNECTING);
- }
- // TODO(crbug.com/1206799): Set up `host_resolver_` to require the expected
- // scheme.
- TEST_F(TransportConnectJobTest, HandlesHttpsEndpoint) {
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- base::MakeRefCounted<TransportSocketParams>(
- url::SchemeHostPort(url::kHttpsScheme, kHostName, 80),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow,
- OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>{"h2", "http/1.1"}),
- &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- }
- // TODO(crbug.com/1206799): Set up `host_resolver_` to require the expected
- // lack of scheme.
- TEST_F(TransportConnectJobTest, HandlesNonStandardEndpoint) {
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- base::MakeRefCounted<TransportSocketParams>(
- HostPortPair(kHostName, 80), NetworkIsolationKey(),
- SecureDnsPolicy::kAllow, OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>()),
- &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- }
- TEST_F(TransportConnectJobTest, SecureDnsPolicy) {
- for (auto secure_dns_policy :
- {SecureDnsPolicy::kAllow, SecureDnsPolicy::kDisable}) {
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- base::MakeRefCounted<TransportSocketParams>(
- url::SchemeHostPort(url::kHttpScheme, kHostName, 80),
- NetworkIsolationKey(), secure_dns_policy,
- OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>{}),
- &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- EXPECT_EQ(secure_dns_policy, host_resolver_.last_secure_dns_policy());
- }
- }
- // Test the case of the IPv6 address stalling, and falling back to the IPv4
- // socket which finishes first.
- TEST_F(TransportConnectJobTest, IPv6FallbackSocketIPv4FinishesFirst) {
- MockTransportClientSocketFactory::Rule rules[] = {
- // The first IPv6 attempt fails.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1:abcd::3:4:ff"), 80)}),
- // The second IPv6 attempt stalls.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kStalled,
- std::vector{IPEndPoint(ParseIP("2:abcd::3:4:ff"), 80)}),
- // After a timeout, we try the IPv4 address.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kPending,
- std::vector{IPEndPoint(ParseIP("2.2.2.2"), 80)})};
- client_socket_factory_.SetRules(rules);
- // Resolve an AddressList with two IPv6 addresses and then a IPv4 address.
- host_resolver_.rules()->AddIPLiteralRule(
- kHostName, "1:abcd::3:4:ff,2:abcd::3:4:ff,2.2.2.2", std::string());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- IPEndPoint endpoint;
- test_delegate.socket()->GetLocalAddress(&endpoint);
- EXPECT_TRUE(endpoint.address().IsIPv4());
- // Check that the failed connection attempt is collected.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(1u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1:abcd::3:4:ff"), 80));
- EXPECT_EQ(3, client_socket_factory_.allocation_count());
- }
- // Test the case of the IPv6 address being slow, thus falling back to trying to
- // connect to the IPv4 address, but having the connect to the IPv6 address
- // finish first.
- TEST_F(TransportConnectJobTest, IPv6FallbackSocketIPv6FinishesFirst) {
- MockTransportClientSocketFactory::Rule rules[] = {
- // The first IPv6 attempt ultimately succeeds, but is delayed.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kDelayed,
- std::vector{IPEndPoint(ParseIP("2:abcd::3:4:ff"), 80)}),
- // The first IPv4 attempt fails.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2.2.2.2"), 80)}),
- // The second IPv4 attempt stalls.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kStalled,
- std::vector{IPEndPoint(ParseIP("3.3.3.3"), 80)})};
- client_socket_factory_.SetRules(rules);
- client_socket_factory_.set_delay(TransportConnectJob::kIPv6FallbackTime +
- base::Milliseconds(50));
- // Resolve an AddressList with a IPv6 address first and then a IPv4 address.
- host_resolver_.rules()->AddIPLiteralRule(
- kHostName, "2:abcd::3:4:ff,2.2.2.2,3.3.3.3", std::string());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- IPEndPoint endpoint;
- test_delegate.socket()->GetLocalAddress(&endpoint);
- EXPECT_TRUE(endpoint.address().IsIPv6());
- // Check that the failed connection attempt on the fallback socket is
- // collected.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(1u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("2.2.2.2"), 80));
- EXPECT_EQ(3, client_socket_factory_.allocation_count());
- }
- TEST_F(TransportConnectJobTest, IPv6NoIPv4AddressesToFallbackTo) {
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kDelayed);
- // Resolve an AddressList with only IPv6 addresses.
- host_resolver_.rules()->AddIPLiteralRule(
- kHostName, "2:abcd::3:4:ff,3:abcd::3:4:ff", std::string());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- IPEndPoint endpoint;
- test_delegate.socket()->GetLocalAddress(&endpoint);
- EXPECT_TRUE(endpoint.address().IsIPv6());
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- EXPECT_EQ(0u, attempts.size());
- EXPECT_EQ(1, client_socket_factory_.allocation_count());
- }
- TEST_F(TransportConnectJobTest, IPv4HasNoFallback) {
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kDelayed);
- // Resolve an AddressList with only IPv4 addresses.
- host_resolver_.rules()->AddIPLiteralRule(kHostName, "1.1.1.1", std::string());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- false /* expect_sync_result */);
- IPEndPoint endpoint;
- test_delegate.socket()->GetLocalAddress(&endpoint);
- EXPECT_TRUE(endpoint.address().IsIPv4());
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- EXPECT_EQ(0u, attempts.size());
- EXPECT_EQ(1, client_socket_factory_.allocation_count());
- }
- TEST_F(TransportConnectJobTest, DnsAliases) {
- host_resolver_.set_synchronous_mode(true);
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kSynchronous);
- // Resolve an AddressList with DNS aliases.
- std::vector<std::string> aliases({"alias1", "alias2", kHostName});
- host_resolver_.rules()->AddIPLiteralRuleWithDnsAliases(kHostName, "2.2.2.2",
- std::move(aliases));
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- true /* expect_sync_result */);
- // Verify that the elements of the alias list are those from the
- // parameter vector.
- EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
- testing::ElementsAre("alias1", "alias2", kHostName));
- }
- TEST_F(TransportConnectJobTest, NoAdditionalDnsAliases) {
- host_resolver_.set_synchronous_mode(true);
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kSynchronous);
- // Resolve an AddressList without additional DNS aliases. (The parameter
- // is an empty vector.)
- std::vector<std::string> aliases;
- host_resolver_.rules()->AddIPLiteralRuleWithDnsAliases(kHostName, "2.2.2.2",
- std::move(aliases));
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultParams(), &test_delegate, nullptr /* net_log */);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- true /* expect_sync_result */);
- // Verify that the alias list only contains kHostName.
- EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
- testing::ElementsAre(kHostName));
- }
- // Test that `TransportConnectJob` will pick up options from
- // `HostResolverEndpointResult`.
- TEST_F(TransportConnectJobTest, EndpointResult) {
- HostResolverEndpointResult endpoint;
- endpoint.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8443),
- IPEndPoint(ParseIP("1.1.1.1"), 8443)};
- endpoint.metadata.supported_protocol_alpns = {"h2"};
- host_resolver_.rules()->AddRule(
- kHostName,
- MockHostResolverBase::RuleResolver::RuleResult(std::vector{endpoint}));
- // The first access succeeds.
- MockTransportClientSocketFactory::Rule rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{IPEndPoint(ParseIP("1::"), 8443)});
- client_socket_factory_.SetRules(base::make_span(&rule, 1));
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- IPEndPoint peer_address;
- test_delegate.socket()->GetPeerAddress(&peer_address);
- EXPECT_EQ(peer_address, IPEndPoint(ParseIP("1::"), 8443));
- EXPECT_EQ(1, client_socket_factory_.allocation_count());
- // There were no failed connection attempts to report.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- EXPECT_EQ(0u, attempts.size());
- }
- // Test that, given multiple `HostResolverEndpointResult` results,
- // `TransportConnectJob` tries each in succession.
- TEST_F(TransportConnectJobTest, MultipleRoutesFallback) {
- std::vector<HostResolverEndpointResult> endpoints(3);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
- IPEndPoint(ParseIP("1.1.1.1"), 8441)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
- IPEndPoint(ParseIP("2.2.2.2"), 8442)};
- endpoints[1].metadata.supported_protocol_alpns = {"h3"};
- endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("4::"), 443),
- IPEndPoint(ParseIP("4.4.4.4"), 443)};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- MockTransportClientSocketFactory::Rule rules[] = {
- // `endpoints[0]`'s addresses each fail.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[0]}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[1]}),
- // `endpoints[1]` is skipped because the ALPN is not compatible.
- // `endpoints[2]`'s first address succeeds.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{endpoints[2].ip_endpoints[0]}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- IPEndPoint peer_address;
- test_delegate.socket()->GetPeerAddress(&peer_address);
- EXPECT_EQ(peer_address, IPEndPoint(ParseIP("4::"), 443));
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(2u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
- }
- // Test that the `HostResolverEndpointResult` fallback works in combination with
- // the IPv4 fallback.
- TEST_F(TransportConnectJobTest, MultipleRoutesIPV4Fallback) {
- HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
- endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
- IPEndPoint(ParseIP("1.1.1.1"), 8441)};
- endpoint1.metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
- endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
- IPEndPoint(ParseIP("2.2.2.2"), 8442)};
- endpoint2.metadata.supported_protocol_alpns = {"h3"};
- endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443),
- IPEndPoint(ParseIP("3.3.3.3"), 443)};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(
- std::vector{endpoint1, endpoint2, endpoint3}));
- MockTransportClientSocketFactory::Rule rules[] = {
- // `endpoint1`'s IPv6 address fails, but takes long enough that the IPv4
- // fallback runs.
- //
- // TODO(davidben): If the network is such that IPv6 connection attempts
- // always stall, we will never try `endpoint2`. Should Happy Eyeballs
- // logic happen before HTTPS RR. Or perhaps we should implement a more
- // Happy-Eyeballs-v2-like strategy.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kDelayedFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
- // `endpoint1`'s IPv4 address fails immediately.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1.1.1.1"), 8441)}),
- // `endpoint2` is skipped because the ALPN is not compatible.
- // `endpoint3`'s IPv6 address never completes.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kStalled,
- std::vector{IPEndPoint(ParseIP("3::"), 443)}),
- // `endpoint3`'s IPv4 address succeeds.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{IPEndPoint(ParseIP("3.3.3.3"), 443)}),
- };
- client_socket_factory_.SetRules(rules);
- client_socket_factory_.set_delay(TransportConnectJob::kIPv6FallbackTime +
- base::Milliseconds(50));
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- IPEndPoint peer_address;
- test_delegate.socket()->GetPeerAddress(&peer_address);
- EXPECT_EQ(peer_address, IPEndPoint(ParseIP("3.3.3.3"), 443));
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(2u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1::"), 8441));
- }
- // Test that `TransportConnectJob` will not continue trying routes given
- // ERR_NETWORK_IO_SUSPENDED.
- TEST_F(TransportConnectJobTest, MultipleRoutesSuspended) {
- std::vector<HostResolverEndpointResult> endpoints(2);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8443)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 443)};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- // The first connect attempt will fail with `ERR_NETWORK_IO_SUSPENDED`.
- // `TransportConnectJob` should not attempt routes after receiving this error.
- MockTransportClientSocketFactory::Rule rule(
- MockTransportClientSocketFactory::Type::kFailing,
- endpoints[0].ip_endpoints, ERR_NETWORK_IO_SUSPENDED);
- client_socket_factory_.SetRules(base::make_span(&rule, 1));
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_NETWORK_IO_SUSPENDED,
- /*expect_sync_result=*/false);
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(1u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_NETWORK_IO_SUSPENDED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8443));
- }
- // Test that, if `HostResolver` supports SVCB for a scheme but the caller didn't
- // pass in any ALPN protocols, `TransportConnectJob` ignores all protocol
- // endpoints.
- TEST_F(TransportConnectJobTest, NoAlpnProtocols) {
- std::vector<HostResolverEndpointResult> endpoints(3);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8081),
- IPEndPoint(ParseIP("1.1.1.1"), 8081)};
- endpoints[0].metadata.supported_protocol_alpns = {"foo", "bar"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8082),
- IPEndPoint(ParseIP("2.2.2.2"), 8082)};
- endpoints[1].metadata.supported_protocol_alpns = {"baz"};
- endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 80),
- IPEndPoint(ParseIP("3.3.3.3"), 80)};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- // `endpoints[2]`'s first address succeeds.
- MockTransportClientSocketFactory::Rule rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{endpoints[2].ip_endpoints[0]});
- client_socket_factory_.SetRules(base::make_span(&rule, 1));
- // Use `DefaultParams()`, an http scheme. That it is http is not very
- // important, but `url::SchemeHostPort` is difficult to use with unknown
- // schemes. See https://crbug.com/869291.
- scoped_refptr<TransportSocketParams> params = DefaultParams();
- ASSERT_TRUE(params->supported_alpns().empty());
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- std::move(params), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- IPEndPoint peer_address;
- test_delegate.socket()->GetPeerAddress(&peer_address);
- EXPECT_EQ(peer_address, IPEndPoint(ParseIP("3::"), 80));
- }
- // Test that, given multiple `HostResolverEndpointResult` results,
- // `TransportConnectJob` reports failure if each one fails.
- TEST_F(TransportConnectJobTest, MultipleRoutesAllFailed) {
- std::vector<HostResolverEndpointResult> endpoints(3);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
- IPEndPoint(ParseIP("1.1.1.1"), 8441)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
- IPEndPoint(ParseIP("2.2.2.2"), 8442)};
- endpoints[1].metadata.supported_protocol_alpns = {"h3"};
- endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 443),
- IPEndPoint(ParseIP("3.3.3.3"), 443)};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- MockTransportClientSocketFactory::Rule rules[] = {
- // `endpoints[0]`'s addresses each fail.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[0]}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[1]}),
- // `endpoints[1]` is skipped because the ALPN is not compatible.
- // `endpoints[2]`'s addresses each fail.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[2].ip_endpoints[0]}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[2].ip_endpoints[1]}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_CONNECTION_FAILED,
- /*expect_sync_result=*/false);
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(4u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
- EXPECT_THAT(attempts[2].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[2].endpoint, IPEndPoint(ParseIP("3::"), 443));
- EXPECT_THAT(attempts[3].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[3].endpoint, IPEndPoint(ParseIP("3.3.3.3"), 443));
- }
- // Test that `TransportConnectJob` reports failure if all provided routes were
- // unusable.
- TEST_F(TransportConnectJobTest, NoUsableRoutes) {
- std::vector<HostResolverEndpointResult> endpoints(2);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
- IPEndPoint(ParseIP("1.1.1.1"), 8441)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
- IPEndPoint(ParseIP("2.2.2.2"), 8442)};
- endpoints[1].metadata.supported_protocol_alpns = {"unrecognized-protocol"};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- // `TransportConnectJob` should not create any sockets.
- client_socket_factory_.set_default_client_socket_type(
- MockTransportClientSocketFactory::Type::kUnexpected);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_NAME_NOT_RESOLVED,
- /*expect_sync_result=*/false);
- }
- // Test that, if the last route is unusable, the error from the
- // previously-attempted route is preserved.
- TEST_F(TransportConnectJobTest, LastRouteUnusable) {
- std::vector<HostResolverEndpointResult> endpoints(2);
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441),
- IPEndPoint(ParseIP("1.1.1.1"), 8441)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3", "h2", "http/1.1"};
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442),
- IPEndPoint(ParseIP("2.2.2.2"), 8442)};
- endpoints[1].metadata.supported_protocol_alpns = {"h3"};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- MockTransportClientSocketFactory::Rule rules[] = {
- // `endpoints[0]`'s addresses each fail.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[0]}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{endpoints[0].ip_endpoints[1]}),
- // `endpoints[1]` is skipped because the ALPN is not compatible.
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_CONNECTION_FAILED,
- /*expect_sync_result=*/false);
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(2u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 8441));
- }
- // `GetHostResolverEndpointResult` should surface information about the endpoint
- // that was actually used.
- TEST_F(TransportConnectJobTest, GetHostResolverEndpointResult) {
- std::vector<HostResolverEndpointResult> endpoints(4);
- // `endpoints[0]` will be skipped due to ALPN mismatch.
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
- endpoints[0].metadata.supported_protocol_alpns = {"h3"};
- endpoints[0].metadata.ech_config_list = {1, 2, 3, 4};
- // `endpoints[1]` will be skipped due to connection failure.
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
- endpoints[1].metadata.supported_protocol_alpns = {"http/1.1"};
- endpoints[1].metadata.ech_config_list = {5, 6, 7, 8};
- // `endpoints[2]` will succeed.
- endpoints[2].ip_endpoints = {IPEndPoint(ParseIP("3::"), 8443)};
- endpoints[2].metadata.supported_protocol_alpns = {"http/1.1"};
- endpoints[2].metadata.ech_config_list = {9, 10, 11, 12};
- // `endpoints[3]` will be not be tried because `endpoints[2]` will already
- // have succeeded.
- endpoints[3].ip_endpoints = {IPEndPoint(ParseIP("4::"), 8444)};
- endpoints[3].metadata.supported_protocol_alpns = {"http/1.1"};
- endpoints[3].metadata.ech_config_list = {13, 14, 15, 16};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- MockTransportClientSocketFactory::Rule rules[] = {
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{IPEndPoint(ParseIP("3::"), 8443)}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- EXPECT_EQ(transport_connect_job.GetHostResolverEndpointResult(),
- endpoints[2]);
- }
- // If the client and server both support ECH, TransportConnectJob should switch
- // to SVCB-reliant mode and disable the A/AAAA fallback.
- TEST_F(TransportConnectJobTest, SvcbReliantIfEch) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kEncryptedClientHello);
- HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
- endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
- endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
- endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
- endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint2.metadata.ech_config_list = {1, 2, 3, 4};
- endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
- // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(
- std::vector{endpoint1, endpoint2, endpoint3}));
- // `TransportConnectJob` should not try `endpoint3`.
- MockTransportClientSocketFactory::Rule rules[] = {
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_CONNECTION_FAILED,
- /*expect_sync_result=*/false);
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(2u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 8441));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("2::"), 8442));
- }
- // SVCB-reliant mode should be disabled for ECH servers when ECH is disabled.
- TEST_F(TransportConnectJobTest, SvcbOptionalIfEchDisabled) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(features::kEncryptedClientHello);
- HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
- endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
- endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
- endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
- endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint2.metadata.ech_config_list = {1, 2, 3, 4};
- endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
- // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(
- std::vector{endpoint1, endpoint2, endpoint3}));
- // `TransportConnectJob` should try `endpoint3`.
- MockTransportClientSocketFactory::Rule rules[] = {
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{IPEndPoint(ParseIP("3::"), 443)}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- }
- // SVCB-reliant mode should be disabled if not all SVCB/HTTPS records include
- // ECH.
- TEST_F(TransportConnectJobTest, SvcbOptionalIfEchInconsistent) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kEncryptedClientHello);
- HostResolverEndpointResult endpoint1, endpoint2, endpoint3;
- endpoint1.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
- endpoint1.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint1.metadata.ech_config_list = {1, 2, 3, 4};
- endpoint2.ip_endpoints = {IPEndPoint(ParseIP("2::"), 8442)};
- endpoint2.metadata.supported_protocol_alpns = {"http/1.1"};
- endpoint2.metadata.ech_config_list = {};
- endpoint3.ip_endpoints = {IPEndPoint(ParseIP("3::"), 443)};
- // `endpoint3` has no `supported_protocol_alpns` and is thus a fallback route.
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(
- std::vector{endpoint1, endpoint2, endpoint3}));
- // `TransportConnectJob` should try `endpoint3`.
- MockTransportClientSocketFactory::Rule rules[] = {
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 8441)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2::"), 8442)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- std::vector{IPEndPoint(ParseIP("3::"), 443)}),
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/false);
- }
- // Overriding the endpoint results should skip DNS resolution.
- TEST_F(TransportConnectJobTest, EndpointResultOverride) {
- // Make DNS resolution fail, to confirm we don't use the result.
- host_resolver_.rules()->AddRule(kHostName, ERR_FAILED);
- // `TransportConnectJob` should try `endpoint`.
- HostResolverEndpointResult endpoint;
- endpoint.ip_endpoints = {IPEndPoint(ParseIP("1::"), 8441)};
- endpoint.metadata.supported_protocol_alpns = {"http/1.1"};
- MockTransportClientSocketFactory::Rule rules[] = {
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kSynchronous,
- endpoint.ip_endpoints),
- };
- client_socket_factory_.SetRules(rules);
- TransportConnectJob::EndpointResultOverride override(
- endpoint, {"alias.example", kHostName});
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr, override);
- test_delegate.StartJobExpectingResult(&transport_connect_job, OK,
- /*expect_sync_result=*/true);
- // Verify information is reported from the override.
- EXPECT_EQ(transport_connect_job.GetHostResolverEndpointResult(), endpoint);
- EXPECT_THAT(test_delegate.socket()->GetDnsAliases(),
- testing::ElementsAre("alias.example", kHostName));
- }
- // If two `HostResolverEndpointResult`s share an IP endpoint,
- // `TransportConnectJob` should not try to connect a second time.
- TEST_F(TransportConnectJobTest, DedupIPEndPoints) {
- std::vector<HostResolverEndpointResult> endpoints(4);
- // Some initial IPEndPoints.
- endpoints[0].ip_endpoints = {IPEndPoint(ParseIP("1::"), 443),
- IPEndPoint(ParseIP("1.1.1.1"), 443)};
- endpoints[0].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
- // Contains a new IPEndPoint, but no common protocols.
- endpoints[1].ip_endpoints = {IPEndPoint(ParseIP("2::"), 443)};
- endpoints[1].metadata.supported_protocol_alpns = {"h3"};
- // Contains mixture of previously seen and new IPEndPoints, so we should only
- // try a subset of them.
- endpoints[2].ip_endpoints = {
- // Duplicate from `endpoints[0]`, should be filtered out.
- IPEndPoint(ParseIP("1::"), 443),
- // Same IP but new port. Should be used.
- IPEndPoint(ParseIP("1::"), 444),
- // Duplicate from `endpoints[1]`, but `endpoints[1]` was dropped, so this
- // should be used.
- IPEndPoint(ParseIP("2::"), 443),
- // Duplicate from `endpoints[0]`, should be filtered out.
- IPEndPoint(ParseIP("1.1.1.1"), 443),
- // New endpoint. Should be used.
- IPEndPoint(ParseIP("2.2.2.2"), 443)};
- endpoints[2].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
- // Contains only previously seen IPEndPoints, so should be filtered out
- // entirely.
- endpoints[3].ip_endpoints = {IPEndPoint(ParseIP("1::"), 443),
- IPEndPoint(ParseIP("1::"), 444),
- IPEndPoint(ParseIP("2.2.2.2"), 443)};
- endpoints[3].metadata.supported_protocol_alpns = {"h2", "http/1.1"};
- host_resolver_.rules()->AddRule(
- kHostName, MockHostResolverBase::RuleResolver::RuleResult(endpoints));
- MockTransportClientSocketFactory::Rule rules[] = {
- // First, try `endpoints[0]`'s addresses.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 443)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1.1.1.1"), 443)}),
- // `endpoints[1]` is unusable, so it is ignored, including for purposes of
- // duplicate endpoints.
- // Only new IP endpoints from `endpoints[2]` should be considered. Note
- // different ports count as different endpoints.
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("1::"), 444)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2::"), 443)}),
- MockTransportClientSocketFactory::Rule(
- MockTransportClientSocketFactory::Type::kFailing,
- std::vector{IPEndPoint(ParseIP("2.2.2.2"), 443)}),
- // `endpoints[3]` only contains duplicate IP endpoints and should be
- // skipped.
- };
- client_socket_factory_.SetRules(rules);
- TestConnectJobDelegate test_delegate;
- TransportConnectJob transport_connect_job(
- DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
- DefaultHttpsParams(), &test_delegate, /*net_log=*/nullptr);
- test_delegate.StartJobExpectingResult(&transport_connect_job,
- ERR_CONNECTION_FAILED,
- /*expect_sync_result=*/false);
- // Check that failed connection attempts are reported.
- ConnectionAttempts attempts = transport_connect_job.GetConnectionAttempts();
- ASSERT_EQ(5u, attempts.size());
- EXPECT_THAT(attempts[0].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[0].endpoint, IPEndPoint(ParseIP("1::"), 443));
- EXPECT_THAT(attempts[1].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[1].endpoint, IPEndPoint(ParseIP("1.1.1.1"), 443));
- EXPECT_THAT(attempts[2].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[2].endpoint, IPEndPoint(ParseIP("1::"), 444));
- EXPECT_THAT(attempts[3].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[3].endpoint, IPEndPoint(ParseIP("2::"), 443));
- EXPECT_THAT(attempts[4].result, test::IsError(ERR_CONNECTION_FAILED));
- EXPECT_EQ(attempts[4].endpoint, IPEndPoint(ParseIP("2.2.2.2"), 443));
- }
- } // namespace
- } // namespace net
|