Land Recent QUIC Changes.

Change from setting QUIC's ack timer to 0ms when any handshake packet is
received to setting it when the handshake is confirmed on the client
side.

Merge internal change: 80306847
https://codereview.chromium.org/742823005/

Preparation for Chrome experiment to enable bandwidth resumption.
Protected behind FLAGS_quic_enable_bandwidth_resumption_experiment

Once this CL is in, I intend to add a Chrome experiment to add the
connection option kBWRE to a small percentage of connections to test the
effect of turning on BW resumption.

If a client provides a previously cached bandwidth estimate (that is
recent, and from the same serving region), then set initial CWND based
on this data.

Behavior change only when both the flag is true, and the Chrome
experiment adds the connection option to client handshakes.

A followup CL (78446219) will add varz to track the distribution of
resulting initial CWNDs.

Merge internal change: 80239310
https://codereview.chromium.org/737153002/

Changes QUIC's SentPacketManager to pass in HAS_RETRANSMITTABLE_DATA to
the SendAlgorithm for FEC packets, so that the SendAlgorithm can count
FEC packets towards congestion control.

Merge internal change: 80171666
https://codereview.chromium.org/731863007/

Record the last packet send time before we start sending the packet

Problem:

Every time QuicConnection sends a new packet, it records the time that
the packet was sent.  It passes this information to the
QuicSentPacketManager, which ultimately stores the information in the
TransmissionInfo.sent_time for the packet.

Later, when the QuicSentPacketManager receives an ack for the packet,
it retrieves its TransmissionInfo and takes a sample of the current
RTT as follows:

rtt_sample = ack_receive_time - transmission_info.sent_time

Previously, QuicConnection was recording the packet "sent_time" as the
time that WritePacket completes.  The problem with this approach is
that the write itself may pause the thread or take a long time.  In
this case, transmission_info.sent_time will be artificially inflated.
When that inflated value is subtracted from the ack time, as above, it
will cause the current RTT sample to become artificially small.

An artificially small RTT will affect our current estimate of the min
RTT, which we currently cannot recover from.  The min_rtt will be
pinned to the aberrant value.

Solution:

Changed the code to record the sent_time as the time that the write
begins.  The drawback of this approach is that any extra send time
will be temporarily factored into our smoothed-RTT calculations.  The
advantage is that it will prevent artificially small RTTs from setting
the min_rtt forever.

Added a corresponding test, which exercises this scenario by
artificially advancing the clock during the write.

Change QUIC to record send timestamp prior to write. Protected by
FLAGS_quic_record_send_time_before_write.

Merge internal change: 80138676
https://codereview.chromium.org/740793002/

Remove a QUIC LOG(DFATAL) that validly occurs when two packets are
queued.

This may occur when the internal server is write blocked when an two
packet REJ is written.

Merge internal change: 80124025
https://codereview.chromium.org/736053002/

Tighten up a QUIC LOG(DFATAL) for packets expected to have a non-zero
nack count.

If the packet is never sent, it never gets nacked, but that wasn't taken
into account.

Merge internal change: 80120917
https://codereview.chromium.org/735353002/

Use override instead of virtual..override in ./net/quic/... and
./net/tools/quic/...

C++11 in Chromium!

$ find .../quic/ \( -iname \*.h -o -iname \*.cc \) -print -exec clang_tidy {} -checks='-*,misc-use-override' -fix \;

Merge internal change: 80111599
https://codereview.chromium.org/741773002/

Log the SNI and UAID fields in handshake messages as quoted strings.

Merge internal change: 80005106
https://codereview.chromium.org/735933002/

[email protected]

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

Cr-Commit-Position: refs/heads/master@{#304960}
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 8073c5bb..7e9f81a 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -27,6 +27,11 @@
   sender_->SetFromConfig(config, is_server, using_pacing);
 }
 
+void PacingSender::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  sender_->ResumeConnectionState(cached_network_params);
+}
+
 void PacingSender::SetNumEmulatedConnections(int num_connections) {
   sender_->SetNumEmulatedConnections(num_connections);
 }
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index 4eb3dab5..d7d3b2d8 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -16,6 +16,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_config.h"
 #include "net/quic/quic_protocol.h"
@@ -38,6 +39,8 @@
   void SetFromConfig(const QuicConfig& config,
                      bool is_server,
                      bool using_pacing) override;
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
@@ -63,6 +66,7 @@
   bool InRecovery() const override;
   QuicByteCount GetSlowStartThreshold() const override;
   CongestionControlType GetCongestionControlType() const override;
+  // End implementation of SendAlgorithmInterface.
 
  private:
   scoped_ptr<SendAlgorithmInterface> sender_;  // Underlying sender.
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 7195f81..322ff1d 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -12,6 +12,7 @@
 
 #include "base/basictypes.h"
 #include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_clock.h"
 #include "net/quic/quic_config.h"
@@ -113,6 +114,10 @@
   virtual QuicByteCount GetSlowStartThreshold() const = 0;
 
   virtual CongestionControlType GetCongestionControlType() const = 0;
+
+  // Called by the Session when we get a bandwidth estimate from the client.
+  virtual void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 2d0efd7..5fa1559 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -27,13 +27,12 @@
 const uint32 kDefaultNumConnections = 2;  // N-connection emulation.
 }  // namespace
 
-TcpCubicSender::TcpCubicSender(
-    const QuicClock* clock,
-    const RttStats* rtt_stats,
-    bool reno,
-    QuicPacketCount initial_tcp_congestion_window,
-    QuicPacketCount max_tcp_congestion_window,
-    QuicConnectionStats* stats)
+TcpCubicSender::TcpCubicSender(const QuicClock* clock,
+                               const RttStats* rtt_stats,
+                               bool reno,
+                               QuicPacketCount initial_tcp_congestion_window,
+                               QuicPacketCount max_tcp_congestion_window,
+                               QuicConnectionStats* stats)
     : hybrid_slow_start_(clock),
       cubic_(clock, stats),
       rtt_stats_(rtt_stats),
@@ -49,8 +48,8 @@
       slowstart_threshold_(max_tcp_congestion_window),
       previous_slowstart_threshold_(0),
       last_cutback_exited_slowstart_(false),
-      max_tcp_congestion_window_(max_tcp_congestion_window) {
-}
+      max_tcp_congestion_window_(max_tcp_congestion_window),
+      clock_(clock) {}
 
 TcpCubicSender::~TcpCubicSender() {
   UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
@@ -73,6 +72,26 @@
   }
 }
 
+void TcpCubicSender::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  // If the previous bandwidth estimate is less than an hour old, store in
+  // preparation for doing bandwidth resumption.
+  int64 seconds_since_estimate =
+      clock_->WallNow().ToUNIXSeconds() - cached_network_params.timestamp();
+  if (seconds_since_estimate > kNumSecondsPerHour) {
+    return;
+  }
+
+  QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
+      cached_network_params.bandwidth_estimate_bytes_per_second());
+  QuicTime::Delta rtt_ms =
+      QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
+  congestion_window_ = bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize;
+
+  // TODO(rjshade): Set appropriate CWND when previous connection was in slow
+  // start at time of estimate.
+}
+
 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) {
   num_connections_ = max(1, num_connections);
   cubic_.SetNumConnections(num_connections_);
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index a7507a27..eeb9331f 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -15,6 +15,7 @@
 #include "net/quic/congestion_control/hybrid_slow_start.h"
 #include "net/quic/congestion_control/prr_sender.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_connection_stats.h"
 #include "net/quic/quic_protocol.h"
@@ -43,6 +44,8 @@
   void SetFromConfig(const QuicConfig& config,
                      bool is_server,
                      bool using_pacing) override;
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
@@ -130,6 +133,8 @@
   // Maximum number of outstanding packets for tcp.
   QuicPacketCount max_tcp_congestion_window_;
 
+  const QuicClock* clock_;
+
   DISALLOW_COPY_AND_ASSIGN(TcpCubicSender);
 };
 
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 427dd8c2..e4737eb1 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -701,5 +701,32 @@
   EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
 }
 
+TEST_F(TcpCubicSenderTest, BandwidthResumption) {
+  // Test that when provided with CachedNetworkParameters and opted in to the
+  // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND
+  // appropriately.
+
+  // Set some common values.
+  CachedNetworkParameters cached_network_params;
+  const QuicPacketCount kNumberOfPackets = 123;
+  const int kBandwidthEstimateBytesPerSecond =
+      kNumberOfPackets * kMaxPacketSize;
+  cached_network_params.set_bandwidth_estimate_bytes_per_second(
+      kBandwidthEstimateBytesPerSecond);
+  cached_network_params.set_min_rtt_ms(1000);
+
+  // Ensure that an old estimate is not used for bandwidth resumption.
+  cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+                                      (kNumSecondsPerHour + 1));
+  sender_->ResumeConnectionState(cached_network_params);
+  EXPECT_EQ(10u, sender_->congestion_window());
+
+  // If the estimate is new enough, make sure it is used.
+  cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+                                      (kNumSecondsPerHour - 1));
+  sender_->ResumeConnectionState(cached_network_params);
+  EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc
index 6cf56d8..9366105e 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -40,7 +40,7 @@
       continue;
     }
 
-    LOG_IF(DFATAL, it->nack_count == 0)
+    LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized())
         << "All packets less than largest observed should have been nacked."
         << "sequence_number:" << sequence_number
         << " largest_observed:" << largest_observed;
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index 5819fb1..fe6a6ea 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -12,8 +12,14 @@
 #include "net/quic/test_tools/mock_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::vector;
+
 namespace net {
 namespace test {
+namespace {
+
+// Default packet length.
+const uint32 kDefaultLength = 1000;
 
 class TcpLossAlgorithmTest : public ::testing::Test {
  protected:
@@ -24,9 +30,16 @@
                          clock_.Now());
   }
 
+  ~TcpLossAlgorithmTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   void SendDataPacket(QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
     unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
@@ -43,6 +56,7 @@
     }
   }
 
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   TCPLossAlgorithm loss_algorithm_;
   RttStats rtt_stats_;
@@ -179,5 +193,6 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+}  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/congestion_control/time_loss_algorithm.cc b/net/quic/congestion_control/time_loss_algorithm.cc
index 9dd9ae9..b5f90b70 100644
--- a/net/quic/congestion_control/time_loss_algorithm.cc
+++ b/net/quic/congestion_control/time_loss_algorithm.cc
@@ -46,8 +46,10 @@
     if (!it->in_flight) {
       continue;
     }
-    LOG_IF(DFATAL, it->nack_count == 0)
-        << "All packets less than largest observed should have been nacked.";
+    LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized())
+        << "All packets less than largest observed should have been nacked."
+        << "sequence_number:" << sequence_number
+        << " largest_observed:" << largest_observed;
 
     // Packets are sent in order, so break when we haven't waited long enough
     // to lose any more packets and leave the loss_time_ set for the timeout.
diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc
index b964d28..1e9b7e5 100644
--- a/net/quic/congestion_control/time_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -12,8 +12,14 @@
 #include "net/quic/test_tools/mock_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::vector;
+
 namespace net {
 namespace test {
+namespace {
+
+// Default packet length.
+const uint32 kDefaultLength = 1000;
 
 class TimeLossAlgorithmTest : public ::testing::Test {
  protected:
@@ -24,9 +30,16 @@
                          clock_.Now());
   }
 
+  ~TimeLossAlgorithmTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   void SendDataPacket(QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
     unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
@@ -43,6 +56,7 @@
     }
   }
 
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   TimeLossAlgorithm loss_algorithm_;
   RttStats rtt_stats_;
@@ -134,5 +148,6 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+}  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc
index 09379f3..b2ea3a7 100644
--- a/net/quic/crypto/common_cert_set.cc
+++ b/net/quic/crypto/common_cert_set.cc
@@ -153,7 +153,7 @@
 
  private:
   CommonCertSetsQUIC() {}
-  virtual ~CommonCertSetsQUIC() {}
+  ~CommonCertSetsQUIC() override {}
 
   friend struct DefaultSingletonTraits<CommonCertSetsQUIC>;
   DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
index 91259680..23e8ea2 100644
--- a/net/quic/crypto/crypto_handshake_message.cc
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -302,8 +302,9 @@
                             static_cast<int>(it->second.size()));
         done = true;
         break;
+      case kSNI:
       case kUAID:
-        ret += it->second;
+        ret += "\"" + it->second + "\"";
         done = true;
         break;
     }
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index d010776..57a5508 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -71,6 +71,9 @@
 // FEC options
 const QuicTag kFHDR = TAG('F', 'H', 'D', 'R');   // FEC protect headers
 
+// Enable bandwidth resumption experiment.
+const QuicTag kBWRE = TAG('B', 'W', 'R', 'E');  // Bandwidth resumption.
+
 // Proof types (i.e. certificate types)
 // NOTE: although it would be silly to do so, specifying both kX509 and kX59R
 // is allowed and is equivalent to specifying only kX509.
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 66583b8..88beca76 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -52,6 +52,8 @@
                                             /*is_secure=*/false,
                                             PRIVACY_MODE_DISABLED),
         &crypto_config_, nullptr);
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void TearDown() override { session_.CloseSessionOnError(ERR_ABORTED); }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index fd9ec5f..62cbc64 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -282,6 +282,11 @@
   max_undecryptable_packets_ = config.max_undecryptable_packets();
 }
 
+void QuicConnection::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  sent_packet_manager_.ResumeConnectionState(cached_network_params);
+}
+
 void QuicConnection::SetNumOpenStreams(size_t num_streams) {
   sent_packet_manager_.SetNumOpenStreams(num_streams);
 }
@@ -911,10 +916,6 @@
     } else {
       // Send an ack much more quickly for crypto handshake packets.
       QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime();
-      if (last_stream_frames_.size() == 1 &&
-          last_stream_frames_[0].stream_id == kCryptoStreamId) {
-        delayed_ack_time = QuicTime::Delta::Zero();
-      }
       ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time));
       DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
     }
@@ -1449,6 +1450,13 @@
            << QuicUtils::StringToHexASCIIDump(
                packet->serialized_packet.packet->AsStringPiece());
 
+  QuicTime packet_send_time = QuicTime::Zero();
+  if (FLAGS_quic_record_send_time_before_write) {
+    // Measure the RTT from before the write begins to avoid underestimating the
+    // min_rtt_, especially in cases where the thread blocks or gets swapped out
+    // during the WritePacket below.
+    packet_send_time = clock_->Now();
+  }
   WriteResult result = writer_->WritePacket(encrypted->data(),
                                             encrypted->length(),
                                             self_address().address(),
@@ -1467,7 +1475,16 @@
       return false;
     }
   }
-  QuicTime now = clock_->Now();
+  if (!FLAGS_quic_record_send_time_before_write) {
+    packet_send_time = clock_->Now();
+  }
+  if (!packet_send_time.IsInitialized()) {
+    // TODO(jokulik): This is only needed because of the two code paths for
+    // initializing packet_send_time.  Once "quic_record_send_time_before_write"
+    // is deprecated, this check can be removed.
+    LOG(DFATAL) << "The packet send time should never be zero. "
+                << "This is a programming bug, please report it.";
+  }
   if (result.status != WRITE_STATUS_ERROR && debug_visitor_.get() != nullptr) {
     // Pass the write result to the visitor.
     debug_visitor_->OnPacketSent(packet->serialized_packet,
@@ -1475,14 +1492,17 @@
                                  packet->encryption_level,
                                  packet->transmission_type,
                                  *encrypted,
-                                 now);
+                                 packet_send_time);
   }
   if (packet->transmission_type == NOT_RETRANSMISSION) {
-    time_of_last_sent_new_packet_ = now;
+    time_of_last_sent_new_packet_ = packet_send_time;
   }
   SetPingAlarm();
-  DVLOG(1) << ENDPOINT << "time of last sent packet: "
-           << now.ToDebuggingValue();
+  DVLOG(1) << ENDPOINT << "time "
+           << (FLAGS_quic_record_send_time_before_write ?
+               "we began writing " : "we finished writing ")
+           << "last sent packet: "
+           << packet_send_time.ToDebuggingValue();
 
   // TODO(ianswett): Change the sequence number length and other packet creator
   // options by a more explicit API than setting a struct value directly,
@@ -1494,7 +1514,7 @@
   bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent(
       &packet->serialized_packet,
       packet->original_sequence_number,
-      now,
+      packet_send_time,
       encrypted->length(),
       packet->transmission_type,
       IsRetransmittable(*packet));
@@ -1585,6 +1605,12 @@
 
 void QuicConnection::OnHandshakeComplete() {
   sent_packet_manager_.SetHandshakeConfirmed();
+  // The client should immediately ack the SHLO to confirm the handshake is
+  // complete with the server.
+  if (!is_server_ && !ack_queued_) {
+    ack_alarm_->Cancel();
+    ack_alarm_->Set(clock_->ApproximateNow());
+  }
 }
 
 void QuicConnection::SendOrQueuePacket(QueuedPacket packet) {
@@ -1598,8 +1624,6 @@
   sent_entropy_manager_.RecordPacketEntropyHash(
       packet.serialized_packet.sequence_number,
       packet.serialized_packet.entropy_hash);
-  LOG_IF(DFATAL, !queued_packets_.empty() && !writer_->IsWriteBlocked())
-      << "Packets should only be left queued if we're write blocked.";
   if (!WritePacket(&packet)) {
     queued_packets_.push_back(packet);
   }
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 96f5cbc..305dc0be4 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -258,6 +258,11 @@
   // Sets connection parameters from the supplied |config|.
   void SetFromConfig(const QuicConfig& config);
 
+  // Called by the Session when the client has provided CachedNetworkParameters.
+  // Virtual for tests.
+  virtual void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params);
+
   // Sets the number of active streams on the connection for congestion control.
   void SetNumOpenStreams(size_t num_streams);
 
@@ -783,8 +788,8 @@
   // This is used for timeouts, and does not indicate the packet was processed.
   QuicTime time_of_last_received_packet_;
 
-  // The last time a new (non-retransmitted) packet was sent for this
-  // connection.
+  // The last time this connection began sending a new (non-retransmitted)
+  // packet.
   QuicTime time_of_last_sent_new_packet_;
 
   // Sequence number of the last sent packet.  Packets are guaranteed to be sent
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 4e58dfd..ede61c8 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -67,7 +67,7 @@
   }
 
   bool GenerateCongestionFeedback(
-      QuicCongestionFeedbackFrame* congestion_feedback) {
+      QuicCongestionFeedbackFrame* congestion_feedback) override {
     if (feedback_ == nullptr) {
       return false;
     }
@@ -95,6 +95,7 @@
 
   // QuicEncrypter interface.
   bool SetKey(StringPiece key) override { return true; }
+
   bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
 
   bool Encrypt(StringPiece nonce,
@@ -149,6 +150,7 @@
 
   // QuicDecrypter interface
   bool SetKey(StringPiece key) override { return true; }
+
   bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
 
   bool Decrypt(StringPiece nonce,
@@ -258,7 +260,7 @@
 
 class TestPacketWriter : public QuicPacketWriter {
  public:
-  explicit TestPacketWriter(QuicVersion version)
+  TestPacketWriter(QuicVersion version, MockClock *clock)
       : version_(version),
         framer_(SupportedVersions(version_)),
         last_packet_size_(0),
@@ -268,7 +270,9 @@
         final_bytes_of_last_packet_(0),
         final_bytes_of_previous_packet_(0),
         use_tagging_decrypter_(false),
-        packets_write_attempts_(0) {
+        packets_write_attempts_(0),
+        clock_(clock),
+        write_pause_time_delta_(QuicTime::Delta::Zero()) {
   }
 
   // QuicPacketWriter interface
@@ -297,6 +301,10 @@
       return WriteResult(WRITE_STATUS_BLOCKED, -1);
     }
     last_packet_size_ = packet.length();
+
+    if (!write_pause_time_delta_.IsZero()) {
+      clock_->AdvanceTime(write_pause_time_delta_);
+    }
     return WriteResult(WRITE_STATUS_OK, last_packet_size_);
   }
 
@@ -310,6 +318,11 @@
 
   void BlockOnNextWrite() { block_on_next_write_ = true; }
 
+  // Sets the amount of time that the writer should before the actual write.
+  void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+    write_pause_time_delta_ = delta;
+  }
+
   const QuicPacketHeader& header() { return framer_.header(); }
 
   size_t frame_count() const { return framer_.num_frames(); }
@@ -390,6 +403,10 @@
   uint32 final_bytes_of_previous_packet_;
   bool use_tagging_decrypter_;
   uint32 packets_write_attempts_;
+  MockClock *clock_;
+  // If non-zero, the clock will pause during WritePacket for this amount of
+  // time.
+  QuicTime::Delta write_pause_time_delta_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPacketWriter);
 };
@@ -597,7 +614,7 @@
   MockPacketWriterFactory(QuicPacketWriter* writer) {
     ON_CALL(*this, Create(_)).WillByDefault(Return(writer));
   }
-  virtual ~MockPacketWriterFactory() {}
+  ~MockPacketWriterFactory() override {}
 
   MOCK_CONST_METHOD1(Create, QuicPacketWriter*(QuicConnection* connection));
 };
@@ -611,7 +628,7 @@
         send_algorithm_(new StrictMock<MockSendAlgorithm>),
         loss_algorithm_(new MockLossAlgorithm()),
         helper_(new TestConnectionHelper(&clock_, &random_generator_)),
-        writer_(new TestPacketWriter(version())),
+        writer_(new TestPacketWriter(version(), &clock_)),
         factory_(writer_.get()),
         connection_(connection_id_, IPEndPoint(), helper_.get(),
                     factory_, false, version()),
@@ -974,6 +991,10 @@
     EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
   }
 
+  void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+    writer_->SetWritePauseTimeDelta(delta);
+  }
+
   void CongestionBlockWrites() {
     EXPECT_CALL(*send_algorithm_,
                 TimeUntilSend(_, _, _)).WillRepeatedly(
@@ -1548,6 +1569,74 @@
   EXPECT_EQ(7u, least_unacked());
 }
 
+// If FLAGS_quic_record_send_time_before_write is disabled, QuicConnection
+// should record the packet sen-tdime after the packet is sent.
+TEST_P(QuicConnectionTest, RecordSentTimeAfterPacketSent) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, false);
+  // We're using a MockClock for the tests, so we have complete control over the
+  // time.
+  // Our recorded timestamp for the last packet sent time will be passed in to
+  // the send_algorithm.  Make sure that it is set to the correct value.
+  QuicTime actual_recorded_send_time = QuicTime::Zero();
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+
+  // First send without any pause and check the result.
+  QuicTime expected_recorded_send_time = clock_.Now();
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+
+  // Now pause during the write, and check the results.
+  actual_recorded_send_time = QuicTime::Zero();
+  const QuicTime::Delta kWritePauseTimeDelta =
+      QuicTime::Delta::FromMilliseconds(5000);
+  SetWritePauseTimeDelta(kWritePauseTimeDelta);
+  expected_recorded_send_time = clock_.Now().Add(kWritePauseTimeDelta);
+
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+  connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+}
+
+// If FLAGS_quic_record_send_time_before_write is enabled, QuicConnection should
+// record the the packet sent-time prior to sending the packet.
+TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, true);
+  // We're using a MockClock for the tests, so we have complete control over the
+  // time.
+  // Our recorded timestamp for the last packet sent time will be passed in to
+  // the send_algorithm.  Make sure that it is set to the correct value.
+  QuicTime actual_recorded_send_time = QuicTime::Zero();
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+
+  // First send without any pause and check the result.
+  QuicTime expected_recorded_send_time = clock_.Now();
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+
+  // Now pause during the write, and check the results.
+  actual_recorded_send_time = QuicTime::Zero();
+  const QuicTime::Delta kWritePauseTimeDelta =
+      QuicTime::Delta::FromMilliseconds(5000);
+  SetWritePauseTimeDelta(kWritePauseTimeDelta);
+  expected_recorded_send_time = clock_.Now();
+
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+  connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+}
+
 TEST_P(QuicConnectionTest, FECSending) {
   // All packets carry version info till version is negotiated.
   QuicPacketCreator* creator =
@@ -1565,7 +1654,8 @@
   creator->set_max_packet_length(length);
 
   // Send 4 protected data packets, which should also trigger 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(5);
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(5);
   // The first stream frame will have 2 fewer overhead bytes than the other 3.
   const string payload(payload_length * 4 + 2, 'a');
   connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr);
@@ -1601,7 +1691,8 @@
       &connection_)->IsFecEnabled());
 
   // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
 
   const QuicTime::Delta retransmission_time =
@@ -1620,8 +1711,9 @@
   EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator(
       &connection_)->IsFecEnabled());
 
-  // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+  // 3 Data and 3 FEC packets.
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
   // Send some more data afterwards to ensure early retransmit doesn't trigger.
   connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr);
@@ -1648,8 +1740,9 @@
   EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator(
       &connection_)->IsFecEnabled());
 
-  // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+  // 3 Data and 3 FEC packet.
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
   // Send some more data afterwards to ensure early retransmit doesn't trigger.
   connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr);
@@ -3070,22 +3163,25 @@
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
-TEST_P(QuicConnectionTest, SendEarlyDelayedAckForCrypto) {
-  QuicTime ack_time = clock_.ApproximateNow();
+TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-  // Process a packet from the crypto stream, which is frame1_'s default.
   ProcessPacket(1);
-  // Check if delayed ack timer is running for the expected interval.
+  // Check that ack is sent and that delayed ack alarm is set.
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
+  EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+  // Completing the handshake as the server does nothing.
+  QuicConnectionPeer::SetIsServer(&connection_, true);
+  connection_.OnHandshakeComplete();
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-  // Simulate delayed ack alarm firing.
-  connection_.GetAckAlarm()->Fire();
-  // Check that ack is sent and that delayed ack alarm is reset.
-  EXPECT_EQ(2u, writer_->frame_count());
-  EXPECT_FALSE(writer_->stop_waiting_frames().empty());
-  EXPECT_FALSE(writer_->ack_frames().empty());
-  EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+
+  // Complete the handshake as the client decreases the delayed ack time to 0ms.
+  QuicConnectionPeer::SetIsServer(&connection_, false);
+  connection_.OnHandshakeComplete();
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  EXPECT_EQ(clock_.ApproximateNow(), connection_.GetAckAlarm()->deadline());
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 1df2313..8e14d775 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -34,6 +34,8 @@
         stream_(new QuicCryptoClientStream(server_id_, session_.get(), nullptr,
                                            &crypto_config_)) {
     session_->SetCryptoStream(stream_.get());
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CompleteCryptoHandshake() {
@@ -128,8 +130,8 @@
 
   // Advance time 5 years to ensure that we pass the expiry time of the cached
   // server config.
-  reinterpret_cast<MockClock*>(const_cast<QuicClock*>(connection_->clock()))
-      ->AdvanceTime(QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
+  connection_->AdvanceTime(
+      QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
 
   // Check that a client hello was sent and that CryptoConnect doesn't fail
   // with an error.
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 1d62376..c4b5893 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -245,8 +245,8 @@
 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
 }
 
-CachedNetworkParameters*
-QuicCryptoServerStream::get_previous_cached_network_params() {
+const CachedNetworkParameters*
+QuicCryptoServerStream::previous_cached_network_params() const {
   return previous_cached_network_params_.get();
 }
 
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 09d9bd8..f88affe 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -82,6 +82,8 @@
   void set_previous_cached_network_params(
       CachedNetworkParameters cached_network_params);
 
+  const CachedNetworkParameters* previous_cached_network_params() const;
+
  protected:
   virtual QuicErrorCode ProcessClientHello(
       const CryptoHandshakeMessage& message,
@@ -93,8 +95,6 @@
   // before going through the parameter negotiation step.
   virtual void OverrideQuicConfigDefaults(QuicConfig* config);
 
-  CachedNetworkParameters* get_previous_cached_network_params();
-
  private:
   friend class test::CryptoTestUtils;
 
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 47d58ce..c93283a 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -54,3 +54,14 @@
 // If true, QUIC connections will delay moving to forward security until the
 // client starts sending foward secure encrypted packets.
 bool FLAGS_enable_quic_delay_forward_security = true;
+
+// Do not flip this flag.  jokulik plans more testing and additional monitoring
+// before the flag can go the auto-flip process.
+//
+// If true, record the timestamp for the last sent new packet before the call to
+// WritePacket, rather than after in QUIC.
+bool FLAGS_quic_record_send_time_before_write = false;
+
+// If true, enables the QUIC bandwidth resumption experiment (triggered by
+// Chrome/Finch).
+bool FLAGS_quic_enable_bandwidth_resumption_experiment = false;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index a75f79b..2ffe618 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -20,5 +20,8 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_delay_forward_security;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write;
+NET_EXPORT_PRIVATE
+extern bool FLAGS_quic_enable_bandwidth_resumption_experiment;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 4e03e3a..578acea 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -87,8 +87,7 @@
     server_framer_.set_visitor(&framer_visitor_);
   }
 
-  virtual ~QuicPacketCreatorTest() override {
-  }
+  ~QuicPacketCreatorTest() override {}
 
   void ProcessPacket(QuicPacket* packet) {
     scoped_ptr<QuicEncryptedPacket> encrypted(
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 3f2472c..ac99144 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -33,7 +33,7 @@
 class MockDelegate : public QuicPacketGenerator::DelegateInterface {
  public:
   MockDelegate() {}
-  virtual ~MockDelegate() override {}
+  ~MockDelegate() override {}
 
   MOCK_METHOD3(ShouldGeneratePacket,
                bool(TransmissionType transmission_type,
@@ -116,7 +116,7 @@
         packet6_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr),
         packet7_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr) {}
 
-  virtual ~QuicPacketGeneratorTest() override {
+  ~QuicPacketGeneratorTest() override {
     delete packet_.packet;
     delete packet_.retransmittable_frames;
     delete packet2_.packet;
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 5aa831e..b631b07a 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -704,7 +704,8 @@
       transmission_type(NOT_RETRANSMISSION),
       all_transmissions(nullptr),
       in_flight(false),
-      is_unackable(false) {}
+      is_unackable(false),
+      is_fec_packet(false) {}
 
 TransmissionInfo::TransmissionInfo(
     RetransmittableFrames* retransmittable_frames,
@@ -719,6 +720,7 @@
       transmission_type(transmission_type),
       all_transmissions(nullptr),
       in_flight(false),
-      is_unackable(false) {}
+      is_unackable(false),
+      is_fec_packet(false) {}
 
 }  // namespace net
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 00064ffd..4cd53a94 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -1099,6 +1099,8 @@
   bool in_flight;
   // True if the packet can never be acked, so it can be removed.
   bool is_unackable;
+  // True if the packet is an FEC packet.
+  bool is_fec_packet;
 };
 
 }  // namespace net
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 7978fed..142871e 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -163,6 +163,11 @@
   }
 }
 
+void QuicSentPacketManager::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  send_algorithm_->ResumeConnectionState(cached_network_params);
+}
+
 void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
   if (n_connection_simulation_) {
     // Ensure the number of connections is between 1 and 5.
@@ -323,6 +328,9 @@
         (retransmission_type == ALL_UNACKED_RETRANSMISSION ||
          frames->encryption_level() == ENCRYPTION_INITIAL)) {
       MarkForRetransmission(sequence_number, retransmission_type);
+    } else if (it->is_fec_packet) {
+      // Remove FEC packets from the packet map, since we can't retransmit them.
+      unacked_packets_.RemoveFromInFlight(sequence_number);
     }
   }
 }
@@ -549,12 +557,18 @@
   }
 
   // Only track packets as in flight that the send algorithm wants us to track.
+  // Since FEC packets should also be counted towards the congestion window,
+  // consider them as retransmittable for the purposes of congestion control.
+  HasRetransmittableData has_congestion_controlled_data =
+      serialized_packet->packet->is_fec_packet() ?
+      HAS_RETRANSMITTABLE_DATA : has_retransmittable_data;
   const bool in_flight =
       send_algorithm_->OnPacketSent(sent_time,
                                     unacked_packets_.bytes_in_flight(),
                                     sequence_number,
                                     bytes,
-                                    has_retransmittable_data);
+                                    has_congestion_controlled_data);
+
   unacked_packets_.AddSentPacket(*serialized_packet,
                                  original_sequence_number,
                                  transmission_type,
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 2a3ea64..2a94e09 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -16,6 +16,7 @@
 #include "net/quic/congestion_control/loss_detection_interface.h"
 #include "net/quic/congestion_control/rtt_stats.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_ack_notifier_manager.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_sustained_bandwidth_recorder.h"
@@ -99,6 +100,10 @@
 
   virtual void SetFromConfig(const QuicConfig& config);
 
+  // Pass the CachedNetworkParameters to the send algorithm.
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params);
+
   void SetNumOpenStreams(size_t num_streams);
 
   void SetHandshakeConfirmed() { handshake_confirmed_ = true; }
@@ -111,6 +116,13 @@
   bool IsUnacked(QuicPacketSequenceNumber sequence_number) const;
 
   // Requests retransmission of all unacked packets of |retransmission_type|.
+  // The behavior of this method depends on the value of |retransmission_type|:
+  // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted.
+  // This can happen, for example, after a version negotiation packet has been
+  // received and all packets needs to be retransmitted with the new version.
+  // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be
+  // retransmitted. This can happen, for example, when a CHLO has been rejected
+  // and the previously encrypted data needs to be encrypted with a new key.
   void RetransmitUnackedPackets(TransmissionType retransmission_type);
 
   // Retransmits the oldest pending packet there is still a tail loss probe
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index d710120..c1e6f202 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -64,9 +64,7 @@
     EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
   }
 
-  virtual ~QuicSentPacketManagerTest() override {
-    STLDeleteElements(&packets_);
-  }
+  ~QuicSentPacketManagerTest() override { STLDeleteElements(&packets_); }
 
   QuicByteCount BytesInFlight() {
     return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_);
@@ -216,7 +214,7 @@
   void SendFecPacket(QuicPacketSequenceNumber sequence_number) {
     EXPECT_CALL(*send_algorithm_,
                 OnPacketSent(_, BytesInFlight(), sequence_number,
-                             kDefaultLength, NO_RETRANSMITTABLE_DATA))
+                             kDefaultLength, HAS_RETRANSMITTABLE_DATA))
                     .Times(1).WillOnce(Return(true));
     SerializedPacket packet(CreateFecPacket(sequence_number));
     manager_.OnPacketSent(&packet, 0, clock_.Now(),
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 1d48182..e0defd6 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -37,14 +37,29 @@
 
 void QuicServerSession::OnConfigNegotiated() {
   QuicSession::OnConfigNegotiated();
-  if (!FLAGS_enable_quic_fec ||
-      !config()->HasReceivedConnectionOptions() ||
-      !ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+
+  if (!config()->HasReceivedConnectionOptions()) {
     return;
   }
-  // kFHDR config maps to FEC protection always for headers stream.
-  // TODO(jri): Add crypto stream in addition to headers for kHDR.
-  headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+
+  // If the client has provided a bandwidth estimate from the same serving
+  // region, then pass it to the sent packet manager in preparation for possible
+  // bandwidth resumption.
+  const CachedNetworkParameters* cached_network_params =
+      crypto_stream_->previous_cached_network_params();
+  if (FLAGS_quic_enable_bandwidth_resumption_experiment &&
+      cached_network_params != nullptr &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) &&
+      cached_network_params->serving_region() == serving_region_) {
+    connection()->ResumeConnectionState(*cached_network_params);
+  }
+
+  if (FLAGS_enable_quic_fec &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+    // kFHDR config maps to FEC protection always for headers stream.
+    // TODO(jri): Add crypto stream in addition to headers for kHDR.
+    headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+  }
 }
 
 void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 2318ab4..e4b163f 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -48,8 +48,8 @@
     session_->PostProcessAfterData();
   }
 
-  void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames)
-      override {
+  void OnWindowUpdateFrames(
+      const vector<QuicWindowUpdateFrame>& frames) override {
     session_->OnWindowUpdateFrames(frames);
     session_->PostProcessAfterData();
   }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index d14d875..d953678 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -54,8 +54,7 @@
       : QuicCryptoStream(session) {
   }
 
-  virtual void OnHandshakeMessage(
-      const CryptoHandshakeMessage& message) override {
+  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
     encryption_established_ = true;
     handshake_confirmed_ = true;
     CryptoHandshakeMessage msg;
@@ -94,7 +93,7 @@
 
   using ReliableQuicStream::CloseWriteSide;
 
-  virtual uint32 ProcessData(const char* data, uint32 data_len) override {
+  uint32 ProcessData(const char* data, uint32 data_len) override {
     return data_len;
   }
 
@@ -131,17 +130,15 @@
     InitializeSession();
   }
 
-  virtual TestCryptoStream* GetCryptoStream() override {
-    return &crypto_stream_;
-  }
+  TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
 
-  virtual TestStream* CreateOutgoingDataStream() override {
+  TestStream* CreateOutgoingDataStream() override {
     TestStream* stream = new TestStream(GetNextStreamId(), this);
     ActivateStream(stream);
     return stream;
   }
 
-  virtual TestStream* CreateIncomingDataStream(QuicStreamId id) override {
+  TestStream* CreateIncomingDataStream(QuicStreamId id) override {
     return new TestStream(id, this);
   }
 
@@ -153,7 +150,7 @@
     return QuicSession::GetIncomingDataStream(stream_id);
   }
 
-  virtual QuicConsumedData WritevData(
+  QuicConsumedData WritevData(
       QuicStreamId id,
       const IOVector& data,
       QuicStreamOffset offset,
@@ -223,6 +220,7 @@
         "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
         "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
         "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CheckClosedStreams() {
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 8c90c9f..43a105b 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -44,7 +44,7 @@
                                                 const string& details));
   MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
   MOCK_METHOD0(OnCanWrite, void());
-  virtual QuicPriority EffectivePriority() const override {
+  QuicPriority EffectivePriority() const override {
     return QuicUtils::HighestPriority();
   }
   virtual bool IsFlowControlEnabled() const {
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 53e5ebe..62bf582a 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -17,6 +17,8 @@
 
 namespace net {
 
+static const int kNumSecondsPerMinute = 60;
+static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60;
 static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
 static const uint64 kNumMicrosPerMilli =
     base::Time::kMicrosecondsPerMillisecond;
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index 04eb1b88..bbff3c9f 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -53,6 +53,9 @@
                         packet.sequence_number_length,
                         transmission_type,
                         sent_time);
+  DCHECK(packet.packet != nullptr);
+  info.is_fec_packet = packet.packet->is_fec_packet();
+
   if (old_sequence_number == 0) {
     if (packet.retransmittable_frames != nullptr &&
         packet.retransmittable_frames->HasCryptoHandshake() == IS_HANDSHAKE) {
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
index d31ce44..ca87e491 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -8,6 +8,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using std::min;
+using std::vector;
 
 namespace net {
 namespace test {
@@ -23,16 +24,26 @@
       : now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {
   }
 
+  ~QuicUnackedPacketMapTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   SerializedPacket CreateRetransmittablePacket(
       QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
   }
 
   SerializedPacket CreateNonRetransmittablePacket(
       QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, nullptr);
+                            packets_.back(), 0, nullptr);
   }
 
   void VerifyInFlightPackets(QuicPacketSequenceNumber* packets,
@@ -94,7 +105,7 @@
           << " packets[" << i << "]:" << packets[i];
     }
   }
-
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   QuicTime now_;
 };
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 814be7b4..b24316f 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -214,6 +214,8 @@
     QuicCryptoServerStream* server,
     const FakeClientOptions& options) {
   PacketSavingConnection* client_conn = new PacketSavingConnection(false);
+  // Advance the time, because timers do not like uninitialized times.
+  client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   TestClientSession client_session(client_conn, DefaultQuicConfig());
   QuicCryptoClientConfig crypto_config;
 
diff --git a/net/quic/test_tools/mock_quic_dispatcher.h b/net/quic/test_tools/mock_quic_dispatcher.h
index f923790..4945724 100644
--- a/net/quic/test_tools/mock_quic_dispatcher.h
+++ b/net/quic/test_tools/mock_quic_dispatcher.h
@@ -22,7 +22,7 @@
                      PacketWriterFactory* packet_writer_factory,
                      QuicConnectionHelperInterface* helper);
 
-  virtual ~MockQuicDispatcher();
+  ~MockQuicDispatcher() override;
 
   MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
                                    const IPEndPoint& client_address,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index fa987de6..3742a6cb 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -150,7 +150,7 @@
 class MockFramerVisitor : public QuicFramerVisitorInterface {
  public:
   MockFramerVisitor();
-  virtual ~MockFramerVisitor();
+  ~MockFramerVisitor() override;
 
   MOCK_METHOD1(OnError, void(QuicFramer* framer));
   // The constructor sets this up to return false by default.
@@ -225,7 +225,7 @@
 class MockConnectionVisitor : public QuicConnectionVisitorInterface {
  public:
   MockConnectionVisitor();
-  virtual ~MockConnectionVisitor();
+  ~MockConnectionVisitor() override;
 
   MOCK_METHOD1(OnStreamFrames, void(const std::vector<QuicStreamFrame>& frame));
   MOCK_METHOD1(OnWindowUpdateFrames,
@@ -293,7 +293,7 @@
   // Uses a Mock helper, ConnectionId of 42, and 127.0.0.1:123.
   MockConnection(bool is_server, const QuicVersionVector& supported_versions);
 
-  virtual ~MockConnection();
+  ~MockConnection() override;
 
   // If the constructor that uses a MockHelper has been used then this method
   // will advance the time of the MockClock.
@@ -324,7 +324,7 @@
     QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicVersion version) override {
+  bool OnProtocolVersionMismatch(QuicVersion version) override {
     return false;
   }
 
@@ -355,7 +355,7 @@
 class MockSession : public QuicSession {
  public:
   explicit MockSession(QuicConnection* connection);
-  virtual ~MockSession();
+  ~MockSession() override;
   MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
@@ -388,14 +388,14 @@
 class TestSession : public QuicSession {
  public:
   TestSession(QuicConnection* connection, const QuicConfig& config);
-  virtual ~TestSession();
+  ~TestSession() override;
 
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
 
   void SetCryptoStream(QuicCryptoStream* stream);
 
-  virtual QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoStream* GetCryptoStream() override;
 
  private:
   QuicCryptoStream* crypto_stream_;
@@ -406,7 +406,7 @@
 class TestClientSession : public QuicClientSessionBase {
  public:
   TestClientSession(QuicConnection* connection, const QuicConfig& config);
-  virtual ~TestClientSession();
+  ~TestClientSession() override;
 
   // QuicClientSessionBase
   MOCK_METHOD1(OnProofValid,
@@ -420,7 +420,7 @@
 
   void SetCryptoStream(QuicCryptoStream* stream);
 
-  virtual QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoStream* GetCryptoStream() override;
 
  private:
   QuicCryptoStream* crypto_stream_;
@@ -431,7 +431,7 @@
 class MockPacketWriter : public QuicPacketWriter {
  public:
   MockPacketWriter();
-  virtual ~MockPacketWriter();
+  ~MockPacketWriter() override;
 
   MOCK_METHOD4(WritePacket,
                WriteResult(const char* buffer,
@@ -449,7 +449,7 @@
 class MockSendAlgorithm : public SendAlgorithmInterface {
  public:
   MockSendAlgorithm();
-  virtual ~MockSendAlgorithm();
+  ~MockSendAlgorithm() override;
 
   MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config,
                                    bool is_server,
@@ -482,6 +482,7 @@
   MOCK_CONST_METHOD0(InRecovery, bool());
   MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount());
   MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType());
+  MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
@@ -490,7 +491,7 @@
 class MockLossAlgorithm : public LossDetectionInterface {
  public:
   MockLossAlgorithm();
-  virtual ~MockLossAlgorithm();
+  ~MockLossAlgorithm() override;
 
   MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType());
   MOCK_METHOD4(DetectLostPackets,
@@ -520,7 +521,7 @@
 class MockEntropyCalculator : public TestEntropyCalculator {
  public:
   MockEntropyCalculator();
-  virtual ~MockEntropyCalculator();
+  ~MockEntropyCalculator() override;
 
   MOCK_CONST_METHOD1(
       EntropyHash,
@@ -542,7 +543,7 @@
 
  protected:
   // Object is ref counted.
-  virtual ~MockAckNotifierDelegate();
+  ~MockAckNotifierDelegate() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockAckNotifierDelegate);
@@ -552,7 +553,7 @@
       public QuicSentPacketManager::NetworkChangeVisitor {
  public:
   MockNetworkChangeVisitor();
-  virtual ~MockNetworkChangeVisitor();
+  ~MockNetworkChangeVisitor() override;
 
   MOCK_METHOD0(OnCongestionWindowChange, void());
 
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 33f30fca..dcc9345 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -221,7 +221,7 @@
                "HTTP/1.1", "200", "OK", kBarResponseBody);
   }
 
-  virtual ~EndToEndTest() {
+  ~EndToEndTest() override {
     // TODO(rtenneti): port RecycleUnusedPort if needed.
     // RecycleUnusedPort(server_address_.port());
     QuicInMemoryCachePeer::ResetForTests();
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 5b5c415..496211f 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -46,6 +46,8 @@
     session_->InitializeSession(
         QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
         &crypto_config_);
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CompleteCryptoHandshake() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 45c1379..9db23659 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -38,14 +38,29 @@
 
 void QuicServerSession::OnConfigNegotiated() {
   QuicSession::OnConfigNegotiated();
-  if (!FLAGS_enable_quic_fec ||
-      !config()->HasReceivedConnectionOptions() ||
-      !net::ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+
+  if (!config()->HasReceivedConnectionOptions()) {
     return;
   }
-  // kFHDR config maps to FEC protection always for headers stream.
-  // TODO(jri): Add crypto stream in addition to headers for kHDR.
-  headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+
+  // If the client has provided a bandwidth estimate from the same serving
+  // region, then pass it to the sent packet manager in preparation for possible
+  // bandwidth resumption.
+  const CachedNetworkParameters* cached_network_params =
+      crypto_stream_->previous_cached_network_params();
+  if (FLAGS_quic_enable_bandwidth_resumption_experiment &&
+      cached_network_params != nullptr &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) &&
+      cached_network_params->serving_region() == serving_region_) {
+    connection()->ResumeConnectionState(*cached_network_params);
+  }
+
+  if (FLAGS_enable_quic_fec &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+    // kFHDR config maps to FEC protection always for headers stream.
+    // TODO(jri): Add crypto stream in addition to headers for kHDR.
+    headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+  }
 }
 
 void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 6a17f539..b0ed5d1e 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -292,7 +292,7 @@
   explicit MockQuicCryptoServerStream(
       const QuicCryptoServerConfig& crypto_config, QuicSession* session)
       : QuicCryptoServerStream(crypto_config, session) {}
-  virtual ~MockQuicCryptoServerStream() {}
+  ~MockQuicCryptoServerStream() override {}
 
   MOCK_METHOD1(SendServerConfigUpdate,
                void(const CachedNetworkParameters* cached_network_parameters));
@@ -383,6 +383,46 @@
   session_->OnCongestionWindowChange(now);
 }
 
+TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) {
+  ValueRestore<bool> old_flag(
+      &FLAGS_quic_enable_bandwidth_resumption_experiment, true);
+
+  // Test that if a client provides a CachedNetworkParameters with the same
+  // serving region as the current server, that this data is passed down to the
+  // send algorithm.
+
+  // Client has sent kBWRE connection option to trigger bandwidth resumption.
+  QuicTagVector copt;
+  copt.push_back(kBWRE);
+  QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+
+  const string kTestServingRegion = "a serving region";
+  session_->set_serving_region(kTestServingRegion);
+
+  QuicCryptoServerStream* crypto_stream =
+      static_cast<QuicCryptoServerStream*>(
+          QuicSessionPeer::GetCryptoStream(session_.get()));
+
+  // No effect if no CachedNetworkParameters provided.
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0);
+  session_->OnConfigNegotiated();
+
+  // No effect if CachedNetworkParameters provided, but different serving
+  // regions.
+  CachedNetworkParameters cached_network_params;
+  cached_network_params.set_bandwidth_estimate_bytes_per_second(1);
+  cached_network_params.set_serving_region("different serving region");
+  crypto_stream->set_previous_cached_network_params(cached_network_params);
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0);
+  session_->OnConfigNegotiated();
+
+  // Same serving region results in CachedNetworkParameters being stored.
+  cached_network_params.set_serving_region(kTestServingRegion);
+  crypto_stream->set_previous_cached_network_params(cached_network_params);
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(1);
+  session_->OnConfigNegotiated();
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace tools
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc
index 4f5484a..8a3600c 100644
--- a/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -97,7 +97,7 @@
     QuicInMemoryCachePeer::ResetForTests();
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
 
     BalsaHeaders request_headers, response_headers;
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 05c3954f8..4e5d7c34 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -95,9 +95,9 @@
         client_address_(net::test::TestPeerIPAddress(), kTestPort),
         writer_is_blocked_(false) {}
 
-  virtual ~QuicTimeWaitListManagerTest() override {}
+  ~QuicTimeWaitListManagerTest() override {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     EXPECT_CALL(writer_, IsWriteBlocked())
         .WillRepeatedly(ReturnPointee(&writer_is_blocked_));
     EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.h b/net/tools/quic/test_tools/mock_quic_dispatcher.h
index df32ce42..81f10047 100644
--- a/net/tools/quic/test_tools/mock_quic_dispatcher.h
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -24,7 +24,7 @@
                      PacketWriterFactory* packet_writer_factory,
                      EpollServer* eps);
 
-  virtual ~MockQuicDispatcher();
+  ~MockQuicDispatcher() override;
 
   MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
                                    const IPEndPoint& client_address,
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index 9db9fb5..e1220cb 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/strings/string_piece.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_session.h"
@@ -94,6 +95,8 @@
   MOCK_METHOD0(OnCanWrite, void());
   MOCK_CONST_METHOD0(HasPendingWrites, bool());
 
+  MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&));
+
   void ReallyProcessUdpPacket(const IPEndPoint& self_address,
                               const IPEndPoint& peer_address,
                               const QuicEncryptedPacket& packet) {