Skip to content

Commit

Permalink
QUIC - Disable Preconnect when QUIC can be spoken to a server with 0RTT
Browse files Browse the repository at this point in the history
handshake.

+ Intend to disable Preconnects via an experiment.
+ Preconnects are not disabled by default.
+ Moved QuicStreamFactoryPeer code into a separate file.
+ Added utility code for tests to populate a dummy server config into the
cache.
+ Added unittests to test disabling of Preconnects and
  ZeroRTT test.

R=rch@chromium.org

Review URL: https://codereview.chromium.org/1502453003

Cr-Commit-Position: refs/heads/master@{#363864}
  • Loading branch information
rtenneti authored and Commit bot committed Dec 9, 2015
1 parent e046180 commit d2e74ca
Show file tree
Hide file tree
Showing 10 changed files with 395 additions and 109 deletions.
1 change: 1 addition & 0 deletions net/http/http_network_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ HttpNetworkSession::Params::Params()
quic_threshold_timeouts_streams_open(0),
quic_close_sessions_on_ip_change(false),
quic_idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds),
quic_disable_preconnect_if_0rtt(false),
proxy_delegate(NULL) {
quic_supported_versions.push_back(QUIC_VERSION_25);
}
Expand Down
2 changes: 2 additions & 0 deletions net/http/http_network_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ class NET_EXPORT HttpNetworkSession
bool quic_close_sessions_on_ip_change;
// Specifes QUIC idle connection state lifetime.
int quic_idle_connection_timeout_seconds;
// If true, disable preconnections if QUIC can do 0RTT.
bool quic_disable_preconnect_if_0rtt;
ProxyDelegate* proxy_delegate;
};

Expand Down
10 changes: 8 additions & 2 deletions net/http/http_stream_factory_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "net/http/http_stream_factory_impl_job.h"
#include "net/http/http_stream_factory_impl_request.h"
#include "net/log/net_log.h"
#include "net/quic/quic_server_id.h"
#include "net/spdy/spdy_http_stream.h"
#include "url/gurl.h"

Expand Down Expand Up @@ -134,6 +135,12 @@ void HttpStreamFactoryImpl::PreconnectStreams(
if (!alternative_service_vector.empty()) {
// TODO(bnc): Pass on multiple alternative services to Job.
alternative_service = alternative_service_vector[0];
if (session_->params().quic_disable_preconnect_if_0rtt &&
alternative_service.protocol == QUIC &&
session_->quic_stream_factory()->ZeroRTTEnabledFor(QuicServerId(
alternative_service.host_port_pair(), request_info.privacy_mode))) {
return;
}
}

// Due to how the socket pools handle priorities and idle sockets, only IDLE
Expand Down Expand Up @@ -219,9 +226,8 @@ AlternativeServiceVector HttpStreamFactoryImpl::GetAlternativeServicesFor(
if (session_->quic_stream_factory()->IsQuicDisabled(origin.port()))
continue;

if (!original_url.SchemeIs("https")) {
if (!original_url.SchemeIs("https"))
continue;
}

enabled_alternative_service_vector.push_back(alternative_service);
}
Expand Down
104 changes: 103 additions & 1 deletion net/http/http_stream_factory_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "net/log/net_log.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_stream_factory_peer.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/mock_client_socket_pool_manager.h"
#include "net/socket/next_proto.h"
Expand Down Expand Up @@ -116,7 +118,6 @@ class MockHttpStreamFactoryImplForPreconnect : public HttpStreamFactoryImpl {
preconnect_done_(false),
waiting_for_preconnect_(false) {}


void WaitForPreconnects() {
while (!preconnect_done_) {
waiting_for_preconnect_ = true;
Expand Down Expand Up @@ -641,6 +642,7 @@ TEST_P(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) {

HttpNetworkSession::Params params;
params.enable_quic = true;
params.quic_disable_preconnect_if_0rtt = false;
params.enable_quic_for_proxies = true;
scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
new SSLConfigServiceDefaults);
Expand Down Expand Up @@ -702,6 +704,7 @@ TEST_P(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) {
HttpNetworkSession::Params params;
params.enable_quic = true;
params.enable_quic_for_proxies = true;
params.quic_disable_preconnect_if_0rtt = false;
scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
new SSLConfigServiceDefaults);
HttpServerPropertiesImpl http_server_properties;
Expand Down Expand Up @@ -750,6 +753,105 @@ TEST_P(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) {
EXPECT_TRUE(iter != retry_info.end());
}

TEST_P(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
for (int num_streams = 1; num_streams < 3; ++num_streams) {
GURL url = GURL("https://www.google.com");

// Set up QUIC as alternative_service.
HttpServerPropertiesImpl http_server_properties;
const AlternativeService alternative_service(QUIC, url.host().c_str(),
url.IntPort());
AlternativeServiceInfoVector alternative_service_info_vector;
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service, 1.0, expiration));
HostPortPair host_port_pair(alternative_service.host_port_pair());
http_server_properties.SetAlternativeServices(
host_port_pair, alternative_service_info_vector);

SpdySessionDependencies session_deps(
GetParam(), ProxyService::CreateFixed("http_proxy"));

// Setup params to disable preconnect, but QUIC doesn't 0RTT.
HttpNetworkSession::Params params =
SpdySessionDependencies::CreateSessionParams(&session_deps);
params.enable_quic = true;
params.quic_disable_preconnect_if_0rtt = true;
params.http_server_properties = http_server_properties.GetWeakPtr();

scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
HttpNetworkSessionPeer peer(session.get());
HostPortPair proxy_host("http_proxy", 80);
CapturePreconnectsHttpProxySocketPool* http_proxy_pool =
new CapturePreconnectsHttpProxySocketPool(
session_deps.host_resolver.get(), session_deps.cert_verifier.get());
CapturePreconnectsSSLSocketPool* ssl_conn_pool =
new CapturePreconnectsSSLSocketPool(session_deps.host_resolver.get(),
session_deps.cert_verifier.get());
scoped_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
peer.SetClientSocketPoolManager(mock_pool_manager.Pass());
PreconnectHelperForURL(num_streams, url, session.get());
EXPECT_EQ(num_streams, ssl_conn_pool->last_num_streams());
}
}

TEST_P(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
for (int num_streams = 1; num_streams < 3; ++num_streams) {
GURL url = GURL("https://www.google.com");

// Set up QUIC as alternative_service.
HttpServerPropertiesImpl http_server_properties;
const AlternativeService alternative_service(QUIC, "www.google.com", 443);
AlternativeServiceInfoVector alternative_service_info_vector;
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service, 1.0, expiration));
HostPortPair host_port_pair(alternative_service.host_port_pair());
http_server_properties.SetAlternativeServices(
host_port_pair, alternative_service_info_vector);

SpdySessionDependencies session_deps(GetParam());

// Setup params to disable preconnect, but QUIC does 0RTT.
HttpNetworkSession::Params params =
SpdySessionDependencies::CreateSessionParams(&session_deps);
params.enable_quic = true;
params.quic_disable_preconnect_if_0rtt = true;
params.http_server_properties = http_server_properties.GetWeakPtr();

scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));

// Setup 0RTT for QUIC.
QuicStreamFactory* factory = session->quic_stream_factory();
factory->set_require_confirmation(false);
test::QuicStreamFactoryPeer::CacheDummyServerConfig(
factory, QuicServerId(host_port_pair, PRIVACY_MODE_DISABLED));

HttpNetworkSessionPeer peer(session.get());
CapturePreconnectsTransportSocketPool* transport_conn_pool =
new CapturePreconnectsTransportSocketPool(
session_deps.host_resolver.get(), session_deps.cert_verifier.get());
scoped_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
mock_pool_manager->SetTransportSocketPool(transport_conn_pool);
peer.SetClientSocketPoolManager(mock_pool_manager.Pass());

HttpRequestInfo request;
request.method = "GET";
request.url = url;
request.load_flags = 0;

SSLConfig ssl_config;
session->ssl_config_service()->GetSSLConfig(&ssl_config);
session->http_stream_factory()->PreconnectStreams(num_streams, request,
ssl_config, ssl_config);
EXPECT_EQ(-1, transport_conn_pool->last_num_streams());
}
}

namespace {

TEST_P(HttpStreamFactoryTest, PrivacyModeDisablesChannelId) {
Expand Down
2 changes: 2 additions & 0 deletions net/net.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -1625,6 +1625,8 @@
'quic/test_tools/quic_spdy_session_peer.h',
'quic/test_tools/quic_spdy_stream_peer.cc',
'quic/test_tools/quic_spdy_stream_peer.h',
'quic/test_tools/quic_stream_factory_peer.cc',
'quic/test_tools/quic_stream_factory_peer.h',
'quic/test_tools/quic_stream_sequencer_peer.cc',
'quic/test_tools/quic_stream_sequencer_peer.h',
'quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc',
Expand Down
4 changes: 4 additions & 0 deletions net/quic/quic_stream_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,10 @@ void QuicStreamFactory::set_require_confirmation(bool require_confirmation) {
}
}

bool QuicStreamFactory::ZeroRTTEnabledFor(const QuicServerId& quic_server_id) {
return !(require_confirmation_ || CryptoConfigCacheIsEmpty(quic_server_id));
}

base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
const QuicServerId& server_id) {
if (!delay_tcp_race_ || require_confirmation_)
Expand Down
2 changes: 2 additions & 0 deletions net/quic/quic_stream_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ class NET_EXPORT_PRIVATE QuicStreamFactory

void set_require_confirmation(bool require_confirmation);

bool ZeroRTTEnabledFor(const QuicServerId& server_id);

// It returns the amount of time waiting job should be delayed.
base::TimeDelta GetTimeDelayForWaitingJob(const QuicServerId& server_id);

Expand Down
122 changes: 16 additions & 106 deletions net/quic/quic_stream_factory_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/quic/test_tools/quic_stream_factory_peer.h"
#include "net/quic/test_tools/quic_test_packet_maker.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/test_task_runner.h"
Expand Down Expand Up @@ -80,112 +81,6 @@ vector<TestParams> GetTestParams() {

} // namespace anonymous

class QuicStreamFactoryPeer {
public:
static const QuicConfig* GetConfig(QuicStreamFactory* factory) {
return &factory->config_;
}

static QuicCryptoClientConfig* GetCryptoConfig(QuicStreamFactory* factory) {
return &factory->crypto_config_;
}

static bool HasActiveSession(QuicStreamFactory* factory,
const HostPortPair& host_port_pair) {
QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
return factory->HasActiveSession(server_id);
}

static QuicChromiumClientSession* GetActiveSession(
QuicStreamFactory* factory,
const HostPortPair& host_port_pair) {
QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
DCHECK(factory->HasActiveSession(server_id));
return factory->active_sessions_[server_id];
}

static scoped_ptr<QuicHttpStream> CreateFromSession(
QuicStreamFactory* factory,
QuicChromiumClientSession* session) {
return factory->CreateFromSession(session);
}

static bool IsLiveSession(QuicStreamFactory* factory,
QuicChromiumClientSession* session) {
for (QuicStreamFactory::SessionIdMap::iterator it =
factory->all_sessions_.begin();
it != factory->all_sessions_.end(); ++it) {
if (it->first == session)
return true;
}
return false;
}

static void SetTaskRunner(QuicStreamFactory* factory,
base::TaskRunner* task_runner) {
factory->task_runner_ = task_runner;
}

static int GetNumberOfLossyConnections(QuicStreamFactory* factory,
uint16 port) {
return factory->number_of_lossy_connections_[port];
}

static bool IsQuicDisabled(QuicStreamFactory* factory, uint16 port) {
return factory->IsQuicDisabled(port);
}

static bool GetDelayTcpRace(QuicStreamFactory* factory) {
return factory->delay_tcp_race_;
}

static void SetDelayTcpRace(QuicStreamFactory* factory, bool delay_tcp_race) {
factory->delay_tcp_race_ = delay_tcp_race;
}

static void SetYieldAfterPackets(QuicStreamFactory* factory,
int yield_after_packets) {
factory->yield_after_packets_ = yield_after_packets;
}

static void SetYieldAfterDuration(QuicStreamFactory* factory,
QuicTime::Delta yield_after_duration) {
factory->yield_after_duration_ = yield_after_duration;
}

static size_t GetNumberOfActiveJobs(QuicStreamFactory* factory,
const QuicServerId& server_id) {
return (factory->active_jobs_[server_id]).size();
}

static int GetNumTimeoutsWithOpenStreams(QuicStreamFactory* factory) {
return factory->num_timeouts_with_open_streams_;
}

static int GetNumPublicResetsPostHandshake(QuicStreamFactory* factory) {
return factory->num_public_resets_post_handshake_;
}

static void MaybeInitialize(QuicStreamFactory* factory) {
factory->MaybeInitialize();
}

static bool HasInitializedData(QuicStreamFactory* factory) {
return factory->has_initialized_data_;
}

static bool SupportsQuicAtStartUp(QuicStreamFactory* factory,
HostPortPair host_port_pair) {
return ContainsKey(factory->quic_supported_servers_at_startup_,
host_port_pair);
}

static bool CryptoConfigCacheIsEmpty(QuicStreamFactory* factory,
QuicServerId& quic_server_id) {
return factory->CryptoConfigCacheIsEmpty(quic_server_id);
}
};

class MockQuicServerInfo : public QuicServerInfo {
public:
MockQuicServerInfo(const QuicServerId& server_id)
Expand Down Expand Up @@ -2736,6 +2631,21 @@ TEST_P(QuicStreamFactoryTest, MaybeInitialize) {
EXPECT_EQ(test_cert, cached->certs()[0]);
}

TEST_P(QuicStreamFactoryTest, QuicDoingZeroRTT) {
Initialize();

factory_->set_require_confirmation(true);
QuicServerId quic_server_id(host_port_pair_, PRIVACY_MODE_DISABLED);
EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));

factory_->set_require_confirmation(false);
EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));

// Load server config and verify QUIC will do 0RTT.
QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id);
EXPECT_TRUE(factory_->ZeroRTTEnabledFor(quic_server_id));
}

TEST_P(QuicStreamFactoryTest, YieldAfterPackets) {
Initialize();
QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0);
Expand Down
Loading

0 comments on commit d2e74ca

Please sign in to comment.