|  | // Copyright (c) 2012 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/quic/quic_stream_factory.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <ostream> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/test/simple_test_tick_clock.h" | 
|  | #include "base/test/test_mock_time_task_runner.h" | 
|  | #include "build/build_config.h" | 
|  | #include "net/base/mock_network_change_notifier.h" | 
|  | #include "net/cert/ct_policy_enforcer.h" | 
|  | #include "net/cert/do_nothing_ct_verifier.h" | 
|  | #include "net/cert/mock_cert_verifier.h" | 
|  | #include "net/dns/mock_host_resolver.h" | 
|  | #include "net/http/http_response_headers.h" | 
|  | #include "net/http/http_response_info.h" | 
|  | #include "net/http/http_server_properties_impl.h" | 
|  | #include "net/http/http_util.h" | 
|  | #include "net/http/transport_security_state.h" | 
|  | #include "net/http/transport_security_state_test_util.h" | 
|  | #include "net/quic/crypto/proof_verifier_chromium.h" | 
|  | #include "net/quic/mock_crypto_client_stream_factory.h" | 
|  | #include "net/quic/mock_quic_data.h" | 
|  | #include "net/quic/properties_based_quic_server_info.h" | 
|  | #include "net/quic/quic_http_stream.h" | 
|  | #include "net/quic/quic_http_utils.h" | 
|  | #include "net/quic/quic_server_info.h" | 
|  | #include "net/quic/quic_stream_factory_peer.h" | 
|  | #include "net/quic/quic_test_packet_maker.h" | 
|  | #include "net/quic/test_task_runner.h" | 
|  | #include "net/socket/next_proto.h" | 
|  | #include "net/socket/socket_test_util.h" | 
|  | #include "net/spdy/spdy_session_test_util.h" | 
|  | #include "net/spdy/spdy_test_util_common.h" | 
|  | #include "net/test/cert_test_util.h" | 
|  | #include "net/test/gtest_util.h" | 
|  | #include "net/test/test_data_directory.h" | 
|  | #include "net/test/test_with_scoped_task_environment.h" | 
|  | #include "net/third_party/quic/core/crypto/crypto_handshake.h" | 
|  | #include "net/third_party/quic/core/crypto/quic_crypto_client_config.h" | 
|  | #include "net/third_party/quic/core/crypto/quic_decrypter.h" | 
|  | #include "net/third_party/quic/core/crypto/quic_encrypter.h" | 
|  | #include "net/third_party/quic/core/http/quic_client_promised_info.h" | 
|  | #include "net/third_party/quic/core/quic_utils.h" | 
|  | #include "net/third_party/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quic/test_tools/mock_clock.h" | 
|  | #include "net/third_party/quic/test_tools/mock_random.h" | 
|  | #include "net/third_party/quic/test_tools/quic_config_peer.h" | 
|  | #include "net/third_party/quic/test_tools/quic_spdy_session_peer.h" | 
|  | #include "net/third_party/quic/test_tools/quic_test_utils.h" | 
|  | #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" | 
|  | #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | using std::string; | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class MockSSLConfigService : public SSLConfigService { | 
|  | public: | 
|  | MockSSLConfigService() {} | 
|  | ~MockSSLConfigService() override {} | 
|  |  | 
|  | void GetSSLConfig(SSLConfig* config) override { *config = config_; } | 
|  |  | 
|  | bool CanShareConnectionWithClientCerts( | 
|  | const std::string& hostname) const override { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | private: | 
|  | SSLConfig config_; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace test { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | enum DestinationType { | 
|  | // In pooling tests with two requests for different origins to the same | 
|  | // destination, the destination should be | 
|  | SAME_AS_FIRST,   // the same as the first origin, | 
|  | SAME_AS_SECOND,  // the same as the second origin, or | 
|  | DIFFERENT,       // different from both. | 
|  | }; | 
|  |  | 
|  | const char kDefaultServerHostName[] = "www.example.org"; | 
|  | const char kServer2HostName[] = "mail.example.org"; | 
|  | const char kDifferentHostname[] = "different.example.com"; | 
|  | const int kDefaultServerPort = 443; | 
|  | const char kDefaultUrl[] = "https://www.example.org/"; | 
|  | const char kServer2Url[] = "https://mail.example.org/"; | 
|  | const char kServer3Url[] = "https://docs.example.org/"; | 
|  | const char kServer4Url[] = "https://images.example.org/"; | 
|  | const int kDefaultRTTMilliSecs = 300; | 
|  | const size_t kMinRetryTimeForDefaultNetworkSecs = 1; | 
|  | const size_t kWaitTimeForNewNetworkSecs = 10; | 
|  | const IPAddress kCachedIPAddress = IPAddress(192, 168, 0, 2); | 
|  | const char kNonCachedIPAddress[] = "192.168.0.1"; | 
|  |  | 
|  | // Run QuicStreamFactoryTest instances with all value combinations of version | 
|  | // and enable_connection_racting. | 
|  | struct TestParams { | 
|  | friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { | 
|  | os << "{ version: " << QuicVersionToString(p.version) | 
|  | << ", client_headers_include_h2_stream_dependency: " | 
|  | << p.client_headers_include_h2_stream_dependency << " }"; | 
|  | return os; | 
|  | } | 
|  |  | 
|  | quic::QuicTransportVersion version; | 
|  | bool client_headers_include_h2_stream_dependency; | 
|  | }; | 
|  |  | 
|  | std::vector<TestParams> GetTestParams() { | 
|  | std::vector<TestParams> params; | 
|  | quic::QuicTransportVersionVector all_supported_versions = | 
|  | quic::AllSupportedTransportVersions(); | 
|  | for (const auto& version : all_supported_versions) { | 
|  | params.push_back(TestParams{version, false}); | 
|  | params.push_back(TestParams{version, true}); | 
|  | } | 
|  | return params; | 
|  | } | 
|  |  | 
|  | // Run QuicStreamFactoryWithDestinationTest instances with all value | 
|  | // combinations of version, enable_connection_racting, and destination_type. | 
|  | struct PoolingTestParams { | 
|  | friend std::ostream& operator<<(std::ostream& os, | 
|  | const PoolingTestParams& p) { | 
|  | os << "{ version: " << QuicVersionToString(p.version) | 
|  | << ", destination_type: "; | 
|  | switch (p.destination_type) { | 
|  | case SAME_AS_FIRST: | 
|  | os << "SAME_AS_FIRST"; | 
|  | break; | 
|  | case SAME_AS_SECOND: | 
|  | os << "SAME_AS_SECOND"; | 
|  | break; | 
|  | case DIFFERENT: | 
|  | os << "DIFFERENT"; | 
|  | break; | 
|  | } | 
|  | os << ", client_headers_include_h2_stream_dependency: " | 
|  | << p.client_headers_include_h2_stream_dependency; | 
|  | os << " }"; | 
|  | return os; | 
|  | } | 
|  |  | 
|  | quic::QuicTransportVersion version; | 
|  | DestinationType destination_type; | 
|  | bool client_headers_include_h2_stream_dependency; | 
|  | }; | 
|  |  | 
|  | std::vector<PoolingTestParams> GetPoolingTestParams() { | 
|  | std::vector<PoolingTestParams> params; | 
|  | quic::QuicTransportVersionVector all_supported_versions = | 
|  | quic::AllSupportedTransportVersions(); | 
|  | for (const quic::QuicTransportVersion version : all_supported_versions) { | 
|  | params.push_back(PoolingTestParams{version, SAME_AS_FIRST, false}); | 
|  | params.push_back(PoolingTestParams{version, SAME_AS_FIRST, true}); | 
|  | params.push_back(PoolingTestParams{version, SAME_AS_SECOND, false}); | 
|  | params.push_back(PoolingTestParams{version, SAME_AS_SECOND, true}); | 
|  | params.push_back(PoolingTestParams{version, DIFFERENT, false}); | 
|  | params.push_back(PoolingTestParams{version, DIFFERENT, true}); | 
|  | } | 
|  | return params; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class QuicHttpStreamPeer { | 
|  | public: | 
|  | static QuicChromiumClientSession::Handle* GetSessionHandle( | 
|  | HttpStream* stream) { | 
|  | return static_cast<QuicHttpStream*>(stream)->quic_session(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // TestConnectionMigrationSocketFactory will vend sockets with incremental port | 
|  | // number. | 
|  | class TestConnectionMigrationSocketFactory : public MockClientSocketFactory { | 
|  | public: | 
|  | TestConnectionMigrationSocketFactory() : next_source_port_num_(1u) {} | 
|  | ~TestConnectionMigrationSocketFactory() override {} | 
|  |  | 
|  | std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket( | 
|  | DatagramSocket::BindType bind_type, | 
|  | NetLog* net_log, | 
|  | const NetLogSource& source) override { | 
|  | SocketDataProvider* data_provider = mock_data().GetNext(); | 
|  | std::unique_ptr<MockUDPClientSocket> socket( | 
|  | new MockUDPClientSocket(data_provider, net_log)); | 
|  | socket->set_source_port(next_source_port_num_++); | 
|  | return std::move(socket); | 
|  | } | 
|  |  | 
|  | private: | 
|  | uint16_t next_source_port_num_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(TestConnectionMigrationSocketFactory); | 
|  | }; | 
|  |  | 
|  | class QuicStreamFactoryTestBase : public WithScopedTaskEnvironment { | 
|  | protected: | 
|  | QuicStreamFactoryTestBase(quic::QuicTransportVersion version, | 
|  | bool client_headers_include_h2_stream_dependency) | 
|  | : host_resolver_(new MockHostResolver), | 
|  | ssl_config_service_(new MockSSLConfigService), | 
|  | socket_factory_(new MockClientSocketFactory), | 
|  | random_generator_(0), | 
|  | runner_(new TestTaskRunner(&clock_)), | 
|  | version_(version), | 
|  | client_maker_( | 
|  | version_, | 
|  | quic::QuicUtils::CreateRandomConnectionId(&random_generator_), | 
|  | &clock_, | 
|  | kDefaultServerHostName, | 
|  | quic::Perspective::IS_CLIENT, | 
|  | client_headers_include_h2_stream_dependency), | 
|  | server_maker_( | 
|  | version_, | 
|  | quic::QuicUtils::CreateRandomConnectionId(&random_generator_), | 
|  | &clock_, | 
|  | kDefaultServerHostName, | 
|  | quic::Perspective::IS_SERVER, | 
|  | false), | 
|  | cert_verifier_(std::make_unique<MockCertVerifier>()), | 
|  | cert_transparency_verifier_(std::make_unique<DoNothingCTVerifier>()), | 
|  | scoped_mock_network_change_notifier_(nullptr), | 
|  | factory_(nullptr), | 
|  | host_port_pair_(kDefaultServerHostName, kDefaultServerPort), | 
|  | url_(kDefaultUrl), | 
|  | url2_(kServer2Url), | 
|  | url3_(kServer3Url), | 
|  | url4_(kServer4Url), | 
|  | privacy_mode_(PRIVACY_MODE_DISABLED), | 
|  | failed_on_default_network_callback_(base::BindRepeating( | 
|  | &QuicStreamFactoryTestBase::OnFailedOnDefaultNetwork, | 
|  | base::Unretained(this))), | 
|  | failed_on_default_network_(false), | 
|  | store_server_configs_in_properties_(false) { | 
|  | test_params_.quic_headers_include_h2_stream_dependency = | 
|  | client_headers_include_h2_stream_dependency; | 
|  | clock_.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1)); | 
|  | } | 
|  |  | 
|  | void Initialize() { | 
|  | DCHECK(!factory_); | 
|  | factory_.reset(new QuicStreamFactory( | 
|  | net_log_.net_log(), host_resolver_.get(), ssl_config_service_.get(), | 
|  | socket_factory_.get(), &http_server_properties_, cert_verifier_.get(), | 
|  | &ct_policy_enforcer_, &transport_security_state_, | 
|  | cert_transparency_verifier_.get(), | 
|  | /*SocketPerformanceWatcherFactory*/ nullptr, | 
|  | &crypto_client_stream_factory_, &random_generator_, &clock_, | 
|  | test_params_.quic_max_packet_length, test_params_.quic_user_agent_id, | 
|  | store_server_configs_in_properties_, | 
|  | test_params_.quic_close_sessions_on_ip_change, | 
|  | test_params_.quic_goaway_sessions_on_ip_change, | 
|  | test_params_.mark_quic_broken_when_network_blackholes, | 
|  | test_params_.quic_idle_connection_timeout_seconds, | 
|  | test_params_.quic_reduced_ping_timeout_seconds, | 
|  | test_params_.quic_retransmittable_on_wire_timeout_milliseconds, | 
|  | test_params_.quic_max_time_before_crypto_handshake_seconds, | 
|  | test_params_.quic_max_idle_time_before_crypto_handshake_seconds, | 
|  | test_params_.quic_migrate_sessions_on_network_change_v2, | 
|  | test_params_.quic_migrate_sessions_early_v2, | 
|  | test_params_.quic_retry_on_alternate_network_before_handshake, | 
|  | test_params_.quic_migrate_idle_sessions, | 
|  | test_params_.quic_idle_session_migration_period, | 
|  | test_params_.quic_max_time_on_non_default_network, | 
|  | test_params_.quic_max_migrations_to_non_default_network_on_write_error, | 
|  | test_params_ | 
|  | .quic_max_migrations_to_non_default_network_on_path_degrading, | 
|  | test_params_.quic_allow_server_migration, | 
|  | test_params_.quic_race_stale_dns_on_connection, | 
|  | test_params_.quic_go_away_on_path_degrading, | 
|  | test_params_.quic_race_cert_verification, | 
|  | test_params_.quic_estimate_initial_rtt, | 
|  | test_params_.quic_headers_include_h2_stream_dependency, | 
|  | test_params_.quic_connection_options, | 
|  | test_params_.quic_client_connection_options, | 
|  | test_params_.quic_enable_socket_recv_optimization)); | 
|  | } | 
|  |  | 
|  | void InitializeConnectionMigrationV2Test( | 
|  | NetworkChangeNotifier::NetworkList connected_networks) { | 
|  | scoped_mock_network_change_notifier_.reset( | 
|  | new ScopedMockNetworkChangeNotifier()); | 
|  | MockNetworkChangeNotifier* mock_ncn = | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier(); | 
|  | mock_ncn->ForceNetworkHandlesSupported(); | 
|  | mock_ncn->SetConnectedNetworksList(connected_networks); | 
|  | test_params_.quic_migrate_sessions_on_network_change_v2 = true; | 
|  | test_params_.quic_migrate_sessions_early_v2 = true; | 
|  | socket_factory_.reset(new TestConnectionMigrationSocketFactory); | 
|  | Initialize(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<HttpStream> CreateStream(QuicStreamRequest* request) { | 
|  | std::unique_ptr<QuicChromiumClientSession::Handle> session = | 
|  | request->ReleaseSessionHandle(); | 
|  | if (!session || !session->IsConnected()) | 
|  | return nullptr; | 
|  |  | 
|  | return std::make_unique<QuicHttpStream>(std::move(session)); | 
|  | } | 
|  |  | 
|  | bool HasActiveSession(const HostPortPair& host_port_pair) { | 
|  | quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(), | 
|  | false); | 
|  | return QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server_id); | 
|  | } | 
|  |  | 
|  | bool HasLiveSession(const HostPortPair& host_port_pair) { | 
|  | quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(), | 
|  | false); | 
|  | return QuicStreamFactoryPeer::HasLiveSession(factory_.get(), host_port_pair, | 
|  | server_id); | 
|  | } | 
|  |  | 
|  | bool HasActiveJob(const HostPortPair& host_port_pair, | 
|  | const PrivacyMode privacy_mode) { | 
|  | quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(), | 
|  | privacy_mode == PRIVACY_MODE_ENABLED); | 
|  | return QuicStreamFactoryPeer::HasActiveJob(factory_.get(), server_id); | 
|  | } | 
|  |  | 
|  | bool HasActiveCertVerifierJob(const quic::QuicServerId& server_id) { | 
|  | return QuicStreamFactoryPeer::HasActiveCertVerifierJob(factory_.get(), | 
|  | server_id); | 
|  | } | 
|  |  | 
|  | // Get the pending, not activated session, if there is only one session alive. | 
|  | QuicChromiumClientSession* GetPendingSession( | 
|  | const HostPortPair& host_port_pair) { | 
|  | quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(), | 
|  | false); | 
|  | return QuicStreamFactoryPeer::GetPendingSession(factory_.get(), server_id, | 
|  | host_port_pair); | 
|  | } | 
|  |  | 
|  | QuicChromiumClientSession* GetActiveSession( | 
|  | const HostPortPair& host_port_pair) { | 
|  | quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(), | 
|  | false); | 
|  | return QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server_id); | 
|  | } | 
|  |  | 
|  | int GetSourcePortForNewSession(const HostPortPair& destination) { | 
|  | return GetSourcePortForNewSessionInner(destination, false); | 
|  | } | 
|  |  | 
|  | int GetSourcePortForNewSessionAndGoAway(const HostPortPair& destination) { | 
|  | return GetSourcePortForNewSessionInner(destination, true); | 
|  | } | 
|  |  | 
|  | int GetSourcePortForNewSessionInner(const HostPortPair& destination, | 
|  | bool goaway_received) { | 
|  | // Should only be called if there is no active session for this destination. | 
|  | EXPECT_FALSE(HasActiveSession(destination)); | 
|  | size_t socket_count = socket_factory_->udp_client_socket_ports().size(); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | GURL url("https://" + destination.host() + "/"); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request.Request( | 
|  | destination, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | stream.reset(); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(destination); | 
|  |  | 
|  | if (socket_count + 1 != socket_factory_->udp_client_socket_ports().size()) { | 
|  | ADD_FAILURE(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (goaway_received) { | 
|  | quic::QuicGoAwayFrame goaway(quic::kInvalidControlFrameId, | 
|  | quic::QUIC_NO_ERROR, 1, ""); | 
|  | session->connection()->OnGoAwayFrame(goaway); | 
|  | } | 
|  |  | 
|  | factory_->OnSessionClosed(session); | 
|  | EXPECT_FALSE(HasActiveSession(destination)); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | return socket_factory_->udp_client_socket_ports()[socket_count]; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> | 
|  | ConstructClientConnectionClosePacket(uint64_t num) { | 
|  | return client_maker_.MakeConnectionClosePacket( | 
|  | num, false, quic::QUIC_CRYPTO_VERSION_NOT_SUPPORTED, "Time to panic!"); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> ConstructClientRstPacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicRstStreamErrorCode error_code) { | 
|  | quic::QuicStreamId stream_id = | 
|  | GetNthClientInitiatedBidirectionalStreamId(0); | 
|  | return client_maker_.MakeRstPacket(packet_number, true, stream_id, | 
|  | error_code); | 
|  | } | 
|  |  | 
|  | static ProofVerifyDetailsChromium DefaultProofVerifyDetails() { | 
|  | // Load a certificate that is valid for *.example.org | 
|  | scoped_refptr<X509Certificate> test_cert( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | 
|  | EXPECT_TRUE(test_cert.get()); | 
|  | ProofVerifyDetailsChromium verify_details; | 
|  | verify_details.cert_verify_result.verified_cert = test_cert; | 
|  | verify_details.cert_verify_result.is_issued_by_known_root = true; | 
|  | return verify_details; | 
|  | } | 
|  |  | 
|  | void NotifyIPAddressChanged() { | 
|  | NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | 
|  | // Spin the message loop so the notification is delivered. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> ConstructGetRequestPacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin) { | 
|  | spdy::SpdyHeaderBlock headers = | 
|  | client_maker_.GetRequestHeaders("GET", "https", "/"); | 
|  | spdy::SpdyPriority priority = | 
|  | ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); | 
|  | size_t spdy_headers_frame_len; | 
|  | return client_maker_.MakeRequestHeadersPacket( | 
|  | packet_number, stream_id, should_include_version, fin, priority, | 
|  | std::move(headers), 0, &spdy_headers_frame_len); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> ConstructGetRequestPacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicStreamId stream_id, | 
|  | quic::QuicStreamId parent_stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | quic::QuicStreamOffset* offset) { | 
|  | spdy::SpdyHeaderBlock headers = | 
|  | client_maker_.GetRequestHeaders("GET", "https", "/"); | 
|  | spdy::SpdyPriority priority = | 
|  | ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); | 
|  | size_t spdy_headers_frame_len; | 
|  | return client_maker_.MakeRequestHeadersPacket( | 
|  | packet_number, stream_id, should_include_version, fin, priority, | 
|  | std::move(headers), parent_stream_id, &spdy_headers_frame_len, offset); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> ConstructGetRequestPacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | quic::QuicStreamOffset* offset) { | 
|  | return ConstructGetRequestPacket(packet_number, stream_id, | 
|  | /*parent_stream_id=*/0, | 
|  | should_include_version, fin, offset); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> ConstructOkResponsePacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin) { | 
|  | spdy::SpdyHeaderBlock headers = server_maker_.GetResponseHeaders("200 OK"); | 
|  | size_t spdy_headers_frame_len; | 
|  | return server_maker_.MakeResponseHeadersPacket( | 
|  | packet_number, stream_id, should_include_version, fin, | 
|  | std::move(headers), &spdy_headers_frame_len); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicReceivedPacket> ConstructInitialSettingsPacket() { | 
|  | return client_maker_.MakeInitialSettingsPacket(1, nullptr); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<quic::QuicReceivedPacket> ConstructInitialSettingsPacket( | 
|  | uint64_t packet_number, | 
|  | quic::QuicStreamOffset* offset) { | 
|  | return client_maker_.MakeInitialSettingsPacket(packet_number, offset); | 
|  | } | 
|  |  | 
|  | // Helper method for server migration tests. | 
|  | void VerifyServerMigration(const quic::QuicConfig& config, | 
|  | IPEndPoint expected_address) { | 
|  | test_params_.quic_allow_server_migration = true; | 
|  | Initialize(); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.SetConfig(config); | 
|  |  | 
|  | // Set up first socket data provider. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 3, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  |  | 
|  | // Run QuicChromiumClientSession::WriteToNewSocket() | 
|  | // posted by QuicChromiumClientSession::MigrateToSocket(). | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | IPEndPoint actual_address; | 
|  | session->GetDefaultSocket()->GetPeerAddress(&actual_address); | 
|  | EXPECT_EQ(actual_address, expected_address); | 
|  | DVLOG(1) << "Socket connected to: " << actual_address.address().ToString() | 
|  | << " " << actual_address.port(); | 
|  | DVLOG(1) << "Expected address: " << expected_address.address().ToString() | 
|  | << " " << expected_address.port(); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Verifies that the QUIC stream factory is initialized correctly. | 
|  | void VerifyInitialization() { | 
|  | store_server_configs_in_properties_ = true; | 
|  | test_params_.quic_idle_connection_timeout_seconds = 500; | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(false); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | const quic::QuicConfig* config = | 
|  | QuicStreamFactoryPeer::GetConfig(factory_.get()); | 
|  | EXPECT_EQ(500, config->IdleNetworkTimeout().ToSeconds()); | 
|  |  | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | const AlternativeService alternative_service1( | 
|  | kProtoQUIC, host_port_pair_.host(), host_port_pair_.port()); | 
|  | AlternativeServiceInfoVector alternative_service_info_vector; | 
|  | base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); | 
|  | alternative_service_info_vector.push_back( | 
|  | AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( | 
|  | alternative_service1, expiration, {version_})); | 
|  | http_server_properties_.SetAlternativeServices( | 
|  | url::SchemeHostPort(url_), alternative_service_info_vector); | 
|  |  | 
|  | HostPortPair host_port_pair2(kServer2HostName, kDefaultServerPort); | 
|  | url::SchemeHostPort server2("https", kServer2HostName, kDefaultServerPort); | 
|  | const AlternativeService alternative_service2( | 
|  | kProtoQUIC, host_port_pair2.host(), host_port_pair2.port()); | 
|  | AlternativeServiceInfoVector alternative_service_info_vector2; | 
|  | alternative_service_info_vector2.push_back( | 
|  | AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( | 
|  | alternative_service2, expiration, {version_})); | 
|  |  | 
|  | http_server_properties_.SetAlternativeServices( | 
|  | server2, alternative_service_info_vector2); | 
|  | // Verify that the properties of both QUIC servers are stored in the | 
|  | // HTTP properties map. | 
|  | EXPECT_EQ(2U, http_server_properties_.alternative_service_map().size()); | 
|  |  | 
|  | http_server_properties_.SetMaxServerConfigsStoredInProperties( | 
|  | kDefaultMaxQuicServerEntries); | 
|  |  | 
|  | quic::QuicServerId quic_server_id(kDefaultServerHostName, 443, | 
|  | PRIVACY_MODE_DISABLED); | 
|  | std::unique_ptr<QuicServerInfo> quic_server_info = | 
|  | std::make_unique<PropertiesBasedQuicServerInfo>( | 
|  | quic_server_id, &http_server_properties_); | 
|  |  | 
|  | // Update quic_server_info's server_config and persist it. | 
|  | QuicServerInfo::State* state = quic_server_info->mutable_state(); | 
|  | // Minimum SCFG that passes config validation checks. | 
|  | const char scfg[] = {// SCFG | 
|  | 0x53, 0x43, 0x46, 0x47, | 
|  | // num entries | 
|  | 0x01, 0x00, | 
|  | // padding | 
|  | 0x00, 0x00, | 
|  | // EXPY | 
|  | 0x45, 0x58, 0x50, 0x59, | 
|  | // EXPY end offset | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // Value | 
|  | '1', '2', '3', '4', '5', '6', '7', '8'}; | 
|  |  | 
|  | // Create temporary strings becasue Persist() clears string data in |state|. | 
|  | string server_config(reinterpret_cast<const char*>(&scfg), sizeof(scfg)); | 
|  | string source_address_token("test_source_address_token"); | 
|  | string cert_sct("test_cert_sct"); | 
|  | string chlo_hash("test_chlo_hash"); | 
|  | string signature("test_signature"); | 
|  | string test_cert("test_cert"); | 
|  | std::vector<string> certs; | 
|  | certs.push_back(test_cert); | 
|  | state->server_config = server_config; | 
|  | state->source_address_token = source_address_token; | 
|  | state->cert_sct = cert_sct; | 
|  | state->chlo_hash = chlo_hash; | 
|  | state->server_config_sig = signature; | 
|  | state->certs = certs; | 
|  |  | 
|  | quic_server_info->Persist(); | 
|  |  | 
|  | quic::QuicServerId quic_server_id2(kServer2HostName, 443, | 
|  | PRIVACY_MODE_DISABLED); | 
|  | std::unique_ptr<QuicServerInfo> quic_server_info2 = | 
|  | std::make_unique<PropertiesBasedQuicServerInfo>( | 
|  | quic_server_id2, &http_server_properties_); | 
|  | // Update quic_server_info2's server_config and persist it. | 
|  | QuicServerInfo::State* state2 = quic_server_info2->mutable_state(); | 
|  |  | 
|  | // Minimum SCFG that passes config validation checks. | 
|  | const char scfg2[] = {// SCFG | 
|  | 0x53, 0x43, 0x46, 0x47, | 
|  | // num entries | 
|  | 0x01, 0x00, | 
|  | // padding | 
|  | 0x00, 0x00, | 
|  | // EXPY | 
|  | 0x45, 0x58, 0x50, 0x59, | 
|  | // EXPY end offset | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // Value | 
|  | '8', '7', '3', '4', '5', '6', '2', '1'}; | 
|  |  | 
|  | // Create temporary strings becasue Persist() clears string data in | 
|  | // |state2|. | 
|  | string server_config2(reinterpret_cast<const char*>(&scfg2), sizeof(scfg2)); | 
|  | string source_address_token2("test_source_address_token2"); | 
|  | string cert_sct2("test_cert_sct2"); | 
|  | string chlo_hash2("test_chlo_hash2"); | 
|  | string signature2("test_signature2"); | 
|  | string test_cert2("test_cert2"); | 
|  | std::vector<string> certs2; | 
|  | certs2.push_back(test_cert2); | 
|  | state2->server_config = server_config2; | 
|  | state2->source_address_token = source_address_token2; | 
|  | state2->cert_sct = cert_sct2; | 
|  | state2->chlo_hash = chlo_hash2; | 
|  | state2->server_config_sig = signature2; | 
|  | state2->certs = certs2; | 
|  |  | 
|  | quic_server_info2->Persist(); | 
|  |  | 
|  | // Verify the MRU order is maintained. | 
|  | const QuicServerInfoMap& quic_server_info_map = | 
|  | http_server_properties_.quic_server_info_map(); | 
|  | EXPECT_EQ(2u, quic_server_info_map.size()); | 
|  | auto quic_server_info_map_it = quic_server_info_map.begin(); | 
|  | EXPECT_EQ(quic_server_info_map_it->first, quic_server_id2); | 
|  | ++quic_server_info_map_it; | 
|  | EXPECT_EQ(quic_server_info_map_it->first, quic_server_id); | 
|  |  | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | // Create a session and verify that the cached state is loaded. | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | HostPortPair(quic_server_id.host(), quic_server_id.port()), | 
|  | version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty( | 
|  | factory_.get(), quic_server_id)); | 
|  | quic::QuicCryptoClientConfig* crypto_config = | 
|  | QuicStreamFactoryPeer::GetCryptoConfig(factory_.get()); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached = | 
|  | crypto_config->LookupOrCreate(quic_server_id); | 
|  | EXPECT_FALSE(cached->server_config().empty()); | 
|  | EXPECT_TRUE(cached->GetServerConfig()); | 
|  | EXPECT_EQ(server_config, cached->server_config()); | 
|  | EXPECT_EQ(source_address_token, cached->source_address_token()); | 
|  | EXPECT_EQ(cert_sct, cached->cert_sct()); | 
|  | EXPECT_EQ(chlo_hash, cached->chlo_hash()); | 
|  | EXPECT_EQ(signature, cached->signature()); | 
|  | ASSERT_EQ(1U, cached->certs().size()); | 
|  | EXPECT_EQ(test_cert, cached->certs()[0]); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  |  | 
|  | // Create a session and verify that the cached state is loaded. | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.2", ""); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | HostPortPair(quic_server_id2.host(), quic_server_id2.port()), | 
|  | version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, GURL("https://mail.example.org/"), | 
|  | net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty( | 
|  | factory_.get(), quic_server_id2)); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached2 = | 
|  | crypto_config->LookupOrCreate(quic_server_id2); | 
|  | EXPECT_FALSE(cached2->server_config().empty()); | 
|  | EXPECT_TRUE(cached2->GetServerConfig()); | 
|  | EXPECT_EQ(server_config2, cached2->server_config()); | 
|  | EXPECT_EQ(source_address_token2, cached2->source_address_token()); | 
|  | EXPECT_EQ(cert_sct2, cached2->cert_sct()); | 
|  | EXPECT_EQ(chlo_hash2, cached2->chlo_hash()); | 
|  | EXPECT_EQ(signature2, cached2->signature()); | 
|  | ASSERT_EQ(1U, cached->certs().size()); | 
|  | EXPECT_EQ(test_cert2, cached2->certs()[0]); | 
|  | } | 
|  |  | 
|  | void RunTestLoopUntilIdle() { | 
|  | while (!runner_->GetPostedTasks().empty()) | 
|  | runner_->RunNextTask(); | 
|  | } | 
|  |  | 
|  | quic::QuicStreamId GetNthClientInitiatedBidirectionalStreamId(int n) { | 
|  | return quic::test::GetNthClientInitiatedBidirectionalStreamId(version_, n); | 
|  | } | 
|  |  | 
|  | quic::QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(int n) { | 
|  | return quic::test::GetNthServerInitiatedUnidirectionalStreamId(version_, n); | 
|  | } | 
|  |  | 
|  | void OnFailedOnDefaultNetwork(int rv) { failed_on_default_network_ = true; } | 
|  |  | 
|  | // Helper methods for tests of connection migration on write error. | 
|  | void TestMigrationOnWriteErrorNonMigratableStream(IoMode write_error_mode, | 
|  | bool migrate_idle_sessions); | 
|  | // Migratable stream triggers write error. | 
|  | void TestMigrationOnWriteErrorMixedStreams(IoMode write_error_mode); | 
|  | // Non-migratable stream triggers write error. | 
|  | void TestMigrationOnWriteErrorMixedStreams2(IoMode write_error_mode); | 
|  | void TestMigrationOnWriteErrorMigrationDisabled(IoMode write_error_mode); | 
|  | void TestMigrationOnWriteError(IoMode write_error_mode); | 
|  | void TestMigrationOnWriteErrorWithMultipleRequests(IoMode write_error_mode); | 
|  | void TestMigrationOnWriteErrorNoNewNetwork(IoMode write_error_mode); | 
|  | void TestMigrationOnMultipleWriteErrors( | 
|  | IoMode write_error_mode_on_old_network, | 
|  | IoMode write_error_mode_on_new_network); | 
|  | void TestMigrationOnNetworkNotificationWithWriteErrorQueuedLater( | 
|  | bool disconnected); | 
|  | void TestMigrationOnWriteErrorWithNotificationQueuedLater(bool disconnected); | 
|  | void TestMigrationOnNetworkDisconnected(bool async_write_before); | 
|  | void TestMigrationOnNetworkMadeDefault(IoMode write_mode); | 
|  | void TestMigrationOnPathDegrading(bool async_write_before); | 
|  | void TestMigrateSessionWithDrainingStream( | 
|  | IoMode write_mode_for_queued_packet); | 
|  | void TestMigrationOnWriteErrorPauseBeforeConnected(IoMode write_error_mode); | 
|  | void TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | IoMode write_error_mode, | 
|  | bool disconnect_before_connect); | 
|  | void TestNoAlternateNetworkBeforeHandshake(quic::QuicErrorCode error); | 
|  | void TestNewConnectionOnAlternateNetworkBeforeHandshake( | 
|  | quic::QuicErrorCode error); | 
|  | void TestOnNetworkMadeDefaultNonMigratableStream(bool migrate_idle_sessions); | 
|  | void TestMigrateSessionEarlyNonMigratableStream(bool migrate_idle_sessions); | 
|  | void TestOnNetworkDisconnectedNoOpenStreams(bool migrate_idle_sessions); | 
|  | void TestOnNetworkMadeDefaultNoOpenStreams(bool migrate_idle_sessions); | 
|  | void TestOnNetworkDisconnectedNonMigratableStream(bool migrate_idle_sessions); | 
|  |  | 
|  | QuicFlagSaver flags_;  // Save/restore all QUIC flag values. | 
|  | std::unique_ptr<MockHostResolverBase> host_resolver_; | 
|  | std::unique_ptr<SSLConfigService> ssl_config_service_; | 
|  | std::unique_ptr<MockClientSocketFactory> socket_factory_; | 
|  | MockCryptoClientStreamFactory crypto_client_stream_factory_; | 
|  | quic::test::MockRandom random_generator_; | 
|  | quic::MockClock clock_; | 
|  | scoped_refptr<TestTaskRunner> runner_; | 
|  | const quic::QuicTransportVersion version_; | 
|  | QuicTestPacketMaker client_maker_; | 
|  | QuicTestPacketMaker server_maker_; | 
|  | HttpServerPropertiesImpl http_server_properties_; | 
|  | std::unique_ptr<CertVerifier> cert_verifier_; | 
|  | TransportSecurityState transport_security_state_; | 
|  | std::unique_ptr<CTVerifier> cert_transparency_verifier_; | 
|  | DefaultCTPolicyEnforcer ct_policy_enforcer_; | 
|  | std::unique_ptr<ScopedMockNetworkChangeNotifier> | 
|  | scoped_mock_network_change_notifier_; | 
|  | std::unique_ptr<QuicStreamFactory> factory_; | 
|  | HostPortPair host_port_pair_; | 
|  | GURL url_; | 
|  | GURL url2_; | 
|  | GURL url3_; | 
|  | GURL url4_; | 
|  |  | 
|  | PrivacyMode privacy_mode_; | 
|  | NetLogWithSource net_log_; | 
|  | TestCompletionCallback callback_; | 
|  | const CompletionRepeatingCallback failed_on_default_network_callback_; | 
|  | bool failed_on_default_network_; | 
|  | NetErrorDetails net_error_details_; | 
|  |  | 
|  | // Variables to configure QuicStreamFactory. | 
|  | HttpNetworkSession::Params test_params_; | 
|  | bool store_server_configs_in_properties_; | 
|  | }; | 
|  |  | 
|  | class QuicStreamFactoryTest : public QuicStreamFactoryTestBase, | 
|  | public ::testing::TestWithParam<TestParams> { | 
|  | protected: | 
|  | QuicStreamFactoryTest() | 
|  | : QuicStreamFactoryTestBase( | 
|  | GetParam().version, | 
|  | GetParam().client_headers_include_h2_stream_dependency) {} | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P(VersionIncludeStreamDependencySequence, | 
|  | QuicStreamFactoryTest, | 
|  | ::testing::ValuesIn(GetTestParams())); | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, Create) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | EXPECT_EQ(DEFAULT_PRIORITY, host_resolver_->last_request_priority()); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | // Will reset stream 3. | 
|  | stream = CreateStream(&request2); | 
|  |  | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result | 
|  | // in streams on different sessions. | 
|  | QuicStreamRequest request3(factory_.get()); | 
|  | EXPECT_EQ(OK, request3.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | stream = CreateStream(&request3);  // Will reset stream 5. | 
|  | stream.reset();                    // Will reset stream 7. | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CreateZeroRtt) { | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(false); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, DefaultInitialRtt) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(session->require_confirmation()); | 
|  | EXPECT_EQ(100000u, session->connection()->GetStats().srtt_us); | 
|  | ASSERT_FALSE(session->config()->HasInitialRoundTripTimeUsToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, FactoryDestroyedWhenJobPending) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | auto request = std::make_unique<QuicStreamRequest>(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request->Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | request.reset(); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | // Tearing down a QuicStreamFactory with a pending Job should not cause any | 
|  | // crash. crbug.com/768343. | 
|  | factory_.reset(); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, RequireConfirmation) { | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(true); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | IPAddress last_address; | 
|  | EXPECT_FALSE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  |  | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  |  | 
|  | EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(session->require_confirmation()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, DontRequireConfirmationFromSameIP) { | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(true); | 
|  | http_server_properties_.SetSupportsQuic(IPAddress(192, 0, 2, 33)); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_THAT(request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()), | 
|  | IsOk()); | 
|  |  | 
|  | IPAddress last_address; | 
|  | EXPECT_FALSE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_FALSE(session->require_confirmation()); | 
|  |  | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  |  | 
|  | EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CachedInitialRtt) { | 
|  | ServerNetworkStats stats; | 
|  | stats.srtt = base::TimeDelta::FromMilliseconds(10); | 
|  | http_server_properties_.SetServerNetworkStats(url::SchemeHostPort(url_), | 
|  | stats); | 
|  | test_params_.quic_estimate_initial_rtt = true; | 
|  |  | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ(10000u, session->connection()->GetStats().srtt_us); | 
|  | ASSERT_TRUE(session->config()->HasInitialRoundTripTimeUsToSend()); | 
|  | EXPECT_EQ(10000u, session->config()->GetInitialRoundTripTimeUsToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, 2gInitialRtt) { | 
|  | ScopedMockNetworkChangeNotifier notifier; | 
|  | notifier.mock_network_change_notifier()->SetConnectionType( | 
|  | NetworkChangeNotifier::CONNECTION_2G); | 
|  | test_params_.quic_estimate_initial_rtt = true; | 
|  |  | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ(1200000u, session->connection()->GetStats().srtt_us); | 
|  | ASSERT_TRUE(session->config()->HasInitialRoundTripTimeUsToSend()); | 
|  | EXPECT_EQ(1200000u, session->config()->GetInitialRoundTripTimeUsToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, 3gInitialRtt) { | 
|  | ScopedMockNetworkChangeNotifier notifier; | 
|  | notifier.mock_network_change_notifier()->SetConnectionType( | 
|  | NetworkChangeNotifier::CONNECTION_3G); | 
|  | test_params_.quic_estimate_initial_rtt = true; | 
|  |  | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ(400000u, session->connection()->GetStats().srtt_us); | 
|  | ASSERT_TRUE(session->config()->HasInitialRoundTripTimeUsToSend()); | 
|  | EXPECT_EQ(400000u, session->config()->GetInitialRoundTripTimeUsToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, GoAway) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | session->OnGoAway(quic::QuicGoAwayFrame()); | 
|  |  | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, GoAwayForConnectionMigrationWithPortOnly) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | session->OnGoAway(quic::QuicGoAwayFrame( | 
|  | quic::kInvalidControlFrameId, quic::QUIC_ERROR_MIGRATING_PORT, 0, | 
|  | "peer connection migration due to port change only")); | 
|  | NetErrorDetails details; | 
|  | EXPECT_FALSE(details.quic_port_migration_detected); | 
|  | session->PopulateNetErrorDetails(&details); | 
|  | EXPECT_TRUE(details.quic_port_migration_detected); | 
|  | details.quic_port_migration_detected = false; | 
|  | stream->PopulateNetErrorDetails(&details); | 
|  | EXPECT_TRUE(details.quic_port_migration_detected); | 
|  |  | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, Pooling) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server2(kServer2HostName, kDefaultServerPort); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, PoolingWithServerMigration) { | 
|  | // Set up session to migrate. | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 443); | 
|  | quic::QuicConfig config; | 
|  | config.SetAlternateServerAddressToSend( | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(alt_address))); | 
|  |  | 
|  | VerifyServerMigration(config, alt_address); | 
|  |  | 
|  | // Close server-migrated session. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | session->CloseSessionOnError(0u, quic::QUIC_NO_ERROR, | 
|  | quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  |  | 
|  | // Set up server IP, socket, proof, and config for new session. | 
|  | HostPortPair server2(kServer2HostName, kDefaultServerPort); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> settings_packet( | 
|  | client_maker_.MakeInitialSettingsPacket(1, nullptr)); | 
|  | MockWrite writes[] = {MockWrite(SYNCHRONOUS, settings_packet->data(), | 
|  | settings_packet->length(), 1)}; | 
|  |  | 
|  | SequencedSocketData socket_data(reads, writes); | 
|  | socket_factory_->AddSocketDataProvider(&socket_data); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | quic::QuicConfig config2; | 
|  | crypto_client_stream_factory_.SetConfig(config2); | 
|  |  | 
|  | // Create new request to cause new session creation. | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback.callback())); | 
|  | EXPECT_EQ(OK, callback.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | // EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server2(kServer2HostName, kDefaultServerPort); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveSession(server2)); | 
|  |  | 
|  | TestCompletionCallback callback3; | 
|  | QuicStreamRequest request3(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request3.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback3.callback())); | 
|  | std::unique_ptr<HttpStream> stream3 = CreateStream(&request3); | 
|  | EXPECT_TRUE(stream3.get()); | 
|  |  | 
|  | EXPECT_TRUE(HasActiveSession(server2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, HttpsPooling) { | 
|  | Initialize(); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server1(kDefaultServerHostName, 443); | 
|  | HostPortPair server2(kServer2HostName, 443); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request.Request( | 
|  | server1, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) { | 
|  | Initialize(); | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server1(kDefaultServerHostName, 443); | 
|  | HostPortPair server2(kServer2HostName, 443); | 
|  | transport_security_state_.EnableStaticPinsForTesting(); | 
|  | ScopedTransportSecurityStateSource scoped_security_state_source; | 
|  |  | 
|  | HashValue primary_pin(HASH_VALUE_SHA256); | 
|  | EXPECT_TRUE(primary_pin.FromString( | 
|  | "sha256/Nn8jk5By4Vkq6BeOVZ7R7AC6XUUBZsWmUbJR1f1Y5FY=")); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | verify_details.cert_verify_result.public_key_hashes.push_back(primary_pin); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request.Request( | 
|  | server1, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) { | 
|  | Initialize(); | 
|  |  | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server1(kDefaultServerHostName, 443); | 
|  | HostPortPair server2(kServer2HostName, 443); | 
|  | transport_security_state_.EnableStaticPinsForTesting(); | 
|  | ScopedTransportSecurityStateSource scoped_security_state_source; | 
|  |  | 
|  | #if defined(STARBOARD) | 
|  | // Cobalt disables static transport security state, we have to add pins | 
|  | // dynamically. | 
|  | test::AddPin(&transport_security_state_, kServer2HostName, 1, 2); | 
|  | #endif | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails(); | 
|  | uint8_t bad_pin = 3; | 
|  | verify_details1.cert_verify_result.public_key_hashes.push_back( | 
|  | test::GetTestHashValue(bad_pin)); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1); | 
|  |  | 
|  | HashValue primary_pin(HASH_VALUE_SHA256); | 
|  | EXPECT_TRUE(primary_pin.FromString( | 
|  | "sha256/Nn8jk5By4Vkq6BeOVZ7R7AC6XUUBZsWmUbJR1f1Y5FY=")); | 
|  | ProofVerifyDetailsChromium verify_details2 = DefaultProofVerifyDetails(); | 
|  | verify_details2.cert_verify_result.public_key_hashes.push_back(primary_pin); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); | 
|  |  | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request.Request( | 
|  | server1, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | TestCompletionCallback callback; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, Goaway) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Mark the session as going away.  Ensure that while it is still alive | 
|  | // that it is no longer active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | factory_->OnSessionGoingAway(session); | 
|  | EXPECT_EQ(true, | 
|  | QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Create a new request for the same destination and verify that a | 
|  | // new session is created. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_NE(session, GetActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(true, | 
|  | QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  |  | 
|  | stream2.reset(); | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MaxOpenStream) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | quic::QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(0); | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | if (version_ == quic::QUIC_VERSION_99) { | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeStreamIdBlockedPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(49))); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket(3, true, stream_id, | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddRead( | 
|  | ASYNC, server_maker_.MakeRstPacket(1, false, stream_id, | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddRead( | 
|  | ASYNC, server_maker_.MakeMaxStreamIdPacket( | 
|  | 4, true, GetNthClientInitiatedBidirectionalStreamId(50))); | 
|  | } else { | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket(2, true, stream_id, | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddRead( | 
|  | ASYNC, server_maker_.MakeRstPacket(1, false, stream_id, | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | } | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  |  | 
|  | std::vector<std::unique_ptr<HttpStream>> streams; | 
|  | // The MockCryptoClientStream sets max_open_streams to be | 
|  | // quic::kDefaultMaxStreamsPerConnection / 2. | 
|  | for (size_t i = 0; i < quic::kDefaultMaxStreamsPerConnection / 2; i++) { | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | int rv = request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()); | 
|  | if (i == 0) { | 
|  | EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | } else { | 
|  | EXPECT_THAT(rv, IsOk()); | 
|  | } | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream); | 
|  | EXPECT_EQ(OK, | 
|  | stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | streams.push_back(std::move(stream)); | 
|  | } | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | CompletionOnceCallback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, callback_.callback())); | 
|  |  | 
|  | // Close the first stream. | 
|  | streams.front()->Close(false); | 
|  | // Trigger exchange of RSTs that in turn allow progress for the last | 
|  | // stream. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  |  | 
|  | // Force close of the connection to suppress the generation of RST | 
|  | // packets when streams are torn down, which wouldn't be relevant to | 
|  | // this test anyway. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | session->connection()->CloseConnection( | 
|  | quic::QUIC_PUBLIC_RESET, "test", | 
|  | quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) { | 
|  | Initialize(); | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | host_resolver_->rules()->AddSimulatedFailure(kDefaultServerHostName); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) { | 
|  | Initialize(); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CancelCreate) { | 
|  | Initialize(); | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | { | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | } | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request2); | 
|  |  | 
|  | EXPECT_TRUE(stream.get()); | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CloseAllSessions) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructClientRstPacket(2, quic::QUIC_RST_ACKNOWLEDGEMENT)); | 
|  | socket_data.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 3, true, quic::QUIC_INTERNAL_ERROR, "net error")); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Close the session and verify that stream saw the error. | 
|  | factory_->CloseAllSessions(ERR_INTERNET_DISCONNECTED, | 
|  | quic::QUIC_INTERNAL_ERROR); | 
|  | EXPECT_EQ(ERR_INTERNET_DISCONNECTED, | 
|  | stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Now attempting to request a stream to the same origin should create | 
|  | // a new session. | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | stream = CreateStream(&request2); | 
|  | stream.reset();  // Will reset stream 3. | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for crbug.com/700617. Test a write error during the | 
|  | // crypto handshake will not hang QuicStreamFactory::Job and should | 
|  | // report QUIC_HANDSHAKE_FAILED to upper layers. Subsequent | 
|  | // QuicStreamRequest should succeed without hanging. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | WriteErrorInCryptoConnectWithAsyncHostResolution) { | 
|  | Initialize(); | 
|  | // Use unmocked crypto stream to do crypto connect. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | // Trigger PACKET_WRITE_ERROR when sending packets in crypto connect. | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request, should fail after the write of the CHLO fails. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult()); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Verify new requests can be sent normally without hanging. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | // Run the message loop to complete host resolution. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Complete handshake. QuicStreamFactory::Job should complete and succeed. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Create QuicHttpStream. | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, WriteErrorInCryptoConnectWithSyncHostResolution) { | 
|  | Initialize(); | 
|  | // Use unmocked crypto stream to do crypto connect. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | // Trigger PACKET_WRITE_ERROR when sending packets in crypto connect. | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request, should fail immediately. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_QUIC_HANDSHAKE_FAILED, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | // Check no active session, or active jobs left for this server. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Verify new requests can be sent normally without hanging. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Complete handshake. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Create QuicHttpStream. | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CloseSessionsOnIPAddressChanged) { | 
|  | test_params_.quic_close_sessions_on_ip_change = true; | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructClientRstPacket(2, quic::QUIC_RST_ACKNOWLEDGEMENT)); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeConnectionClosePacket( | 
|  | 3, true, quic::QUIC_IP_ADDRESS_CHANGED, "net error")); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Check an active session exisits for the destination. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  |  | 
|  | IPAddress last_address; | 
|  | EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  | // Change the IP address and verify that stream saw the error and the active | 
|  | // session is closed. | 
|  | NotifyIPAddressChanged(); | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, | 
|  | stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_TRUE(factory_->require_confirmation()); | 
|  | EXPECT_FALSE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  | // Check no active session exists for the destination. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Now attempting to request a stream to the same origin should create | 
|  | // a new session. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | stream = CreateStream(&request2); | 
|  |  | 
|  | // Check a new active session exisits for the destination and the old session | 
|  | // is no longer live. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  |  | 
|  | stream.reset();  // Will reset stream 3. | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Test that if goaway_session_on_ip_change is set, old sessions will be marked | 
|  | // as going away on IP address change instead of being closed. New requests will | 
|  | // go to a new connection. | 
|  | TEST_P(QuicStreamFactoryTest, GoAwaySessionsOnIPAddressChanged) { | 
|  | test_params_.quic_goaway_sessions_on_ip_change = true; | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | quic_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, true)); | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic::QuicStreamOffset header_stream_offset2 = 0; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset2)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Receive an IP address change notification. | 
|  | NotifyIPAddressChanged(); | 
|  |  | 
|  | // The connection should still be alive, but marked as going away. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Resume the data, response should be read from the original connection. | 
|  | quic_data1.Resume(); | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Second request should be sent on a new connection. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | // Check an active session exisits for the destination. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  |  | 
|  | stream.reset(); | 
|  | stream2.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, OnIPAddressChangedWithConnectionMigration) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructClientRstPacket(2, quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | IPAddress last_address; | 
|  | EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  |  | 
|  | // Change the IP address and verify that the connection is unaffected. | 
|  | NotifyIPAddressChanged(); | 
|  | EXPECT_FALSE(factory_->require_confirmation()); | 
|  | EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address)); | 
|  |  | 
|  | // Attempting a new request to the same origin uses the same connection. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | stream = CreateStream(&request2); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnNetworkMadeDefaultWithSynchronousWrite) { | 
|  | TestMigrationOnNetworkMadeDefault(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnNetworkMadeDefaultWithAsyncWrite) { | 
|  | TestMigrationOnNetworkMadeDefault(ASYNC); | 
|  | } | 
|  |  | 
|  | // Sets up a test which attempts connection migration successfully after probing | 
|  | // when a new network is made as default and the old default is still available. | 
|  | // |write_mode| specifies the write mode for the last write before | 
|  | // OnNetworkMadeDefault is delivered to session. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnNetworkMadeDefault( | 
|  | IoMode write_mode) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging Read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | write_mode, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on the new socket. | 
|  | MockQuicData quic_data2; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(3, true)); | 
|  | quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data2.AddWrite(ASYNC, | 
|  | client_maker_.MakeAckAndPingPacket(4, false, 1, 1, 1)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 5, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 2, 2, 1, true)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Deliver a signal that a alternate network is connected now, this should | 
|  | // cause the connection to start early migration on path degrading. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Due to lack of alternate network, session will not mgirate connection. | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | // A task will be posted to migrate to the new default network. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  |  | 
|  | // Execute the posted task to migrate back to the default network. | 
|  | task_runner->RunUntilIdle(); | 
|  | // Another task to try send a new connectivity probe is posted. And a task to | 
|  | // retry migrate back to default network is scheduled. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket, declare probing as successful. And a new task to WriteToNewSocket | 
|  | // will be posted to complete migration. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta(), next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to send connectivity | 
|  | // probe and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to mgirate back to the default network in 0.4s, which | 
|  | // is also cancelled due to the success migration on the previous trial. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for http://859674. | 
|  | // This test veries that a writer will not attempt to write packets until being | 
|  | // unblocked on both socket level and network level. In this test, a probing | 
|  | // writer is used to send two connectivity probes to the peer: where the first | 
|  | // one completes successfully, while a connectivity response is received before | 
|  | // completes sending the second one. The connection migration attempt will | 
|  | // proceed while the probing writer is blocked at the socket level, which will | 
|  | // block the writer on the network level. Once connection migration completes | 
|  | // successfully, the probing writer will be unblocked on the network level, it | 
|  | // will not attempt to write new packets until the socket level is unblocked. | 
|  | TEST_P(QuicStreamFactoryTest, MigratedToBlockedSocketAfterProbing) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging Read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on the new socket. | 
|  | MockQuicData quic_data2; | 
|  | // First connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(3, true)); | 
|  | quic_data2.AddRead(ASYNC, | 
|  | ERR_IO_PENDING);  // Pause so that we can control time. | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | // Second connectivity probe which will complete asynchronously. | 
|  | quic_data2.AddWrite(ASYNC, | 
|  | client_maker_.MakeConnectivityProbingPacket(4, true)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite(ASYNC, | 
|  | client_maker_.MakeAckAndPingPacket(5, false, 1, 1, 1)); | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 6, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 2, 2, 1, true)); | 
|  |  | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Deliver a signal that a alternate network is connected now, this should | 
|  | // cause the connection to start early migration on path degrading. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Due to lack of alternate network, session will not mgirate connection. | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | // A task will be posted to migrate to the new default network. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  |  | 
|  | // Execute the posted task to migrate back to the default network. | 
|  | task_runner->RunUntilIdle(); | 
|  | // Another task to resend a new connectivity probe is posted. And a task to | 
|  | // retry migrate back to default network is scheduled. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  |  | 
|  | // Fast forward to send the second connectivity probe. The write will be | 
|  | // asynchronous and complete after the read completes. | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket, declare probing as successful. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. Second task will retry migrate back to | 
|  | // default but cancelled, and the third task will retry send connectivity | 
|  | // probe but also cancelled. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  | task_runner->RunUntilIdle(); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Run the message loop to complete the asynchronous write of ack and ping. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to retry migrate back | 
|  | // to default network and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | expected_delay; | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to retry sending connectivity probe in 0.4s and has | 
|  | // also been cancelled due to the successful probing. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | expected_delay = | 
|  | base::TimeDelta::FromMilliseconds(3 * 2 * kDefaultRTTMilliSecs) - | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that session times out connection migration attempt | 
|  | // with signals delivered in the following order (no alternate network is | 
|  | // available): | 
|  | // - default network disconnected is delivered: session attempts connection | 
|  | //   migration but found not alternate network. Session waits for a new network | 
|  | //   comes up in the next kWaitTimeForNewNetworkSecs seconds. | 
|  | // - no new network is connected, migration times out. Session is closed. | 
|  | TEST_P(QuicStreamFactoryTest, MigrationTimeoutWithNoNewNetwork) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there are no networks | 
|  | // to migrate to, this should cause the session to wait for a new network. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // The migration will not fail until the migration alarm timeout. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(true, session->connection()->writer()->IsWriteBlocked()); | 
|  |  | 
|  | // Migration will be timed out after kWaitTimeForNewNetwokSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(kWaitTimeForNewNetworkSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // The connection should now be closed. A request for response | 
|  | // headers should fail. | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, callback_.WaitForResult()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that connectivity probes will be sent even if there is | 
|  | // a non-migratable stream. However, when connection migrates to the | 
|  | // successfully probed path, any non-migratable streams will be reset. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkMadeDefaultNonMigratableStream_MigrateIdleSessions) { | 
|  | TestOnNetworkMadeDefaultNonMigratableStream(true); | 
|  | } | 
|  |  | 
|  | // This test verifies that connectivity probes will be sent even if there is | 
|  | // a non-migratable stream. However, when connection migrates to the | 
|  | // successfully probed path, any non-migratable stream will be reset. And if | 
|  | // the connection becomes idle then, close the connection. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkMadeDefaultNonMigratableStream_DoNotMigrateIdleSessions) { | 
|  | TestOnNetworkMadeDefaultNonMigratableStream(false); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestOnNetworkMadeDefaultNonMigratableStream( | 
|  | bool migrate_idle_sessions) { | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | if (!migrate_idle_sessions) { | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstAckAndConnectionClosePacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, | 
|  | quic::QuicTime::Delta::FromMilliseconds(0), 1, 1, 1, | 
|  | quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, | 
|  | "net error")); | 
|  | } | 
|  |  | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used for probing. | 
|  | MockQuicData quic_data1; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(2, true)); | 
|  | quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data1.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | if (migrate_idle_sessions) { | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // A RESET will be sent to the peer to cancel the non-migratable stream. | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndPingPacket(4, false, 1, 1, 1)); | 
|  | } | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created, but marked as non-migratable. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Session will start to probe the alternative | 
|  | // network. Although there is a non-migratable stream, session will still be | 
|  | // active until probing is declared as successful. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Resume data to read a connectivity probing response, which will cause | 
|  | // non-migtable streams to be closed. | 
|  | quic_data1.Resume(); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultConnectionMigrationDisabled) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set session config to have connection migration disabled. | 
|  | quic::test::QuicConfigPeer::SetReceivedDisableConnectionMigration( | 
|  | session->config()); | 
|  | EXPECT_TRUE(session->config()->DisableConnectionMigration()); | 
|  |  | 
|  | // Trigger connection migration. Since there is a non-migratable stream, | 
|  | // this should cause session to continue but be marked as going away. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkDisconnectedNonMigratableStream_DoNotMigrateIdleSessions) { | 
|  | TestOnNetworkDisconnectedNonMigratableStream(false); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkDisconnectedNonMigratableStream_MigrateIdleSessions) { | 
|  | TestOnNetworkDisconnectedNonMigratableStream(true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestOnNetworkDisconnectedNonMigratableStream( | 
|  | bool migrate_idle_sessions) { | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData failed_socket_data; | 
|  | MockQuicData socket_data; | 
|  | if (migrate_idle_sessions) { | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | failed_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | failed_socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | // A RESET will be sent to the peer to cancel the non-migratable stream. | 
|  | failed_socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | failed_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // Ping packet to send after migration. | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(3, /*include_version=*/true)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } else { | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created, but marked as non-migratable. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there is a non-migratable stream, | 
|  | // this should cause a RST_STREAM frame to be emitted with | 
|  | // quic::QUIC_STREAM_CANCELLED error code. | 
|  | // If migate idle session, the connection will then be migrated to the | 
|  | // alternate network. Otherwise, the connection will be closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | EXPECT_EQ(migrate_idle_sessions, | 
|  | QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | if (migrate_idle_sessions) { | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(failed_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(failed_socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkDisconnectedConnectionMigrationDisabled) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_RST_ACKNOWLEDGEMENT)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set session config to have connection migration disabled. | 
|  | quic::test::QuicConfigPeer::SetReceivedDisableConnectionMigration( | 
|  | session->config()); | 
|  | EXPECT_TRUE(session->config()->DisableConnectionMigration()); | 
|  |  | 
|  | // Trigger connection migration. Since there is a non-migratable stream, | 
|  | // this should cause a RST_STREAM frame to be emitted with | 
|  | // quic::QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkMadeDefaultNoOpenStreams_DoNotMigrateIdleSessions) { | 
|  | TestOnNetworkMadeDefaultNoOpenStreams(false); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkMadeDefaultNoOpenStreams_MigrateIdleSessions) { | 
|  | TestOnNetworkMadeDefaultNoOpenStreams(true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestOnNetworkMadeDefaultNoOpenStreams( | 
|  | bool migrate_idle_sessions) { | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | if (!migrate_idle_sessions) { | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 2, true, quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, | 
|  | "net error")); | 
|  | } | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | if (migrate_idle_sessions) { | 
|  | // Set up the second socket data provider that is used for probing. | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(2, true)); | 
|  | quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data1.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndPingPacket(3, false, 1, 1, 1)); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(0u, session->GetNumDrainingStreams()); | 
|  |  | 
|  | // Trigger connection migration. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | if (migrate_idle_sessions) { | 
|  | quic_data1.Resume(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | } | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkDisconnectedNoOpenStreams_DoNotMigateIdleSessions) { | 
|  | TestOnNetworkDisconnectedNoOpenStreams(false); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | OnNetworkDisconnectedNoOpenStreams_MigateIdleSessions) { | 
|  | TestOnNetworkDisconnectedNoOpenStreams(true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestOnNetworkDisconnectedNoOpenStreams( | 
|  | bool migrate_idle_sessions) { | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData default_socket_data; | 
|  | default_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | default_socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | default_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData alternate_socket_data; | 
|  | if (migrate_idle_sessions) { | 
|  | // Set up second socket data provider that is used after migration. | 
|  | alternate_socket_data.AddRead(SYNCHRONOUS, | 
|  | ERR_IO_PENDING);  // Hanging read. | 
|  | // Ping packet to send after migration. | 
|  | alternate_socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Ensure that session is active. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there are no active streams, | 
|  | // the session will be closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | EXPECT_TRUE(default_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(default_socket_data.AllWriteDataConsumed()); | 
|  | if (migrate_idle_sessions) { | 
|  | EXPECT_TRUE(alternate_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(alternate_socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // This test verifies session migrates to the alternate network immediately when | 
|  | // default network disconnects with a synchronous write before migration. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnDefaultNetworkDisconnectedSync) { | 
|  | TestMigrationOnNetworkDisconnected(/*async_write_before*/ false); | 
|  | } | 
|  |  | 
|  | // This test verifies session migrates to the alternate network immediately when | 
|  | // default network disconnects with an asynchronously write before migration. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnDefaultNetworkDisconnectedAsync) { | 
|  | TestMigrationOnNetworkDisconnected(/*async_write_before*/ true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnNetworkDisconnected( | 
|  | bool async_write_before) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kDefaultNetworkForTests); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Use the test task runner. | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(packet_number++, &header_stream_offset)); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | if (async_write_before) { | 
|  | socket_data.AddWrite(ASYNC, OK); | 
|  | packet_number++; | 
|  | } | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | if (async_write_before) | 
|  | session->SendPing(); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakePingPacket(packet_number++, /*include_version=*/true)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndRstPacket( | 
|  | packet_number++, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Trigger connection migration. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // The connection should still be alive, not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Ensure that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Run the message loop so that data queued in the new socket is read by the | 
|  | // packet reader. | 
|  | runner_->RunNextTask(); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Check that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // There should be posted tasks not executed, which is to migrate back to | 
|  | // default network. | 
|  | EXPECT_FALSE(runner_->GetPostedTasks().empty()); | 
|  |  | 
|  | // Receive signal to mark new network as default. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test receives NCN signals in the following order: | 
|  | // - default network disconnected | 
|  | // - after a pause, new network is connected. | 
|  | // - new network is made default. | 
|  | TEST_P(QuicStreamFactoryTest, NewNetworkConnectedAfterNoNetwork) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Use the test task runner. | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Trigger connection migration. Since there are no networks | 
|  | // to migrate to, this should cause the session to wait for a new network. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // The connection should still be alive, not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(3, /*include_version=*/true)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Add a new network and notify the stream factory of a new connected network. | 
|  | // This causes a PING packet to be sent over the new network. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList({kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Ensure that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Run the message loop so that data queued in the new socket is read by the | 
|  | // packet reader. | 
|  | runner_->RunNextTask(); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Check that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // There should posted tasks not executed, which is to migrate back to default | 
|  | // network. | 
|  | EXPECT_FALSE(runner_->GetPostedTasks().empty()); | 
|  |  | 
|  | // Receive signal to mark new network as default. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for http://crbug.com/872011. | 
|  | // This test verifies that migrate to the probing socket will not trigger | 
|  | // new packets being read synchronously and generate ACK frame while | 
|  | // processing the initial connectivity probe response, which may cause a | 
|  | // connection being closed with INTERNAL_ERROR as pending ACK frame is not | 
|  | // allowed when processing a new packet. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateToProbingSocket) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging Read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket( | 
|  | packet_number++, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used for probing on the | 
|  | // alternate network. | 
|  | MockQuicData quic_data2; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( | 
|  | packet_number++, true)); | 
|  | quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // First connectivity probe to receive from the server, which will complete | 
|  | // connection migraiton on path degrading. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | // Read multiple connectivity probes synchronously. | 
|  | quic_data2.AddRead(SYNCHRONOUS, | 
|  | server_maker_.MakeConnectivityProbingPacket(2, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, | 
|  | server_maker_.MakeConnectivityProbingPacket(3, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, | 
|  | server_maker_.MakeConnectivityProbingPacket(4, false)); | 
|  | quic_data2.AddWrite( | 
|  | ASYNC, client_maker_.MakeAckPacket(packet_number++, 1, 4, 1, 1, true)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 5, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndRstPacket( | 
|  | packet_number++, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 5, 1, 1, true)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session will start to probe the alternate network. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  |  | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta(), next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to send connectivity | 
|  | // probe and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to mgirate back to the default network in 0.4s. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  |  | 
|  | // Deliver a signal that the alternate network now becomes default to session, | 
|  | // this will cancel mgirate back to default network timer. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that the connection migrates to the alternate network | 
|  | // early when path degrading is detected with an ASYNCHRONOUS write before | 
|  | // migration. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateEarlyOnPathDegradingAysnc) { | 
|  | TestMigrationOnPathDegrading(/*async_write_before_migration*/ true); | 
|  | } | 
|  |  | 
|  | // This test verifies that the connection migrates to the alternate network | 
|  | // early when path degrading is detected with a SYNCHRONOUS write before | 
|  | // migration. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateEarlyOnPathDegradingSync) { | 
|  | TestMigrationOnPathDegrading(/*async_write_before_migration*/ false); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnPathDegrading( | 
|  | bool async_write_before) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging Read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket( | 
|  | packet_number++, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | if (async_write_before) { | 
|  | quic_data1.AddWrite(ASYNC, OK); | 
|  | packet_number++; | 
|  | } | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on the new socket. | 
|  | MockQuicData quic_data2; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( | 
|  | packet_number++, true)); | 
|  | quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndPingPacket( | 
|  | packet_number++, false, 1, 1, 1)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndRstPacket( | 
|  | packet_number++, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 2, 2, 1, true)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | if (async_write_before) | 
|  | session->SendPing(); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session will start to probe the alternate network. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  |  | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta(), next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to send connectivity | 
|  | // probe and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to mgirate back to the default network in 0.4s. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  |  | 
|  | // Deliver a signal that the alternate network now becomes default to session, | 
|  | // this will cancel mgirate back to default network timer. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that the session marks itself GOAWAY on path degrading | 
|  | // and it does not receive any new request | 
|  | TEST_P(QuicStreamFactoryTest, GoawayOnPathDegrading) { | 
|  | test_params_.quic_go_away_on_path_degrading = true; | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | quic_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, true)); | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic::QuicStreamOffset header_stream_offset2 = 0; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset2)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Creat request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cerf_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Trigger the connection to report path degrading to the session. | 
|  | // Session will mark itself GOAWAY. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  |  | 
|  | // The connection should still be alive, but marked as going away. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Second request should be sent on a new connection. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | // Resume the data, verify old request can read response on the old session | 
|  | // successfully. | 
|  | quic_data1.Resume(); | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  | EXPECT_EQ(0U, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Check an active session exists for the destination. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  | EXPECT_NE(session, session2); | 
|  |  | 
|  | stream.reset(); | 
|  | stream2.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that the connection will not migrate to a bad socket | 
|  | // when path degrading is detected. | 
|  | TEST_P(QuicStreamFactoryTest, DoNotMigrateToBadSocketOnPathDegrading) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data.AddWrite(SYNCHRONOUS, | 
|  | ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | quic_data.AddRead(ASYNC, ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | false, false)); | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket that will immediately return disconnected. | 
|  | // The stream factory will abort probe the alternate network. | 
|  | MockConnect bad_connect = MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED); | 
|  | SequencedSocketData socket_data(bad_connect, base::span<MockRead>(), | 
|  | base::span<MockWrite>()); | 
|  | socket_factory_->AddSocketDataProvider(&socket_data); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session will start to probe the alternate network. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume the data, and response header is received over the original network. | 
|  | quic_data.Resume(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Verify there is no pending task as probing alternate network is halted. | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for http://crbug.com/847569. | 
|  | // This test verifies that the connection migrates to the alternate network | 
|  | // early when there is no active stream but a draining stream. | 
|  | // The first packet being written after migration is a synchrnous write, which | 
|  | // will cause a PING packet being sent. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionWithDrainingStreamSync) { | 
|  | TestMigrateSessionWithDrainingStream(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | // Regression test for http://crbug.com/847569. | 
|  | // This test verifies that the connection migrates to the alternate network | 
|  | // early when there is no active stream but a draining stream. | 
|  | // The first packet being written after migration is an asynchronous write, no | 
|  | // PING packet will be sent. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionWithDrainingStreamAsync) { | 
|  | TestMigrateSessionWithDrainingStream(ASYNC); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrateSessionWithDrainingStream( | 
|  | IoMode write_mode_for_queued_packet) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket( | 
|  | packet_number++, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | // Read an out of order packet with FIN to drain the stream. | 
|  | quic_data1.AddRead( | 
|  | ASYNC, ConstructOkResponsePacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), false, | 
|  | true));  // keep sending version. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeAckPacket( | 
|  | packet_number++, 2, 2, 2, 1, true)); | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used after migration. | 
|  | MockQuicData quic_data2; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( | 
|  | packet_number++, false)); | 
|  | quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(3, false)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data2.AddWrite( | 
|  | write_mode_for_queued_packet, | 
|  | client_maker_.MakeAckPacket(packet_number++, 2, 3, 3, 1, true)); | 
|  | if (write_mode_for_queued_packet == SYNCHRONOUS) { | 
|  | quic_data2.AddWrite(ASYNC, | 
|  | client_maker_.MakePingPacket(packet_number++, false)); | 
|  | } | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeAckPacket( | 
|  | packet_number++, 1, 3, 1, 1, true)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Run the message loop to receive the out of order packet which contains a | 
|  | // FIN and drains the stream. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session should still start to probe the alternate network. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(1u, session->GetNumDrainingStreams()); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta(), next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to send connectivity | 
|  | // probe and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to mgirate back to the default network in 0.4s. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Deliver a signal that the alternate network now becomes default to session, | 
|  | // this will cancel mgirate back to default network timer. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for http://crbug.com/835444. | 
|  | // This test verifies that the connection migrates to the alternate network | 
|  | // when the alternate network is connected after path has been degrading. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnNewNetworkConnectAfterPathDegrading) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | MockQuicData quic_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging Read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on the new socket. | 
|  | MockQuicData quic_data2; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(3, true)); | 
|  | quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data2.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data2.AddWrite(ASYNC, | 
|  | client_maker_.MakeAckAndPingPacket(4, false, 1, 1, 1)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 5, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 2, 2, 1, true)); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Due to lack of alternate network, session will not mgirate connection. | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Deliver a signal that a alternate network is connected now, this should | 
|  | // cause the connection to start early migration on path degrading. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Next connectivity probe is scheduled to be sent in 2 * | 
|  | // kDefaultRTTMilliSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // The connection should still be alive, and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume quic data and a connectivity probe response will be read on the new | 
|  | // socket. | 
|  | quic_data2.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // There should be three pending tasks, the nearest one will complete | 
|  | // migration to the new network. | 
|  | EXPECT_EQ(3u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta(), next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Now there are two pending tasks, the nearest one was to send connectivity | 
|  | // probe and has been cancelled due to successful migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There's one more task to mgirate back to the default network in 0.4s. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs) - | 
|  | base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs); | 
|  | EXPECT_EQ(expected_delay, next_task_delay); | 
|  |  | 
|  | // Deliver a signal that the alternate network now becomes default to session, | 
|  | // this will cancel mgirate back to default network timer. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Verify that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that multiple sessions are migrated on connection | 
|  | // migration signal. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateMultipleSessionsToBadSocketsAfterDisconnected) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  |  | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data1.AddWrite(ASYNC, OK); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddWrite(ASYNC, OK); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server1(kDefaultServerHostName, 443); | 
|  | HostPortPair server2(kServer2HostName, 443); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.2", ""); | 
|  |  | 
|  | // Create request and QuicHttpStream to create session1. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request1.Request( | 
|  | server1, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream to create session2. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session1 = GetActiveSession(server1); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(server2); | 
|  | EXPECT_NE(session1, session2); | 
|  |  | 
|  | // Cause QUIC stream to be created and send GET so session1 has an open | 
|  | // stream. | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = url_; | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | HttpResponseInfo response1; | 
|  | HttpRequestHeaders request_headers1; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers1, &response1, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Cause QUIC stream to be created and send GET so session2 has an open | 
|  | // stream. | 
|  | HttpRequestInfo request_info2; | 
|  | request_info2.method = "GET"; | 
|  | request_info2.url = url_; | 
|  | request_info2.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | HttpResponseInfo response2; | 
|  | HttpRequestHeaders request_headers2; | 
|  | EXPECT_EQ(OK, stream2->SendRequest(request_headers2, &response2, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Cause both sessions to be paused due to DISCONNECTED. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // Ensure that both sessions are paused but alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session1)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  |  | 
|  | // Add new sockets to use post migration. Those are bad sockets and will cause | 
|  | // migration to fail. | 
|  | MockConnect connect_result = | 
|  | MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED); | 
|  | SequencedSocketData socket_data3(connect_result, base::span<MockRead>(), | 
|  | base::span<MockWrite>()); | 
|  | socket_factory_->AddSocketDataProvider(&socket_data3); | 
|  | SequencedSocketData socket_data4(connect_result, base::span<MockRead>(), | 
|  | base::span<MockWrite>()); | 
|  | socket_factory_->AddSocketDataProvider(&socket_data4); | 
|  |  | 
|  | // Connect the new network and cause migration to bad sockets, causing | 
|  | // sessions to close. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList({kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session1)); | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that session attempts connection migration with signals | 
|  | // delivered in the following order (no alternate network is available): | 
|  | // - path degrading is detected: session attempts connection migration but no | 
|  | //   alternate network is available, session caches path degrading signal in | 
|  | //   connection and stays on the original network. | 
|  | // - original network backs up, request is served in the orignal network, | 
|  | //   session is not marked as going away. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnPathDegradingWithNoNewNetwork) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | quic_data.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | quic_data.AddWrite(SYNCHRONOUS, | 
|  | ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause for path degrading signal. | 
|  |  | 
|  | // The rest of the data will still flow in the original socket as there is no | 
|  | // new network after path degrading. | 
|  | quic_data.AddRead(ASYNC, ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | false, false)); | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Trigger connection migration on path degrading. Since there are no networks | 
|  | // to migrate to, the session will remain on the original network, not marked | 
|  | // as going away. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  | EXPECT_TRUE(session->connection()->IsPathDegrading()); | 
|  |  | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Resume so that rest of the data will flow in the original socket. | 
|  | quic_data.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that session with non-migratable stream will probe the | 
|  | // alternate network on path degrading, and close the non-migratable streams | 
|  | // when probe is successful. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionEarlyNonMigratableStream_DoNotMigrateIdleSessions) { | 
|  | TestMigrateSessionEarlyNonMigratableStream(false); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionEarlyNonMigratableStream_MigrateIdleSessions) { | 
|  | TestMigrateSessionEarlyNonMigratableStream(true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrateSessionEarlyNonMigratableStream( | 
|  | bool migrate_idle_sessions) { | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | if (!migrate_idle_sessions) { | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstAckAndConnectionClosePacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, | 
|  | quic::QuicTime::Delta::FromMilliseconds(0), 1, 1, 1, | 
|  | quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS, | 
|  | "net error")); | 
|  | } | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the second socket data provider that is used for probing. | 
|  | MockQuicData quic_data1; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(2, true)); | 
|  | quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data1.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(1, false)); | 
|  | if (migrate_idle_sessions) { | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // A RESET will be sent to the peer to cancel the non-migratable stream. | 
|  | quic_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | // Ping packet to send after migration is completed. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndPingPacket(4, false, 1, 1, 1)); | 
|  | } | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created, but marked as non-migratable. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there is a non-migratable stream, | 
|  | // this should cause session to migrate. | 
|  | session->OnPathDegrading(); | 
|  |  | 
|  | // Run the message loop so that data queued in the new socket is read by the | 
|  | // packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Resume the data to read the connectivity probing response to declare probe | 
|  | // as successful. Non-migratable streams will be closed. | 
|  | quic_data1.Resume(); | 
|  | if (migrate_idle_sessions) | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(0u, session->GetNumActiveStreams()); | 
|  |  | 
|  | EXPECT_TRUE(quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set session config to have connection migration disabled. | 
|  | quic::test::QuicConfigPeer::SetReceivedDisableConnectionMigration( | 
|  | session->config()); | 
|  | EXPECT_TRUE(session->config()->DisableConnectionMigration()); | 
|  |  | 
|  | // Trigger connection migration. Since there is a non-migratable stream, | 
|  | // this should cause session to be continue without migrating. | 
|  | session->OnPathDegrading(); | 
|  |  | 
|  | // Run the message loop so that data queued in the new socket is read by the | 
|  | // packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Regression test for http://crbug.com/791886. | 
|  | // This test verifies that the old packet writer which encountered an | 
|  | // asynchronous write error will be blocked during migration on write error. New | 
|  | // packets would not be written until the one with write error is rewritten on | 
|  | // the new network. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnAysncWriteError) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | // base::RunLoop() controls mocked socket writes and reads. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(ASYNC, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, | 
|  | ConstructGetRequestPacket( | 
|  | 3, GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 5, false, GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | quic::QUIC_STREAM_CANCELLED, 0, | 
|  | /*include_stop_sending_if_v99=*/true)); | 
|  |  | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request #1 and QuicHttpStream. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = GURL("https://www.example.org/"); | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Request #2 returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | HttpRequestInfo request_info2; | 
|  | request_info2.method = "GET"; | 
|  | request_info2.url = GURL("https://www.example.org/"); | 
|  | request_info2.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream1. This should cause an async write error. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Run the message loop so that asynchronous write completes and a connection | 
|  | // migration on write error attempt is posted in QuicStreamFactory's task | 
|  | // runner. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Send GET request on stream. This will cause another write attempt before | 
|  | // migration on write error is exectued. | 
|  | HttpResponseInfo response2; | 
|  | HttpRequestHeaders request_headers2; | 
|  | EXPECT_EQ(OK, stream2->SendRequest(request_headers2, &response2, | 
|  | callback2.callback())); | 
|  |  | 
|  | // Run the task runner so that migration on write error is finally executed. | 
|  | task_runner->RunUntilIdle(); | 
|  |  | 
|  | // Verify the session is still alive and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  | // There should be one task posted to migrate back to the default network in | 
|  | // kMinRetryTimeForDefaultNetworkSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs), | 
|  | task_runner->NextPendingTaskDelay()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream1.reset(); | 
|  | stream2.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Verify session is not marked as going away after connection migration on | 
|  | // write error and migrate back to default network logic is applied to bring the | 
|  | // migrated session back to the default network. Migration singals delivered | 
|  | // in the following order (alternate network is always availabe): | 
|  | // - session on the default network encountered a write error; | 
|  | // - session successfully migrated to the non-default network; | 
|  | // - session attempts to migrate back to default network post migration; | 
|  | // - migration back to the default network is successful. | 
|  | TEST_P(QuicStreamFactoryTest, MigrateBackToDefaultPostMigrationOnWriteError) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can control time. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(ASYNC, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | quic_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request QuicHttpStream. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = GURL("https://www.example.org/"); | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request. This should cause an async write error. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Run the message loop so that asynchronous write completes and a connection | 
|  | // migration on write error attempt is posted in QuicStreamFactory's task | 
|  | // runner. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Run the task runner so that migration on write error is finally executed. | 
|  | task_runner->RunUntilIdle(); | 
|  |  | 
|  | // Verify the session is still alive and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | // There should be one task posted to migrate back to the default network in | 
|  | // kMinRetryTimeForDefaultNetworkSecs. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta expected_delay = | 
|  | base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs); | 
|  | EXPECT_EQ(expected_delay, task_runner->NextPendingTaskDelay()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Set up the third socket data provider for migrate back to default network. | 
|  | MockQuicData quic_data3; | 
|  | // Connectivity probe to be sent on the new path. | 
|  | quic_data3.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(3, false)); | 
|  | // Connectivity probe to receive from the server. | 
|  | quic_data3.AddRead(ASYNC, | 
|  | server_maker_.MakeConnectivityProbingPacket(2, false)); | 
|  | quic_data3.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data3.AddWrite(ASYNC, client_maker_.MakeAckPacket(4, 1, 2, 1, 1, true)); | 
|  | quic_data3.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 5, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 0, | 
|  | /*include_stop_sending_if_v99=*/true)); | 
|  | quic_data3.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Fast forward to fire the migrate back timer and verify the session | 
|  | // successfully migrates back to the default network. | 
|  | task_runner->FastForwardBy(expected_delay); | 
|  |  | 
|  | // Verify the session is still alive and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // There should be one task posted to one will resend a connectivity probe and | 
|  | // the other will retry migrate back, both are cancelled. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | task_runner->FastForwardBy( | 
|  | base::TimeDelta::FromSeconds(2 * kMinRetryTimeForDefaultNetworkSecs)); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | stream1.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data3.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data3.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that the connection will not attempt connection migration | 
|  | // (send connectivity probes on alternate path) when path degrading is detected | 
|  | // and handshake is not confirmed. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | NoMigrationOnPathDegradingBeforeHandshakeConfirmed) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | // Use cold start mode to send crypto message for handshake. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Ensure that session is alive but not active. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | QuicChromiumClientSession* session = GetPendingSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session will ignore the signal as handshake is not completed. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that if a connection is closed with | 
|  | // QUIC_NETWORK_IDLE_TIMEOUT before handshake is completed and there is no | 
|  | // alternate network, no new connection will be created. | 
|  | TEST_P(QuicStreamFactoryTest, NoAlternateNetworkBeforeHandshakeOnIdleTimeout) { | 
|  | TestNoAlternateNetworkBeforeHandshake(quic::QUIC_NETWORK_IDLE_TIMEOUT); | 
|  | } | 
|  |  | 
|  | // This test verifies that if a connection is closed with QUIC_HANDSHAKE_TIMEOUT | 
|  | // and there is no alternate network, no new connection will be created. | 
|  | TEST_P(QuicStreamFactoryTest, NoAlternateNetworkOnHandshakeTimeout) { | 
|  | TestNoAlternateNetworkBeforeHandshake(quic::QUIC_HANDSHAKE_TIMEOUT); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestNoAlternateNetworkBeforeHandshake( | 
|  | quic::QuicErrorCode quic_error) { | 
|  | DCHECK(quic_error == quic::QUIC_NETWORK_IDLE_TIMEOUT || | 
|  | quic_error == quic::QUIC_HANDSHAKE_TIMEOUT); | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | // Use cold start mode to send crypto message for handshake. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Ensure that session is alive but not active. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | QuicChromiumClientSession* session = GetPendingSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Cause the connection to report path degrading to the session. | 
|  | // Session will ignore the signal as handshake is not completed. | 
|  | session->connection()->OnPathDegradingTimeout(); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Cause the connection to close due to |quic_error| before handshake. | 
|  | quic::QuicString error_details; | 
|  | if (quic_error == quic::QUIC_NETWORK_IDLE_TIMEOUT) { | 
|  | error_details = "No recent network activity."; | 
|  | } else { | 
|  | error_details = "Handshake timeout expired."; | 
|  | } | 
|  | session->connection()->CloseConnection( | 
|  | quic_error, error_details, quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  |  | 
|  | // A task will be posted to clean up the session in the factory. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | task_runner->FastForwardUntilNoTasksRemain(); | 
|  |  | 
|  | // No new session should be created as there is no alternate network. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, NewConnectionBeforeHandshakeAfterIdleTimeout) { | 
|  | TestNewConnectionOnAlternateNetworkBeforeHandshake( | 
|  | quic::QUIC_NETWORK_IDLE_TIMEOUT); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, NewConnectionAfterHandshakeTimeout) { | 
|  | TestNewConnectionOnAlternateNetworkBeforeHandshake( | 
|  | quic::QUIC_HANDSHAKE_TIMEOUT); | 
|  | } | 
|  |  | 
|  | // Sets up a test to verify that a new connection will be created on the | 
|  | // alternate network after the initial connection fails before handshake with | 
|  | // signals delivered in the following order (alternate network is available): | 
|  | // - the default network is not able to complete crypto handshake; | 
|  | // - the original connection is closed with |quic_error|; | 
|  | // - a new connection is created on the alternate network and is able to finish | 
|  | //   crypto handshake; | 
|  | // - the new session on the alternate network attempts to migrate back to the | 
|  | //   default network by sending probes; | 
|  | // - default network being disconnected is delivered: session will stop probing | 
|  | //   the original network. | 
|  | // - alternate network is made by default. | 
|  | void QuicStreamFactoryTestBase:: | 
|  | TestNewConnectionOnAlternateNetworkBeforeHandshake( | 
|  | quic::QuicErrorCode quic_error) { | 
|  | DCHECK(quic_error == quic::QUIC_NETWORK_IDLE_TIMEOUT || | 
|  | quic_error == quic::QUIC_HANDSHAKE_TIMEOUT); | 
|  | test_params_.quic_retry_on_alternate_network_before_handshake = true; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | // Use cold start mode to send crypto message for handshake. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | // Socket data for connection on the default network. | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Socket data for connection on the alternate network. | 
|  | MockQuicData socket_data2; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause. | 
|  | // Change the encryption level after handshake is confirmed. | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); | 
|  | socket_data2.AddWrite( | 
|  | ASYNC, ConstructInitialSettingsPacket(2, &header_stream_offset)); | 
|  | socket_data2.AddWrite( | 
|  | ASYNC, ConstructGetRequestPacket( | 
|  | 3, GetNthClientInitiatedBidirectionalStreamId(0), true, true, | 
|  | &header_stream_offset)); | 
|  | socket_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 5, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Socket data for probing on the default network. | 
|  | MockQuicData probing_data; | 
|  | probing_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | probing_data.AddWrite(SYNCHRONOUS, | 
|  | client_maker_.MakeConnectivityProbingPacket(4, false)); | 
|  | probing_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Ensure that session is alive but not active. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | QuicChromiumClientSession* session = GetPendingSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_FALSE(failed_on_default_network_); | 
|  |  | 
|  | quic::QuicString error_details; | 
|  | if (quic_error == quic::QUIC_NETWORK_IDLE_TIMEOUT) { | 
|  | error_details = "No recent network activity."; | 
|  | } else { | 
|  | error_details = "Handshake timeout expired."; | 
|  | } | 
|  | session->connection()->CloseConnection( | 
|  | quic_error, error_details, quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  |  | 
|  | // A task will be posted to clean up the session in the factory. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | task_runner->FastForwardUntilNoTasksRemain(); | 
|  |  | 
|  | // Verify a new session is created on the alternate network. | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | QuicChromiumClientSession* session2 = GetPendingSession(host_port_pair_); | 
|  | EXPECT_NE(session, session2); | 
|  | EXPECT_TRUE(failed_on_default_network_); | 
|  |  | 
|  | // Confirm the handshake on the alternate network. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | // Resume the data now so that data can be sent and read. | 
|  | socket_data2.Resume(); | 
|  |  | 
|  | // Create the stream. | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | // Send the request. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | // Run the message loop to finish asynchronous mock write. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // Read the response. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // There should be a new task posted to migrate back to the default network. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs), | 
|  | next_task_delay); | 
|  | task_runner->FastForwardBy(next_task_delay); | 
|  |  | 
|  | // There should be two tasks posted. One will retry probing and the other | 
|  | // will retry migrate back. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | next_task_delay = task_runner->NextPendingTaskDelay(); | 
|  | EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), | 
|  | next_task_delay); | 
|  |  | 
|  | // Deliver the signal that the default network is disconnected. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | // Verify no connectivity probes will be sent as probing will be cancelled. | 
|  | task_runner->FastForwardUntilNoTasksRemain(); | 
|  | // Deliver the signal that the alternate network is made default. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Test that connection will be closed with PACKET_WRITE_ERROR if a write error | 
|  | // is triggered before handshake is confirmed and connection migration is turned | 
|  | // on. | 
|  | TEST_P(QuicStreamFactoryTest, MigrationOnWriteErrorBeforeHandshakeConfirmed) { | 
|  | DCHECK(!test_params_.quic_retry_on_alternate_network_before_handshake); | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  |  | 
|  | // Use unmocked crypto stream to do crypto connect. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | // Trigger PACKET_WRITE_ERROR when sending packets in crypto connect. | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request, should fail after the write of the CHLO fails. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult()); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Verify new requests can be sent normally. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | // Run the message loop to complete host resolution. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Complete handshake. QuicStreamFactory::Job should complete and succeed. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Create QuicHttpStream. | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Test that if the original connection is closed with QUIC_PACKET_WRITE_ERROR | 
|  | // before handshake is confirmed and new connection before handshake is turned | 
|  | // on, a new connection will be retried on the alternate network. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | RetryConnectionOnWriteErrorBeforeHandshakeConfirmed) { | 
|  | test_params_.quic_retry_on_alternate_network_before_handshake = true; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  |  | 
|  | // Use unmocked crypto stream to do crypto connect. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | // Socket data for connection on the default network. | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | // Trigger PACKET_WRITE_ERROR when sending packets in crypto connect. | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Socket data for connection on the alternate network. | 
|  | MockQuicData socket_data2; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause. | 
|  | // Change the encryption level after handshake is confirmed. | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); | 
|  | socket_data2.AddWrite( | 
|  | ASYNC, ConstructInitialSettingsPacket(2, &header_stream_offset)); | 
|  | socket_data2.AddWrite( | 
|  | ASYNC, ConstructGetRequestPacket( | 
|  | 3, GetNthClientInitiatedBidirectionalStreamId(0), true, true, | 
|  | &header_stream_offset)); | 
|  | socket_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request, should fail after the write of the CHLO fails. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | // Ensure that the session is alive but not active. | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | QuicChromiumClientSession* session = GetPendingSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  |  | 
|  | // Confirm the handshake on the alternate network. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Resume the data now so that data can be sent and read. | 
|  | socket_data2.Resume(); | 
|  |  | 
|  | // Create the stream. | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | // Send the request. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | // Run the message loop to finish asynchronous mock write. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // Read the response. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteError( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, which triggers | 
|  | // a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Run the message loop so that the migration attempt is executed and | 
|  | // data queued in the new socket is read by the packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify that session is alive and not marked as going awya. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorSynchronous) { | 
|  | TestMigrationOnWriteError(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorAsync) { | 
|  | TestMigrationOnWriteError(ASYNC); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNoNewNetwork( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Use the test task runner, to force the migration alarm timeout later. | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. This causes a write error, which triggers | 
|  | // a connection migration attempt. Since there are no networks | 
|  | // to migrate to, this causes the session to wait for a new network. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Complete any pending writes. Pending async MockQuicData writes | 
|  | // are run on the message loop, not on the test runner. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Write error causes migration task to be posted. Spin the loop. | 
|  | if (write_error_mode == ASYNC) | 
|  | runner_->RunNextTask(); | 
|  |  | 
|  | // Migration has not yet failed. The session should be alive and active. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_TRUE(session->connection()->writer()->IsWriteBlocked()); | 
|  |  | 
|  | // The migration will not fail until the migration alarm timeout. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Force migration alarm timeout to run. | 
|  | RunTestLoopUntilIdle(); | 
|  |  | 
|  | // The connection should be closed. A request for response headers | 
|  | // should fail. | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, callback_.WaitForResult()); | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, | 
|  | stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | NetErrorDetails error_details; | 
|  | stream->PopulateNetErrorDetails(&error_details); | 
|  | EXPECT_EQ(error_details.quic_connection_error, | 
|  | quic::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorNoNewNetworkSynchronous) { | 
|  | TestMigrationOnWriteErrorNoNewNetwork(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNoNewNetworkAsync) { | 
|  | TestMigrationOnWriteErrorNoNewNetwork(ASYNC); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithMultipleRequestsSync) { | 
|  | TestMigrationOnWriteErrorWithMultipleRequests(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithMultipleRequestsAsync) { | 
|  | TestMigrationOnWriteErrorWithMultipleRequests(ASYNC); | 
|  | } | 
|  |  | 
|  | // Sets up a test which verifies that connection migration on write error can | 
|  | // eventually succeed and rewrite the packet on the new network with *multiple* | 
|  | // migratable streams. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorWithMultipleRequests( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | quic::QUIC_STREAM_CANCELLED, 0, | 
|  | /*include_stop_sending_if_v99=*/true)); | 
|  |  | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request #1 and QuicHttpStream. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = GURL("https://www.example.org/"); | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Second request returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  | HttpRequestInfo request_info2; | 
|  | request_info2.method = "GET"; | 
|  | request_info2.url = GURL("https://www.example.org/"); | 
|  | request_info2.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, which triggers | 
|  | // a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Run the message loop so that the migration attempt is executed and | 
|  | // data queued in the new socket is read by the packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify session is still alive and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream1.reset(); | 
|  | stream2.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnWriteErrorWithMixedRequestsSync) { | 
|  | TestMigrationOnWriteErrorMixedStreams(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnWriteErrorWithMixedRequestsAsync) { | 
|  | TestMigrationOnWriteErrorMixedStreams(ASYNC); | 
|  | } | 
|  |  | 
|  | // Sets up a test that verifies connection migration manages to migrate to | 
|  | // alternate network after encountering a SYNC/ASYNC write error based on | 
|  | // |write_error_mode| on the original network. | 
|  | // Note there are mixed types of unfinished requests before migration: one | 
|  | // migratable and one non-migratable. The *migratable* one triggers write | 
|  | // error. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMixedStreams( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(packet_number++, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstPacket(packet_number++, true, | 
|  | GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | quic::QUIC_STREAM_CANCELLED, 0, | 
|  | /*include_stop_sending_if_v99=*/true)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndRstPacket( | 
|  | packet_number++, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request #1 and QuicHttpStream. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = GURL("https://www.example.org/"); | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Second request returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | HttpRequestInfo request_info2; | 
|  | request_info2.method = "GET"; | 
|  | request_info2.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info2.url = GURL("https://www.example.org/"); | 
|  | request_info2.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream 1. This should cause a write error, which | 
|  | // triggers a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Run the message loop so that the migration attempt is executed and | 
|  | // data queued in the new socket is read by the packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify that the session is still alive and not marked as going away. | 
|  | // Non-migratable stream should be closed due to migration. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream1.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnWriteErrorWithMixedRequests2Sync) { | 
|  | TestMigrationOnWriteErrorMixedStreams2(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateOnWriteErrorWithMixedRequests2Async) { | 
|  | TestMigrationOnWriteErrorMixedStreams2(ASYNC); | 
|  | } | 
|  |  | 
|  | // The one triggers write error is a non-migratable stream. | 
|  | // Sets up a test that verifies connection migration manages to migrate to | 
|  | // alternate network after encountering a SYNC/ASYNC write error based on | 
|  | // |write_error_mode| on the original network. | 
|  | // Note there are mixed types of unfinished requests before migration: one | 
|  | // migratable and one non-migratable. The *non-migratable* one triggers write | 
|  | // error. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMixedStreams2( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | int packet_number = 1; | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(packet_number++, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, | 
|  | ERR_ADDRESS_UNREACHABLE);  // Write error. | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | // The packet triggered writer error will be sent anyway even if the stream | 
|  | // will be cancelled later. | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | true, true, &header_stream_offset)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeRstPacket(packet_number++, true, | 
|  | GetNthClientInitiatedBidirectionalStreamId(1), | 
|  | quic::QUIC_STREAM_CANCELLED, 0, | 
|  | /*include_stop_sending_if_v99=*/true)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | ConstructGetRequestPacket(packet_number++, | 
|  | GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | true, true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeAckAndRstPacket( | 
|  | packet_number++, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request #1 and QuicHttpStream. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  |  | 
|  | HttpRequestInfo request_info1; | 
|  | request_info1.method = "GET"; | 
|  | request_info1.url = GURL("https://www.example.org/"); | 
|  | request_info1.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Second request returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | HttpRequestInfo request_info2; | 
|  | request_info2.method = "GET"; | 
|  | request_info2.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info2.url = GURL("https://www.example.org/"); | 
|  | request_info2.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(2u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream 2 which is non-migratable. This should cause a | 
|  | // write error, which triggers a connection migration attempt. | 
|  | HttpResponseInfo response2; | 
|  | HttpRequestHeaders request_headers2; | 
|  | EXPECT_EQ(OK, stream2->SendRequest(request_headers2, &response2, | 
|  | callback2.callback())); | 
|  |  | 
|  | // Run the message loop so that the migration attempt is executed and | 
|  | // data queued in the new socket is read by the packet reader. Session is | 
|  | // still alive and not marked as going away, non-migratable stream will be | 
|  | // closed. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream 1. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream1->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream1.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that when a connection encounters a packet write error, it | 
|  | // will cancel non-migratable streams, and migrate to the alternate network. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNonMigratableStream( | 
|  | IoMode write_error_mode, | 
|  | bool migrate_idle_sessions) { | 
|  | DVLOG(1) << "Write error mode: " | 
|  | << ((write_error_mode == SYNCHRONOUS) ? "SYNCHRONOUS" : "ASYNC"); | 
|  | DVLOG(1) << "Migrate idle sessions: " << migrate_idle_sessions; | 
|  | test_params_.quic_migrate_idle_sessions = migrate_idle_sessions; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData failed_socket_data; | 
|  | MockQuicData socket_data; | 
|  | if (migrate_idle_sessions) { | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | // The socket data provider for the original socket before migration. | 
|  | failed_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | failed_socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | failed_socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | failed_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // Although the write error occurs when writing a packet for the | 
|  | // non-migratable stream and the stream will be cancelled during migration, | 
|  | // the packet will still be retransimitted at the connection level. | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | // A RESET will be sent to the peer to cancel the non-migratable stream. | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 3, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } else { | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | } | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created, but marked as non-migratable. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION_TO_CELLULAR; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, which triggers | 
|  | // a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Run message loop to execute migration attempt. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Migration closes the non-migratable stream and: | 
|  | // if migrate idle session is enabled, it migrates to the alternate network | 
|  | // successfully; otherwise the connection is closed. | 
|  | EXPECT_EQ(migrate_idle_sessions, | 
|  | QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(migrate_idle_sessions, HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | if (migrate_idle_sessions) { | 
|  | EXPECT_TRUE(failed_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(failed_socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P( | 
|  | QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorNonMigratableStreamSync_DoNotMigrateIdleSessions) { | 
|  | TestMigrationOnWriteErrorNonMigratableStream(SYNCHRONOUS, false); | 
|  | } | 
|  |  | 
|  | TEST_P( | 
|  | QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorNonMigratableStreamAsync_DoNotMigrateIdleSessions) { | 
|  | TestMigrationOnWriteErrorNonMigratableStream(ASYNC, false); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorNonMigratableStreamSync_MigrateIdleSessions) { | 
|  | TestMigrationOnWriteErrorNonMigratableStream(SYNCHRONOUS, true); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorNonMigratableStreamAsync_MigrateIdleSessions) { | 
|  | TestMigrationOnWriteErrorNonMigratableStream(ASYNC, true); | 
|  | } | 
|  |  | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMigrationDisabled( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set session config to have connection migration disabled. | 
|  | quic::test::QuicConfigPeer::SetReceivedDisableConnectionMigration( | 
|  | session->config()); | 
|  | EXPECT_TRUE(session->config()->DisableConnectionMigration()); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, which triggers | 
|  | // a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | // Run message loop to execute migration attempt. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // Migration fails, and session is closed and deleted. | 
|  | EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorMigrationDisabledSynchronous) { | 
|  | TestMigrationOnWriteErrorMigrationDisabled(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorMigrationDisabledAsync) { | 
|  | TestMigrationOnWriteErrorMigrationDisabled(ASYNC); | 
|  | } | 
|  |  | 
|  | // Sets up a test which verifies that connection migration on write error can | 
|  | // eventually succeed and rewrite the packet on the new network with singals | 
|  | // delivered in the following order (alternate network is always availabe): | 
|  | // - original network encounters a SYNC/ASYNC write error based on | 
|  | //   |write_error_mode_on_old_network|, the packet failed to be written is | 
|  | //   cached, session migrates immediately to the alternate network. | 
|  | // - an immediate SYNC/ASYNC write error based on | 
|  | //   |write_error_mode_on_new_network| is encountered after migration to the | 
|  | //   alternate network, session migrates immediately to the original network. | 
|  | // - an immediate SYNC/ASYNC write error based on | 
|  | //   |write_error_mode_on_old_network| is encountered after migration to the | 
|  | //   original network, session migrates immediately to the alternate network. | 
|  | // - finally, session successfully sends the packet and reads the response on | 
|  | //   the alternate network. | 
|  | // TODO(zhongyi): once https://crbug.com/855666 is fixed, this test should be | 
|  | // modified to test that session is closed early if hopping between networks | 
|  | // with consecutive write errors is detected. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnMultipleWriteErrors( | 
|  | IoMode write_error_mode_on_old_network, | 
|  | IoMode write_error_mode_on_new_network) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set up the socket data used by the original network, which encounters a | 
|  | // write erorr. | 
|  | MockQuicData socket_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data1.AddWrite(write_error_mode_on_old_network, | 
|  | ERR_ADDRESS_UNREACHABLE);  // Write Error | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the socket data used by the alternate network, which also | 
|  | // encounters a write error. | 
|  | MockQuicData failed_quic_data2; | 
|  | failed_quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | failed_quic_data2.AddWrite(write_error_mode_on_new_network, ERR_FAILED); | 
|  | failed_quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the third socket data used by original network, which encounters a | 
|  | // write error again. | 
|  | MockQuicData failed_quic_data1; | 
|  | failed_quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | failed_quic_data1.AddWrite(write_error_mode_on_old_network, ERR_FAILED); | 
|  | failed_quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up the last socket data used by the alternate network, which will | 
|  | // finish migration successfully. The request is rewritten to this new socket, | 
|  | // and the response to the request is read on this socket. | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | // This should encounter a write error on network 1, | 
|  | // then migrate to network 2, which encounters another write error, | 
|  | // and migrate again to network 1, which encoutners one more write error. | 
|  | // Finally the session migrates to network 2 successfully. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(failed_quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(failed_quic_data2.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(failed_quic_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(failed_quic_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncSync) { | 
|  | TestMigrationOnMultipleWriteErrors( | 
|  | /*write_error_mode_on_old_network*/ SYNCHRONOUS, | 
|  | /*write_error_mode_on_new_network*/ SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncAsync) { | 
|  | TestMigrationOnMultipleWriteErrors( | 
|  | /*write_error_mode_on_old_network*/ SYNCHRONOUS, | 
|  | /*write_error_mode_on_new_network*/ ASYNC); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncSync) { | 
|  | TestMigrationOnMultipleWriteErrors( | 
|  | /*write_error_mode_on_old_network*/ ASYNC, | 
|  | /*write_error_mode_on_new_network*/ SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncAsync) { | 
|  | TestMigrationOnMultipleWriteErrors( | 
|  | /*write_error_mode_on_old_network*/ ASYNC, | 
|  | /*write_error_mode_on_new_network*/ ASYNC); | 
|  | } | 
|  |  | 
|  | // Verifies that a connection is closed when connection migration is triggered | 
|  | // on network being disconnected and the handshake is not confirmed. | 
|  | TEST_P(QuicStreamFactoryTest, NoMigrationBeforeHandshakeOnNetworkDisconnected) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  |  | 
|  | // Use cold start mode to do crypto connect, and send CHLO packet on wire. | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1)); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | // Deliver the network notification, which should cause the connection to be | 
|  | // closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | EXPECT_EQ(ERR_NETWORK_CHANGED, callback_.WaitForResult()); | 
|  |  | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Sets up the connection migration test where network change notification is | 
|  | // queued BEFORE connection migration attempt on write error is posted. | 
|  | void QuicStreamFactoryTestBase:: | 
|  | TestMigrationOnNetworkNotificationWithWriteErrorQueuedLater( | 
|  | bool disconnected) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // First queue a network change notification in the message loop. | 
|  | if (disconnected) { | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkDisconnected(kDefaultNetworkForTests); | 
|  | } else { | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kNewNetworkForTests); | 
|  | } | 
|  | // Send GET request on stream. This should cause a write error, | 
|  | // which triggers a connection migration attempt. This will queue a | 
|  | // migration attempt behind the notification in the message loop. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // Verify the session is still alive and not marked as going away post | 
|  | // migration. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that session attempts connection migration successfully | 
|  | // with signals delivered in the following order (alternate network is always | 
|  | // available): | 
|  | // - a notification that default network is disconnected is queued. | 
|  | // - write error is triggered: session posts a task to attempt connection | 
|  | //   migration, |migration_pending_| set to true. | 
|  | // - default network disconnected is delivered: session immediately migrates to | 
|  | //   the alternate network, |migration_pending_| set to false. | 
|  | // - connection migration on write error attempt aborts: writer encountered | 
|  | //   error is no longer in active use. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateOnNetworkDisconnectedWithWriteErrorQueuedLater) { | 
|  | TestMigrationOnNetworkNotificationWithWriteErrorQueuedLater( | 
|  | /*disconnected=*/true); | 
|  | } | 
|  |  | 
|  | // This test verifies that session attempts connection migration successfully | 
|  | // with signals delivered in the following order (alternate network is always | 
|  | // available): | 
|  | // - a notification that alternate network is made default is queued. | 
|  | // - write error is triggered: session posts a task to attempt connection | 
|  | //   migration, block future migrations. | 
|  | // - new default notification is delivered: migrate back timer spins and task is | 
|  | //   posted to migrate to the new default network. | 
|  | // - connection migration on write error attempt proceeds successfully: session | 
|  | // is | 
|  | //   marked as going away, future migrations unblocked. | 
|  | // - migrate back to default network task executed: session is already on the | 
|  | //   default network, no-op. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateOnWriteErrorWithNetworkMadeDefaultQueuedEarlier) { | 
|  | TestMigrationOnNetworkNotificationWithWriteErrorQueuedLater( | 
|  | /*disconnected=*/false); | 
|  | } | 
|  |  | 
|  | // Sets up the connection migration test where network change notification is | 
|  | // queued AFTER connection migration attempt on write error is posted. | 
|  | void QuicStreamFactoryTestBase:: | 
|  | TestMigrationOnWriteErrorWithNotificationQueuedLater(bool disconnected) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, | 
|  | // which triggers a connection migration attempt. This will queue a | 
|  | // migration attempt in the message loop. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Now queue a network change notification in the message loop behind | 
|  | // the migration attempt. | 
|  | if (disconnected) { | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkDisconnected(kDefaultNetworkForTests); | 
|  | } else { | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->QueueNetworkMadeDefault(kNewNetworkForTests); | 
|  | } | 
|  |  | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // Verify session is still alive and not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that session attempts connection migration successfully | 
|  | // with signals delivered in the following order (alternate network is always | 
|  | // available): | 
|  | // - write error is triggered: session posts a task to complete connection | 
|  | //   migration. | 
|  | // - a notification that alternate network is made default is queued. | 
|  | // - connection migration attempt proceeds successfully, session is marked as | 
|  | //   going away. | 
|  | // - new default notification is delivered after connection migration has been | 
|  | //   completed. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateOnWriteErrorWithNetworkMadeDefaultQueuedLater) { | 
|  | TestMigrationOnWriteErrorWithNotificationQueuedLater(/*disconnected=*/false); | 
|  | } | 
|  |  | 
|  | // This test verifies that session attempts connection migration successfully | 
|  | // with signals delivered in the following order (alternate network is always | 
|  | // available): | 
|  | // - write error is triggered: session posts a task to complete connection | 
|  | //   migration. | 
|  | // - a notification that default network is diconnected is queued. | 
|  | // - connection migration attempt proceeds successfully, session is marked as | 
|  | //   going away. | 
|  | // - disconnect notification is delivered after connection migration has been | 
|  | //   completed. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateOnWriteErrorWithNetworkDisconnectedQueuedLater) { | 
|  | TestMigrationOnWriteErrorWithNotificationQueuedLater(/*disconnected=*/true); | 
|  | } | 
|  |  | 
|  | // This tests connection migration on write error with signals delivered in the | 
|  | // following order: | 
|  | // - a synchronous/asynchronous write error is triggered base on | 
|  | //   |write_error_mode|: connection migration attempt is posted. | 
|  | // - old default network disconnects, migration waits for a new network. | 
|  | // - after a pause, new network is connected: session will migrate to new | 
|  | //   network immediately. | 
|  | // - migration on writer error is exectued and aborts as writer passed in is no | 
|  | //   longer active in use. | 
|  | // - new network is made default. | 
|  | void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorPauseBeforeConnected( | 
|  | IoMode write_error_mode) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Use the test task runner. | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, ERR_FAILED); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = url_; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // The connection should still be alive, not marked as going away. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | // The response to the earlier request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // On a DISCONNECTED notification, nothing happens. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | // Add a new network and notify the stream factory of a new connected network. | 
|  | // This causes a PING packet to be sent over the new network. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList({kNewNetworkForTests}); | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Ensure that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Run the message loop migration for write error can finish. | 
|  | runner_->RunUntilIdle(); | 
|  |  | 
|  | // Response headers are received over the new network. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Check that the session is still alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // There should be no posted tasks not executed, no way to migrate back to | 
|  | // default network. | 
|  | EXPECT_TRUE(runner_->GetPostedTasks().empty()); | 
|  |  | 
|  | // Receive signal to mark new network as default. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnSyncWriteErrorPauseBeforeConnected) { | 
|  | TestMigrationOnWriteErrorPauseBeforeConnected(SYNCHRONOUS); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnAsyncWriteErrorPauseBeforeConnected) { | 
|  | TestMigrationOnWriteErrorPauseBeforeConnected(ASYNC); | 
|  | } | 
|  |  | 
|  | // This test verifies that when session successfully migrate to the alternate | 
|  | // network, packet write error on the old writer will be ignored and will not | 
|  | // trigger connection migration on write error. | 
|  | TEST_P(QuicStreamFactoryTest, IgnoreWriteErrorFromOldWriterAfterMigration) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner so that we can verify whether the migrate on | 
|  | // write error task is posted. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | socket_data.AddWrite(ASYNC, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(3, /*include_version=*/true)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | // Now notify network is disconnected, cause the migration to complete | 
|  | // immediately. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | // There will be two pending task, one will complete migration with no delay | 
|  | // and the other will attempt to migrate back to the default network with | 
|  | // delay. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Complete migration. | 
|  | task_runner->RunUntilIdle(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Resume the old socket data, a write error will be delivered to the old | 
|  | // packet writer. Verify no additional task is posted. | 
|  | socket_data.Resume(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that when session successfully migrate to the alternate | 
|  | // network, packet read error on the old reader will be ignored and will not | 
|  | // close the connection. | 
|  | TEST_P(QuicStreamFactoryTest, IgnoreReadErrorFromOldReaderAfterMigration) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | socket_data.AddRead(ASYNC, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is written to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 3, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | // Now notify network is disconnected, cause the migration to complete | 
|  | // immediately. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | // There will be two pending task, one will complete migration with no delay | 
|  | // and the other will attempt to migrate back to the default network with | 
|  | // delay. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Complete migration. | 
|  | task_runner->RunUntilIdle(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Resume the old socket data, a read error will be delivered to the old | 
|  | // packet reader. Verify that the session is not affected. | 
|  | socket_data.Resume(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that after migration on network is executed, packet | 
|  | // read error on the old reader will be ignored and will not close the | 
|  | // connection. | 
|  | TEST_P(QuicStreamFactoryTest, IgnoreReadErrorOnOldReaderDuringMigration) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | socket_data.AddRead(ASYNC, ERR_ADDRESS_UNREACHABLE); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is written to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 3, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | // Now notify network is disconnected, cause the migration to complete | 
|  | // immediately. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | // There will be two pending task, one will complete migration with no delay | 
|  | // and the other will attempt to migrate back to the default network with | 
|  | // delay. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Resume the old socket data, a read error will be delivered to the old | 
|  | // packet reader. Verify that the session is not affected. | 
|  | socket_data.Resume(); | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Complete migration. | 
|  | task_runner->RunUntilIdle(); | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that after migration on write error is posted, packet | 
|  | // read error on the old reader will be ignored and will not close the | 
|  | // connection. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | IgnoreReadErrorOnOldReaderDuringPendingMigrationOnWriteError) { | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(ASYNC, ERR_FAILED);              // Write error. | 
|  | socket_data.AddRead(ASYNC, ERR_ADDRESS_UNREACHABLE);  // Read error. | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is written to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  |  | 
|  | socket_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause. | 
|  | socket_data1.AddRead(ASYNC, ERR_FAILED);  // Read error to close connection. | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | // Run the message loop to complete asynchronous write and read with errors. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // There will be one pending task to complete migration on write error. | 
|  | // Verify session is not closed with read error. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Complete migration. | 
|  | task_runner->RunUntilIdle(); | 
|  | // There will be one more task posted attempting to migrate back to the | 
|  | // default network. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Resume to consume the read error on new socket, which will close | 
|  | // the connection. | 
|  | socket_data1.Resume(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Migrate on asynchronous write error, old network disconnects after alternate | 
|  | // network connects. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithDisconnectAfterConnectAysnc) { | 
|  | TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | ASYNC, /*disconnect_before_connect*/ false); | 
|  | } | 
|  |  | 
|  | // Migrate on synchronous write error, old network disconnects after alternate | 
|  | // network connects. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithDisconnectAfterConnectSync) { | 
|  | TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | SYNCHRONOUS, /*disconnect_before_connect*/ false); | 
|  | } | 
|  |  | 
|  | // Migrate on asynchronous write error, old network disconnects before alternate | 
|  | // network connects. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithDisconnectBeforeConnectAysnc) { | 
|  | TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | ASYNC, /*disconnect_before_connect*/ true); | 
|  | } | 
|  |  | 
|  | // Migrate on synchronous write error, old network disconnects before alternate | 
|  | // network connects. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | MigrateSessionOnWriteErrorWithDisconnectBeforeConnectSync) { | 
|  | TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | SYNCHRONOUS, /*disconnect_before_connect*/ true); | 
|  | } | 
|  |  | 
|  | // Setps up test which verifies that session successfully migrate to alternate | 
|  | // network with signals delivered in the following order: | 
|  | // *NOTE* Signal (A) and (B) can reverse order based on | 
|  | // |disconnect_before_connect|. | 
|  | // - (No alternate network is connected) session connects to | 
|  | //   kDefaultNetworkForTests. | 
|  | // - An async/sync write error is encountered based on |write_error_mode|: | 
|  | //   session posted task to migrate session on write error. | 
|  | // - Posted task is executed, miration moves to pending state due to lack of | 
|  | //   alternate network. | 
|  | // - (A) An alternate network is connected, pending migration completes. | 
|  | // - (B) Old default network disconnects, no migration will be attempted as | 
|  | //   session has already migrate to the alternate network. | 
|  | // - The alternate network is made default. | 
|  | void QuicStreamFactoryTestBase:: | 
|  | TestMigrationOnWriteErrorWithMultipleNotifications( | 
|  | IoMode write_error_mode, | 
|  | bool disconnect_before_connect) { | 
|  | InitializeConnectionMigrationV2Test({kDefaultNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data.AddWrite(write_error_mode, ERR_FAILED);  // Write error. | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. This should cause a write error, which triggers | 
|  | // a connection migration attempt. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  | // Run the message loop so that posted task to migrate to socket will be | 
|  | // executed. A new task will be posted to wait for a new network. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // In this particular code path, the network will not yet be marked | 
|  | // as going away and the session will still be alive. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 3, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->SetConnectedNetworksList( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | if (disconnect_before_connect) { | 
|  | // Now deliver a DISCONNECT notification. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // Now deliver a CONNECTED notification and completes migration. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  | } else { | 
|  | // Now deliver a CONNECTED notification and completes migration. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkConnected(kNewNetworkForTests); | 
|  |  | 
|  | // Now deliver a DISCONNECT notification. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  | } | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // This is the callback for the response headers that returned | 
|  | // pending previously, because no result was available.  Check that | 
|  | // the result is now available due to the successful migration. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | // Deliver a MADEDEFAULT notification. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kNewNetworkForTests); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(session, GetActiveSession(host_port_pair_)); | 
|  |  | 
|  | stream.reset(); | 
|  | stream2.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies after session migrates off the default network, it keeps | 
|  | // retrying migrate back to the default network until successfully gets on the | 
|  | // default network or the idle migration period threshold is exceeded. | 
|  | // The default threshold is 30s. | 
|  | TEST_P(QuicStreamFactoryTest, DefaultIdleMigrationPeriod) { | 
|  | test_params_.quic_migrate_idle_sessions = true; | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner and a test tick tock. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  | QuicStreamFactoryPeer::SetTickClock(factory_.get(), | 
|  | task_runner->GetMockTickClock()); | 
|  |  | 
|  | MockQuicData default_socket_data; | 
|  | default_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | default_socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | default_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | MockQuicData alternate_socket_data; | 
|  | alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // Ping packet to send after migration. | 
|  | alternate_socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up probing socket for migrating back to the default network. | 
|  | MockQuicData quic_data;                          // retry count: 0. | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data1;                          // retry count: 1 | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2;                          // retry count: 2 | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data3;                          // retry count: 3 | 
|  | quic_data3.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data3.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data3.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data4;                          // retry count: 4 | 
|  | quic_data4.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data4.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data4.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data5;                          // retry count: 5 | 
|  | quic_data5.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data5.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data5.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Ensure that session is active. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there are no active streams, | 
|  | // the session will be closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // The nearest task will complete migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(base::TimeDelta()); | 
|  |  | 
|  | // The migrate back timer will fire. Due to default network | 
|  | // being disconnected, no attempt will be exercised to migrate back. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs), | 
|  | task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(task_runner->NextPendingTaskDelay()); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Deliver the signal that the old default network now backs up. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | // A task is posted to migrate back to the default network immediately. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(base::TimeDelta()); | 
|  |  | 
|  | // Retry migrate back in 1, 2, 4, 8, 16s. | 
|  | // Session will be closed due to idle migration timeout. | 
|  | for (int i = 0; i < 5; i++) { | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | // A task is posted to migrate back to the default network in 2^i seconds. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(UINT64_C(1) << i), | 
|  | task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(task_runner->NextPendingTaskDelay()); | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE(default_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(default_socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(alternate_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(alternate_socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CustomIdleMigrationPeriod) { | 
|  | // The customized threshold is 15s. | 
|  | test_params_.quic_migrate_idle_sessions = true; | 
|  | test_params_.quic_idle_session_migration_period = | 
|  | base::TimeDelta::FromSeconds(15); | 
|  | InitializeConnectionMigrationV2Test( | 
|  | {kDefaultNetworkForTests, kNewNetworkForTests}); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Using a testing task runner and a test tick tock. | 
|  | auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); | 
|  | QuicStreamFactoryPeer::SetTickClock(factory_.get(), | 
|  | task_runner->GetMockTickClock()); | 
|  |  | 
|  | MockQuicData default_socket_data; | 
|  | default_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | default_socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | default_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up second socket data provider that is used after migration. | 
|  | MockQuicData alternate_socket_data; | 
|  | alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | // Ping packet to send after migration. | 
|  | alternate_socket_data.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(2, /*include_version=*/true)); | 
|  | alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Set up probing socket for migrating back to the default network. | 
|  | MockQuicData quic_data;                          // retry count: 0. | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data1;                          // retry count: 1 | 
|  | quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data1.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2;                          // retry count: 2 | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data2.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data3;                          // retry count: 3 | 
|  | quic_data3.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data3.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data3.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data4;                          // retry count: 4 | 
|  | quic_data4.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read. | 
|  | quic_data4.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); | 
|  | quic_data4.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Ensure that session is active. | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Trigger connection migration. Since there are no active streams, | 
|  | // the session will be closed. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkDisconnected(kDefaultNetworkForTests); | 
|  |  | 
|  | // The nearest task will complete migration. | 
|  | EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(base::TimeDelta()); | 
|  |  | 
|  | // The migrate back timer will fire. Due to default network | 
|  | // being disconnected, no attempt will be exercised to migrate back. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs), | 
|  | task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(task_runner->NextPendingTaskDelay()); | 
|  | EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); | 
|  |  | 
|  | // Deliver the signal that the old default network now backs up. | 
|  | scoped_mock_network_change_notifier_->mock_network_change_notifier() | 
|  | ->NotifyNetworkMadeDefault(kDefaultNetworkForTests); | 
|  |  | 
|  | // A task is posted to migrate back to the default network immediately. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta(), task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(base::TimeDelta()); | 
|  |  | 
|  | // Retry migrate back in 1, 2, 4, 8s. | 
|  | // Session will be closed due to idle migration timeout. | 
|  | for (int i = 0; i < 4; i++) { | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | // A task is posted to migrate back to the default network in 2^i seconds. | 
|  | EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(UINT64_C(1) << i), | 
|  | task_runner->NextPendingTaskDelay()); | 
|  | task_runner->FastForwardBy(task_runner->NextPendingTaskDelay()); | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE(default_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(default_socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(alternate_socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(alternate_socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerMigration) { | 
|  | test_params_.quic_allow_server_migration = true; | 
|  | Initialize(); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data1; | 
|  | quic::QuicStreamOffset header_stream_offset = 0; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructInitialSettingsPacket(1, &header_stream_offset)); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, ConstructGetRequestPacket( | 
|  | 2, GetNthClientInitiatedBidirectionalStreamId(0), true, | 
|  | true, &header_stream_offset)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Send GET request on stream. | 
|  | HttpResponseInfo response; | 
|  | HttpRequestHeaders request_headers; | 
|  | EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, | 
|  | callback_.callback())); | 
|  |  | 
|  | IPEndPoint ip; | 
|  | session->GetDefaultSocket()->GetPeerAddress(&ip); | 
|  | DVLOG(1) << "Socket connected to: " << ip.address().ToString() << " " | 
|  | << ip.port(); | 
|  |  | 
|  | // Set up second socket data provider that is used after | 
|  | // migration. The request is rewritten to this new socket, and the | 
|  | // response to the request is read on this new socket. | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakePingPacket(3, /*include_version=*/true)); | 
|  | socket_data2.AddRead( | 
|  | ASYNC, | 
|  | ConstructOkResponsePacket( | 
|  | 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( | 
|  | 4, false, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED, 1, 1, 1, true)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | const uint8_t kTestIpAddress[] = {1, 2, 3, 4}; | 
|  | const uint16_t kTestPort = 123; | 
|  | session->Migrate(NetworkChangeNotifier::kInvalidNetworkHandle, | 
|  | IPEndPoint(IPAddress(kTestIpAddress), kTestPort), true, | 
|  | net_log_); | 
|  |  | 
|  | session->GetDefaultSocket()->GetPeerAddress(&ip); | 
|  | DVLOG(1) << "Socket migrated to: " << ip.address().ToString() << " " | 
|  | << ip.port(); | 
|  |  | 
|  | // The session should be alive and active. | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_EQ(1u, session->GetNumActiveStreams()); | 
|  |  | 
|  | // Run the message loop so that data queued in the new socket is read by the | 
|  | // packet reader. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Verify that response headers on the migrated socket were delivered to the | 
|  | // stream. | 
|  | EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | 
|  | EXPECT_EQ(200, response.headers->response_code()); | 
|  |  | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv4) { | 
|  | // Add alternate IPv4 server address to config. | 
|  | IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123); | 
|  | quic::QuicConfig config; | 
|  | config.SetAlternateServerAddressToSend( | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(alt_address))); | 
|  | VerifyServerMigration(config, alt_address); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv6) { | 
|  | // Add a resolver rule to make initial connection to an IPv6 address. | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "fe80::aebc:32ff:febb:1e33", ""); | 
|  | // Add alternate IPv6 server address to config. | 
|  | IPEndPoint alt_address = IPEndPoint( | 
|  | IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), 123); | 
|  | quic::QuicConfig config; | 
|  | config.SetAlternateServerAddressToSend( | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(alt_address))); | 
|  | VerifyServerMigration(config, alt_address); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) { | 
|  | // Add a resolver rule to make initial connection to an IPv6 address. | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "fe80::aebc:32ff:febb:1e33", ""); | 
|  | // Add alternate IPv4 server address to config. | 
|  | IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123); | 
|  | quic::QuicConfig config; | 
|  | config.SetAlternateServerAddressToSend( | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(alt_address))); | 
|  | IPEndPoint expected_address( | 
|  | ConvertIPv4ToIPv4MappedIPv6(alt_address.address()), alt_address.port()); | 
|  | VerifyServerMigration(config, expected_address); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) { | 
|  | test_params_.quic_allow_server_migration = true; | 
|  | Initialize(); | 
|  |  | 
|  | // Add a resolver rule to make initial connection to an IPv4 address. | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), "1.2.3.4", | 
|  | ""); | 
|  | // Add alternate IPv6 server address to config. | 
|  | IPEndPoint alt_address = IPEndPoint( | 
|  | IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), 123); | 
|  | quic::QuicConfig config; | 
|  | config.SetAlternateServerAddressToSend( | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(alt_address))); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | crypto_client_stream_factory_.SetConfig(config); | 
|  |  | 
|  | // Set up only socket data provider. | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthClientInitiatedBidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Create request and QuicHttpStream. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Cause QUIC stream to be created. | 
|  | HttpRequestInfo request_info; | 
|  | request_info.method = "GET"; | 
|  | request_info.url = GURL("https://www.example.org/"); | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | // Ensure that session is alive and active. | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | IPEndPoint actual_address; | 
|  | session->GetDefaultSocket()->GetPeerAddress(&actual_address); | 
|  | // No migration should have happened. | 
|  | IPEndPoint expected_address = | 
|  | IPEndPoint(IPAddress(1, 2, 3, 4), kDefaultServerPort); | 
|  | EXPECT_EQ(actual_address, expected_address); | 
|  | DVLOG(1) << "Socket connected to: " << actual_address.address().ToString() | 
|  | << " " << actual_address.port(); | 
|  | DVLOG(1) << "Expected address: " << expected_address.address().ToString() | 
|  | << " " << expected_address.port(); | 
|  |  | 
|  | stream.reset(); | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, OnCertDBChanged) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, nullptr)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream); | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | // Change the CA cert and verify that stream saw the event. | 
|  | factory_->OnCertDBChanged(); | 
|  |  | 
|  | EXPECT_FALSE(factory_->require_confirmation()); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_FALSE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Now attempting to request a stream to the same origin should create | 
|  | // a new session. | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  | EXPECT_NE(session, session2); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); | 
|  | EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2)); | 
|  |  | 
|  | stream2.reset(); | 
|  | stream.reset(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) { | 
|  | Initialize(); | 
|  |  | 
|  | std::vector<string> cannoncial_suffixes; | 
|  | cannoncial_suffixes.push_back(string(".c.youtube.com")); | 
|  | cannoncial_suffixes.push_back(string(".googlevideo.com")); | 
|  |  | 
|  | for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) { | 
|  | string r1_host_name("r1"); | 
|  | string r2_host_name("r2"); | 
|  | r1_host_name.append(cannoncial_suffixes[i]); | 
|  | r2_host_name.append(cannoncial_suffixes[i]); | 
|  |  | 
|  | HostPortPair host_port_pair1(r1_host_name, 80); | 
|  | quic::QuicCryptoClientConfig* crypto_config = | 
|  | QuicStreamFactoryPeer::GetCryptoConfig(factory_.get()); | 
|  | quic::QuicServerId server_id1(host_port_pair1.host(), | 
|  | host_port_pair1.port(), privacy_mode_); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached1 = | 
|  | crypto_config->LookupOrCreate(server_id1); | 
|  | EXPECT_FALSE(cached1->proof_valid()); | 
|  | EXPECT_TRUE(cached1->source_address_token().empty()); | 
|  |  | 
|  | // Mutate the cached1 to have different data. | 
|  | // TODO(rtenneti): mutate other members of CachedState. | 
|  | cached1->set_source_address_token(r1_host_name); | 
|  | cached1->SetProofValid(); | 
|  |  | 
|  | HostPortPair host_port_pair2(r2_host_name, 80); | 
|  | quic::QuicServerId server_id2(host_port_pair2.host(), | 
|  | host_port_pair2.port(), privacy_mode_); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached2 = | 
|  | crypto_config->LookupOrCreate(server_id2); | 
|  | EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token()); | 
|  | EXPECT_TRUE(cached2->proof_valid()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) { | 
|  | Initialize(); | 
|  | std::vector<string> cannoncial_suffixes; | 
|  | cannoncial_suffixes.push_back(string(".c.youtube.com")); | 
|  | cannoncial_suffixes.push_back(string(".googlevideo.com")); | 
|  |  | 
|  | for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) { | 
|  | string r3_host_name("r3"); | 
|  | string r4_host_name("r4"); | 
|  | r3_host_name.append(cannoncial_suffixes[i]); | 
|  | r4_host_name.append(cannoncial_suffixes[i]); | 
|  |  | 
|  | HostPortPair host_port_pair1(r3_host_name, 80); | 
|  | quic::QuicCryptoClientConfig* crypto_config = | 
|  | QuicStreamFactoryPeer::GetCryptoConfig(factory_.get()); | 
|  | quic::QuicServerId server_id1(host_port_pair1.host(), | 
|  | host_port_pair1.port(), privacy_mode_); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached1 = | 
|  | crypto_config->LookupOrCreate(server_id1); | 
|  | EXPECT_FALSE(cached1->proof_valid()); | 
|  | EXPECT_TRUE(cached1->source_address_token().empty()); | 
|  |  | 
|  | // Mutate the cached1 to have different data. | 
|  | // TODO(rtenneti): mutate other members of CachedState. | 
|  | cached1->set_source_address_token(r3_host_name); | 
|  | cached1->SetProofInvalid(); | 
|  |  | 
|  | HostPortPair host_port_pair2(r4_host_name, 80); | 
|  | quic::QuicServerId server_id2(host_port_pair2.host(), | 
|  | host_port_pair2.port(), privacy_mode_); | 
|  | quic::QuicCryptoClientConfig::CachedState* cached2 = | 
|  | crypto_config->LookupOrCreate(server_id2); | 
|  | EXPECT_NE(cached1->source_address_token(), cached2->source_address_token()); | 
|  | EXPECT_TRUE(cached2->source_address_token().empty()); | 
|  | EXPECT_FALSE(cached2->proof_valid()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) { | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(false); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | // If we are waiting for disk cache, we would have posted a task. Verify that | 
|  | // the CancelWaitForDataReady task hasn't been posted. | 
|  | ASSERT_EQ(0u, runner_->GetPostedTasks().size()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) { | 
|  | test_params_.quic_reduced_ping_timeout_seconds = 10; | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, | 
|  | ConstructInitialSettingsPacket(1, nullptr)); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | HostPortPair server2(kServer2HostName, kDefaultServerPort); | 
|  |  | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::CONFIRM_HANDSHAKE); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  | host_resolver_->rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); | 
|  |  | 
|  | // Quic should use default PING timeout when no previous connection times out | 
|  | // with open stream. | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(quic::kPingTimeoutSecs), | 
|  | QuicStreamFactoryPeer::GetPingTimeout(factory_.get())); | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(quic::kPingTimeoutSecs), | 
|  | session->connection()->ping_timeout()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | HttpRequestInfo request_info; | 
|  | request_info.traffic_annotation = | 
|  | MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); | 
|  | EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  |  | 
|  | DVLOG(1) | 
|  | << "Created 1st session and initialized a stream. Now trigger timeout"; | 
|  | session->connection()->CloseConnection( | 
|  | quic::QUIC_NETWORK_IDLE_TIMEOUT, "test", | 
|  | quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  | // Need to spin the loop now to ensure that | 
|  | // QuicStreamFactory::OnSessionClosed() runs. | 
|  | base::RunLoop run_loop; | 
|  | run_loop.RunUntilIdle(); | 
|  |  | 
|  | // The first connection times out with open stream, QUIC should reduce initial | 
|  | // PING time for subsequent connections. | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(10), | 
|  | QuicStreamFactoryPeer::GetPingTimeout(factory_.get())); | 
|  |  | 
|  | // Test two-in-a-row timeouts with open streams. | 
|  | DVLOG(1) << "Create 2nd session and timeout with open stream"; | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, | 
|  | request2.Request( | 
|  | server2, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback2.callback())); | 
|  | QuicChromiumClientSession* session2 = GetActiveSession(server2); | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(10), | 
|  | session2->connection()->ping_timeout()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  | EXPECT_EQ(OK, | 
|  | stream2->InitializeStream(&request_info, false, DEFAULT_PRIORITY, | 
|  | net_log_, CompletionOnceCallback())); | 
|  | session2->connection()->CloseConnection( | 
|  | quic::QUIC_NETWORK_IDLE_TIMEOUT, "test", | 
|  | quic::ConnectionCloseBehavior::SILENT_CLOSE); | 
|  | // Need to spin the loop now to ensure that | 
|  | // QuicStreamFactory::OnSessionClosed() runs. | 
|  | base::RunLoop run_loop2; | 
|  | run_loop2.RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Verifies that the QUIC stream factory is initialized correctly. | 
|  | TEST_P(QuicStreamFactoryTest, MaybeInitialize) { | 
|  | VerifyInitialization(); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, StartCertVerifyJob) { | 
|  | Initialize(); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Save current state of |race_cert_verification|. | 
|  | bool race_cert_verification = | 
|  | QuicStreamFactoryPeer::GetRaceCertVerification(factory_.get()); | 
|  |  | 
|  | // Load server config. | 
|  | HostPortPair host_port_pair(kDefaultServerHostName, kDefaultServerPort); | 
|  | quic::QuicServerId quic_server_id(host_port_pair_.host(), | 
|  | host_port_pair_.port(), | 
|  | privacy_mode_ == PRIVACY_MODE_ENABLED); | 
|  | QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id); | 
|  |  | 
|  | QuicStreamFactoryPeer::SetRaceCertVerification(factory_.get(), true); | 
|  | EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id)); | 
|  |  | 
|  | // Start CertVerifyJob. | 
|  | quic::QuicAsyncStatus status = QuicStreamFactoryPeer::StartCertVerifyJob( | 
|  | factory_.get(), quic_server_id, /*cert_verify_flags=*/0, net_log_); | 
|  | if (status == quic::QUIC_PENDING) { | 
|  | // Verify CertVerifierJob has started. | 
|  | EXPECT_TRUE(HasActiveCertVerifierJob(quic_server_id)); | 
|  |  | 
|  | while (HasActiveCertVerifierJob(quic_server_id)) { | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | } | 
|  | } | 
|  | // Verify CertVerifierJob has finished. | 
|  | EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id)); | 
|  |  | 
|  | // Start a QUIC request. | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | // Restore |race_cert_verification|. | 
|  | QuicStreamFactoryPeer::SetRaceCertVerification(factory_.get(), | 
|  | race_cert_verification); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  |  | 
|  | // Verify there are no outstanding CertVerifierJobs after request has | 
|  | // finished. | 
|  | EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, YieldAfterPackets) { | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(false); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ConstructClientConnectionClosePacket(1)); | 
|  | socket_data.AddRead(ASYNC, OK); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading | 
|  | // posts a task. | 
|  | // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver?? | 
|  | SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc", | 
|  | "StartReading"); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets | 
|  | // called. | 
|  | base::RunLoop run_loop; | 
|  | run_loop.RunUntilIdle(); | 
|  |  | 
|  | // Verify task that the observer's executed_count is 1, which indicates | 
|  | // QuicChromiumPacketReader::StartReading() has posted only one task and | 
|  | // yielded the read. | 
|  | EXPECT_EQ(1u, observer.executed_count()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_FALSE(stream.get());  // Session is already closed. | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, YieldAfterDuration) { | 
|  | Initialize(); | 
|  | factory_->set_require_confirmation(false); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | QuicStreamFactoryPeer::SetYieldAfterDuration( | 
|  | factory_.get(), quic::QuicTime::Delta::FromMilliseconds(-1)); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ConstructClientConnectionClosePacket(1)); | 
|  | socket_data.AddRead(ASYNC, OK); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | "192.168.0.1", ""); | 
|  |  | 
|  | // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading | 
|  | // posts a task. | 
|  | // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver?? | 
|  | SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc", | 
|  | "StartReading"); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets | 
|  | // called. | 
|  | base::RunLoop run_loop; | 
|  | run_loop.RunUntilIdle(); | 
|  |  | 
|  | // Verify task that the observer's executed_count is 1, which indicates | 
|  | // QuicChromiumPacketReader::StartReading() has posted only one task and | 
|  | // yielded the read. | 
|  | EXPECT_EQ(1u, observer.executed_count()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_FALSE(stream.get());  // Session is already closed. | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerPushSessionAffinity) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get())); | 
|  |  | 
|  | string url = "https://www.example.org/"; | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | quic::QuicClientPromisedInfo promised( | 
|  | session, GetNthServerInitiatedUnidirectionalStreamId(0), kDefaultUrl); | 
|  | (*QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get()) | 
|  | ->promised_by_url())[kDefaultUrl] = &promised; | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback_.callback())); | 
|  |  | 
|  | EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get())); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicStreamFactoryTest, ServerPushPrivacyModeMismatch) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data1; | 
|  | socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data1.AddWrite( | 
|  | SYNCHRONOUS, client_maker_.MakeRstPacket( | 
|  | 2, true, GetNthServerInitiatedUnidirectionalStreamId(0), | 
|  | quic::QUIC_STREAM_CANCELLED)); | 
|  | socket_data1.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get())); | 
|  |  | 
|  | string url = "https://www.example.org/"; | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | quic::QuicClientPromisedInfo promised( | 
|  | session, GetNthServerInitiatedUnidirectionalStreamId(0), kDefaultUrl); | 
|  |  | 
|  | quic::QuicClientPushPromiseIndex* index = | 
|  | QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get()); | 
|  |  | 
|  | (*index->promised_by_url())[kDefaultUrl] = &promised; | 
|  | EXPECT_EQ(index->GetPromised(kDefaultUrl), &promised); | 
|  |  | 
|  | // Doing the request should not use the push stream, but rather | 
|  | // cancel it because the privacy modes do not match. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, PRIVACY_MODE_ENABLED, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get())); | 
|  | EXPECT_EQ(index->GetPromised(kDefaultUrl), nullptr); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data1.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // Pool to existing session with matching quic::QuicServerId | 
|  | // even if destination is different. | 
|  | TEST_P(QuicStreamFactoryTest, PoolByOrigin) { | 
|  | Initialize(); | 
|  |  | 
|  | HostPortPair destination1("first.example.com", 443); | 
|  | HostPortPair destination2("second.example.com", 443); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | destination1, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  | EXPECT_TRUE(HasActiveSession(host_port_pair_)); | 
|  |  | 
|  | // Second request returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(destination2, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | QuicChromiumClientSession::Handle* session1 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream1.get()); | 
|  | QuicChromiumClientSession::Handle* session2 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream2.get()); | 
|  | EXPECT_TRUE(session1->SharesSameSession(*session2)); | 
|  | EXPECT_EQ(quic::QuicServerId(host_port_pair_.host(), host_port_pair_.port(), | 
|  | privacy_mode_ == PRIVACY_MODE_ENABLED), | 
|  | session1->server_id()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | class QuicStreamFactoryWithDestinationTest | 
|  | : public QuicStreamFactoryTestBase, | 
|  | public ::testing::TestWithParam<PoolingTestParams> { | 
|  | protected: | 
|  | QuicStreamFactoryWithDestinationTest() | 
|  | : QuicStreamFactoryTestBase( | 
|  | GetParam().version, | 
|  | GetParam().client_headers_include_h2_stream_dependency), | 
|  | destination_type_(GetParam().destination_type), | 
|  | hanging_read_(SYNCHRONOUS, ERR_IO_PENDING, 0) {} | 
|  |  | 
|  | HostPortPair GetDestination() { | 
|  | switch (destination_type_) { | 
|  | case SAME_AS_FIRST: | 
|  | return origin1_; | 
|  | case SAME_AS_SECOND: | 
|  | return origin2_; | 
|  | case DIFFERENT: | 
|  | return HostPortPair(kDifferentHostname, 443); | 
|  | default: | 
|  | NOTREACHED(); | 
|  | return HostPortPair(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void AddHangingSocketData() { | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data( | 
|  | new SequencedSocketData(base::make_span(&hanging_read_, 1), | 
|  | base::span<MockWrite>())); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data)); | 
|  | } | 
|  |  | 
|  | bool AllDataConsumed() { | 
|  | for (const auto& socket_data_ptr : sequenced_socket_data_vector_) { | 
|  | if (!socket_data_ptr->AllReadDataConsumed() || | 
|  | !socket_data_ptr->AllWriteDataConsumed()) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | DestinationType destination_type_; | 
|  | HostPortPair origin1_; | 
|  | HostPortPair origin2_; | 
|  | MockRead hanging_read_; | 
|  | std::vector<std::unique_ptr<SequencedSocketData>> | 
|  | sequenced_socket_data_vector_; | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P(VersionIncludeStreamDependencySequence, | 
|  | QuicStreamFactoryWithDestinationTest, | 
|  | ::testing::ValuesIn(GetPoolingTestParams())); | 
|  |  | 
|  | // A single QUIC request fails because the certificate does not match the origin | 
|  | // hostname, regardless of whether it matches the alternative service hostname. | 
|  | TEST_P(QuicStreamFactoryWithDestinationTest, InvalidCertificate) { | 
|  | if (destination_type_ == DIFFERENT) | 
|  | return; | 
|  |  | 
|  | Initialize(); | 
|  |  | 
|  | GURL url("https://mail.example.com/"); | 
|  | origin1_ = HostPortPair::FromURL(url); | 
|  |  | 
|  | // Not used for requests, but this provides a test case where the certificate | 
|  | // is valid for the hostname of the alternative service. | 
|  | origin2_ = HostPortPair("mail.example.org", 433); | 
|  |  | 
|  | HostPortPair destination = GetDestination(); | 
|  |  | 
|  | scoped_refptr<X509Certificate> cert( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | 
|  | ASSERT_FALSE(cert->VerifyNameMatch(origin1_.host())); | 
|  | ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host())); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details; | 
|  | verify_details.cert_verify_result.verified_cert = cert; | 
|  | verify_details.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | AddHangingSocketData(); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request.Request( | 
|  | destination, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_QUIC_HANDSHAKE_FAILED)); | 
|  |  | 
|  | EXPECT_TRUE(AllDataConsumed()); | 
|  | } | 
|  |  | 
|  | // QuicStreamRequest is pooled based on |destination| if certificate matches. | 
|  | TEST_P(QuicStreamFactoryWithDestinationTest, SharedCertificate) { | 
|  | Initialize(); | 
|  |  | 
|  | GURL url1("https://www.example.org/"); | 
|  | GURL url2("https://mail.example.org/"); | 
|  | origin1_ = HostPortPair::FromURL(url1); | 
|  | origin2_ = HostPortPair::FromURL(url2); | 
|  |  | 
|  | HostPortPair destination = GetDestination(); | 
|  |  | 
|  | scoped_refptr<X509Certificate> cert( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | 
|  | ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host())); | 
|  | ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host())); | 
|  | ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname)); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details; | 
|  | verify_details.cert_verify_result.verified_cert = cert; | 
|  | verify_details.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> settings_packet( | 
|  | client_maker_.MakeInitialSettingsPacket(1, nullptr)); | 
|  | MockWrite writes[] = {MockWrite(SYNCHRONOUS, settings_packet->data(), | 
|  | settings_packet->length(), 1)}; | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data( | 
|  | new SequencedSocketData(reads, writes)); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data)); | 
|  |  | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | destination, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url1, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  | EXPECT_TRUE(HasActiveSession(origin1_)); | 
|  |  | 
|  | // Second request returns synchronously because it pools to existing session. | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(OK, request2.Request(destination, version_, privacy_mode_, | 
|  | DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2, net_log_, | 
|  | &net_error_details_, | 
|  | failed_on_default_network_callback_, | 
|  | callback2.callback())); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | QuicChromiumClientSession::Handle* session1 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream1.get()); | 
|  | QuicChromiumClientSession::Handle* session2 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream2.get()); | 
|  | EXPECT_TRUE(session1->SharesSameSession(*session2)); | 
|  |  | 
|  | EXPECT_EQ(quic::QuicServerId(origin1_.host(), origin1_.port(), | 
|  | privacy_mode_ == PRIVACY_MODE_ENABLED), | 
|  | session1->server_id()); | 
|  |  | 
|  | EXPECT_TRUE(AllDataConsumed()); | 
|  | } | 
|  |  | 
|  | // QuicStreamRequest is not pooled if PrivacyMode differs. | 
|  | TEST_P(QuicStreamFactoryWithDestinationTest, DifferentPrivacyMode) { | 
|  | Initialize(); | 
|  |  | 
|  | GURL url1("https://www.example.org/"); | 
|  | GURL url2("https://mail.example.org/"); | 
|  | origin1_ = HostPortPair::FromURL(url1); | 
|  | origin2_ = HostPortPair::FromURL(url2); | 
|  |  | 
|  | HostPortPair destination = GetDestination(); | 
|  |  | 
|  | scoped_refptr<X509Certificate> cert( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | 
|  | ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host())); | 
|  | ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host())); | 
|  | ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname)); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details1; | 
|  | verify_details1.cert_verify_result.verified_cert = cert; | 
|  | verify_details1.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details2; | 
|  | verify_details2.cert_verify_result.verified_cert = cert; | 
|  | verify_details2.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); | 
|  |  | 
|  | MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> settings_packet( | 
|  | client_maker_.MakeInitialSettingsPacket(1, nullptr)); | 
|  | MockWrite writes[] = {MockWrite(SYNCHRONOUS, settings_packet->data(), | 
|  | settings_packet->length(), 1)}; | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data( | 
|  | new SequencedSocketData(reads, writes)); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data)); | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data1( | 
|  | new SequencedSocketData(reads, writes)); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data1.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data1)); | 
|  |  | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | destination, version_, PRIVACY_MODE_DISABLED, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url1, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(OK, callback_.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  | EXPECT_TRUE(HasActiveSession(origin1_)); | 
|  |  | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | destination, version_, PRIVACY_MODE_ENABLED, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback2.callback())); | 
|  | EXPECT_EQ(OK, callback2.WaitForResult()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | // |request2| does not pool to the first session, because PrivacyMode does not | 
|  | // match.  Instead, another session is opened to the same destination, but | 
|  | // with a different quic::QuicServerId. | 
|  | QuicChromiumClientSession::Handle* session1 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream1.get()); | 
|  | QuicChromiumClientSession::Handle* session2 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream2.get()); | 
|  | EXPECT_FALSE(session1->SharesSameSession(*session2)); | 
|  |  | 
|  | EXPECT_EQ(quic::QuicServerId(origin1_.host(), origin1_.port(), false), | 
|  | session1->server_id()); | 
|  | EXPECT_EQ(quic::QuicServerId(origin2_.host(), origin2_.port(), true), | 
|  | session2->server_id()); | 
|  |  | 
|  | EXPECT_TRUE(AllDataConsumed()); | 
|  | } | 
|  |  | 
|  | // QuicStreamRequest is not pooled if certificate does not match its origin. | 
|  | TEST_P(QuicStreamFactoryWithDestinationTest, DisjointCertificate) { | 
|  | Initialize(); | 
|  |  | 
|  | GURL url1("https://news.example.org/"); | 
|  | GURL url2("https://mail.example.com/"); | 
|  | origin1_ = HostPortPair::FromURL(url1); | 
|  | origin2_ = HostPortPair::FromURL(url2); | 
|  |  | 
|  | HostPortPair destination = GetDestination(); | 
|  |  | 
|  | scoped_refptr<X509Certificate> cert1( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); | 
|  | ASSERT_TRUE(cert1->VerifyNameMatch(origin1_.host())); | 
|  | ASSERT_FALSE(cert1->VerifyNameMatch(origin2_.host())); | 
|  | ASSERT_FALSE(cert1->VerifyNameMatch(kDifferentHostname)); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details1; | 
|  | verify_details1.cert_verify_result.verified_cert = cert1; | 
|  | verify_details1.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1); | 
|  |  | 
|  | scoped_refptr<X509Certificate> cert2( | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem")); | 
|  | ASSERT_TRUE(cert2->VerifyNameMatch(origin2_.host())); | 
|  | ASSERT_FALSE(cert2->VerifyNameMatch(kDifferentHostname)); | 
|  |  | 
|  | ProofVerifyDetailsChromium verify_details2; | 
|  | verify_details2.cert_verify_result.verified_cert = cert2; | 
|  | verify_details2.cert_verify_result.is_issued_by_known_root = true; | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); | 
|  |  | 
|  | MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; | 
|  | std::unique_ptr<quic::QuicEncryptedPacket> settings_packet( | 
|  | client_maker_.MakeInitialSettingsPacket(1, nullptr)); | 
|  | MockWrite writes[] = {MockWrite(SYNCHRONOUS, settings_packet->data(), | 
|  | settings_packet->length(), 1)}; | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data( | 
|  | new SequencedSocketData(reads, writes)); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data)); | 
|  | std::unique_ptr<SequencedSocketData> sequenced_socket_data1( | 
|  | new SequencedSocketData(reads, writes)); | 
|  | socket_factory_->AddSocketDataProvider(sequenced_socket_data1.get()); | 
|  | sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data1)); | 
|  |  | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request1.Request( | 
|  | destination, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url1, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream1 = CreateStream(&request1); | 
|  | EXPECT_TRUE(stream1.get()); | 
|  | EXPECT_TRUE(HasActiveSession(origin1_)); | 
|  |  | 
|  | TestCompletionCallback callback2; | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ( | 
|  | ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | destination, version_, privacy_mode_, DEFAULT_PRIORITY, SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback2.callback())); | 
|  | EXPECT_THAT(callback2.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); | 
|  | EXPECT_TRUE(stream2.get()); | 
|  |  | 
|  | // |request2| does not pool to the first session, because the certificate does | 
|  | // not match.  Instead, another session is opened to the same destination, but | 
|  | // with a different quic::QuicServerId. | 
|  | QuicChromiumClientSession::Handle* session1 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream1.get()); | 
|  | QuicChromiumClientSession::Handle* session2 = | 
|  | QuicHttpStreamPeer::GetSessionHandle(stream2.get()); | 
|  | EXPECT_FALSE(session1->SharesSameSession(*session2)); | 
|  |  | 
|  | EXPECT_EQ(quic::QuicServerId(origin1_.host(), origin1_.port(), | 
|  | privacy_mode_ == PRIVACY_MODE_ENABLED), | 
|  | session1->server_id()); | 
|  | EXPECT_EQ(quic::QuicServerId(origin2_.host(), origin2_.port(), | 
|  | privacy_mode_ == PRIVACY_MODE_ENABLED), | 
|  | session2->server_id()); | 
|  |  | 
|  | EXPECT_TRUE(AllDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test verifies that QuicStreamFactory::ClearCachedStatesInCryptoConfig | 
|  | // correctly transform an origin filter to a ServerIdFilter. Whether the | 
|  | // deletion itself works correctly is tested in QuicCryptoClientConfigTest. | 
|  | TEST_P(QuicStreamFactoryTest, ClearCachedStatesInCryptoConfig) { | 
|  | Initialize(); | 
|  | quic::QuicCryptoClientConfig* crypto_config = | 
|  | QuicStreamFactoryPeer::GetCryptoConfig(factory_.get()); | 
|  |  | 
|  | struct TestCase { | 
|  | TestCase(const std::string& host, | 
|  | int port, | 
|  | PrivacyMode privacy_mode, | 
|  | quic::QuicCryptoClientConfig* crypto_config) | 
|  | : server_id(host, port, privacy_mode), | 
|  | state(crypto_config->LookupOrCreate(server_id)) { | 
|  | std::vector<string> certs(1); | 
|  | certs[0] = "cert"; | 
|  | state->SetProof(certs, "cert_sct", "chlo_hash", "signature"); | 
|  | state->set_source_address_token("TOKEN"); | 
|  | state->SetProofValid(); | 
|  |  | 
|  | EXPECT_FALSE(state->certs().empty()); | 
|  | } | 
|  |  | 
|  | quic::QuicServerId server_id; | 
|  | quic::QuicCryptoClientConfig::CachedState* state; | 
|  | } test_cases[] = { | 
|  | TestCase("www.google.com", 443, privacy_mode_, crypto_config), | 
|  | TestCase("www.example.com", 443, privacy_mode_, crypto_config), | 
|  | TestCase("www.example.com", 4433, privacy_mode_, crypto_config)}; | 
|  |  | 
|  | // Clear cached states for the origin https://www.example.com:4433. | 
|  | GURL origin("https://www.example.com:4433"); | 
|  | factory_->ClearCachedStatesInCryptoConfig(base::Bind( | 
|  | static_cast<bool (*)(const GURL&, const GURL&)>(::operator==), origin)); | 
|  | EXPECT_FALSE(test_cases[0].state->certs().empty()); | 
|  | EXPECT_FALSE(test_cases[1].state->certs().empty()); | 
|  | EXPECT_TRUE(test_cases[2].state->certs().empty()); | 
|  |  | 
|  | // Clear all cached states. | 
|  | factory_->ClearCachedStatesInCryptoConfig( | 
|  | base::Callback<bool(const GURL&)>()); | 
|  | EXPECT_TRUE(test_cases[0].state->certs().empty()); | 
|  | EXPECT_TRUE(test_cases[1].state->certs().empty()); | 
|  | EXPECT_TRUE(test_cases[2].state->certs().empty()); | 
|  | } | 
|  |  | 
|  | // Passes connection options and client connection options to QuicStreamFactory, | 
|  | // then checks that its internal quic::QuicConfig is correct. | 
|  | TEST_P(QuicStreamFactoryTest, ConfigConnectionOptions) { | 
|  | test_params_.quic_connection_options.push_back(quic::kTIME); | 
|  | test_params_.quic_connection_options.push_back(quic::kTBBR); | 
|  | test_params_.quic_connection_options.push_back(quic::kREJ); | 
|  |  | 
|  | test_params_.quic_client_connection_options.push_back(quic::kTBBR); | 
|  | test_params_.quic_client_connection_options.push_back(quic::k1RTT); | 
|  |  | 
|  | Initialize(); | 
|  |  | 
|  | const quic::QuicConfig* config = | 
|  | QuicStreamFactoryPeer::GetConfig(factory_.get()); | 
|  | EXPECT_EQ(test_params_.quic_connection_options, | 
|  | config->SendConnectionOptions()); | 
|  | EXPECT_TRUE(config->HasClientRequestedIndependentOption( | 
|  | quic::kTBBR, quic::Perspective::IS_CLIENT)); | 
|  | EXPECT_TRUE(config->HasClientRequestedIndependentOption( | 
|  | quic::k1RTT, quic::Perspective::IS_CLIENT)); | 
|  | } | 
|  |  | 
|  | // Verifies that the host resolver uses the request priority passed to | 
|  | // QuicStreamRequest::Request(). | 
|  | TEST_P(QuicStreamFactoryTest, HostResolverUsesRequestPriority) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, MAXIMUM_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | EXPECT_EQ(MAXIMUM_PRIORITY, host_resolver_->last_request_priority()); | 
|  |  | 
|  | EXPECT_TRUE(socket_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(socket_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // This test imported from m74 quic implementation tests priority switching | 
|  | // for ProxyClientSocket. Cobalt does not have the related commits, so this | 
|  | // feature is not testable and is not used by anyone. | 
|  | #if !defined(COBALT_QUIC46) | 
|  | TEST_P(QuicStreamFactoryTest, HostResolverRequestReprioritizedOnSetPriority) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, MAXIMUM_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | EXPECT_EQ(MAXIMUM_PRIORITY, host_resolver_->last_request_priority()); | 
|  | EXPECT_EQ(MAXIMUM_PRIORITY, host_resolver_->request_priority(1)); | 
|  |  | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url2_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_EQ(DEFAULT_PRIORITY, host_resolver_->last_request_priority()); | 
|  | EXPECT_EQ(DEFAULT_PRIORITY, host_resolver_->request_priority(2)); | 
|  |  | 
|  | request.SetPriority(LOWEST); | 
|  | EXPECT_EQ(LOWEST, host_resolver_->request_priority(1)); | 
|  | EXPECT_EQ(DEFAULT_PRIORITY, host_resolver_->request_priority(2)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Passes |quic_max_time_before_crypto_handshake_seconds| and | 
|  | // |quic_max_idle_time_before_crypto_handshake_seconds| to QuicStreamFactory, | 
|  | // checks that its internal quic::QuicConfig is correct. | 
|  | TEST_P(QuicStreamFactoryTest, ConfigMaxTimeBeforeCryptoHandshake) { | 
|  | test_params_.quic_max_time_before_crypto_handshake_seconds = 11; | 
|  | test_params_.quic_max_idle_time_before_crypto_handshake_seconds = 13; | 
|  | Initialize(); | 
|  |  | 
|  | const quic::QuicConfig* config = | 
|  | QuicStreamFactoryPeer::GetConfig(factory_.get()); | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(11), | 
|  | config->max_time_before_crypto_handshake()); | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(13), | 
|  | config->max_idle_time_before_crypto_handshake()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution | 
|  | // succeeds asynchronously, then crypto handshake fails synchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackAsyncSync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_FAILED); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_TRUE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | // |host_resolver_| has not finished host resolution at this point, so | 
|  | // |host_resolution_callback| should not have a result. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  |  | 
|  | // Allow |host_resolver_| to finish host resolution. | 
|  | // Since the request fails immediately after host resolution (getting | 
|  | // ERR_FAILED from socket reads/writes), |host_resolution_callback| should be | 
|  | // called with ERR_QUIC_PROTOCOL_ERROR since that's the next result in | 
|  | // forming the connection. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(host_resolution_callback.have_result()); | 
|  | EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, host_resolution_callback.WaitForResult()); | 
|  |  | 
|  | // Calling WaitForHostResolution() a second time should return | 
|  | // false since host resolution has finished already. | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | EXPECT_TRUE(callback_.have_result()); | 
|  | EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution | 
|  | // succeeds asynchronously, then crypto handshake fails asynchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackAsyncAsync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | factory_->set_require_confirmation(true); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | socket_data.AddRead(ASYNC, ERR_FAILED); | 
|  | socket_data.AddWrite(ASYNC, ERR_FAILED); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_TRUE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | // |host_resolver_| has not finished host resolution at this point, so | 
|  | // |host_resolution_callback| should not have a result. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  |  | 
|  | // Allow |host_resolver_| to finish host resolution. Since crypto handshake | 
|  | // will hang after host resolution, |host_resolution_callback| should run with | 
|  | // ERR_IO_PENDING since that's the next result in forming the connection. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(host_resolution_callback.have_result()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, host_resolution_callback.WaitForResult()); | 
|  |  | 
|  | // Calling WaitForHostResolution() a second time should return | 
|  | // false since host resolution has finished already. | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | EXPECT_FALSE(callback_.have_result()); | 
|  | socket_data.GetSequencedSocketData()->Resume(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(callback_.have_result()); | 
|  | EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution | 
|  | // succeeds synchronously, then crypto handshake fails synchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackSyncSync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_FAILED); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // WaitForHostResolution() should return false since host | 
|  | // resolution has finished already. | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  | EXPECT_FALSE(callback_.have_result()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution | 
|  | // succeeds synchronously, then crypto handshake fails asynchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackSyncAsync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Host resolution will succeed synchronously, but Request() as a whole | 
|  | // will fail asynchronously. | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | factory_->set_require_confirmation(true); | 
|  |  | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(ASYNC, ERR_IO_PENDING);  // Pause | 
|  | socket_data.AddRead(ASYNC, ERR_FAILED); | 
|  | socket_data.AddWrite(ASYNC, ERR_FAILED); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // WaitForHostResolution() should return false since host | 
|  | // resolution has finished already. | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  |  | 
|  | EXPECT_FALSE(callback_.have_result()); | 
|  | socket_data.GetSequencedSocketData()->Resume(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(callback_.have_result()); | 
|  | EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution fails | 
|  | // synchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackFailSync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Host resolution will fail synchronously. | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_NAME_NOT_RESOLVED, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // WaitForHostResolution() should return false since host | 
|  | // resolution has failed already. | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  | } | 
|  |  | 
|  | // Verify ResultAfterHostResolutionCallback behavior when host resolution fails | 
|  | // asynchronously. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackFailAsync) { | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_TRUE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | // Allow |host_resolver_| to fail host resolution. |host_resolution_callback| | 
|  | // Should run with ERR_NAME_NOT_RESOLVED since that's the error host | 
|  | // resolution failed with. | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(host_resolution_callback.have_result()); | 
|  | EXPECT_EQ(ERR_NAME_NOT_RESOLVED, host_resolution_callback.WaitForResult()); | 
|  |  | 
|  | EXPECT_TRUE(callback_.have_result()); | 
|  | EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult()); | 
|  | } | 
|  |  | 
|  | // Cobalt does not allow stale DNS cache. | 
|  | #if !defined(COBALT_QUIC46) | 
|  | // With dns race experiment turned on, and DNS resolve succeeds synchronously, | 
|  | // the final connection is established through the resolved DNS. No racing | 
|  | // connection. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceAndHostResolutionSync) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for synchronous return. | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_THAT(request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()), | 
|  | IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, DNS resolve returns async, no matching cache in | 
|  | // host resolver, connection should be successful and through resolved DNS. No | 
|  | // racing connection. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceAndHostResolutionAsync) { | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_TRUE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  |  | 
|  | // Cause the host resolution to return. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(host_resolution_callback.WaitForResult(), IsOk()); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, DNS resolve returns async, stale dns used, | 
|  | // connects synchrounously, and then the resolved DNS matches. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsyncStaleMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kCachedIPAddress.ToString(), ""); | 
|  |  | 
|  | // Set up the same address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check that the racing job is running. | 
|  | EXPECT_TRUE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Resolve dns and return. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kCachedIPAddress.ToString()); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale dns used, connect | 
|  | // async, and then the result matches. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | ResultAfterDNSRaceHostResolveAsyncConnectAsyncStaleMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kCachedIPAddress.ToString(), ""); | 
|  |  | 
|  | // Set up the same address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Send Crypto handshake so connect will call back. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | // Check that the racing job is running. | 
|  | EXPECT_TRUE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Resolve dns and call back, make sure job finishes. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kCachedIPAddress.ToString()); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale dns used, dns resolve | 
|  | // return, then connection finishes and matches with the result. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | ResultAfterDNSRaceHostResolveAsyncStaleMatchConnectAsync) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kCachedIPAddress.ToString(), ""); | 
|  |  | 
|  | // Set up the same address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Finish dns async, check we still need to wait for stale connection async. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(callback_.have_result()); | 
|  |  | 
|  | // Finish stale connection async, and the stale connection should pass dns | 
|  | // validation. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kCachedIPAddress.ToString()); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connects | 
|  | // sync, but dns no match | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | ResultAfterDNSRaceHostResolveAsyncStaleSyncNoMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Socket for the stale connection which will invoke connection closure. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 2, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Socket for the new connection. | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check the stale connection is running. | 
|  | EXPECT_TRUE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Finish dns resolution and check the job has finished. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connects | 
|  | // async, finishes before dns, but no match | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleAsyncResolveAsyncNoMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in the stale resolvercache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 2, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Finish the stale connection. | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_TRUE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Finish host resolution and check the job is done. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connects | 
|  | // async, dns finishes first, but no match | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncStaleAsyncNoMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 1, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); | 
|  | quic_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | // Finish dns resolution, but need to wait for stale connection. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( | 
|  | quic::QuicSession::HANDSHAKE_CONFIRMED); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve returns error sync, same behavior | 
|  | // as experiment is not on | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveError) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set synchronous failure in resolver. | 
|  | host_resolver_->set_synchronous_mode(true); | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | QuicStreamRequest request(factory_.get()); | 
|  |  | 
|  | EXPECT_EQ(ERR_NAME_NOT_RESOLVED, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, no cache available, dns resolve returns error | 
|  | // async | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsyncError) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set asynchronous failure in resolver. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | QuicStreamRequest request(factory_.get()); | 
|  |  | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Resolve and expect result that shows the resolution error. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, staled used and connects | 
|  | // sync, dns returns error and no connection is established. | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleSyncHostResolveError) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set asynchronous failure in resolver. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  |  | 
|  | // Set up an address in the stale cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Socket for the stale connection which is supposed to disconnect. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 2, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check that the stale connection is running. | 
|  | EXPECT_TRUE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Finish host resolution. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connection | 
|  | // return error, then dns matches | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleErrorDNSMatches) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in host resolver for asynchronous return. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kCachedIPAddress.ToString(), ""); | 
|  |  | 
|  | // Set up the same address in the stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Simulate synchronous connect failure. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  | EXPECT_FALSE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connection | 
|  | // returns error, dns no match, new connection is established | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleErrorDNSNoMatch) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in host resolver. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Add failure for the stale connection. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check that the stale connection fails. | 
|  | EXPECT_FALSE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Finish host resolution and check the job finishes ok. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsOk()); | 
|  |  | 
|  | std::unique_ptr<HttpStream> stream = CreateStream(&request); | 
|  | EXPECT_TRUE(stream.get()); | 
|  |  | 
|  | QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | session->peer_address().impl().socket_address().ToStringWithoutPort(), | 
|  | kNonCachedIPAddress); | 
|  |  | 
|  | EXPECT_TRUE(quic_data2.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async, stale used and connection | 
|  | // returns error, dns no match, new connection error | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleErrorDNSNoMatchError) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Set an address in host resolver asynchronously. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | // Set up a different address in the stale cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Add failure for stale connection. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | // Add failure for resolved dns connection. | 
|  | MockQuicData quic_data2; | 
|  | quic_data2.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE); | 
|  | quic_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check the stale connection fails. | 
|  | EXPECT_FALSE(HasLiveSession(host_port_pair_)); | 
|  | EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); | 
|  |  | 
|  | // Check the resolved dns connection fails. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_ADDRESS_IN_USE)); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async and stale connect async, dns | 
|  | // resolve returns error and then preconnect finishes | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsync) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Add asynchronous failure in host resolver. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  |  | 
|  | // Set up an address in stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | // Socket data for stale connection which is supposed to disconnect. | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 1, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // host resolution returned but stale connection hasn't finished yet. | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, dns resolve async and stale connect async, dns | 
|  | // resolve returns error and then preconnect fails. | 
|  | TEST_P(QuicStreamFactoryTest, | 
|  | ResultAfterDNSRaceResolveAsyncErrorStaleAsyncError) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Add asynchronous failure to host resolver. | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | factory_->set_require_confirmation(true); | 
|  | crypto_client_stream_factory_.set_handshake_mode( | 
|  | MockCryptoClientStream::ZERO_RTT); | 
|  | host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); | 
|  |  | 
|  | // Set up an address in stale resolver cache. | 
|  | HostCache::Key key(host_port_pair_.host(), ADDRESS_FAMILY_UNSPECIFIED, 0); | 
|  | HostCache::Entry entry(OK, | 
|  | AddressList::CreateFromIPAddress(kCachedIPAddress, 0), | 
|  | HostCache::Entry::SOURCE_DNS); | 
|  | base::TimeDelta zero; | 
|  | HostCache* cache = host_resolver_->GetHostCache(); | 
|  | cache->Set(key, entry, base::TimeTicks::Now(), zero); | 
|  | // Expire the cache | 
|  | cache->OnNetworkChange(); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); | 
|  | quic_data.AddWrite( | 
|  | SYNCHRONOUS, | 
|  | client_maker_.MakeConnectionClosePacket( | 
|  | 1, true, quic::QUIC_STALE_CONNECTION_CANCELLED, "net error")); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Host Resolution returns failure but stale connection hasn't finished. | 
|  | host_resolver_->ResolveAllPending(); | 
|  |  | 
|  | // Check that the final error is on resolution failure. | 
|  | EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | } | 
|  |  | 
|  | // With dns race experiment on, test that host resolution callback behaves | 
|  | // normal as experiment is not on | 
|  | TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsync) { | 
|  | test_params_.quic_race_stale_dns_on_connection = true; | 
|  | host_resolver_ = std::make_unique<MockCachingHostResolver>(); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | host_resolver_->set_ondemand_mode(true); | 
|  | host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), | 
|  | kNonCachedIPAddress, ""); | 
|  |  | 
|  | MockQuicData quic_data; | 
|  | quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | quic_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | QuicStreamRequest request(factory_.get()); | 
|  | EXPECT_EQ(ERR_IO_PENDING, | 
|  | request.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, | 
|  | SocketTag(), | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback())); | 
|  |  | 
|  | // Check that expect_on_host_resolution_ is properlly set. | 
|  | TestCompletionCallback host_resolution_callback; | 
|  | EXPECT_TRUE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_FALSE(host_resolution_callback.have_result()); | 
|  |  | 
|  | host_resolver_->ResolveAllPending(); | 
|  | EXPECT_THAT(host_resolution_callback.WaitForResult(), IsOk()); | 
|  |  | 
|  | // Check that expect_on_host_resolution_ is flipped back. | 
|  | EXPECT_FALSE( | 
|  | request.WaitForHostResolution(host_resolution_callback.callback())); | 
|  |  | 
|  | EXPECT_TRUE(quic_data.AllReadDataConsumed()); | 
|  | EXPECT_TRUE(quic_data.AllWriteDataConsumed()); | 
|  | } | 
|  | #endif  // COBALT_QUIC46 | 
|  |  | 
|  | // Test that QuicStreamRequests with similar and different tags results in | 
|  | // reused and unique QUIC streams using appropriately tagged sockets. | 
|  | TEST_P(QuicStreamFactoryTest, Tag) { | 
|  | MockTaggingClientSocketFactory* socket_factory = | 
|  | new MockTaggingClientSocketFactory(); | 
|  | socket_factory_.reset(socket_factory); | 
|  | Initialize(); | 
|  | ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); | 
|  | crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); | 
|  |  | 
|  | // Prepare to establish two QUIC sessions. | 
|  | MockQuicData socket_data; | 
|  | socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data.AddSocketDataToFactory(socket_factory_.get()); | 
|  | MockQuicData socket_data2; | 
|  | socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); | 
|  | socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket()); | 
|  | socket_data2.AddSocketDataToFactory(socket_factory_.get()); | 
|  |  | 
|  | #if defined(OS_ANDROID) | 
|  | SocketTag tag1(SocketTag::UNSET_UID, 0x12345678); | 
|  | SocketTag tag2(getuid(), 0x87654321); | 
|  | #else | 
|  | // On non-Android platforms we can only use the default constructor. | 
|  | SocketTag tag1, tag2; | 
|  | #endif | 
|  |  | 
|  | // Request a stream with |tag1|. | 
|  | QuicStreamRequest request1(factory_.get()); | 
|  | int rv = request1.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, tag1, | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()); | 
|  | EXPECT_THAT(callback_.GetResult(rv), IsOk()); | 
|  | EXPECT_EQ(socket_factory->GetLastProducedUDPSocket()->tag(), tag1); | 
|  | EXPECT_TRUE(socket_factory->GetLastProducedUDPSocket() | 
|  | ->tagged_before_data_transferred()); | 
|  | std::unique_ptr<QuicChromiumClientSession::Handle> stream1 = | 
|  | request1.ReleaseSessionHandle(); | 
|  | EXPECT_TRUE(stream1); | 
|  | EXPECT_TRUE(stream1->IsConnected()); | 
|  |  | 
|  | // Request a stream with |tag1| and verify underlying session is reused. | 
|  | QuicStreamRequest request2(factory_.get()); | 
|  | rv = request2.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, tag1, | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()); | 
|  | EXPECT_THAT(callback_.GetResult(rv), IsOk()); | 
|  | std::unique_ptr<QuicChromiumClientSession::Handle> stream2 = | 
|  | request2.ReleaseSessionHandle(); | 
|  | EXPECT_TRUE(stream2); | 
|  | EXPECT_TRUE(stream2->IsConnected()); | 
|  | EXPECT_TRUE(stream2->SharesSameSession(*stream1)); | 
|  |  | 
|  | // Request a stream with |tag2| and verify a new session is created. | 
|  | QuicStreamRequest request3(factory_.get()); | 
|  | rv = request3.Request( | 
|  | host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, tag2, | 
|  | /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, | 
|  | failed_on_default_network_callback_, callback_.callback()); | 
|  | EXPECT_THAT(callback_.GetResult(rv), IsOk()); | 
|  | EXPECT_EQ(socket_factory->GetLastProducedUDPSocket()->tag(), tag2); | 
|  | EXPECT_TRUE(socket_factory->GetLastProducedUDPSocket() | 
|  | ->tagged_before_data_transferred()); | 
|  | std::unique_ptr<QuicChromiumClientSession::Handle> stream3 = | 
|  | request3.ReleaseSessionHandle(); | 
|  | EXPECT_TRUE(stream3); | 
|  | EXPECT_TRUE(stream3->IsConnected()); | 
|  | #if defined(OS_ANDROID) | 
|  | EXPECT_FALSE(stream3->SharesSameSession(*stream1)); | 
|  | #else | 
|  | // Same tag should reuse session. | 
|  | EXPECT_TRUE(stream3->SharesSameSession(*stream1)); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace net |