Adds ability to disable connection pooling in QUIC.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#293823}
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 3abfe74..e72ebd1c 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -1038,6 +1038,8 @@
       &params->enable_quic_time_based_loss_detection);
   globals.quic_always_require_handshake_confirmation.CopyToIfSet(
       &params->quic_always_require_handshake_confirmation);
+  globals.quic_disable_connection_pooling.CopyToIfSet(
+      &params->quic_disable_connection_pooling);
   globals.enable_quic_port_selection.CopyToIfSet(
       &params->enable_quic_port_selection);
   globals.quic_max_packet_length.CopyToIfSet(&params->quic_max_packet_length);
@@ -1153,6 +1155,8 @@
                                                quic_trial_params));
     globals->quic_always_require_handshake_confirmation.set(
         ShouldQuicAlwaysRequireHandshakeConfirmation(quic_trial_params));
+    globals->quic_disable_connection_pooling.set(
+        ShouldQuicDisableConnectionPooling(quic_trial_params));
     globals->enable_quic_port_selection.set(
         ShouldEnableQuicPortSelection(command_line));
     globals->quic_connection_options =
@@ -1337,6 +1341,14 @@
 }
 
 // static
+bool IOThread::ShouldQuicDisableConnectionPooling(
+    const VariationParameters& quic_trial_params) {
+  return LowerCaseEqualsASCII(
+      GetVariationParam(quic_trial_params, "disable_connection_pooling"),
+      "true");
+}
+
+// static
 size_t IOThread::GetQuicMaxPacketLength(
     const CommandLine& command_line,
     base::StringPiece quic_trial_group,
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index a989118..68eb7cf 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -188,6 +188,7 @@
     Optional<bool> enable_quic_time_based_loss_detection;
     Optional<bool> enable_quic_port_selection;
     Optional<bool> quic_always_require_handshake_confirmation;
+    Optional<bool> quic_disable_connection_pooling;
     Optional<size_t> quic_max_packet_length;
     net::QuicTagVector quic_connection_options;
     Optional<std::string> quic_user_agent_id;
@@ -358,6 +359,10 @@
   static bool ShouldQuicAlwaysRequireHandshakeConfirmation(
       const VariationParameters& quic_trial_params);
 
+  // Returns true if QUIC should disable connection pooling.
+  static bool ShouldQuicDisableConnectionPooling(
+      const VariationParameters& quic_trial_params);
+
   // Returns the maximum length for QUIC packets, based on any flags in
   // |command_line| or the field trial.  Returns 0 if there is an error
   // parsing any of the options, or if the default value should be used.
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 173ff58..252474a9 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -133,6 +133,7 @@
             params.quic_supported_versions);
   EXPECT_EQ(net::QuicTagVector(), params.quic_connection_options);
   EXPECT_FALSE(params.quic_always_require_handshake_confirmation);
+  EXPECT_FALSE(params.quic_disable_connection_pooling);
 }
 
 TEST_F(IOThreadTest, EnableQuicFromCommandLine) {
@@ -331,4 +332,14 @@
   EXPECT_TRUE(params.quic_always_require_handshake_confirmation);
 }
 
+TEST_F(IOThreadTest,
+       QuicDisableConnectionPoolingFromFieldTrialParams) {
+  field_trial_group_ = "Enabled";
+  field_trial_params_["disable_connection_pooling"] = "true";
+  ConfigureQuicGlobals();
+  net::HttpNetworkSession::Params params;
+  InitializeNetworkSessionParams(&params);
+  EXPECT_TRUE(params.quic_disable_connection_pooling);
+}
+
 }  // namespace test
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 776df15..b7a4b74 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -91,6 +91,7 @@
       enable_quic_port_selection(true),
       enable_quic_time_based_loss_detection(false),
       quic_always_require_handshake_confirmation(false),
+      quic_disable_connection_pooling(false),
       quic_clock(NULL),
       quic_random(NULL),
       quic_max_packet_length(kDefaultMaxPacketSize),
@@ -132,6 +133,7 @@
           params.enable_quic_port_selection,
           params.enable_quic_time_based_loss_detection,
           params.quic_always_require_handshake_confirmation,
+          params.quic_disable_connection_pooling,
           params.quic_connection_options),
       spdy_session_pool_(params.host_resolver,
                          params.ssl_config_service,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index da8ac72a2..d1e4234 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -112,6 +112,7 @@
     bool enable_quic_port_selection;
     bool enable_quic_time_based_loss_detection;
     bool quic_always_require_handshake_confirmation;
+    bool quic_disable_connection_pooling;
     HostPortPair origin_to_force_quic_on;
     QuicClock* quic_clock;  // Will be owned by QuicStreamFactory.
     QuicRandom* quic_random;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 51b3b9d..545db5b 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -486,6 +486,7 @@
     bool enable_port_selection,
     bool enable_time_based_loss_detection,
     bool always_require_handshake_confirmation,
+    bool disable_connection_pooling,
     const QuicTagVector& connection_options)
     : require_confirmation_(true),
       host_resolver_(host_resolver),
@@ -503,6 +504,7 @@
       enable_port_selection_(enable_port_selection),
       always_require_handshake_confirmation_(
           always_require_handshake_confirmation),
+      disable_connection_pooling_(disable_connection_pooling),
       port_seed_(random_generator_->RandUint64()),
       weak_factory_(this) {
   DCHECK(transport_security_state_);
@@ -584,6 +586,9 @@
     const QuicServerId& server_id,
     const AddressList& address_list) {
   DCHECK(!HasActiveSession(server_id));
+  if (disable_connection_pooling_) {
+    return false;
+  }
   for (size_t i = 0; i < address_list.size(); ++i) {
     const IPEndPoint& address = address_list[i];
     const IpAliasKey ip_alias_key(address, server_id.is_https());
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 330f5f5..c5aa835a 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -104,6 +104,7 @@
       bool enable_port_selection,
       bool enable_time_based_loss_detection,
       bool always_require_handshake_confirmation,
+      bool disable_connection_pooling,
       const QuicTagVector& connection_options);
   virtual ~QuicStreamFactory();
 
@@ -281,6 +282,9 @@
   // introduce at least one RTT for the handshake before the client sends data.
   bool always_require_handshake_confirmation_;
 
+  // Set if we do not want connection pooling.
+  bool disable_connection_pooling_;
+
   // Each profile will (probably) have a unique port_seed_ value.  This value is
   // used to help seed a pseudo-random number generator (PortSuggester) so that
   // we consistently (within this profile) suggest the same ephemeral port when
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 7650184..374eda4 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -84,6 +84,10 @@
     }
     return false;
   }
+
+  static void DisableConnectionPooling(QuicStreamFactory* factory) {
+    factory->disable_connection_pooling_ = true;
+  }
 };
 
 class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
@@ -110,7 +114,8 @@
                  SupportedVersions(GetParam()),
                  /*enable_port_selection=*/true,
                  /*enable_time_based_loss_detection=*/true,
-                 /*always_require_handshake_confirmation=*/true,
+                 /*always_require_handshake_confirmation=*/false,
+                 /*disable_connection_pooling=*/false,
                  QuicTagVector()),
         host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
         is_https_(false),
@@ -418,6 +423,61 @@
   EXPECT_TRUE(socket_data.at_write_eof());
 }
 
+TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
+  MockRead reads[] = {
+    MockRead(ASYNC, OK, 0)  // EOF
+  };
+  DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
+  DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
+  socket_factory_.AddSocketDataProvider(&socket_data1);
+  socket_factory_.AddSocketDataProvider(&socket_data2);
+  socket_data1.StopAfter(1);
+  socket_data2.StopAfter(1);
+
+  HostPortPair server2("mail.google.com", kDefaultServerPort);
+  host_resolver_.set_synchronous_mode(true);
+  host_resolver_.rules()->AddIPLiteralRule(
+      kDefaultServerHostName, "192.168.0.1", "");
+  host_resolver_.rules()->AddIPLiteralRule(
+      "mail.google.com", "192.168.0.1", "");
+
+  // Disable connection pooling.
+  QuicStreamFactoryPeer::DisableConnectionPooling(&factory_);
+
+  QuicStreamRequest request(&factory_);
+  EXPECT_EQ(OK,
+            request.Request(host_port_pair_,
+                            is_https_,
+                            privacy_mode_,
+                            "GET",
+                            net_log_,
+                            callback_.callback()));
+  scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+  EXPECT_TRUE(stream.get());
+
+  TestCompletionCallback callback;
+  QuicStreamRequest request2(&factory_);
+  EXPECT_EQ(OK,
+            request2.Request(server2,
+                             is_https_,
+                             privacy_mode_,
+                             "GET",
+                             net_log_,
+                             callback.callback()));
+  scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+  EXPECT_TRUE(stream2.get());
+
+  EXPECT_NE(
+      QuicStreamFactoryPeer::GetActiveSession(
+          &factory_, host_port_pair_, is_https_),
+      QuicStreamFactoryPeer::GetActiveSession(&factory_, server2, is_https_));
+
+  EXPECT_TRUE(socket_data1.at_read_eof());
+  EXPECT_TRUE(socket_data1.at_write_eof());
+  EXPECT_TRUE(socket_data2.at_read_eof());
+  EXPECT_TRUE(socket_data2.at_write_eof());
+}
+
 TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
   MockRead reads[] = {
     MockRead(ASYNC, OK, 0)  // EOF
@@ -548,6 +608,75 @@
   EXPECT_TRUE(socket_data.at_write_eof());
 }
 
+TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
+  MockRead reads[] = {
+    MockRead(ASYNC, OK, 0)  // EOF
+  };
+  DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
+  DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
+  socket_factory_.AddSocketDataProvider(&socket_data1);
+  socket_factory_.AddSocketDataProvider(&socket_data2);
+  socket_data1.StopAfter(1);
+  socket_data2.StopAfter(1);
+
+  HostPortPair server1("www.example.org", 443);
+  HostPortPair server2("mail.example.org", 443);
+
+  // Load a cert that is valid for:
+  //   www.example.org (server1)
+  //   mail.example.org (server2)
+  //   www.example.com
+  base::FilePath certs_dir = GetTestCertsDirectory();
+  scoped_refptr<X509Certificate> test_cert(
+      ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
+  ASSERT_NE(static_cast<X509Certificate*>(NULL), 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;
+  crypto_client_stream_factory_.set_proof_verify_details(&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", "");
+
+  // Disable connection pooling.
+  QuicStreamFactoryPeer::DisableConnectionPooling(&factory_);
+
+  QuicStreamRequest request(&factory_);
+  is_https_ = true;
+  EXPECT_EQ(OK,
+            request.Request(server1,
+                            is_https_,
+                            privacy_mode_,
+                            "GET",
+                            net_log_,
+                            callback_.callback()));
+  scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+  EXPECT_TRUE(stream.get());
+
+  TestCompletionCallback callback;
+  QuicStreamRequest request2(&factory_);
+  EXPECT_EQ(OK,
+            request2.Request(server2,
+                             is_https_,
+                             privacy_mode_,
+                             "GET",
+                             net_log_,
+                             callback_.callback()));
+  scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+  EXPECT_TRUE(stream2.get());
+
+  EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(
+                &factory_, server1, is_https_),
+            QuicStreamFactoryPeer::GetActiveSession(
+                &factory_, server2, is_https_));
+
+  EXPECT_TRUE(socket_data1.at_read_eof());
+  EXPECT_TRUE(socket_data1.at_write_eof());
+  EXPECT_TRUE(socket_data2.at_read_eof());
+  EXPECT_TRUE(socket_data2.at_write_eof());
+}
+
 TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithCertMismatch) {
   MockRead reads[] = {
     MockRead(ASYNC, OK, 0)  // EOF
@@ -682,6 +811,81 @@
   EXPECT_TRUE(socket_data.at_write_eof());
 }
 
+TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
+  MockRead reads[] = {
+    MockRead(ASYNC, OK, 0)  // EOF
+  };
+  DeterministicSocketData socket_data1(reads, arraysize(reads), NULL, 0);
+  DeterministicSocketData socket_data2(reads, arraysize(reads), NULL, 0);
+  socket_factory_.AddSocketDataProvider(&socket_data1);
+  socket_factory_.AddSocketDataProvider(&socket_data2);
+  socket_data1.StopAfter(1);
+  socket_data2.StopAfter(1);
+
+  HostPortPair server1("www.example.org", 443);
+  HostPortPair server2("mail.example.org", 443);
+  uint8 primary_pin = 1;
+  uint8 backup_pin = 2;
+  test::AddPin(&transport_security_state_, "mail.example.org", primary_pin,
+               backup_pin);
+
+  // Load a cert that is valid for:
+  //   www.example.org (server1)
+  //   mail.example.org (server2)
+  base::FilePath certs_dir = GetTestCertsDirectory();
+  scoped_refptr<X509Certificate> test_cert(
+      ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
+  ASSERT_NE(static_cast<X509Certificate*>(NULL), 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;
+  verify_details.cert_verify_result.public_key_hashes.push_back(
+      test::GetTestHashValue(primary_pin));
+  crypto_client_stream_factory_.set_proof_verify_details(&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", "");
+
+  // Disable connection pooling.
+  QuicStreamFactoryPeer::DisableConnectionPooling(&factory_);
+
+  QuicStreamRequest request(&factory_);
+  is_https_ = true;
+  EXPECT_EQ(OK,
+            request.Request(server1,
+                            is_https_,
+                            privacy_mode_,
+                            "GET",
+                            net_log_,
+                            callback_.callback()));
+  scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+  EXPECT_TRUE(stream.get());
+
+  TestCompletionCallback callback;
+  QuicStreamRequest request2(&factory_);
+  EXPECT_EQ(OK,
+            request2.Request(server2,
+                             is_https_,
+                             privacy_mode_,
+                             "GET",
+                             net_log_,
+                             callback_.callback()));
+  scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+  EXPECT_TRUE(stream2.get());
+
+  EXPECT_NE(QuicStreamFactoryPeer::GetActiveSession(
+                &factory_, server1, is_https_),
+            QuicStreamFactoryPeer::GetActiveSession(
+                &factory_, server2, is_https_));
+
+  EXPECT_TRUE(socket_data1.at_read_eof());
+  EXPECT_TRUE(socket_data1.at_write_eof());
+  EXPECT_TRUE(socket_data2.at_read_eof());
+  EXPECT_TRUE(socket_data2.at_write_eof());
+}
+
 TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
   MockRead reads[] = {
     MockRead(ASYNC, OK, 0)  // EOF