Merge from Chromium at DEPS revision r214332

This commit was generated by merge_to_master.py.

Change-Id: I82a7c38de906244dc882493568013be659aa65d1
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 5398cc6..cd0923d 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -46,8 +46,14 @@
     QuicPacketSequenceNumber /*acked_sequence_number*/,
     QuicByteCount bytes_acked,
     QuicTime::Delta rtt) {
-  latest_rtt_ = rtt;
+  // RTT can't be negative.
+  DCHECK_LE(0, rtt.ToMicroseconds());
+
   data_in_flight_ -= bytes_acked;
+  if (rtt.IsInfinite()) {
+    return;
+  }
+  latest_rtt_ = rtt;
 }
 
 void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) {
@@ -105,4 +111,10 @@
   return latest_rtt_;
 }
 
+QuicTime::Delta FixRateSender::RetransmissionDelay() {
+  // TODO(pwestin): Calculate and return retransmission delay.
+  // Use 2 * the latest RTT for now.
+  return latest_rtt_.Add(latest_rtt_);
+}
+
 }  // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 545f2d3..251ab39 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -44,6 +44,7 @@
       HasRetransmittableData has_retransmittable_data) OVERRIDE;
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
+  virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc
index c8d2c86..07421ae 100644
--- a/net/quic/congestion_control/inter_arrival_sender.cc
+++ b/net/quic/congestion_control/inter_arrival_sender.cc
@@ -14,6 +14,8 @@
 const float kMinBitrateReduction = 0.05f;
 const uint64 kMinBitrateKbit = 10;
 const int kInitialRttMs = 60;  // At a typical RTT 60 ms.
+const float kAlpha = 0.125f;
+const float kOneMinusAlpha = 1 - kAlpha;
 
 static const int kBitrateSmoothingPeriodMs = 1000;
 static const int kMinBitrateSmoothingPeriodMs = 500;
@@ -200,18 +202,25 @@
     QuicPacketSequenceNumber /*acked_sequence_number*/,
     QuicByteCount acked_bytes,
     QuicTime::Delta rtt) {
-  DCHECK(!rtt.IsZero());
-  DCHECK(!rtt.IsInfinite());
+  // RTT can't be negative.
+  DCHECK_LE(0, rtt.ToMicroseconds());
+
+  if (probing_) {
+    probe_->OnAcknowledgedPacket(acked_bytes);
+  }
+
+  if (rtt.IsInfinite()) {
+    return;
+  }
+
   if (smoothed_rtt_.IsZero()) {
     smoothed_rtt_ = rtt;
   } else {
     smoothed_rtt_ = QuicTime::Delta::FromMicroseconds(
-        (smoothed_rtt_.ToMicroseconds() * 3 + rtt.ToMicroseconds()) / 4);
+        kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() +
+        kAlpha * rtt.ToMicroseconds());
   }
-  state_machine_->set_rtt(SmoothedRtt());
-  if (probing_) {
-    probe_->OnAcknowledgedPacket(acked_bytes);
-  }
+  state_machine_->set_rtt(smoothed_rtt_);
 }
 
 void InterArrivalSender::OnIncomingLoss(QuicTime ack_receive_time) {
@@ -305,6 +314,12 @@
   return smoothed_rtt_;
 }
 
+QuicTime::Delta InterArrivalSender::RetransmissionDelay() {
+  // TODO(pwestin): Calculate and return retransmission delay.
+  // Use 2 * the smoothed RTT for now.
+  return smoothed_rtt_.Add(smoothed_rtt_);
+}
+
 void InterArrivalSender::EstimateNewBandwidth(QuicTime feedback_receive_time,
                                               QuicBandwidth sent_bandwidth) {
   QuicBandwidth new_bandwidth = bitrate_ramp_up_->GetNewBitrate(sent_bandwidth);
diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h
index 7997d0d..9889c0d 100644
--- a/net/quic/congestion_control/inter_arrival_sender.h
+++ b/net/quic/congestion_control/inter_arrival_sender.h
@@ -58,6 +58,7 @@
 
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
+  virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index a6bd0a8..1773c82 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -16,6 +16,11 @@
 static const int kHistoryPeriodMs = 5000;
 
 static const int kDefaultRetransmissionTimeMs = 500;
+// TCP RFC calls for 1 second RTO however Linux differs from this default and
+// define the minimum RTO to 200ms, we will use the same until we have data to
+// support a higher or lower value.
+static const int kMinRetransmissionTimeMs = 200;
+static const int kMaxRetransmissionTimeMs = 10000;
 static const size_t kMaxRetransmissions = 10;
 static const size_t kTailDropWindowSize = 5;
 static const size_t kTailDropMaxRetransmissions = 4;
@@ -152,18 +157,30 @@
 const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay(
     size_t unacked_packets_count,
     size_t number_retransmissions) {
-  // TODO(pwestin): This should take the RTT into account instead of a hard
-  // coded kDefaultRetransmissionTimeMs. Ideally the variance of the RTT too.
-  if (unacked_packets_count <= kTailDropWindowSize) {
-    if (number_retransmissions <= kTailDropMaxRetransmissions) {
-      return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+  QuicTime::Delta retransmission_delay = send_algorithm_->RetransmissionDelay();
+  if (retransmission_delay.IsZero()) {
+    // We are in the initial state, use default timeout values.
+    if (unacked_packets_count <= kTailDropWindowSize) {
+      if (number_retransmissions <= kTailDropMaxRetransmissions) {
+        return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+      }
+      number_retransmissions -= kTailDropMaxRetransmissions;
     }
-    number_retransmissions -= kTailDropMaxRetransmissions;
+    retransmission_delay =
+        QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
   }
+  // Calcluate exponential back off.
+  retransmission_delay = QuicTime::Delta::FromMilliseconds(
+      retransmission_delay.ToMilliseconds() * static_cast<size_t>(
+          (1 << min<size_t>(number_retransmissions, kMaxRetransmissions))));
 
-  return QuicTime::Delta::FromMilliseconds(
-      kDefaultRetransmissionTimeMs *
-      (1 << min<size_t>(number_retransmissions, kMaxRetransmissions)));
+  if (retransmission_delay.ToMilliseconds() < kMinRetransmissionTimeMs) {
+    return QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs);
+  }
+  if (retransmission_delay.ToMilliseconds() > kMaxRetransmissionTimeMs) {
+    return QuicTime::Delta::FromMilliseconds(kMaxRetransmissionTimeMs);
+  }
+  return retransmission_delay;
 }
 
 const QuicTime::Delta QuicCongestionManager::SmoothedRtt() {
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index f2c4e7b..440201c 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -77,6 +77,11 @@
 
   // TODO(satyamshekhar): Monitor MinRtt.
   virtual QuicTime::Delta SmoothedRtt() = 0;
+
+  // Get the send algorithm specific retransmission delay, called RTO in TCP,
+  // Note 1: the caller is responsible for sanity checking this value.
+  // Note 2: this will return zero if we don't have enough data for an estimate.
+  virtual QuicTime::Delta RetransmissionDelay() = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index e71b8c2..73c05da 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -15,7 +15,11 @@
 const int64 kMaxCongestionWindow = 10000;
 const int kMaxBurstLength = 3;
 const int kInitialRttMs = 60;  // At a typical RTT 60 ms.
-};
+const float kAlpha = 0.125f;
+const float kOneMinusAlpha = (1 - kAlpha);
+const float kBeta = 0.25f;
+const float kOneMinusBeta = (1 - kBeta);
+};  // namespace
 
 TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno)
     : hybrid_slow_start_(clock),
@@ -29,7 +33,12 @@
       end_sequence_number_(0),
       congestion_window_(kInitialCongestionWindow),
       slowstart_threshold_(kMaxCongestionWindow),
-      delay_min_(QuicTime::Delta::Zero()) {
+      delay_min_(QuicTime::Delta::Zero()),
+      smoothed_rtt_(QuicTime::Delta::Zero()),
+      mean_deviation_(QuicTime::Delta::Zero()) {
+}
+
+TcpCubicSender::~TcpCubicSender() {
 }
 
 void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame(
@@ -136,11 +145,15 @@
 }
 
 QuicTime::Delta TcpCubicSender::SmoothedRtt() {
-  // TODO(satyamshekhar): Return the smoothed averaged RTT.
-  if (delay_min_.IsZero()) {
+  if (smoothed_rtt_.IsZero()) {
     return QuicTime::Delta::FromMilliseconds(kInitialRttMs);
   }
-  return delay_min_;
+  return smoothed_rtt_;
+}
+
+QuicTime::Delta TcpCubicSender::RetransmissionDelay() {
+  return QuicTime::Delta::FromMicroseconds(
+      smoothed_rtt_.ToMicroseconds() + 4 * mean_deviation_.ToMicroseconds());
 }
 
 void TcpCubicSender::Reset() {
@@ -218,6 +231,21 @@
   if (delay_min_.IsZero() || delay_min_ > rtt) {
     delay_min_ = rtt;
   }
+  // First time call.
+  if (smoothed_rtt_.IsZero()) {
+    smoothed_rtt_ = rtt;
+    mean_deviation_ = QuicTime::Delta::FromMicroseconds(
+        rtt.ToMicroseconds() / 2);
+  } else {
+    mean_deviation_ = QuicTime::Delta::FromMicroseconds(
+        kOneMinusBeta * mean_deviation_.ToMicroseconds() +
+        kBeta * abs(smoothed_rtt_.ToMicroseconds() - rtt.ToMicroseconds()));
+    smoothed_rtt_ = QuicTime::Delta::FromMicroseconds(
+        kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() +
+        kAlpha * rtt.ToMicroseconds());
+    DLOG(INFO) << "Cubic; mean_deviation_:" << mean_deviation_.ToMicroseconds();
+  }
+
   // Hybrid start triggers when cwnd is larger than some threshold.
   if (congestion_window_ <= slowstart_threshold_ &&
       congestion_window_ >= kHybridStartLowWindow) {
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 0b7e948..1774023 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -28,6 +28,7 @@
  public:
   // Reno option provided for testing.
   TcpCubicSender(const QuicClock* clock, bool reno);
+  virtual ~TcpCubicSender();
 
   // Start implementation of SendAlgorithmInterface.
   virtual void OnIncomingQuicCongestionFeedbackFrame(
@@ -50,6 +51,7 @@
       HasRetransmittableData has_retransmittable_data) OVERRIDE;
   virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
   virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
+  virtual QuicTime::Delta RetransmissionDelay() OVERRIDE;
   // End implementation of SendAlgorithmInterface.
 
  private:
@@ -94,6 +96,14 @@
   // Min RTT during this session.
   QuicTime::Delta delay_min_;
 
+  // Smoothed RTT during this session.
+  QuicTime::Delta smoothed_rtt_;
+
+  // Mean RTT deviation during this session.
+  // Approximation of standard deviation, the error is roughly 1.25 times
+  // larger than the standard deviation, for a normally distributed signal.
+  QuicTime::Delta mean_deviation_;
+
   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 a9e468f..68a8d6b 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -17,11 +17,12 @@
 
 class TcpCubicSenderPeer : public TcpCubicSender {
  public:
-  explicit TcpCubicSenderPeer(const QuicClock* clock, bool reno)
+  TcpCubicSenderPeer(const QuicClock* clock, bool reno)
       : TcpCubicSender(clock, reno) {
   }
   using TcpCubicSender::AvailableCongestionWindow;
   using TcpCubicSender::CongestionWindow;
+  using TcpCubicSender::AckAccounting;
 };
 
 class TcpCubicSenderTest : public ::testing::Test {
@@ -221,5 +222,33 @@
   EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
 }
 
+TEST_F(TcpCubicSenderTest, RetransmissionDelay) {
+  const int64 kRttMs = 10;
+  const int64 kDeviationMs = 3;
+  EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay());
+
+  sender_->AckAccounting(QuicTime::Delta::FromMilliseconds(kRttMs));
+
+  // Initial value is to set the median deviation to half of the initial
+  // rtt, the median in then multiplied by a factor of 4 and finaly the
+  // smoothed rtt is added which is the inital rtt.
+  QuicTime::Delta expected_delay =
+      QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
+  EXPECT_EQ(expected_delay, sender_->RetransmissionDelay());
+
+  for (int i = 0; i < 100; ++i) {
+    // Run to make sure that we converge.
+    sender_->AckAccounting(
+        QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs));
+    sender_->AckAccounting(
+        QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs));
+  }
+  expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
+
+  EXPECT_NEAR(kRttMs, sender_->SmoothedRtt().ToMilliseconds(), 1);
+  EXPECT_NEAR(expected_delay.ToMilliseconds(),
+              sender_->RetransmissionDelay().ToMilliseconds(),
+              1);
+}
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h
index ca9a2b1..451f84d 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter.h
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h
@@ -61,6 +61,8 @@
   unsigned char key_[16];
   // The nonce prefix.
   unsigned char nonce_prefix_[4];
+  // last_seq_num_ is the last sequence number observed.
+  QuicPacketSequenceNumber last_seq_num_;
 
 #if defined(USE_OPENSSL)
   ScopedEVPCipherCtx ctx_;
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
index 4729ef8..1cd3540 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc
@@ -250,7 +250,7 @@
 
 }  // namespace
 
-Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {
+Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() : last_seq_num_(0) {
   ignore_result(g_gcm_support_checker.Get());
 }
 
@@ -350,6 +350,12 @@
   size_t ciphertext_size = GetCiphertextSize(plaintext.length());
   scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
 
+  if (last_seq_num_ != 0 && sequence_number <= last_seq_num_) {
+    DLOG(FATAL) << "Sequence numbers regressed";
+    return NULL;
+  }
+  last_seq_num_ = sequence_number;
+
   uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
   COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
   memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
index c32efcf..79d0ec1 100644
--- a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
+++ b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc
@@ -21,7 +21,7 @@
 
 }  // namespace
 
-Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {}
+Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() : last_seq_num_(0) {}
 
 Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
 
@@ -118,6 +118,12 @@
   size_t ciphertext_size = GetCiphertextSize(plaintext.length());
   scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
 
+  if (last_seq_num_ != 0 && sequence_number <= last_seq_num_) {
+    DLOG(FATAL) << "Sequence numbers regressed";
+    return NULL;
+  }
+  last_seq_num_ = sequence_number;
+
   uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
   COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
   memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
diff --git a/net/quic/crypto/common_cert_set_0.c b/net/quic/crypto/common_cert_set_0.c
index d89548a..1133733 100644
--- a/net/quic/crypto/common_cert_set_0.c
+++ b/net/quic/crypto/common_cert_set_0.c
@@ -9,7 +9,7 @@
 #include "net/quic/crypto/common_cert_set_1_50.inc"
 #include "net/quic/crypto/common_cert_set_51_100.inc"
 
-static const size_t kNumCerts = 101;
+static const size_t kNumCerts = 102;
 static const unsigned char* const kCerts[] = {
   kDERCert0,
   kDERCert1,
@@ -112,6 +112,7 @@
   kDERCert98,
   kDERCert99,
   kDERCert100,
+  kDERCert101,
 };
 
 static const size_t kLens[] = {
@@ -125,6 +126,7 @@
   985,
   989,
   1022,
+  1032,
   1049,
   1055,
   1071,
@@ -218,4 +220,4 @@
   1770,
 };
 
-static const uint64 kHash = GG_UINT64_C(0xde8086f914a3af54);
+static const uint64 kHash = GG_UINT64_C(0xc9fef74053f99f39);
diff --git a/net/quic/crypto/common_cert_set_1_50.inc b/net/quic/crypto/common_cert_set_1_50.inc
index c151f1e..5ee471b 100644
--- a/net/quic/crypto/common_cert_set_1_50.inc
+++ b/net/quic/crypto/common_cert_set_1_50.inc
@@ -1641,6 +1641,191 @@
 Certificate:
     Data:
         Version: 3 (0x2)
+        Serial Number: 146025 (0x23a69)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
+        Validity
+            Not Before: Apr  5 15:15:55 2013 GMT
+            Not After : Apr  4 15:15:55 2015 GMT
+        Subject: C=US, O=Google Inc, CN=Google Internet Authority G2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9c:2a:04:77:5c:d8:50:91:3a:06:a3:82:e0:d8:
+                    50:48:bc:89:3f:f1:19:70:1a:88:46:7e:e0:8f:c5:
+                    f1:89:ce:21:ee:5a:fe:61:0d:b7:32:44:89:a0:74:
+                    0b:53:4f:55:a4:ce:82:62:95:ee:eb:59:5f:c6:e1:
+                    05:80:12:c4:5e:94:3f:bc:5b:48:38:f4:53:f7:24:
+                    e6:fb:91:e9:15:c4:cf:f4:53:0d:f4:4a:fc:9f:54:
+                    de:7d:be:a0:6b:6f:87:c0:d0:50:1f:28:30:03:40:
+                    da:08:73:51:6c:7f:ff:3a:3c:a7:37:06:8e:bd:4b:
+                    11:04:eb:7d:24:de:e6:f9:fc:31:71:fb:94:d5:60:
+                    f3:2e:4a:af:42:d2:cb:ea:c4:6a:1a:b2:cc:53:dd:
+                    15:4b:8b:1f:c8:19:61:1f:cd:9d:a8:3e:63:2b:84:
+                    35:69:65:84:c8:19:c5:46:22:f8:53:95:be:e3:80:
+                    4a:10:c6:2a:ec:ba:97:20:11:c7:39:99:10:04:a0:
+                    f0:61:7a:95:25:8c:4e:52:75:e2:b6:ed:08:ca:14:
+                    fc:ce:22:6a:b3:4e:cf:46:03:97:97:03:7e:c0:b1:
+                    de:7b:af:45:33:cf:ba:3e:71:b7:de:f4:25:25:c2:
+                    0d:35:89:9d:9d:fb:0e:11:79:89:1e:37:c5:af:8e:
+                    72:69
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier: 
+                keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E
+
+            X509v3 Subject Key Identifier: 
+                4A:DD:06:16:1B:BC:F6:68:B5:76:F5:81:B6:BB:62:1A:BA:5A:81:2F
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://crl.geotrust.com/crls/gtglobal.crl
+
+            Authority Information Access: 
+                OCSP - URI:http://gtglobal-ocsp.geotrust.com
+
+            X509v3 Certificate Policies: 
+                Policy: 1.3.6.1.4.1.11129.2.5.1
+
+    Signature Algorithm: sha1WithRSAEncryption
+         36:d7:06:80:11:27:ad:2a:14:9b:38:77:b3:23:a0:75:58:bb:
+         b1:7e:83:42:ba:72:da:1e:d8:8e:36:06:97:e0:f0:95:3b:37:
+         fd:1b:42:58:fe:22:c8:6b:bd:38:5e:d1:3b:25:6e:12:eb:5e:
+         67:76:46:40:90:da:14:c8:78:0d:ed:95:66:da:8e:86:6f:80:
+         a1:ba:56:32:95:86:dc:dc:6a:ca:04:8c:5b:7f:f6:bf:cc:6f:
+         85:03:58:c3:68:51:13:cd:fd:c8:f7:79:3d:99:35:f0:56:a3:
+         bd:e0:59:ed:4f:44:09:a3:9e:38:7a:f6:46:d1:1d:12:9d:4f:
+         be:d0:40:fc:55:fe:06:5e:3c:da:1c:56:bd:96:51:7b:6f:57:
+         2a:db:a2:aa:96:dc:8c:74:c2:95:be:f0:6e:95:13:ff:17:f0:
+         3c:ac:b2:10:8d:cc:73:fb:e8:8f:02:c6:f0:fb:33:b3:95:3b:
+         e3:c2:cb:68:58:73:db:a8:24:62:3b:06:35:9d:0d:a9:33:bd:
+         78:03:90:2e:4c:78:5d:50:3a:81:d4:ee:a0:c8:70:38:dc:b2:
+         f9:67:fa:87:40:5d:61:c0:51:8f:6b:83:6b:cd:05:3a:ca:e1:
+         a7:05:78:fc:ca:da:94:d0:2c:08:3d:7e:16:79:c8:a0:50:20:
+         24:54:33:71
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----
+#endif
+static const unsigned char kDERCert10[] = {
+  0x30, 0x82, 0x04, 0x04, 0x30, 0x82, 0x02, 0xec, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x03, 0x02, 0x3a, 0x69, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31,
+  0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+  0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47,
+  0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+  0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
+  0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+  0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30,
+  0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x35, 0x35, 0x35, 0x5a, 0x17, 0x0d,
+  0x31, 0x35, 0x30, 0x34, 0x30, 0x34, 0x31, 0x35, 0x31, 0x35, 0x35, 0x35,
+  0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+  0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+  0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e,
+  0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c,
+  0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
+  0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+  0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+  0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+  0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3,
+  0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a,
+  0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a,
+  0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f,
+  0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1,
+  0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4,
+  0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53,
+  0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f,
+  0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73,
+  0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b,
+  0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb,
+  0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4,
+  0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19,
+  0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65,
+  0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80,
+  0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99,
+  0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75,
+  0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e,
+  0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf,
+  0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2,
+  0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37,
+  0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
+  0xfb, 0x30, 0x81, 0xf8, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+  0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb,
+  0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc,
+  0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+  0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81,
+  0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x12, 0x06, 0x03,
+  0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01,
+  0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+  0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03,
+  0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0,
+  0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72,
+  0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
+  0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c,
+  0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x08,
+  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f,
+  0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01,
+  0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x74, 0x67,
+  0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2d, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67,
+  0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
+  0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10, 0x30, 0x0e, 0x30, 0x0c,
+  0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01,
+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+  0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x36, 0xd7, 0x06, 0x80,
+  0x11, 0x27, 0xad, 0x2a, 0x14, 0x9b, 0x38, 0x77, 0xb3, 0x23, 0xa0, 0x75,
+  0x58, 0xbb, 0xb1, 0x7e, 0x83, 0x42, 0xba, 0x72, 0xda, 0x1e, 0xd8, 0x8e,
+  0x36, 0x06, 0x97, 0xe0, 0xf0, 0x95, 0x3b, 0x37, 0xfd, 0x1b, 0x42, 0x58,
+  0xfe, 0x22, 0xc8, 0x6b, 0xbd, 0x38, 0x5e, 0xd1, 0x3b, 0x25, 0x6e, 0x12,
+  0xeb, 0x5e, 0x67, 0x76, 0x46, 0x40, 0x90, 0xda, 0x14, 0xc8, 0x78, 0x0d,
+  0xed, 0x95, 0x66, 0xda, 0x8e, 0x86, 0x6f, 0x80, 0xa1, 0xba, 0x56, 0x32,
+  0x95, 0x86, 0xdc, 0xdc, 0x6a, 0xca, 0x04, 0x8c, 0x5b, 0x7f, 0xf6, 0xbf,
+  0xcc, 0x6f, 0x85, 0x03, 0x58, 0xc3, 0x68, 0x51, 0x13, 0xcd, 0xfd, 0xc8,
+  0xf7, 0x79, 0x3d, 0x99, 0x35, 0xf0, 0x56, 0xa3, 0xbd, 0xe0, 0x59, 0xed,
+  0x4f, 0x44, 0x09, 0xa3, 0x9e, 0x38, 0x7a, 0xf6, 0x46, 0xd1, 0x1d, 0x12,
+  0x9d, 0x4f, 0xbe, 0xd0, 0x40, 0xfc, 0x55, 0xfe, 0x06, 0x5e, 0x3c, 0xda,
+  0x1c, 0x56, 0xbd, 0x96, 0x51, 0x7b, 0x6f, 0x57, 0x2a, 0xdb, 0xa2, 0xaa,
+  0x96, 0xdc, 0x8c, 0x74, 0xc2, 0x95, 0xbe, 0xf0, 0x6e, 0x95, 0x13, 0xff,
+  0x17, 0xf0, 0x3c, 0xac, 0xb2, 0x10, 0x8d, 0xcc, 0x73, 0xfb, 0xe8, 0x8f,
+  0x02, 0xc6, 0xf0, 0xfb, 0x33, 0xb3, 0x95, 0x3b, 0xe3, 0xc2, 0xcb, 0x68,
+  0x58, 0x73, 0xdb, 0xa8, 0x24, 0x62, 0x3b, 0x06, 0x35, 0x9d, 0x0d, 0xa9,
+  0x33, 0xbd, 0x78, 0x03, 0x90, 0x2e, 0x4c, 0x78, 0x5d, 0x50, 0x3a, 0x81,
+  0xd4, 0xee, 0xa0, 0xc8, 0x70, 0x38, 0xdc, 0xb2, 0xf9, 0x67, 0xfa, 0x87,
+  0x40, 0x5d, 0x61, 0xc0, 0x51, 0x8f, 0x6b, 0x83, 0x6b, 0xcd, 0x05, 0x3a,
+  0xca, 0xe1, 0xa7, 0x05, 0x78, 0xfc, 0xca, 0xda, 0x94, 0xd0, 0x2c, 0x08,
+  0x3d, 0x7e, 0x16, 0x79, 0xc8, 0xa0, 0x50, 0x20, 0x24, 0x54, 0x33, 0x71,
+};
+
+#if 0
+Certificate:
+    Data:
+        Version: 3 (0x2)
         Serial Number: 120033005 (0x7278eed)
     Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root
@@ -1723,7 +1908,7 @@
 pN19+kSElK7XCQQidg9kUTWpJA/5C9sy2sL+wbkqXHonE8qxSDpx0EM=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert10[] = {
+static const unsigned char kDERCert11[] = {
   0x30, 0x82, 0x04, 0x15, 0x30, 0x82, 0x03, 0x7e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x8e, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -1908,7 +2093,7 @@
 /aJqMoPifm/wEo6jZnZAl/sR4fdzH9qLHDFCi58RxUmlYO1IKwWEFasviixRcsA=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert11[] = {
+static const unsigned char kDERCert12[] = {
   0x30, 0x82, 0x04, 0x1b, 0x30, 0x82, 0x03, 0x03, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x37, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5a,
@@ -2094,7 +2279,7 @@
 OCM9OmWCXnlxFfglK30Z
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert12[] = {
+static const unsigned char kDERCert13[] = {
   0x30, 0x82, 0x04, 0x2b, 0x30, 0x82, 0x03, 0x13, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x01, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
   0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x63, 0x31, 0x0b, 0x30,
@@ -2285,7 +2470,7 @@
 HFSQTZGaJoutooBQjRQU
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert13[] = {
+static const unsigned char kDERCert14[] = {
   0x30, 0x82, 0x04, 0x2b, 0x30, 0x82, 0x03, 0x13, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x12, 0x11, 0x20, 0x96, 0xf6, 0xc8, 0x03, 0x7c, 0x9e, 0x07,
   0xb1, 0x38, 0xbf, 0x2e, 0x72, 0x10, 0x8a, 0xd7, 0xed, 0x30, 0x0d, 0x06,
@@ -2468,7 +2653,7 @@
 l96Sh2EhiHtBRj38PU/QVFs=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert14[] = {
+static const unsigned char kDERCert15[] = {
   0x30, 0x82, 0x04, 0x2d, 0x30, 0x82, 0x03, 0x96, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x46, 0x9f, 0x18, 0x2b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -2660,7 +2845,7 @@
 +MPpZqmyIJ3E+LgDYqeF0RhjWw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert15[] = {
+static const unsigned char kDERCert16[] = {
   0x30, 0x82, 0x04, 0x2f, 0x30, 0x82, 0x03, 0x17, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x37, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -2853,7 +3038,7 @@
 fxq9CncU1dXMMRKi7wajF8HgGKvHUw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert16[] = {
+static const unsigned char kDERCert17[] = {
   0x30, 0x82, 0x04, 0x32, 0x30, 0x82, 0x03, 0x1a, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x44, 0xa5,
   0xf1, 0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -3041,7 +3226,7 @@
 wWEWo4qMmd4QBfLe7aUJZJeEj0KoeyLE
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert17[] = {
+static const unsigned char kDERCert18[] = {
   0x30, 0x82, 0x04, 0x34, 0x30, 0x82, 0x03, 0x1c, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x5c, 0x26, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5a,
@@ -3229,7 +3414,7 @@
 ipQl7r5/eycMkkuZxTM9k+BicSmByyZ6p8g=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert18[] = {
+static const unsigned char kDERCert19[] = {
   0x30, 0x82, 0x04, 0x36, 0x30, 0x82, 0x03, 0x1e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x12, 0xb9, 0xb0, 0xbc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x50,
@@ -3418,7 +3603,7 @@
 Vo9OEkJPtHxb/RD4eOObUj3NqZl1sMPJ/SQ=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert19[] = {
+static const unsigned char kDERCert20[] = {
   0x30, 0x82, 0x04, 0x36, 0x30, 0x82, 0x03, 0x1e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x12, 0xb9, 0xb0, 0xe2, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x50,
@@ -3601,7 +3786,7 @@
 3psFGsYsPFchCA9U+ihjbOgbnA/P3TBEE7lX/g==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert20[] = {
+static const unsigned char kDERCert21[] = {
   0x30, 0x82, 0x04, 0x38, 0x30, 0x82, 0x03, 0xa1, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x6d, 0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -3787,7 +3972,7 @@
 pG1FJseIVqDwavfY5/wnfmcI0L36tsNhAgFlubgvz1o=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert21[] = {
+static const unsigned char kDERCert22[] = {
   0x30, 0x82, 0x04, 0x3c, 0x30, 0x82, 0x03, 0x24, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x48, 0x4b, 0xac, 0xf1, 0xaa, 0xc7, 0xd7, 0x13, 0x43,
   0xd1, 0xa2, 0x74, 0x35, 0x49, 0x97, 0x25, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -3970,7 +4155,7 @@
 B/I8h+FY/43FMjAnk9ciR1xgbARK4bUKZaPd9MdU+/TY7w==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert22[] = {
+static const unsigned char kDERCert23[] = {
   0x30, 0x82, 0x04, 0x3e, 0x30, 0x82, 0x03, 0xa7, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x13, 0xf5, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -4156,7 +4341,7 @@
 nXZwC99CcvhPQRFkpdLq/NWvEfQVOGecIKhLd1qRMkIy54Wz3zY=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert23[] = {
+static const unsigned char kDERCert24[] = {
   0x30, 0x82, 0x04, 0x42, 0x30, 0x82, 0x03, 0xab, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x42, 0x87, 0x40, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -4337,7 +4522,7 @@
 95OBBaqStB+3msAHF/XLxrRMDtdW3HEgdDjWdMbWj2uvi42gbCkLYeA=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert24[] = {
+static const unsigned char kDERCert25[] = {
   0x30, 0x82, 0x04, 0x45, 0x30, 0x82, 0x03, 0xae, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x33, 0x65, 0x50, 0x08, 0x79, 0xad, 0x73, 0xe2, 0x30,
   0xb9, 0xe0, 0x1d, 0x0d, 0x7f, 0xac, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -4527,7 +4712,7 @@
 0OF5xgl41fW9sbPFf6ZLr0kRyJecT3xwaRZcLbjQ3xwyUrne88MG6IMi
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert25[] = {
+static const unsigned char kDERCert26[] = {
   0x30, 0x82, 0x04, 0x46, 0x30, 0x82, 0x03, 0x2e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x75, 0x8a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5a,
@@ -4712,7 +4897,7 @@
 7TPK
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert26[] = {
+static const unsigned char kDERCert27[] = {
   0x30, 0x82, 0x04, 0x4f, 0x30, 0x82, 0x03, 0xb8, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x58, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -4908,7 +5093,7 @@
 I5e4KnHi7f5piGe/Jlw=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert27[] = {
+static const unsigned char kDERCert28[] = {
   0x30, 0x82, 0x04, 0x5a, 0x30, 0x82, 0x03, 0x42, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x41, 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -5105,7 +5290,7 @@
 +mKhcZKMCha3PbVKZVsC
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert28[] = {
+static const unsigned char kDERCert29[] = {
   0x30, 0x82, 0x04, 0x5b, 0x30, 0x82, 0x03, 0x43, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x5b, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -5299,7 +5484,7 @@
 iQ8HV/rRV+9Nstd3yLz4ZQ+e
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert29[] = {
+static const unsigned char kDERCert30[] = {
   0x30, 0x82, 0x04, 0x5e, 0x30, 0x82, 0x03, 0x46, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x42, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5a,
@@ -5496,7 +5681,7 @@
 wFZUTKiL8IkyhtyTMr5NGvo1dbU=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert30[] = {
+static const unsigned char kDERCert31[] = {
   0x30, 0x82, 0x04, 0x60, 0x30, 0x82, 0x03, 0x48, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x45, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -5694,7 +5879,7 @@
 c738B0E0t6pu7qfb0ZM87ZDsMpKI2cgjbHQh
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert31[] = {
+static const unsigned char kDERCert32[] = {
   0x30, 0x82, 0x04, 0x67, 0x30, 0x82, 0x03, 0x4f, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x44, 0xa5,
   0xf5, 0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -5889,7 +6074,7 @@
 t7pLwD2kIYwXnM/Yv+ZX/s3r+jAa1f7oJZepvjvq
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert32[] = {
+static const unsigned char kDERCert33[] = {
   0x30, 0x82, 0x04, 0x6a, 0x30, 0x82, 0x03, 0x52, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x47, 0x86, 0x9f, 0xe5, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x48,
@@ -6085,7 +6270,7 @@
 huNMrUnjl1nOG5srztxl1Asoa06ERlFE9zMILViXIa4=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert33[] = {
+static const unsigned char kDERCert34[] = {
   0x30, 0x82, 0x04, 0x6c, 0x30, 0x82, 0x03, 0x54, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x4d, 0x5f, 0x2c, 0x34, 0x08, 0xb2, 0x4c, 0x20, 0xcd,
   0x6d, 0x50, 0x7e, 0x24, 0x4d, 0xc9, 0xec, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -6285,7 +6470,7 @@
 xlMSeDe0E3OPN5deBJv5mYuTPiZCl5/9HrXVy4hINKJmoPqsco/dRy+CdA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert34[] = {
+static const unsigned char kDERCert35[] = {
   0x30, 0x82, 0x04, 0x77, 0x30, 0x82, 0x03, 0x5f, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x47, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -6487,7 +6672,7 @@
 DOEtZGWRvsK5
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert35[] = {
+static const unsigned char kDERCert36[] = {
   0x30, 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x3f, 0x11, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -6690,7 +6875,7 @@
 TercGL7FG81kwA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert36[] = {
+static const unsigned char kDERCert37[] = {
   0x30, 0x82, 0x04, 0x86, 0x30, 0x82, 0x03, 0x6e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x5d, 0xd4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -6890,7 +7075,7 @@
 kLRLaIHQwvrgPw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert37[] = {
+static const unsigned char kDERCert38[] = {
   0x30, 0x82, 0x04, 0x86, 0x30, 0x82, 0x03, 0x6e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x52, 0x42, 0x06, 0x4a, 0x4f, 0x37, 0xfe, 0x43, 0x69,
   0x48, 0x7a, 0x96, 0x67, 0xff, 0x5d, 0x27, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7093,7 +7278,7 @@
 eufnIVkJjTChrFzKGXr4
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert38[] = {
+static const unsigned char kDERCert39[] = {
   0x30, 0x82, 0x04, 0x8b, 0x30, 0x82, 0x03, 0x73, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2f, 0x4e, 0xe1,
   0x42, 0xf9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
@@ -7287,7 +7472,7 @@
 ndoe5KWHgKbOQ7cUfZ84
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert39[] = {
+static const unsigned char kDERCert40[] = {
   0x30, 0x82, 0x04, 0x8b, 0x30, 0x82, 0x03, 0xf4, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x04, 0x00, 0x03, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -7487,7 +7672,7 @@
 bxQe3FL+vN8MvSk/dvsRX2hoFQ==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert40[] = {
+static const unsigned char kDERCert41[] = {
   0x30, 0x82, 0x04, 0x8f, 0x30, 0x82, 0x03, 0x77, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x76, 0x10, 0x12, 0x8a, 0x17, 0xb6, 0x82, 0xbb, 0x3a,
   0x1f, 0x9d, 0x1a, 0x9a, 0x35, 0xc0, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7681,7 +7866,7 @@
 +le9yemPRiE5n1FlTI46vihBcB0=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert41[] = {
+static const unsigned char kDERCert42[] = {
   0x30, 0x82, 0x04, 0x90, 0x30, 0x82, 0x03, 0xf9, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x1b, 0x09, 0x3b, 0x78, 0x60, 0x96, 0xda, 0x37, 0xbb,
   0xa4, 0x51, 0x94, 0x46, 0xc8, 0x96, 0x78, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7882,7 +8067,7 @@
 xNMvmpAxwpJTlu1yp/7E2jkpUWjtkI2Xjv5FGbc=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert42[] = {
+static const unsigned char kDERCert43[] = {
   0x30, 0x82, 0x04, 0x99, 0x30, 0x82, 0x03, 0x81, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x3d, 0x3a, 0x05, 0x26, 0x09, 0xb6, 0x2e, 0xe5, 0x8c,
   0x36, 0x29, 0x38, 0x63, 0x54, 0xe1, 0x24, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8080,7 +8265,7 @@
 EhpORLpbFk0wufO0dM5u8mhWWN3Yof1UBfQjkYXJ+Q==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert43[] = {
+static const unsigned char kDERCert44[] = {
   0x30, 0x82, 0x04, 0x9b, 0x30, 0x82, 0x04, 0x04, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x42, 0x87, 0x2d, 0x4c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -8283,7 +8468,7 @@
 CeJldM6JRI17KJBorqzCOMhWDTOIKH9U/Dw8UAmTPTg=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert44[] = {
+static const unsigned char kDERCert45[] = {
   0x30, 0x82, 0x04, 0x9c, 0x30, 0x82, 0x03, 0x84, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x69, 0x48, 0xa2, 0x6b, 0x20, 0x1a, 0xa4, 0x21, 0xe8,
   0x98, 0xb1, 0xc4, 0x92, 0xc7, 0xc5, 0x8e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8481,7 +8666,7 @@
 SApKv9ClOwqwVLht4wj5NI0LjosSzBcaM4eVyJ4K3FBTF3s=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert45[] = {
+static const unsigned char kDERCert46[] = {
   0x30, 0x82, 0x04, 0x9f, 0x30, 0x82, 0x04, 0x08, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x46, 0x9e, 0x91, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -8684,7 +8869,7 @@
 8/ifBlIK3se2e4/hEfcEejX/arxbx1BJCHBvlEPNnsdw8dvQbdqP
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert46[] = {
+static const unsigned char kDERCert47[] = {
   0x30, 0x82, 0x04, 0xa3, 0x30, 0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x5a, 0xb6, 0x1d, 0xac, 0x1e, 0x4d, 0xa2, 0x06, 0x14,
   0xc7, 0x55, 0x3d, 0x3d, 0xa9, 0xb2, 0xdc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8887,7 +9072,7 @@
 lQX7CkTJn6lAJUsyEa8H/gjVQnHp4VOLFR/dKgeVcCRvZF7Tt5AuiyHY
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert47[] = {
+static const unsigned char kDERCert48[] = {
   0x30, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x10, 0xe7, 0x76, 0xe8, 0xa6, 0x5a, 0x6e, 0x37, 0x7e,
   0x05, 0x03, 0x06, 0xd4, 0x3c, 0x25, 0xea, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9092,7 +9277,7 @@
 dXGWDYoGC+vd0PA8fcYumEZqOMcCtci4smV13tqQCLZ3uFMAJctHynNf
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert48[] = {
+static const unsigned char kDERCert49[] = {
   0x30, 0x82, 0x04, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x46, 0xea, 0xf0, 0x96, 0x05, 0x4c, 0xc5, 0xe3, 0xfa,
   0x65, 0xea, 0x6e, 0x9f, 0x42, 0xc6, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9297,7 +9482,7 @@
 +y3kL48ThqsxE0ATrG7ttRAwixtQqc7ujMrrfLW5Fj3U+m+SbR6ivfsCSsVwvvE=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert49[] = {
+static const unsigned char kDERCert50[] = {
   0x30, 0x82, 0x04, 0xab, 0x30, 0x82, 0x03, 0x93, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x2e, 0x79, 0x83, 0x2e, 0x90, 0x88, 0x87, 0xea, 0x8b,
   0x8e, 0xf3, 0x1a, 0x6e, 0xe6, 0x7a, 0x44, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9503,7 +9688,7 @@
 FJ4O0dXG14HdrSSrrAcF4h1ow3BmX9M=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert50[] = {
+static const unsigned char kDERCert51[] = {
   0x30, 0x82, 0x04, 0xc3, 0x30, 0x82, 0x03, 0xab, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x7f, 0x71, 0xc1, 0xd3, 0xa2, 0x26, 0xb0, 0xd2, 0xb1,
   0x13, 0xf3, 0xe6, 0x81, 0x67, 0x64, 0x3e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
diff --git a/net/quic/crypto/common_cert_set_51_100.inc b/net/quic/crypto/common_cert_set_51_100.inc
index 0a1b0d1..3c79622 100644
--- a/net/quic/crypto/common_cert_set_51_100.inc
+++ b/net/quic/crypto/common_cert_set_51_100.inc
@@ -102,7 +102,7 @@
 CPMr3u00HUSe0gST9MsFFy0JLS1j7/YmC3s=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert51[] = {
+static const unsigned char kDERCert52[] = {
   0x30, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0x2f, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x35, 0x97, 0x31, 0x87, 0xf3, 0x87, 0x3a, 0x07, 0x32,
   0x7e, 0xce, 0x58, 0x0c, 0x9b, 0x7e, 0xda, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -310,7 +310,7 @@
 YnZ+mJqiSRyGvrJVlSwtJyG8GbDxPq220Rre7bbuNQ==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert52[] = {
+static const unsigned char kDERCert53[] = {
   0x30, 0x82, 0x04, 0xcb, 0x30, 0x82, 0x03, 0xb3, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x18, 0xa2, 0x23, 0x6c, 0xd7, 0x27, 0xc7, 0x52, 0x8d,
   0xf6, 0x7b, 0x4b, 0x85, 0x6e, 0xff, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -512,7 +512,7 @@
 tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert53[] = {
+static const unsigned char kDERCert54[] = {
   0x30, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x04, 0x39, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x25, 0x0c, 0xe8, 0xe0, 0x30, 0x61, 0x2e, 0x9f, 0x2b,
   0x89, 0xf7, 0x05, 0x4d, 0x7c, 0xf8, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -721,7 +721,7 @@
 kOSQzOE6N9ZTAl9FLS+mT0lB6t+PL5ccdtt4QGPL5NXXUzgOERA4
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert54[] = {
+static const unsigned char kDERCert55[] = {
   0x30, 0x82, 0x04, 0xd3, 0x30, 0x82, 0x03, 0xbb, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x48, 0xfc, 0x4b, 0x0a, 0x37, 0x06, 0xff, 0x46, 0xfe,
   0xd3, 0xde, 0x5d, 0x4c, 0x1e, 0xca, 0x62, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -930,7 +930,7 @@
 U+4=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert55[] = {
+static const unsigned char kDERCert56[] = {
   0x30, 0x82, 0x04, 0xde, 0x30, 0x82, 0x03, 0xc6, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x02, 0x03, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
   0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x63, 0x31, 0x0b,
@@ -1142,7 +1142,7 @@
 1N3PIxL4
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert56[] = {
+static const unsigned char kDERCert57[] = {
   0x30, 0x82, 0x04, 0xe2, 0x30, 0x82, 0x03, 0xca, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x6e, 0xba, 0xf0, 0x8f, 0x79, 0x83, 0xfa, 0x9d, 0xe1,
   0xb2, 0x6f, 0x96, 0xfc, 0x6e, 0x98, 0xbf, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -1354,7 +1354,7 @@
 dI/f+P++v44=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert57[] = {
+static const unsigned char kDERCert58[] = {
   0x30, 0x82, 0x04, 0xe4, 0x30, 0x82, 0x03, 0xcc, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x4e, 0x6c, 0x48, 0x88, 0x36, 0xbb, 0x28, 0xce, 0x2b,
   0xe3, 0x5a, 0xc3, 0x79, 0x8f, 0x4a, 0x24, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -1566,7 +1566,7 @@
 BO69zlOPDyk=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert58[] = {
+static const unsigned char kDERCert59[] = {
   0x30, 0x82, 0x04, 0xe4, 0x30, 0x82, 0x03, 0xcc, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x4f, 0xe3, 0xe2, 0x65, 0x21, 0x07, 0xab, 0x20, 0x37,
   0x41, 0x6e, 0x48, 0x70, 0xce, 0xd2, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -1778,7 +1778,7 @@
 cdnUl4XmGFO3
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert59[] = {
+static const unsigned char kDERCert60[] = {
   0x30, 0x82, 0x04, 0xe5, 0x30, 0x82, 0x03, 0xcd, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x07, 0x6f, 0x12, 0x46, 0x81, 0x45, 0x9c, 0x28, 0xd5,
   0x48, 0xd6, 0x97, 0xc4, 0x0e, 0x00, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -1990,7 +1990,7 @@
 WUO8dpjzPDDbHDAu
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert60[] = {
+static const unsigned char kDERCert61[] = {
   0x30, 0x82, 0x04, 0xe8, 0x30, 0x82, 0x03, 0xd0, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x74, 0x86, 0x21, 0x96, 0x95, 0x10, 0xc9, 0x29, 0x26,
   0x29, 0x4b, 0xcc, 0x8b, 0xf8, 0x29, 0x2c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -2202,7 +2202,7 @@
 FhvXMwUw+wCqKOtfDecUViddfLQ=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert61[] = {
+static const unsigned char kDERCert62[] = {
   0x30, 0x82, 0x04, 0xf0, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x7a, 0xac, 0xa2, 0x1d, 0x53, 0x9d, 0x14, 0x54, 0x11,
   0x3c, 0x04, 0x5e, 0xd8, 0x35, 0xf8, 0xea, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -2415,7 +2415,7 @@
 HkBDfZSgaQ78LvtS9v0uMtjLa73r
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert62[] = {
+static const unsigned char kDERCert63[] = {
   0x30, 0x82, 0x04, 0xf1, 0x30, 0x82, 0x03, 0xd9, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x4b, 0x75, 0x57, 0x82, 0x69, 0x39, 0x0c, 0x9b, 0xe3,
   0x2f, 0x12, 0xec, 0x5f, 0x6d, 0x94, 0x5e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -2628,7 +2628,7 @@
 M2jlVZ6qW8swC53HD79oRIGXi1FK
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert63[] = {
+static const unsigned char kDERCert64[] = {
   0x30, 0x82, 0x04, 0xf1, 0x30, 0x82, 0x03, 0xd9, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x6f, 0x25, 0xdc, 0x15, 0xaf, 0xdf, 0x5e, 0xa3, 0x08,
   0x56, 0x0c, 0x3b, 0x7a, 0x4f, 0xc7, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -2839,7 +2839,7 @@
 uhZ2VrLWSJLyi6Y+t6xcaeoLP2ZFuQ==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert64[] = {
+static const unsigned char kDERCert65[] = {
   0x30, 0x82, 0x04, 0xf2, 0x30, 0x82, 0x03, 0xda, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x38, 0x63, 0xe9, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -3050,7 +3050,7 @@
 wfsm5p9GJKaxB825DOgNghYAHZaS/KYIoA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert65[] = {
+static const unsigned char kDERCert66[] = {
   0x30, 0x82, 0x04, 0xf5, 0x30, 0x82, 0x03, 0xdd, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x4c, 0x0e, 0x8c, 0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -3264,7 +3264,7 @@
 Ia+AR/+G2zkRyOZQzUVtWZbKVXZttY6w3gloAA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert66[] = {
+static const unsigned char kDERCert67[] = {
   0x30, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x03, 0xe0, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x40, 0x89, 0x95, 0x44, 0x7e, 0x5f, 0xb1, 0x19, 0xd8,
   0x65, 0x73, 0x70, 0x2f, 0x8d, 0x64, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -3470,7 +3470,7 @@
 SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert67[] = {
+static const unsigned char kDERCert68[] = {
   0x30, 0x82, 0x04, 0xfb, 0x30, 0x82, 0x04, 0x64, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x02, 0x01, 0x0d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
   0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xbb, 0x31,
@@ -3684,7 +3684,7 @@
 6JhaPnufAotiwIWBgGA1fqUdDNKc32JFDdv8N/v1JSI=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert68[] = {
+static const unsigned char kDERCert69[] = {
   0x30, 0x82, 0x04, 0xfc, 0x30, 0x82, 0x03, 0xe4, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x16, 0x90, 0xc3, 0x29, 0xb6, 0x78, 0x06, 0x07, 0x51,
   0x1f, 0x05, 0xb0, 0x34, 0x48, 0x46, 0xcb, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -3898,7 +3898,7 @@
 fyeJ0o5A+j3uBkkL/vSkNEl3iD1CkZa0LJwL5tRBxN+tkA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert69[] = {
+static const unsigned char kDERCert70[] = {
   0x30, 0x82, 0x04, 0xfe, 0x30, 0x82, 0x03, 0xe6, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x45, 0x4f, 0xa2, 0x0d, 0x78, 0x11, 0x74, 0x59, 0xf8,
   0xc6, 0xab, 0x3c, 0x7b, 0xcd, 0x03, 0x0e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -4124,7 +4124,7 @@
 dZCN4dazxVD8XdX7b5Lh9H7wrq/5ObPOSwGcvU738fJvzsA22A==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert70[] = {
+static const unsigned char kDERCert71[] = {
   0x30, 0x82, 0x05, 0x01, 0x30, 0x82, 0x03, 0xe9, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x6f, 0xae, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5a,
@@ -4341,7 +4341,7 @@
 0lqBJEvC8jv7NOZpe/9dmzBGWWktDfJ//PsKKeo1FNC7PKOxEEE=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert71[] = {
+static const unsigned char kDERCert72[] = {
   0x30, 0x82, 0x05, 0x02, 0x30, 0x82, 0x03, 0xea, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x20, 0x93, 0x42, 0xda, 0xa7, 0x64, 0x7c, 0x05, 0xc5,
   0xf5, 0xfd, 0x93, 0x76, 0xa4, 0x42, 0x8c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -4558,7 +4558,7 @@
 XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert72[] = {
+static const unsigned char kDERCert73[] = {
   0x30, 0x82, 0x05, 0x03, 0x30, 0x82, 0x03, 0xeb, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x18, 0xb2, 0xcb, 0xba, 0xa3, 0x04, 0xf1, 0xa0, 0x0f,
   0xc1, 0xf2, 0xf3, 0x26, 0x46, 0x2a, 0x4a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -4772,7 +4772,7 @@
 Z0nf1R7CqJgrTEeDgUwuRMLvyGPui3tbMfYmYb95HLCpTqnJUHvi
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert73[] = {
+static const unsigned char kDERCert74[] = {
   0x30, 0x82, 0x05, 0x03, 0x30, 0x82, 0x03, 0xeb, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x4c, 0xcd, 0x4a, 0x9a, 0x5b, 0x45, 0x13, 0x21, 0x8c,
   0xcf, 0x90, 0x2f, 0x8b, 0x2b, 0x51, 0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -4987,7 +4987,7 @@
 9DLJTlCDh6I0SD1PNXf82Ijq9n0ezkO21cJqfjhmY03n7jLvDyToKmf6
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert74[] = {
+static const unsigned char kDERCert75[] = {
   0x30, 0x82, 0x05, 0x06, 0x30, 0x82, 0x03, 0xee, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x11, 0xa3, 0xb4, 0xd0, 0xec, 0x8d, 0xb7, 0x7f, 0x9d,
   0xa0, 0xcd, 0x5d, 0x2d, 0x51, 0x2f, 0x42, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -5200,7 +5200,7 @@
 KOUiAgOCRJo0Y577KM/ozS4OUiDtSss4fJ2ubnnXlSyokfOGASGRS7VApA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert75[] = {
+static const unsigned char kDERCert76[] = {
   0x30, 0x82, 0x05, 0x07, 0x30, 0x82, 0x03, 0xef, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x02, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
   0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x68, 0x31, 0x0b,
@@ -5418,7 +5418,7 @@
 YxtLufbBfVlmq9HzijAFGHpBR6vHZxQ6fGCxCE7QzsfhraZN7q4yrKzGWg==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert76[] = {
+static const unsigned char kDERCert77[] = {
   0x30, 0x82, 0x05, 0x07, 0x30, 0x82, 0x03, 0xef, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x4c, 0x0e, 0xa6, 0xdb, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -5634,7 +5634,7 @@
 8TttlmsB5CNMscHg0hIhnynUrZU9pvfnMsV1twtX2KT5wOzsMjMMTa7oCNXsqg==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert77[] = {
+static const unsigned char kDERCert78[] = {
   0x30, 0x82, 0x05, 0x0a, 0x30, 0x82, 0x03, 0xf2, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x45, 0x6b, 0x9a, 0xdc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -5850,7 +5850,7 @@
 +qrLMgx5qoZ0bERU9tgHns2Y9CMFCS+iU7XbCoHMXyPLeRHFEVuFaycBifMOuw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert78[] = {
+static const unsigned char kDERCert79[] = {
   0x30, 0x82, 0x05, 0x0a, 0x30, 0x82, 0x03, 0xf2, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x7b, 0x11, 0x55, 0xeb, 0x78, 0x9a, 0x90, 0x85, 0xb5,
   0x8c, 0x92, 0xff, 0x42, 0xb7, 0xfe, 0x56, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -6067,7 +6067,7 @@
 DA==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert79[] = {
+static const unsigned char kDERCert80[] = {
   0x30, 0x82, 0x05, 0x0d, 0x30, 0x82, 0x03, 0xf5, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x4c, 0x0e, 0xc9, 0x18, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
@@ -6276,7 +6276,7 @@
 FxdzPcwl
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert80[] = {
+static const unsigned char kDERCert81[] = {
   0x30, 0x82, 0x05, 0x12, 0x30, 0x82, 0x04, 0x7b, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x02, 0x01, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
   0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xbb, 0x31,
@@ -6500,7 +6500,7 @@
 y1Vx1frt
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert81[] = {
+static const unsigned char kDERCert82[] = {
   0x30, 0x82, 0x05, 0x12, 0x30, 0x82, 0x04, 0x7b, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x04, 0x07, 0x27, 0x62, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a,
   0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x75,
@@ -6711,7 +6711,7 @@
 BxxsCzAwxw==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert82[] = {
+static const unsigned char kDERCert83[] = {
   0x30, 0x82, 0x05, 0x13, 0x30, 0x82, 0x04, 0x7c, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x57, 0xbf, 0xfb, 0x03, 0xfb, 0x2c, 0x46, 0xd4, 0xe1,
   0x9e, 0xce, 0xe0, 0xd7, 0x43, 0x7f, 0x13, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -6930,7 +6930,7 @@
 J4Su08i9t4L6dCzgM6aP
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert83[] = {
+static const unsigned char kDERCert84[] = {
   0x30, 0x82, 0x05, 0x1b, 0x30, 0x82, 0x04, 0x03, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x08, 0x0a, 0x57, 0x82, 0x2c, 0xc6, 0xf5, 0xe1, 0x4f,
   0x19, 0xb7, 0x09, 0x55, 0xc8, 0x03, 0x42, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7149,7 +7149,7 @@
 fyyysLJbsSoGDjZbYzTIO2mz71GsmmiF7S4tRP6eCdcm+A==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert84[] = {
+static const unsigned char kDERCert85[] = {
   0x30, 0x82, 0x05, 0x2e, 0x30, 0x82, 0x04, 0x16, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x03, 0x0e, 0x95, 0x29, 0x4d, 0xae, 0xc1, 0x2c, 0x03,
   0xcf, 0x31, 0xab, 0x5b, 0x02, 0x71, 0xd7, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7361,7 +7361,7 @@
 pWlCG4MRXYQo0yeu7CqrL2BCxcR4
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert85[] = {
+static const unsigned char kDERCert86[] = {
   0x30, 0x82, 0x05, 0x51, 0x30, 0x82, 0x04, 0xba, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x5f, 0xa6, 0xbe, 0x80, 0xb6, 0x86, 0xc6, 0x2f, 0x01,
   0xed, 0x0c, 0xab, 0xb1, 0x96, 0xa1, 0x05, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7592,7 +7592,7 @@
 qQ2mRHNQ3XBb7a1+Srwi1agm5MKFIA3Z
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert86[] = {
+static const unsigned char kDERCert87[] = {
   0x30, 0x82, 0x05, 0xe4, 0x30, 0x82, 0x04, 0xcc, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x5b, 0x77, 0x59, 0xc6, 0x17, 0x84, 0xe1, 0x5e, 0xc7,
   0x27, 0xc0, 0x32, 0x95, 0x29, 0x28, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -7835,7 +7835,7 @@
 Rs/iGAZeqa6ogZpHFt4MKGwlJ7net4RYxh84HqTEy2Y=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert87[] = {
+static const unsigned char kDERCert88[] = {
   0x30, 0x82, 0x05, 0xec, 0x30, 0x82, 0x04, 0xd4, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x6e, 0xcc, 0x7a, 0xa5, 0xa7, 0x03, 0x20, 0x09, 0xb8,
   0xce, 0xbc, 0xf4, 0xe9, 0x52, 0xd4, 0x91, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8076,7 +8076,7 @@
 T4ycHpLODzMgGUlZVDZsxOn5ZhsgbLJvPiQ5b5H7tNiTUMDCl97pk16XIAVKCRM=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert88[] = {
+static const unsigned char kDERCert89[] = {
   0x30, 0x82, 0x05, 0xfb, 0x30, 0x82, 0x04, 0xe3, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x71, 0x63, 0x66, 0x35, 0xeb, 0xf3, 0x82, 0x3d, 0x7e,
   0x13, 0x09, 0x59, 0xa2, 0xd8, 0xe5, 0xde, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8336,7 +8336,7 @@
 GVnm4XA3OA3b7rDi
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert89[] = {
+static const unsigned char kDERCert90[] = {
   0x30, 0x82, 0x06, 0x08, 0x30, 0x82, 0x03, 0xf0, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0a, 0x61, 0x5d, 0xaa, 0xd2, 0x00, 0x06, 0x00, 0x00, 0x00,
   0x40, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
@@ -8585,7 +8585,7 @@
 Gh/aWKfkT8Fhrryi/ks=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert90[] = {
+static const unsigned char kDERCert91[] = {
   0x30, 0x82, 0x06, 0x0a, 0x30, 0x82, 0x04, 0xf2, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x11, 0x2a, 0x00, 0x6d, 0x37, 0xe5, 0x10, 0x6f, 0xd6,
   0xca, 0x7c, 0xc3, 0xef, 0xba, 0xcc, 0x18, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -8847,7 +8847,7 @@
 pnj1Hn3eGjp4fNwqcQajLW8FVSOLkO8=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert91[] = {
+static const unsigned char kDERCert92[] = {
   0x30, 0x82, 0x06, 0x13, 0x30, 0x82, 0x03, 0xfb, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x0a, 0x61, 0x03, 0x33, 0x36, 0x00, 0x05, 0x00, 0x00, 0x00,
   0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
@@ -9097,7 +9097,7 @@
 wHGkQeta4/wULkuI/a5uW2XpJ+S/5LAjwbJ9W2Il1z4Q1A==
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert92[] = {
+static const unsigned char kDERCert93[] = {
   0x30, 0x82, 0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x2c, 0x48, 0xdd, 0x93, 0x0d, 0xf5, 0x59, 0x8e, 0xf9,
   0x3c, 0x99, 0x54, 0x7a, 0x60, 0xed, 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9348,7 +9348,7 @@
 XmnUG623kHdq2FlveasB+lXwiiFm5WVu/XzT3x7rfj8GkPsZC9MGAht4Q5mo
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert93[] = {
+static const unsigned char kDERCert94[] = {
   0x30, 0x82, 0x06, 0x29, 0x30, 0x82, 0x05, 0x11, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x64, 0x1b, 0xe8, 0x20, 0xce, 0x02, 0x08, 0x13, 0xf3,
   0x2d, 0x4d, 0x2d, 0x95, 0xd6, 0x7e, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9592,7 +9592,7 @@
 YhHB2QmcQrmy1KotmDojYMyimvFu6M+O0Ro8XhnF15s1sAIjJOUFuNWI4+D6ufRf
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert94[] = {
+static const unsigned char kDERCert95[] = {
   0x30, 0x82, 0x06, 0x2c, 0x30, 0x82, 0x05, 0x95, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x6e, 0x4f, 0xfa, 0xb3, 0xc5, 0xe6, 0x69, 0xc4, 0xd1,
   0x67, 0xc9, 0x92, 0xab, 0xe8, 0x58, 0xc4, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -9855,7 +9855,7 @@
 0q6Dp6jOW6c=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert95[] = {
+static const unsigned char kDERCert96[] = {
   0x30, 0x82, 0x06, 0x34, 0x30, 0x82, 0x04, 0x1c, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x01, 0x18, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
   0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30,
@@ -10119,7 +10119,7 @@
 qhykguAzx/Q=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert96[] = {
+static const unsigned char kDERCert97[] = {
   0x30, 0x82, 0x06, 0x34, 0x30, 0x82, 0x04, 0x1c, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x01, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
   0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30,
@@ -10370,7 +10370,7 @@
 9ZKNu8BVIASm2LAXFszj0Mi0PeXZhMbT9m5teMl5Q+h6N/9cNUm/ocU=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert97[] = {
+static const unsigned char kDERCert98[] = {
   0x30, 0x82, 0x06, 0x55, 0x30, 0x82, 0x05, 0x3d, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x08, 0x51, 0xf9, 0x59, 0x81, 0x41, 0x45, 0xca, 0xbd,
   0xe0, 0x24, 0xe2, 0x12, 0xc9, 0xc2, 0x0e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -10624,7 +10624,7 @@
 Ib4p1I5eFdZCSucyb6Sxa1GDWL4/bcf72gMhy2oWGU4K8K2Eyl2Us1p292E=
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert98[] = {
+static const unsigned char kDERCert99[] = {
   0x30, 0x82, 0x06, 0x58, 0x30, 0x82, 0x05, 0x40, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x0a, 0x5f, 0x11, 0x4d, 0x03, 0x5b, 0x17, 0x91, 0x17,
   0xd2, 0xef, 0xd4, 0x03, 0x8c, 0x3f, 0x3b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -10884,7 +10884,7 @@
 ThXxl0wLS6+B1EaUYixDpzwlSBlj8lyqFYl2hIVzkX0oPAmDgrz3
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert99[] = {
+static const unsigned char kDERCert100[] = {
   0x30, 0x82, 0x06, 0xe3, 0x30, 0x82, 0x05, 0xcb, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x08, 0xbb, 0xb0, 0x25, 0x47, 0x13, 0x4b, 0xc9, 0xb1,
   0x10, 0xd7, 0xc1, 0xa2, 0x12, 0x59, 0xc5, 0x30, 0x0d, 0x06, 0x09, 0x2a,
@@ -11156,7 +11156,7 @@
 zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA
 -----END CERTIFICATE-----
 #endif
-static const unsigned char kDERCert100[] = {
+static const unsigned char kDERCert101[] = {
   0x30, 0x82, 0x06, 0xe6, 0x30, 0x82, 0x05, 0xce, 0xa0, 0x03, 0x02, 0x01,
   0x02, 0x02, 0x10, 0x03, 0x37, 0xb9, 0x28, 0x34, 0x7c, 0x60, 0xa6, 0xae,
   0xc5, 0xad, 0xb1, 0x21, 0x7f, 0x38, 0x60, 0x30, 0x0d, 0x06, 0x09, 0x2a,
diff --git a/net/quic/crypto/common_cert_set_test.cc b/net/quic/crypto/common_cert_set_test.cc
index 6ce020d..325d0b2 100644
--- a/net/quic/crypto/common_cert_set_test.cc
+++ b/net/quic/crypto/common_cert_set_test.cc
@@ -78,7 +78,7 @@
 
   const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
 
-  const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54);
+  const uint64 in_hash = GG_UINT64_C(0xc9fef74053f99f39);
   uint64 hash;
   uint32 index;
   ASSERT_TRUE(sets->MatchCert(
@@ -96,7 +96,7 @@
 TEST(CommonCertSets, NonMatch) {
   const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
   StringPiece not_a_cert("hello");
-  const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54);
+  const uint64 in_hash = GG_UINT64_C(0xc9fef74053f99f39);
   uint64 hash;
   uint32 index;
   EXPECT_FALSE(sets->MatchCert(
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index c0688b4..00cc342 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -573,6 +573,13 @@
 #endif
   }
 
+  if (proof_verifier_.get() && !cached->proof_valid()) {
+    // If we are expecting a certificate chain, double the size of the client
+    // hello so that the response from the server can be larger - hopefully
+    // including the whole certificate chain.
+    out->set_minimum_size(kClientHelloMinimumSize * 2);
+  }
+
   if (common_cert_sets) {
     out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
   }
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index b28207f..e0475b5 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -137,7 +137,12 @@
   }
 
   char orbit_bytes[kOrbitSize];
-  rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
+  if (options.orbit.size() == kOrbitSize) {
+    memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
+  } else {
+    DCHECK(options.orbit.empty());
+    rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
+  }
   msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
 
   if (options.channel_id_enabled) {
@@ -674,44 +679,60 @@
   const QuicTag* their_proof_demands;
   size_t num_their_proof_demands;
 
-  if (proof_source_.get() != NULL &&
+  if (proof_source_.get() == NULL ||
       client_hello.GetTaglist(kPDMD, &their_proof_demands,
-                              &num_their_proof_demands) ==
+                              &num_their_proof_demands) !=
           QUIC_NO_ERROR) {
-    for (size_t i = 0; i < num_their_proof_demands; i++) {
-      if (their_proof_demands[i] != kX509) {
-        continue;
-      }
+    return;
+  }
 
-      const vector<string>* certs;
-      string signature;
-      if (!proof_source_->GetProof(info.sni.as_string(), config->serialized,
-                                   &certs, &signature)) {
+  bool x509_supported = false, x509_ecdsa_supported = false;
+  for (size_t i = 0; i < num_their_proof_demands; i++) {
+    switch (their_proof_demands[i]) {
+      case kX509:
+        x509_supported = true;
+        x509_ecdsa_supported = true;
         break;
-      }
-
-      StringPiece their_common_set_hashes;
-      StringPiece their_cached_cert_hashes;
-      client_hello.GetStringPiece(kCCS, &their_common_set_hashes);
-      client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes);
-
-      const string compressed = CertCompressor::CompressChain(
-          *certs, their_common_set_hashes, their_cached_cert_hashes,
-          config->common_cert_sets);
-
-      // kMaxUnverifiedSize is the number of bytes that the certificate chain
-      // and signature can consume before we will demand a valid
-      // source-address token.
-      // TODO(agl): make this configurable.
-      static const size_t kMaxUnverifiedSize = 400;
-      if (info.valid_source_address_token ||
-          signature.size() + compressed.size() < kMaxUnverifiedSize) {
-        out->SetStringPiece(kCertificateTag, compressed);
-        out->SetStringPiece(kPROF, signature);
-      }
-      break;
+      case kX59R:
+        x509_supported = true;
+        break;
     }
   }
+
+  if (!x509_supported) {
+    return;
+  }
+
+  const vector<string>* certs;
+  string signature;
+  if (!proof_source_->GetProof(info.sni.as_string(), config->serialized,
+                               x509_ecdsa_supported, &certs, &signature)) {
+    return;
+  }
+
+  StringPiece their_common_set_hashes;
+  StringPiece their_cached_cert_hashes;
+  client_hello.GetStringPiece(kCCS, &their_common_set_hashes);
+  client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes);
+
+  const string compressed = CertCompressor::CompressChain(
+      *certs, their_common_set_hashes, their_cached_cert_hashes,
+      config->common_cert_sets);
+
+  // kREJOverheadBytes is a very rough estimate of how much of a REJ
+  // message is taken up by things other than the certificates.
+  const size_t kREJOverheadBytes = 112;
+  // kMaxUnverifiedSize is the number of bytes that the certificate chain
+  // and signature can consume before we will demand a valid source-address
+  // token.
+  const size_t kMaxUnverifiedSize = client_hello.size() - kREJOverheadBytes;
+  COMPILE_ASSERT(kClientHelloMinimumSize >= kREJOverheadBytes,
+                 overhead_calculation_may_underflow);
+  if (info.valid_source_address_token ||
+      signature.size() + compressed.size() < kMaxUnverifiedSize) {
+    out->SetStringPiece(kCertificateTag, compressed);
+    out->SetStringPiece(kPROF, signature);
+  }
 }
 
 scoped_refptr<QuicCryptoServerConfig::Config>
diff --git a/net/quic/crypto/crypto_server_config.h b/net/quic/crypto/crypto_server_config.h
index f4816b6..651e928 100644
--- a/net/quic/crypto/crypto_server_config.h
+++ b/net/quic/crypto/crypto_server_config.h
@@ -58,6 +58,9 @@
     // id contains the server config id for the resulting config. If empty, a
     // random id is generated.
     std::string id;
+    // orbit contains the kOrbitSize bytes of the orbit value for the server
+    // config. If |orbit| is empty then a random orbit is generated.
+    std::string orbit;
   };
 
   // |source_address_token_secret|: secret key material used for encrypting and
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index 9ecf3f2..469e582 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -54,7 +54,7 @@
   url_canon::CanonHostInfo host_info;
   string canonicalized_host(CanonicalizeHost(sni.as_string(), &host_info));
   return !host_info.IsIPAddress() &&
-      IsCanonicalizedHostCompliant(canonicalized_host, "") &&
+      IsCanonicalizedHostCompliant(canonicalized_host, std::string()) &&
       sni.find_last_of('.') != string::npos;
 }
 
diff --git a/net/quic/crypto/proof_source.h b/net/quic/crypto/proof_source.h
index b788a79..277549f 100644
--- a/net/quic/crypto/proof_source.h
+++ b/net/quic/crypto/proof_source.h
@@ -44,6 +44,7 @@
   // This function may be called concurrently.
   virtual bool GetProof(const std::string& hostname,
                         const std::string& server_config,
+                        bool ecdsa_ok,
                         const std::vector<std::string>** out_certs,
                         std::string* out_signature) = 0;
 };
diff --git a/net/quic/crypto/proof_source_chromium.cc b/net/quic/crypto/proof_source_chromium.cc
index 48c2b77..7522631 100644
--- a/net/quic/crypto/proof_source_chromium.cc
+++ b/net/quic/crypto/proof_source_chromium.cc
@@ -14,6 +14,7 @@
 
 bool ProofSourceChromium::GetProof(const string& hostname,
                                    const string& server_config,
+                                   bool ecdsa_ok,
                                    const vector<string>** out_certs,
                                    string* out_signature) {
   return false;
diff --git a/net/quic/crypto/proof_source_chromium.h b/net/quic/crypto/proof_source_chromium.h
index fb0b6a6..70ab92d 100644
--- a/net/quic/crypto/proof_source_chromium.h
+++ b/net/quic/crypto/proof_source_chromium.h
@@ -25,6 +25,7 @@
   // ProofSource interface
   virtual bool GetProof(const std::string& hostname,
                         const std::string& server_config,
+                        bool ecdsa_ok,
                         const std::vector<std::string>** out_certs,
                         std::string* out_signature) OVERRIDE;
 
diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc
index 9032953..3258c12 100644
--- a/net/quic/crypto/proof_test.cc
+++ b/net/quic/crypto/proof_test.cc
@@ -35,9 +35,10 @@
   string error_details, signature, first_signature;
   CertVerifyResult cert_verify_result;
 
-  ASSERT_TRUE(source->GetProof(hostname, server_config, &first_certs,
-                               &first_signature));
-  ASSERT_TRUE(source->GetProof(hostname, server_config, &certs, &signature));
+  ASSERT_TRUE(source->GetProof(hostname, server_config, false /* no ECDSA */,
+                               &first_certs, &first_signature));
+  ASSERT_TRUE(source->GetProof(hostname, server_config, false /* no ECDSA */,
+                               &certs, &signature));
 
   // Check that the proof source is caching correctly:
   ASSERT_EQ(first_certs, certs);
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index f407606..fef8445 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -69,8 +69,9 @@
 QuicConnection::QuicConnection(QuicGuid guid,
                                IPEndPoint address,
                                QuicConnectionHelperInterface* helper,
-                               bool is_server)
-    : framer_(kQuicVersion1,
+                               bool is_server,
+                               QuicVersion version)
+    : framer_(version,
               helper->GetClock()->ApproximateNow(),
               is_server),
       helper_(helper),
@@ -106,7 +107,7 @@
   helper_->SetConnection(this);
   helper_->SetTimeoutAlarm(idle_network_timeout_);
   framer_.set_visitor(this);
-  framer_.set_entropy_calculator(&entropy_manager_);
+  framer_.set_received_entropy_calculator(&received_entropy_manager_);
   outgoing_ack_.sent_info.least_unacked = 0;
   outgoing_ack_.sent_info.entropy_hash = 0;
   outgoing_ack_.received_info.largest_observed = 0;
@@ -133,17 +134,20 @@
 }
 
 bool QuicConnection::SelectMutualVersion(
-    const QuicTagVector& available_versions) {
-  // TODO(satyamshekhar): Make this generic.
-  if (std::find(available_versions.begin(), available_versions.end(),
-                kQuicVersion1) == available_versions.end()) {
-    return false;
+    const QuicVersionVector& available_versions) {
+  // Try to find the highest mutual version by iterating over supported
+  // versions, starting with the highest, and breaking out of the loop once we
+  // find a matching version in the provided available_versions vector.
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    const QuicVersion& version = kSupportedQuicVersions[i];
+    if (std::find(available_versions.begin(), available_versions.end(),
+                  version) != available_versions.end()) {
+      framer_.set_version(version);
+      return true;
+    }
   }
 
-  // Right now we only support kQuicVersion1 so it's okay not to
-  // update the framer version. When we start supporting more
-  // versions please update.
-  return true;
+  return false;
 }
 
 void QuicConnection::OnError(QuicFramer* framer) {
@@ -166,7 +170,7 @@
   CloseConnection(QUIC_PUBLIC_RESET, true);
 }
 
-bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) {
+bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
   // TODO(satyamshekhar): Implement no server state in this mode.
   if (!is_server_) {
     LOG(DFATAL) << ENDPOINT << "Framer called OnProtocolVersionMismatch. "
@@ -205,10 +209,11 @@
       DCHECK(false);
   }
 
-  // Right now we only support kQuicVersion1 so it's okay not to
-  // update the framer version. When we start supporting more
-  // versions please update.
   version_negotiation_state_ = NEGOTIATED_VERSION;
+
+  // Store the new version.
+  framer_.set_version(received_version);
+
   // TODO(satyamshekhar): Store the sequence number of this packet and close the
   // connection if we ever received a packet with incorrect version and whose
   // sequence number is greater.
@@ -408,7 +413,8 @@
     DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:"
                 << incoming_ack.received_info.largest_observed << " vs "
                 << peer_largest_observed_packet_;
-    // We got an error for data we have not sent.  Error out.
+    // A new ack has a diminished largest_observed value.  Error out.
+    // If this was an old packet, we wouldn't even have checked.
     return false;
   }
 
@@ -454,7 +460,7 @@
     return false;
   }
 
-  if (!entropy_manager_.IsValidEntropy(
+  if (!sent_entropy_manager_.IsValidEntropy(
           incoming_ack.received_info.largest_observed,
           incoming_ack.received_info.missing_packets,
           incoming_ack.received_info.entropy_hash)) {
@@ -544,7 +550,7 @@
         *(incoming_ack.received_info.missing_packets.begin());
   }
 
-  entropy_manager_.ClearSentEntropyBefore(least_packet_awaited_by_peer_ - 1);
+  sent_entropy_manager_.ClearEntropyBefore(least_packet_awaited_by_peer_ - 1);
 
   SequenceNumberSet acked_packets;
   HandleAckForSentPackets(incoming_ack, &acked_packets);
@@ -579,7 +585,7 @@
       DVLOG(1) << ENDPOINT << "Updating entropy hashed since we missed packets";
       // There were some missing packets that we won't ever get now. Recalculate
       // the received entropy hash.
-      entropy_manager_.RecalculateReceivedEntropyHash(
+      received_entropy_manager_.RecalculateEntropyHash(
           incoming_ack.sent_info.least_unacked,
           incoming_ack.sent_info.entropy_hash);
     }
@@ -697,8 +703,10 @@
 }
 
 void QuicConnection::SendVersionNegotiationPacket() {
-  QuicTagVector supported_versions;
-  supported_versions.push_back(kQuicVersion1);
+  QuicVersionVector supported_versions;
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    supported_versions.push_back(kSupportedQuicVersions[i]);
+  }
   QuicEncryptedPacket* encrypted =
       packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
   // TODO(satyamshekhar): implement zero server state negotiation.
@@ -864,8 +872,8 @@
         header.packet_sequence_number;
     time_largest_observed_ = time_of_last_received_packet_;
   }
-  entropy_manager_.RecordReceivedPacketEntropyHash(sequence_number,
-                                                   header.entropy_hash);
+  received_entropy_manager_.RecordPacketEntropyHash(
+      sequence_number, header.entropy_hash);
 }
 
 bool QuicConnection::MaybeRetransmitPacketForRTO(
@@ -1160,7 +1168,7 @@
   int bytes_written = helper_->WritePacketToWire(packet, error);
   if (debug_visitor_) {
     // WritePacketToWire returned -1, then |error| will be populated with
-    // a NetErrorCode, which we want to pass along to the visitor.
+    // an error code, which we want to pass along to the visitor.
     debug_visitor_->OnPacketSent(sequence_number, level, packet,
                                  bytes_written == -1 ? *error : bytes_written);
   }
@@ -1203,7 +1211,7 @@
                                        QuicPacket* packet,
                                        QuicPacketEntropyHash entropy_hash,
                                        HasRetransmittableData retransmittable) {
-  entropy_manager_.RecordSentPacketEntropyHash(sequence_number, entropy_hash);
+  sent_entropy_manager_.RecordPacketEntropyHash(sequence_number, entropy_hash);
   if (!WritePacket(level, sequence_number, packet, retransmittable, NO_FORCE)) {
     queued_packets_.push_back(QueuedPacket(sequence_number, packet, level,
                                            retransmittable));
@@ -1231,10 +1239,10 @@
     outgoing_ack_.sent_info.least_unacked =
         packet_creator_.sequence_number() + 1;
   }
-  outgoing_ack_.sent_info.entropy_hash = entropy_manager_.SentEntropyHash(
+  outgoing_ack_.sent_info.entropy_hash = sent_entropy_manager_.EntropyHash(
       outgoing_ack_.sent_info.least_unacked - 1);
   outgoing_ack_.received_info.entropy_hash =
-      entropy_manager_.ReceivedEntropyHash(
+      received_entropy_manager_.EntropyHash(
           outgoing_ack_.received_info.largest_observed);
 }
 
@@ -1446,8 +1454,8 @@
   SerializedPacket serialized_packet =
       packet_creator_.SerializeConnectionClose(&frame);
 
-  // We need to update the sent entrophy hash for all sent packets.
-  entropy_manager_.RecordSentPacketEntropyHash(
+  // We need to update the sent entropy hash for all sent packets.
+  sent_entropy_manager_.RecordPacketEntropyHash(
       serialized_packet.sequence_number,
       serialized_packet.entropy_hash);
 
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index d869937..3fd80f0 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -30,9 +30,10 @@
 #include "net/quic/quic_blocked_writer_interface.h"
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_packet_entropy_manager.h"
 #include "net/quic/quic_packet_generator.h"
 #include "net/quic/quic_protocol.h"
+#include "net/quic/quic_received_entropy_manager.h"
+#include "net/quic/quic_sent_entropy_manager.h"
 #include "net/quic/quic_stats.h"
 
 namespace net {
@@ -101,7 +102,7 @@
 
   // Called when the protocol version on the received packet doensn't match
   // current protocol version of the connection.
-  virtual void OnProtocolVersionMismatch(QuicTag version) = 0;
+  virtual void OnProtocolVersionMismatch(QuicVersion version) = 0;
 
   // Called when the complete header of a packet has been parsed.
   virtual void OnPacketHeader(const QuicPacketHeader& header) = 0;
@@ -220,7 +221,8 @@
   QuicConnection(QuicGuid guid,
                  IPEndPoint address,
                  QuicConnectionHelperInterface* helper,
-                 bool is_server);
+                 bool is_server,
+                 QuicVersion version);
   virtual ~QuicConnection();
 
   static void DeleteEnclosedFrame(QuicFrame* frame);
@@ -276,11 +278,11 @@
   bool ProcessValidatedPacket();
 
   // The version of the protocol this connection is using.
-  QuicTag version() const { return framer_.version(); }
+  QuicVersion version() const { return framer_.version(); }
 
   // From QuicFramerVisitorInterface
   virtual void OnError(QuicFramer* framer) OVERRIDE;
-  virtual bool OnProtocolVersionMismatch(QuicTag received_version) OVERRIDE;
+  virtual bool OnProtocolVersionMismatch(QuicVersion received_version) OVERRIDE;
   virtual void OnPacket() OVERRIDE;
   virtual void OnPublicResetPacket(
       const QuicPublicResetPacket& packet) OVERRIDE;
@@ -448,7 +450,11 @@
 
   QuicConnectionHelperInterface* helper() { return helper_.get(); }
 
- protected:
+  // Selects and updates the version of the protocol being used by selecting a
+  // version from |available_versions| which is also supported. Returns true if
+  // such a version exists, false otherwise.
+  bool SelectMutualVersion(const QuicVersionVector& available_versions);
+
   QuicFramer framer_;
 
  private:
@@ -519,10 +525,6 @@
                               RetransmissionTimeComparator>
       RetransmissionTimeouts;
 
-  // Selects and updates the version of the protocol being used by selecting a
-  // version from |available_versions| which is also supported. Returns true if
-  // such a version exists, false otherwise.
-  bool SelectMutualVersion(const QuicTagVector& available_versions);
   // Sends a version negotiation packet to the peer.
   void SendVersionNegotiationPacket();
 
@@ -651,7 +653,8 @@
 
   FecGroupMap group_map_;
 
-  QuicPacketEntropyManager entropy_manager_;
+  QuicReceivedEntropyManager received_entropy_manager_;
+  QuicSentEntropyManager sent_entropy_manager_;
 
   QuicConnectionVisitorInterface* visitor_;
   QuicConnectionDebugVisitorInterface* debug_visitor_;
diff --git a/net/quic/quic_connection_helper.cc b/net/quic/quic_connection_helper.cc
index 2dd5f68..c9b44d3 100644
--- a/net/quic/quic_connection_helper.cc
+++ b/net/quic/quic_connection_helper.cc
@@ -92,6 +92,7 @@
 }
 
 void QuicConnectionHelper::SetAckAlarm(QuicTime::Delta delay) {
+  ack_alarm_time_ = clock_->Now().Add(delay);
   if (!ack_alarm_registered_) {
     task_runner_->PostDelayedTask(
         FROM_HERE,
@@ -100,7 +101,6 @@
         base::TimeDelta::FromMicroseconds(delay.ToMicroseconds()));
   }
   ack_alarm_registered_ = true;
-  ack_alarm_time_ = clock_->Now().Add(delay);
 }
 
 void QuicConnectionHelper::ClearAckAlarm() {
@@ -140,11 +140,15 @@
 
 void QuicConnectionHelper::OnRetransmissionAlarm() {
   QuicTime when = connection_->OnRetransmissionTimeout();
-  if (when.IsInitialized()) {
-    QuicTime now = clock_->Now();
-    DCHECK_LE(now.ToDebuggingValue(), when.ToDebuggingValue());
-    SetRetransmissionAlarm(when.Subtract(now));
+  if (!when.IsInitialized()) {
+    return;
   }
+  QuicTime now = clock_->Now();
+  QuicTime::Delta delta(when.Subtract(now));
+  if (delta < QuicTime::Delta::FromSeconds(0)) {
+    delta = QuicTime::Delta::FromSeconds(0);
+  }
+  SetRetransmissionAlarm(delta);
 }
 
 void QuicConnectionHelper::OnSendAlarm() {
@@ -167,8 +171,9 @@
   }
 
   // Alarm may have been reset to a later time.
-  if (clock_->Now() < ack_alarm_time_) {
-    SetAckAlarm(ack_alarm_time_.Subtract(clock_->Now()));
+  QuicTime now = clock_->Now();
+  if (now < ack_alarm_time_) {
+    SetAckAlarm(ack_alarm_time_.Subtract(now));
     return;
   }
 
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index c9c7ba5..21ff95b 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -30,7 +30,7 @@
   TestConnection(QuicGuid guid,
                  IPEndPoint address,
                  QuicConnectionHelper* helper)
-      : QuicConnection(guid, address, helper, false) {
+      : QuicConnection(guid, address, helper, false, QuicVersionMax()) {
   }
 
   void SendAck() {
@@ -59,7 +59,7 @@
 
   QuicConnectionHelperTest()
       : guid_(2),
-        framer_(kQuicVersion1, QuicTime::Zero(), false),
+        framer_(QuicVersionMax(), QuicTime::Zero(), false),
         net_log_(BoundNetLog()),
         frame_(1, false, 0, kData) {
     Initialize();
@@ -304,6 +304,9 @@
   AddWrite(SYNCHRONOUS, ConstructDataPacket(2));
   Initialize();
 
+  EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
+      testing::Return(QuicTime::Delta::Zero()));
+
   QuicTime::Delta kDefaultRetransmissionTime =
       QuicTime::Delta::FromMilliseconds(500);
   QuicTime start = clock_.ApproximateNow();
@@ -328,6 +331,9 @@
   AddWrite(SYNCHRONOUS, ConstructDataPacket(3));
   Initialize();
 
+  EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
+      testing::Return(QuicTime::Delta::Zero()));
+
   QuicTime::Delta kDefaultRetransmissionTime =
       QuicTime::Delta::FromMilliseconds(500);
   QuicTime start = clock_.ApproximateNow();
@@ -442,6 +448,8 @@
   Initialize();
 
   // Test that if we send a packet with a delay, it ends up queued.
+  EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
+      testing::Return(QuicTime::Delta::Zero()));
   EXPECT_CALL(
       *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
           testing::Return(QuicTime::Delta::FromMicroseconds(1)));
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 0ca1802..3405cd0 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -225,7 +225,8 @@
                  packet.length()));
 }
 
-void QuicConnectionLogger::OnProtocolVersionMismatch(QuicTag received_version) {
+void QuicConnectionLogger::OnProtocolVersionMismatch(
+    QuicVersion received_version) {
   // TODO(rtenneti): Add logging.
 }
 
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 81a5441..1d2bd2d 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -32,7 +32,7 @@
   virtual void OnPacketReceived(const IPEndPoint& self_address,
                                 const IPEndPoint& peer_address,
                                 const QuicEncryptedPacket& packet) OVERRIDE;
-  virtual void OnProtocolVersionMismatch(QuicTag version) OVERRIDE;
+  virtual void OnProtocolVersionMismatch(QuicVersion version) OVERRIDE;
   virtual void OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
   virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
   virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index b170d0d..274f868 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -13,6 +13,7 @@
 #include "net/quic/crypto/quic_decrypter.h"
 #include "net/quic/crypto/quic_encrypter.h"
 #include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_protocol.h"
 #include "net/quic/quic_utils.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/mock_random.h"
@@ -250,7 +251,7 @@
              sizeof(final_bytes_of_last_packet_));
     }
 
-    QuicFramer framer(kQuicVersion1, QuicTime::Zero(), is_server_);
+    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), is_server_);
     if (use_tagging_decrypter_) {
       framer.SetDecrypter(new TaggingDecrypter);
     }
@@ -380,7 +381,7 @@
                  IPEndPoint address,
                  TestConnectionHelper* helper,
                  bool is_server)
-      : QuicConnection(guid, address, helper, is_server),
+      : QuicConnection(guid, address, helper, is_server, QuicVersionMax()),
         helper_(helper) {
     helper_->set_is_server(!is_server);
   }
@@ -409,6 +410,10 @@
     return QuicConnectionPeer::IsServer(this);
   }
 
+  void set_version(QuicVersion version) {
+    framer_.set_version(version);
+  }
+
   void set_is_server(bool is_server) {
     helper_->set_is_server(!is_server);
     QuicPacketCreatorPeer::SetIsServer(
@@ -418,6 +423,7 @@
 
   using QuicConnection::SendOrQueuePacket;
   using QuicConnection::DontWaitForPacketsBefore;
+  using QuicConnection::SelectMutualVersion;
 
  private:
   TestConnectionHelper* helper_;
@@ -429,7 +435,7 @@
  protected:
   QuicConnectionTest()
       : guid_(42),
-        framer_(kQuicVersion1, QuicTime::Zero(), false),
+        framer_(QuicVersionMax(), QuicTime::Zero(), false),
         creator_(guid_, &framer_, QuicRandom::GetInstance(), false),
         send_algorithm_(new StrictMock<MockSendAlgorithm>),
         helper_(new TestConnectionHelper(&clock_, &random_generator_)),
@@ -446,6 +452,8 @@
     EXPECT_CALL(*receive_algorithm_,
                 RecordIncomingPacket(_, _, _, _)).Times(AnyNumber());
     EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
+    EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
+        Return(QuicTime::Delta::Zero()));
   }
 
   QuicAckFrame* outgoing_ack() {
@@ -823,6 +831,25 @@
   EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
 }
 
+TEST_F(QuicConnectionTest, DISABLED_AckReceiptCausesAckSend) {
+  ProcessPacket(1);
+  // Delay sending, then queue up an ack.
+  EXPECT_CALL(*send_algorithm_,
+              TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
+                  testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+  QuicConnectionPeer::SendAck(&connection_);
+
+  // Process an ack with a least unacked of the received ack.
+  // This causes an ack to be sent when TimeUntilSend returns 0.
+  EXPECT_CALL(*send_algorithm_,
+              TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly(
+                  testing::Return(QuicTime::Delta::Zero()));
+  // Skip a packet and then record an ack.
+  creator_.set_sequence_number(2);
+  QuicAckFrame frame(0, QuicTime::Zero(), 3);
+  ProcessAckPacket(&frame, true);
+}
+
 TEST_F(QuicConnectionTest, LeastUnackedLower) {
   SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
   SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
@@ -2093,8 +2120,9 @@
 
 // TODO(satyamsehkhar): Add more test when we start supporting more versions.
 TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) {
-  QuicTag kRandomVersion = 143;
-  QuicFramerPeer::SetVersion(&framer_, kRandomVersion);
+  // TODO(rjshade): Update this to use a real version once we have multiple
+  //                versions in the codebase.
+  framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
 
   QuicPacketHeader header;
   header.public_header.guid = guid_;
@@ -2113,14 +2141,21 @@
   scoped_ptr<QuicEncryptedPacket> encrypted(
       framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
 
-  QuicFramerPeer::SetVersion(&framer_, kQuicVersion1);
+  framer_.set_version(QuicVersionMax());
   connection_.set_is_server(true);
   connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
   EXPECT_TRUE(helper_->version_negotiation_packet() != NULL);
-  EXPECT_EQ(1u,
+
+  size_t num_versions = arraysize(kSupportedQuicVersions);
+  EXPECT_EQ(num_versions,
             helper_->version_negotiation_packet()->versions.size());
-  EXPECT_EQ(kQuicVersion1,
-            helper_->version_negotiation_packet()->versions[0]);
+
+  // We expect all versions in kSupportedQuicVersions to be
+  // included in the packet.
+  for (size_t i = 0; i < num_versions; ++i) {
+    EXPECT_EQ(kSupportedQuicVersions[i],
+              helper_->version_negotiation_packet()->versions[i]);
+  }
 }
 
 TEST_F(QuicConnectionTest, CheckSendStats) {
@@ -2251,6 +2286,27 @@
   connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
 }
 
+//// The QUIC_VERSION_X versions are deliberately set, rather than using all
+//// values in kSupportedQuicVersions.
+//TEST_F(QuicConnectionTest, SelectMutualVersion) {
+//  // Set the connection to speak QUIC_VERSION_6.
+//  connection_.set_version(QUIC_VERSION_6);
+//  EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
+//
+//  // Pass in available versions which includes a higher mutually supported
+//  // version.  The higher mutually supported version should be selected.
+//  EXPECT_TRUE(
+//      connection_.SelectMutualVersion({QUIC_VERSION_6, QUIC_VERSION_7}));
+//  EXPECT_EQ(connection_.version(), QUIC_VERSION_7);
+//
+//  // Expect that the lower version is selected.
+//  EXPECT_TRUE(connection_.SelectMutualVersion({QUIC_VERSION_6}));
+//  EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
+//
+//  // Shouldn't be able to find a mutually supported version.
+//  EXPECT_FALSE(connection_.SelectMutualVersion({QUIC_VERSION_UNSUPPORTED}));
+//}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index fb829db..5f72739 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -122,12 +122,11 @@
 
   // CompleteCryptoHandshake returns the number of client hellos sent. This
   // test should send:
-  //   * One to get a source-address token.
+  //   * One to get a source-address token and certificates.
   //   * One to complete the handshake.
   // TODO(rtenneti): Until we set the crypto_config.SetProofVerifier to enable
   // ProofVerifier in CryptoTestUtils::HandshakeWithFakeClient, we would not
   // have sent the following client hello.
-  //   * One to get the server's certificates
   EXPECT_EQ(2, CompleteCryptoHandshake());
   EXPECT_TRUE(stream_.encryption_established());
   EXPECT_TRUE(stream_.handshake_confirmed());
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 1df3590..e4484f6 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -53,7 +53,7 @@
 
 }  // namespace
 
-QuicFramer::QuicFramer(QuicTag version,
+QuicFramer::QuicFramer(QuicVersion version,
                        QuicTime creation_time,
                        bool is_server)
     : visitor_(NULL),
@@ -142,8 +142,13 @@
   return 8;
 }
 
-bool QuicFramer::IsSupportedVersion(QuicTag version) {
-  return version == kQuicVersion1;
+bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    if (version == kSupportedQuicVersions[i]) {
+      return true;
+    }
+  }
+  return false;
 }
 
 size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
@@ -342,7 +347,7 @@
 
 QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket(
     const QuicPacketPublicHeader& header,
-    const QuicTagVector& supported_versions) {
+    const QuicVersionVector& supported_versions) {
   DCHECK(header.version_flag);
   size_t len = GetVersionNegotiationPacketSize(supported_versions.size());
   QuicDataWriter writer(len);
@@ -359,7 +364,7 @@
   }
 
   for (size_t i = 0; i < supported_versions.size(); ++i) {
-    if (!writer.WriteUInt32(supported_versions[i])) {
+    if (!writer.WriteUInt32(QuicVersionToQuicTag(supported_versions[i]))) {
       return NULL;
     }
   }
@@ -413,7 +418,7 @@
       set_detailed_error("Unable to read supported version in negotiation.");
       return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
     }
-    public_header->versions.push_back(version);
+    public_header->versions.push_back(QuicTagToQuicVersion(version));
   } while (!reader_->IsDoneReading());
 
   visitor_->OnVersionNegotiationPacket(*public_header);
@@ -568,7 +573,7 @@
 
   if (header.public_header.version_flag) {
     DCHECK(!is_server_);
-    writer->WriteUInt32(quic_version_);
+    writer->WriteUInt32(QuicVersionToQuicTag(quic_version_));
   }
 
   if (!AppendPacketSequenceNumber(header.public_header.sequence_number_length,
@@ -712,14 +717,19 @@
       break;
   }
 
+  // Read the version only if the packet is from the client.
+  // version flag from the server means version negotiation packet.
   if (public_header->version_flag && is_server_) {
-    QuicTag version;
-    if (!reader_->ReadUInt32(&version)) {
-      // Read the version only if the packet is from the client.
-      // version flag from the server means version negotiation packet.
+    QuicTag version_tag;
+    if (!reader_->ReadUInt32(&version_tag)) {
       set_detailed_error("Unable to read protocol version.");
       return false;
     }
+
+    // If the version from the new packet is the same as the version of this
+    // framer, then the public flags should be set to something we understand.
+    // If not, this raises an error.
+    QuicVersion version = QuicTagToQuicVersion(version_tag);
     if (version == quic_version_ && public_flags > PACKET_PUBLIC_FLAGS_MAX) {
       set_detailed_error("Illegal public flags value.");
       return false;
@@ -1549,7 +1559,7 @@
           CalculateLargestObserved(frame.received_info.missing_packets, --it);
       // Overwrite entropy hash for received packets.
       writer->WriteUInt8ToOffset(
-          entropy_calculator_->ReceivedEntropyHash(largest_observed),
+          entropy_calculator_->EntropyHash(largest_observed),
           received_entropy_offset);
       // Overwrite largest_observed.
       writer->WriteUInt48ToOffset(largest_observed & k6ByteSequenceNumberMask,
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index dd3eaef..b62d56f 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -64,7 +64,7 @@
   // |quic_version_|. The visitor should return true after it updates the
   // version of the |framer_| to |received_version| or false to stop processing
   // this packet.
-  virtual bool OnProtocolVersionMismatch(QuicTag received_version) = 0;
+  virtual bool OnProtocolVersionMismatch(QuicVersion received_version) = 0;
 
   // Called when a new packet has been received, before it
   // has been validated or processed.
@@ -141,7 +141,7 @@
   // missing packets are not added and the largest observed might be lowered.
   // This should return the received entropy hash of the packets received up to
   // and including |sequence_number|.
-  virtual QuicPacketEntropyHash ReceivedEntropyHash(
+  virtual QuicPacketEntropyHash EntropyHash(
       QuicPacketSequenceNumber sequence_number) const = 0;
 };
 
@@ -153,14 +153,14 @@
  public:
   // Constructs a new framer that installs a kNULL QuicEncrypter and
   // QuicDecrypter for level ENCRYPTION_NONE.
-  QuicFramer(QuicTag quic_version,
+  QuicFramer(QuicVersion quic_version,
              QuicTime creation_time,
              bool is_server);
 
   virtual ~QuicFramer();
 
   // Returns true if |version| is a supported protocol version.
-  bool IsSupportedVersion(QuicTag version);
+  bool IsSupportedVersion(const QuicVersion version) const;
 
   // Calculates the largest observed packet to advertise in the case an Ack
   // Frame was truncated.  last_written in this case is the iterator for the
@@ -184,20 +184,26 @@
     fec_builder_ = builder;
   }
 
-  QuicTag version() const {
+  QuicVersion version() const {
     return quic_version_;
   }
 
-  void set_version(QuicTag version) {
+  void set_version(const QuicVersion version) {
     DCHECK(IsSupportedVersion(version));
     quic_version_ = version;
   }
 
+  // Does not DCHECK for supported version. Used by tests to set unsupported
+  // version to trigger version negotiation.
+  void set_version_for_tests(const QuicVersion version) {
+    quic_version_ = version;
+  }
+
   // Set entropy calculator to be called from the framer when it needs the
   // entropy of a truncated ack frame. An entropy calculator must be set or else
   // the framer will likely crash. If this is called multiple times, only the
-  // last visitor will be used.
-  void set_entropy_calculator(
+  // last calculator will be used.
+  void set_received_entropy_calculator(
       QuicReceivedEntropyHashCalculatorInterface* entropy_calculator) {
     entropy_calculator_ = entropy_calculator;
   }
@@ -285,7 +291,7 @@
 
   QuicEncryptedPacket* ConstructVersionNegotiationPacket(
       const QuicPacketPublicHeader& header,
-      const QuicTagVector& supported_versions);
+      const QuicVersionVector& supported_versions);
 
   // SetDecrypter sets the primary decrypter, replacing any that already exists,
   // and takes ownership. If an alternative decrypter is in place then the
@@ -419,7 +425,7 @@
   // Buffer containing decrypted payload data during parsing.
   scoped_ptr<QuicData> decrypted_;
   // Version of the protocol being used.
-  QuicTag quic_version_;
+  QuicVersion quic_version_;
   // Primary decrypter used to decrypt packets during parsing.
   scoped_ptr<QuicDecrypter> decrypter_;
   // Alternative decrypter that can also be used to decrypt packets.
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 97c0ac6..b7a4e30 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -221,7 +221,7 @@
     revived_packets_++;
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE {
+  virtual bool OnProtocolVersionMismatch(QuicVersion version) OVERRIDE {
     DLOG(INFO) << "QuicFramer Version Mismatch, version: " << version;
     version_mismatch_++;
     return true;
@@ -305,17 +305,20 @@
   QuicGoAwayFrame goaway_frame_;
 };
 
-class QuicFramerTest : public ::testing::Test {
+class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
  public:
   QuicFramerTest()
       : encrypter_(new test::TestEncrypter()),
         decrypter_(new test::TestDecrypter()),
         start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
-        framer_(kQuicVersion1, start_, true) {
+        framer_(QuicVersionMax(), start_, true) {
     framer_.SetDecrypter(decrypter_);
     framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
     framer_.set_visitor(&visitor_);
-    framer_.set_entropy_calculator(&entropy_calculator_);
+    framer_.set_received_entropy_calculator(&entropy_calculator_);
+
+    QuicVersion version = GetParam();
+    framer_.set_version(version);
   }
 
   bool CheckEncryption(QuicPacketSequenceNumber sequence_number,
@@ -415,7 +418,12 @@
   test::TestEntropyCalculator entropy_calculator_;
 };
 
-TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) {
+// Run all framer tests with QUIC version 6.
+INSTANTIATE_TEST_CASE_P(QuicFramerTests,
+                        QuicFramerTest,
+                        ::testing::Values(QUIC_VERSION_6));
+
+TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) {
   // A few quick manual sanity checks
   CheckCalculatePacketSequenceNumber(GG_UINT64_C(1), GG_UINT64_C(0));
   CheckCalculatePacketSequenceNumber(kEpoch + 1, kMask);
@@ -435,7 +443,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochEnd) {
+TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochEnd) {
   // Cases where the last number was close to the end of the range
   for (uint64 i = 0; i < 10; i++) {
     QuicPacketSequenceNumber last = kEpoch - i;
@@ -454,7 +462,7 @@
 
 // Next check where we're in a non-zero epoch to verify we handle
 // reverse wrapping, too.
-TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearPrevEpoch) {
+TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearPrevEpoch) {
   const uint64 prev_epoch = 1 * kEpoch;
   const uint64 cur_epoch = 2 * kEpoch;
   // Cases where the last number was close to the start of the range
@@ -473,7 +481,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextEpoch) {
+TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextEpoch) {
   const uint64 cur_epoch = 2 * kEpoch;
   const uint64 next_epoch = 3 * kEpoch;
   // Cases where the last number was close to the end of the range
@@ -493,7 +501,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) {
+TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) {
   const uint64 max_number = numeric_limits<uint64>::max();
   const uint64 max_epoch = max_number & ~kMask;
 
@@ -516,14 +524,14 @@
   }
 }
 
-TEST_F(QuicFramerTest, EmptyPacket) {
+TEST_P(QuicFramerTest, EmptyPacket) {
   char packet[] = { 0x00 };
   QuicEncryptedPacket encrypted(packet, 0, false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
   EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
 }
 
-TEST_F(QuicFramerTest, LargePacket) {
+TEST_P(QuicFramerTest, LargePacket) {
   unsigned char packet[kMaxPacketSize + 1] = {
     // public flags (8 byte guid)
     0x3C,
@@ -555,7 +563,7 @@
   EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
 }
 
-TEST_F(QuicFramerTest, PacketHeader) {
+TEST_P(QuicFramerTest, PacketHeader) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -606,7 +614,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWith4ByteGuid) {
+TEST_P(QuicFramerTest, PacketHeaderWith4ByteGuid) {
   QuicFramerPeer::SetLastSerializedGuid(&framer_,
                                         GG_UINT64_C(0xFEDCBA9876543210));
 
@@ -661,7 +669,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeader1ByteGuid) {
+TEST_P(QuicFramerTest, PacketHeader1ByteGuid) {
   QuicFramerPeer::SetLastSerializedGuid(&framer_,
                                         GG_UINT64_C(0xFEDCBA9876543210));
 
@@ -715,7 +723,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWith0ByteGuid) {
+TEST_P(QuicFramerTest, PacketHeaderWith0ByteGuid) {
   QuicFramerPeer::SetLastSerializedGuid(&framer_,
                                         GG_UINT64_C(0xFEDCBA9876543210));
 
@@ -768,7 +776,10 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) {
+TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
+  // Set a specific version.
+  framer_.set_version(QUIC_VERSION_6);
+
   unsigned char packet[] = {
     // public flags (version)
     0x3D,
@@ -792,7 +803,7 @@
             visitor_.header_->public_header.guid);
   EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
   EXPECT_TRUE(visitor_.header_->public_header.version_flag);
-  EXPECT_EQ(kQuicVersion1, visitor_.header_->public_header.versions[0]);
+  EXPECT_EQ(QUIC_VERSION_6, visitor_.header_->public_header.versions[0]);
   EXPECT_FALSE(visitor_.header_->fec_flag);
   EXPECT_FALSE(visitor_.header_->entropy_flag);
   EXPECT_EQ(0, visitor_.header_->entropy_hash);
@@ -824,7 +835,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
+TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) {
   QuicFramerPeer::SetLastSequenceNumber(&framer_,
                                         GG_UINT64_C(0x123456789ABA));
 
@@ -879,7 +890,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
+TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) {
   QuicFramerPeer::SetLastSequenceNumber(&framer_,
                                         GG_UINT64_C(0x123456789ABA));
 
@@ -934,7 +945,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
+TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) {
   QuicFramerPeer::SetLastSequenceNumber(&framer_,
                                         GG_UINT64_C(0x123456789ABA));
 
@@ -989,9 +1000,9 @@
   }
 }
 
-TEST_F(QuicFramerTest, InvalidPublicFlag) {
+TEST_P(QuicFramerTest, InvalidPublicFlag) {
   unsigned char packet[] = {
-    // public flags
+    // public flags, unknown flag at bit 6
     0x40,
     // guid
     0x10, 0x32, 0x54, 0x76,
@@ -1026,7 +1037,10 @@
                        QUIC_INVALID_PACKET_HEADER);
 };
 
-TEST_F(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
+TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
+  // Set a specific version.
+  framer_.set_version(QUIC_VERSION_6);
+
   unsigned char packet[] = {
     // public flags (8 byte guid and version flag and an unknown flag)
     0x4D,
@@ -1065,7 +1079,7 @@
                        QUIC_INVALID_PACKET_HEADER);
 };
 
-TEST_F(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
+TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
   unsigned char packet[] = {
     // public flags (8 byte guid, version flag and an unknown flag)
     0x7D,
@@ -1091,7 +1105,7 @@
   EXPECT_EQ(1, visitor_.version_mismatch_);
 };
 
-TEST_F(QuicFramerTest, InvalidPrivateFlag) {
+TEST_P(QuicFramerTest, InvalidPrivateFlag) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1128,7 +1142,7 @@
                        QUIC_INVALID_PACKET_HEADER);
 };
 
-TEST_F(QuicFramerTest, PaddingFrame) {
+TEST_P(QuicFramerTest, PaddingFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1171,7 +1185,7 @@
       "Unable to read frame type.", QUIC_INVALID_FRAME_DATA);
 }
 
-TEST_F(QuicFramerTest, StreamFrame) {
+TEST_P(QuicFramerTest, StreamFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1241,7 +1255,10 @@
   }
 }
 
-TEST_F(QuicFramerTest, StreamFrameWithVersion) {
+TEST_P(QuicFramerTest, StreamFrameWithVersion) {
+  // Set a specific version.
+  framer_.set_version(QUIC_VERSION_6);
+
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -1279,7 +1296,7 @@
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_TRUE(visitor_.header_.get()->public_header.version_flag);
-  EXPECT_EQ(kQuicVersion1, visitor_.header_.get()->public_header.versions[0]);
+  EXPECT_EQ(QUIC_VERSION_6, visitor_.header_.get()->public_header.versions[0]);
   EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion));
 
   ASSERT_EQ(1u, visitor_.stream_frames_.size());
@@ -1315,7 +1332,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, RejectPacket) {
+TEST_P(QuicFramerTest, RejectPacket) {
   visitor_.accept_packet_ = false;
 
   unsigned char packet[] = {
@@ -1358,7 +1375,7 @@
   EXPECT_EQ(0u, visitor_.ack_frames_.size());
 }
 
-TEST_F(QuicFramerTest, RevivedStreamFrame) {
+TEST_P(QuicFramerTest, RevivedStreamFrame) {
   unsigned char payload[] = {
     // frame type (stream frame)
     0x01,
@@ -1416,7 +1433,7 @@
   EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
 }
 
-TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
+TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1472,7 +1489,7 @@
   EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
 }
 
-TEST_F(QuicFramerTest, AckFrame) {
+TEST_P(QuicFramerTest, AckFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1567,7 +1584,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
+TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1626,7 +1643,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
+TEST_P(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1724,7 +1741,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
+TEST_P(QuicFramerTest, CongestionFeedbackFrameFixRate) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1779,7 +1796,7 @@
 }
 
 
-TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
+TEST_P(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1804,7 +1821,7 @@
   EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
 }
 
-TEST_F(QuicFramerTest, RstStreamFrame) {
+TEST_P(QuicFramerTest, RstStreamFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1863,7 +1880,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, ConnectionCloseFrame) {
+TEST_P(QuicFramerTest, ConnectionCloseFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1950,7 +1967,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, GoAwayFrame) {
+TEST_P(QuicFramerTest, GoAwayFrame) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -2011,7 +2028,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, PublicResetPacket) {
+TEST_P(QuicFramerTest, PublicResetPacket) {
   unsigned char packet[] = {
     // public flags (public reset, 8 byte guid)
     0x3E,
@@ -2063,7 +2080,10 @@
   }
 }
 
-TEST_F(QuicFramerTest, VersionNegotiationPacket) {
+TEST_P(QuicFramerTest, VersionNegotiationPacket) {
+  // Set a specific version.
+  framer_.set_version(QUIC_VERSION_6);
+
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -2082,7 +2102,7 @@
   ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
   ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
   EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
-  EXPECT_EQ(kQuicVersion1,
+  EXPECT_EQ(QUIC_VERSION_6,
             visitor_.version_negotiation_packet_->versions[0]);
 
   for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_GUID; ++i) {
@@ -2100,7 +2120,7 @@
   }
 }
 
-TEST_F(QuicFramerTest, FecPacket) {
+TEST_P(QuicFramerTest, FecPacket) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -2137,7 +2157,7 @@
   EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy);
 }
 
-TEST_F(QuicFramerTest, ConstructPaddingFramePacket) {
+TEST_P(QuicFramerTest, ConstructPaddingFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2182,7 +2202,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2227,7 +2247,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2272,7 +2292,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2317,7 +2337,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructStreamFramePacket) {
+TEST_P(QuicFramerTest, ConstructStreamFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2374,7 +2394,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
+TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2393,6 +2413,8 @@
   QuicFrames frames;
   frames.push_back(QuicFrame(&stream_frame));
 
+  // Set a specific version.
+  framer_.set_version(QUIC_VERSION_6);
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -2434,7 +2456,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) {
+TEST_P(QuicFramerTest, ConstructVersionNegotiationPacket) {
   QuicPacketPublicHeader header;
   header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.reset_flag = false;
@@ -2448,13 +2470,12 @@
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
     'Q', '0', '0', '6',
-    'Q', '2', '.', '0',
+    // 'Q', '0', '0', '7',
   };
 
-  const int kQuicVersion2 = MakeQuicTag('Q', '2', '.', '0');
-  QuicTagVector versions;
-  versions.push_back(kQuicVersion1);
-  versions.push_back(kQuicVersion2);
+  QuicVersionVector versions;
+  versions.push_back(QUIC_VERSION_6);
+  // versions.push_back(QUIC_VERSION_7);
   scoped_ptr<QuicEncryptedPacket> data(
       framer_.ConstructVersionNegotiationPacket(header, versions));
 
@@ -2463,7 +2484,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructAckFramePacket) {
+TEST_P(QuicFramerTest, ConstructAckFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2527,7 +2548,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
+TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2576,7 +2597,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
+TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2649,7 +2670,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
+TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2696,7 +2717,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) {
+TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2718,7 +2739,7 @@
   ASSERT_TRUE(data == NULL);
 }
 
-TEST_F(QuicFramerTest, ConstructRstFramePacket) {
+TEST_P(QuicFramerTest, ConstructRstFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2772,7 +2793,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructCloseFramePacket) {
+TEST_P(QuicFramerTest, ConstructCloseFramePacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2849,7 +2870,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructGoAwayPacket) {
+TEST_P(QuicFramerTest, ConstructGoAwayPacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2903,7 +2924,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructPublicResetPacket) {
+TEST_P(QuicFramerTest, ConstructPublicResetPacket) {
   QuicPublicResetPacket reset_packet;
   reset_packet.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   reset_packet.public_header.reset_flag = true;
@@ -2934,7 +2955,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, ConstructFecPacket) {
+TEST_P(QuicFramerTest, ConstructFecPacket) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2979,7 +3000,7 @@
                                       AsChars(packet), arraysize(packet));
 }
 
-TEST_F(QuicFramerTest, EncryptPacket) {
+TEST_P(QuicFramerTest, EncryptPacket) {
   QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
   unsigned char packet[] = {
     // public flags (8 byte guid)
@@ -3013,7 +3034,7 @@
   EXPECT_TRUE(CheckEncryption(sequence_number, raw.get()));
 }
 
-TEST_F(QuicFramerTest, EncryptPacketWithVersionFlag) {
+TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
   QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC);
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
@@ -3052,7 +3073,7 @@
 // TODO(rch): re-enable after https://codereview.chromium.org/11820005/
 // lands.  Currently this is causing valgrind problems, but it should be
 // fixed in the followup CL.
-TEST_F(QuicFramerTest, DISABLED_CalculateLargestReceived) {
+TEST_P(QuicFramerTest, DISABLED_CalculateLargestReceived) {
   SequenceNumberSet missing;
   missing.insert(1);
   missing.insert(5);
@@ -3071,7 +3092,7 @@
 }
 
 // TODO(rch) enable after landing the revised truncation CL.
-TEST_F(QuicFramerTest, DISABLED_Truncation) {
+TEST_P(QuicFramerTest, DISABLED_Truncation) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -3127,7 +3148,7 @@
   ASSERT_TRUE(framer_.ProcessPacket(*close_packet));
 }
 
-TEST_F(QuicFramerTest, CleanTruncation) {
+TEST_P(QuicFramerTest, CleanTruncation) {
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -3207,7 +3228,7 @@
   EXPECT_EQ(original_raw_length, raw_close_packet->length());
 }
 
-TEST_F(QuicFramerTest, EntropyFlagTest) {
+TEST_P(QuicFramerTest, EntropyFlagTest) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -3246,7 +3267,7 @@
   EXPECT_FALSE(visitor_.header_->fec_flag);
 };
 
-TEST_F(QuicFramerTest, FecEntropyTest) {
+TEST_P(QuicFramerTest, FecEntropyTest) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -3287,7 +3308,7 @@
   EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
 };
 
-TEST_F(QuicFramerTest, StopPacketProcessing) {
+TEST_P(QuicFramerTest, StopPacketProcessing) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -3348,7 +3369,7 @@
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
 }
 
-TEST_F(QuicFramerTest, ConnectionCloseWithInvalidAck) {
+TEST_P(QuicFramerTest, ConnectionCloseWithInvalidAck) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index d9919f0..b09e7a3 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -46,7 +46,7 @@
   TestQuicConnection(QuicGuid guid,
                      IPEndPoint address,
                      QuicConnectionHelper* helper)
-      : QuicConnection(guid, address, helper, false) {
+      : QuicConnection(guid, address, helper, false, QuicVersionMax()) {
   }
 
   void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
@@ -118,7 +118,7 @@
         use_closing_stream_(false),
         read_buffer_(new IOBufferWithSize(4096)),
         guid_(2),
-        framer_(kQuicVersion1, QuicTime::Zero(), false),
+        framer_(QuicVersionMax(), QuicTime::Zero(), false),
         creator_(guid_, &framer_, &random_, false) {
     IPAddressNumber ip;
     CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
@@ -168,6 +168,8 @@
     runner_ = new TestTaskRunner(&clock_);
     send_algorithm_ = new MockSendAlgorithm();
     receive_algorithm_ = new TestReceiveAlgorithm(NULL);
+    EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly(
+        testing::Return(QuicTime::Delta::Zero()));
     EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).
         WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
     helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index a52b867..2aaf45d 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -141,7 +141,7 @@
     feedback.tcp.accumulated_number_of_lost_packets = 0;
     feedback.tcp.receive_window = 256000;
 
-    QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
+    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(QuicFrame(&ack));
     frames.push_back(QuicFrame(&feedback));
@@ -193,7 +193,7 @@
   scoped_ptr<QuicEncryptedPacket> ConstructPacket(
       const QuicPacketHeader& header,
       const QuicFrame& frame) {
-    QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
+    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(frame);
     scoped_ptr<QuicPacket> packet(
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 51071f9..eec8ab3 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -213,7 +213,7 @@
 }
 
 QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
-    const QuicTagVector& supported_versions) {
+    const QuicVersionVector& supported_versions) {
   DCHECK(is_server_);
   QuicPacketPublicHeader header;
   header.guid = guid_;
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 8abd49c..6c21a94 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -129,7 +129,7 @@
   // serialized packet to a random bool and returns that value as a member of
   // SerializedPacket.
   QuicEncryptedPacket* SerializeVersionNegotiationPacket(
-      const QuicTagVector& supported_versions);
+      const QuicVersionVector& supported_versions);
 
   QuicPacketSequenceNumber sequence_number() const {
     return sequence_number_;
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 7a8daa4..b55f350 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -30,8 +30,8 @@
 class QuicPacketCreatorTest : public ::testing::TestWithParam<bool> {
  protected:
   QuicPacketCreatorTest()
-      : server_framer_(kQuicVersion1, QuicTime::Zero(), true),
-        client_framer_(kQuicVersion1, QuicTime::Zero(), false),
+      : server_framer_(QuicVersionMax(), QuicTime::Zero(), true),
+        client_framer_(QuicVersionMax(), QuicTime::Zero(), false),
         id_(1),
         sequence_number_(0),
         guid_(2),
@@ -179,8 +179,8 @@
 
 TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
   QuicPacketCreatorPeer::SetIsServer(&creator_, true);
-  QuicTagVector versions;
-  versions.push_back(kQuicVersion1);
+  QuicVersionVector versions;
+  versions.push_back(QuicVersionMax());
   scoped_ptr<QuicEncryptedPacket> encrypted(
       creator_.SerializeVersionNegotiationPacket(versions));
 
diff --git a/net/quic/quic_packet_entropy_manager.cc b/net/quic/quic_packet_entropy_manager.cc
deleted file mode 100644
index 5f152c0..0000000
--- a/net/quic/quic_packet_entropy_manager.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_packet_entropy_manager.h"
-
-#include "base/logging.h"
-#include "net/base/linked_hash_map.h"
-
-using std::make_pair;
-using std::max;
-using std::min;
-
-namespace net {
-
-QuicPacketEntropyManager::QuicPacketEntropyManager()
-    : sent_packets_entropy_hash_(0),
-      received_packets_entropy_hash_(0),
-      largest_received_sequence_number_(0) {}
-
-QuicPacketEntropyManager::~QuicPacketEntropyManager() {}
-
-QuicPacketSequenceNumber
-QuicPacketEntropyManager::LargestReceivedSequenceNumber() const {
-  if (received_packets_entropy_.empty()) {
-    return 0;
-  }
-  return received_packets_entropy_.rbegin()->first;
-}
-
-void QuicPacketEntropyManager::RecordReceivedPacketEntropyHash(
-    QuicPacketSequenceNumber sequence_number,
-    QuicPacketEntropyHash entropy_hash) {
-  if (sequence_number < largest_received_sequence_number_) {
-    DLOG(INFO) << "Ignoring received packet entropy for sequence_number:"
-               << sequence_number << " less than largest_peer_sequence_number:"
-               << largest_received_sequence_number_;
-    return;
-  }
-  received_packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
-  received_packets_entropy_hash_ ^= entropy_hash;
-  DVLOG(2) << "setting cumulative received entropy hash to: "
-           << static_cast<int>(received_packets_entropy_hash_)
-           << " updated with sequence number " << sequence_number
-           << " entropy hash: " << static_cast<int>(entropy_hash);
-}
-
-void QuicPacketEntropyManager::RecordSentPacketEntropyHash(
-    QuicPacketSequenceNumber sequence_number,
-    QuicPacketEntropyHash entropy_hash) {
-  // TODO(satyamshekhar): Check this logic again when/if we enable packet
-  // reordering.
-  sent_packets_entropy_hash_ ^= entropy_hash;
-  sent_packets_entropy_.insert(
-      make_pair(sequence_number,
-                make_pair(entropy_hash, sent_packets_entropy_hash_)));
-  DVLOG(2) << "setting cumulative sent entropy hash to: "
-           << static_cast<int>(sent_packets_entropy_hash_)
-           << " updated with sequence number " << sequence_number
-           << " entropy hash: " << static_cast<int>(entropy_hash);
-}
-
-QuicPacketEntropyHash QuicPacketEntropyManager::ReceivedEntropyHash(
-    QuicPacketSequenceNumber sequence_number) const {
-  DCHECK_LE(sequence_number, LargestReceivedSequenceNumber());
-  DCHECK_GE(sequence_number, largest_received_sequence_number_);
-  if (sequence_number == LargestReceivedSequenceNumber()) {
-    return received_packets_entropy_hash_;
-  }
-
-  ReceivedEntropyMap::const_iterator it =
-      received_packets_entropy_.upper_bound(sequence_number);
-  // When this map is empty we should only query entropy for
-  // |largest_received_sequence_number_|.
-  LOG_IF(WARNING, it != received_packets_entropy_.end())
-      << "largest_received: " << LargestReceivedSequenceNumber()
-      << " sequence_number: " << sequence_number;
-
-  // TODO(satyamshekhar): Make this O(1).
-  QuicPacketEntropyHash hash = received_packets_entropy_hash_;
-  for (; it != received_packets_entropy_.end(); ++it) {
-    hash ^= it->second;
-  }
-  return hash;
-}
-
-QuicPacketEntropyHash QuicPacketEntropyManager::SentEntropyHash(
-    QuicPacketSequenceNumber sequence_number) const {
-  SentEntropyMap::const_iterator it =
-      sent_packets_entropy_.find(sequence_number);
-  if (it == sent_packets_entropy_.end()) {
-    // Should only happen when we have not received ack for any packet.
-    DCHECK_EQ(0u, sequence_number);
-    return 0;
-  }
-  return it->second.second;
-}
-
-void QuicPacketEntropyManager::RecalculateReceivedEntropyHash(
-    QuicPacketSequenceNumber peer_least_unacked,
-    QuicPacketEntropyHash entropy_hash) {
-  DLOG_IF(WARNING, peer_least_unacked > LargestReceivedSequenceNumber())
-      << "Prematurely updating the entropy manager before registering the "
-      << "entropy of the containing packet creates a temporary inconsistency.";
-  if (peer_least_unacked < largest_received_sequence_number_) {
-    DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked
-               << " less than largest_peer_sequence_number:"
-               << largest_received_sequence_number_;
-    return;
-  }
-  largest_received_sequence_number_ = peer_least_unacked;
-  received_packets_entropy_hash_ = entropy_hash;
-  ReceivedEntropyMap::iterator it =
-      received_packets_entropy_.lower_bound(peer_least_unacked);
-  // TODO(satyamshekhar): Make this O(1).
-  for (; it != received_packets_entropy_.end(); ++it) {
-    received_packets_entropy_hash_ ^= it->second;
-  }
-  // Discard entropies before least unacked.
-  received_packets_entropy_.erase(
-      received_packets_entropy_.begin(),
-      received_packets_entropy_.lower_bound(
-          min(peer_least_unacked, LargestReceivedSequenceNumber())));
-}
-
-bool QuicPacketEntropyManager::IsValidEntropy(
-    QuicPacketSequenceNumber sequence_number,
-    const SequenceNumberSet& missing_packets,
-    QuicPacketEntropyHash entropy_hash) const {
-  SentEntropyMap::const_iterator entropy_it =
-      sent_packets_entropy_.find(sequence_number);
-  if (entropy_it == sent_packets_entropy_.end()) {
-    DCHECK_EQ(0u, sequence_number);
-    // Close connection if something goes wrong.
-    return 0 == sequence_number;
-  }
-  QuicPacketEntropyHash expected_entropy_hash = entropy_it->second.second;
-  for (SequenceNumberSet::const_iterator it = missing_packets.begin();
-       it != missing_packets.end(); ++it) {
-    entropy_it = sent_packets_entropy_.find(*it);
-    DCHECK(entropy_it != sent_packets_entropy_.end());
-    expected_entropy_hash ^= entropy_it->second.first;
-  }
-  DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
-      << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
-      << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
-  return entropy_hash == expected_entropy_hash;
-}
-
-void QuicPacketEntropyManager::ClearSentEntropyBefore(
-    QuicPacketSequenceNumber sequence_number) {
-  if (sent_packets_entropy_.empty()) {
-    return;
-  }
-  SentEntropyMap::iterator it = sent_packets_entropy_.begin();
-  while (it->first < sequence_number) {
-    sent_packets_entropy_.erase(it);
-    it = sent_packets_entropy_.begin();
-    DCHECK(it != sent_packets_entropy_.end());
-  }
-  DVLOG(2) << "Cleared entropy before: "
-           << sent_packets_entropy_.begin()->first;
-}
-
-}  // namespace net
diff --git a/net/quic/quic_packet_entropy_manager.h b/net/quic/quic_packet_entropy_manager.h
deleted file mode 100644
index fb205a4..0000000
--- a/net/quic/quic_packet_entropy_manager.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Manages the packet entropy calculation for both sent and received packets
-// for a connection.
-
-#ifndef NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_
-#define NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_
-
-#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-// Records all sent and received packets by a connection to track the cumulative
-// entropy of both sent and received packets separately. It is used by the
-// connection to validate an ack frame sent by the peer as a preventive measure
-// against the optimistic ack attack. Also, called by the framer when it
-// truncates an ack frame to get the correct entropy value for the ack frame
-// being serialized.
-class NET_EXPORT_PRIVATE QuicPacketEntropyManager :
-    public QuicReceivedEntropyHashCalculatorInterface {
- public:
-  QuicPacketEntropyManager();
-  virtual ~QuicPacketEntropyManager();
-
-  // Record the received entropy hash against |sequence_number|.
-  void RecordReceivedPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
-                                       QuicPacketEntropyHash entropy_hash);
-
-  // Record |entropy_hash| for sent packet corresponding to |sequence_number|.
-  void RecordSentPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
-                                   QuicPacketEntropyHash entropy_hash);
-
-  // QuicReceivedEntropyHashCalculatorInterface
-  // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
-  // the received entropy hash for the truncated ack frame.
-  virtual QuicPacketEntropyHash ReceivedEntropyHash(
-      QuicPacketSequenceNumber sequence_number) const OVERRIDE;
-
-  QuicPacketEntropyHash SentEntropyHash(
-      QuicPacketSequenceNumber sequence_number) const;
-
-  QuicPacketSequenceNumber LargestReceivedSequenceNumber() const;
-
-  // Recalculate the received entropy hash and clears old packet entropies,
-  // now that the sender sent us the |entropy_hash| for packets up to,
-  // but not including, |peer_least_unacked|.
-  void RecalculateReceivedEntropyHash(
-      QuicPacketSequenceNumber peer_least_unacked,
-      QuicPacketEntropyHash entropy_hash);
-
-  // Returns true if |entropy_hash| matches the expected sent entropy hash
-  // up to |sequence_number| removing sequence numbers from |missing_packets|.
-  bool IsValidEntropy(QuicPacketSequenceNumber sequence_number,
-                      const SequenceNumberSet& missing_packets,
-                      QuicPacketEntropyHash entropy_hash) const;
-
-  // Removes not required entries from |sent_packets_entropy_| before
-  // |sequence_number|.
-  void ClearSentEntropyBefore(QuicPacketSequenceNumber sequence_number);
-
-  QuicPacketEntropyHash sent_packets_entropy_hash() const {
-    return sent_packets_entropy_hash_;
-  }
-
-  QuicPacketEntropyHash received_packets_entropy_hash() const {
-    return received_packets_entropy_hash_;
-  }
-
- private:
-  typedef linked_hash_map<QuicPacketSequenceNumber,
-                          std::pair<QuicPacketEntropyHash,
-                               QuicPacketEntropyHash> > SentEntropyMap;
-  typedef std::map<QuicPacketSequenceNumber,
-                   QuicPacketEntropyHash> ReceivedEntropyMap;
-
-  // Linked hash map from sequence numbers to the sent entropy hash up to the
-  // sequence number in the key.
-  SentEntropyMap sent_packets_entropy_;
-
-  // Cumulative hash of entropy of all sent packets.
-  QuicPacketEntropyHash sent_packets_entropy_hash_;
-
-  // TODO(satyamshekhar): Can be optimized using an interval set like data
-  // structure.
-  // Map of received sequence numbers to their corresponding entropy.
-  // Every received packet has an entry, and packets without the entropy bit set
-  // have an entropy value of 0.
-  // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
-  ReceivedEntropyMap received_packets_entropy_;
-
-  // Cumulative hash of entropy of all received packets.
-  QuicPacketEntropyHash received_packets_entropy_hash_;
-
-  // The largest sequence number cleared by RecalculateReceivedEntropyHash.
-  // Received entropy cannot be calculated for numbers less than it.
-  QuicPacketSequenceNumber largest_received_sequence_number_;
-};
-
-}  // namespace net
-
-#endif  // NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_
diff --git a/net/quic/quic_packet_entropy_manager_test.cc b/net/quic/quic_packet_entropy_manager_test.cc
deleted file mode 100644
index 0016211..0000000
--- a/net/quic/quic_packet_entropy_manager_test.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_packet_entropy_manager.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::make_pair;
-using std::pair;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-class QuicPacketEntropyManagerTest : public ::testing::Test {
- protected:
-  QuicPacketEntropyManager entropy_manager_;
-};
-
-TEST_F(QuicPacketEntropyManagerTest, ReceivedPacketEntropyHash) {
-  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
-  entropies.push_back(make_pair(1, 12));
-  entropies.push_back(make_pair(7, 1));
-  entropies.push_back(make_pair(2, 33));
-  entropies.push_back(make_pair(5, 3));
-  entropies.push_back(make_pair(8, 34));
-
-  for (size_t i = 0; i < entropies.size(); ++i) {
-    entropy_manager_.RecordReceivedPacketEntropyHash(entropies[i].first,
-                                                     entropies[i].second);
-  }
-
-  sort(entropies.begin(), entropies.end());
-
-  QuicPacketEntropyHash hash = 0;
-  size_t index = 0;
-  for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
-    if (entropies[index].first == i) {
-      hash ^= entropies[index].second;
-      ++index;
-    }
-    EXPECT_EQ(hash, entropy_manager_.ReceivedEntropyHash(i));
-  }
-};
-
-TEST_F(QuicPacketEntropyManagerTest, EntropyHashBelowLeastObserved) {
-  EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0));
-  entropy_manager_.RecordReceivedPacketEntropyHash(4, 5);
-  EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3));
-};
-
-TEST_F(QuicPacketEntropyManagerTest, EntropyHashAboveLargestObserved) {
-  EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0));
-  entropy_manager_.RecordReceivedPacketEntropyHash(4, 5);
-  EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3));
-};
-
-TEST_F(QuicPacketEntropyManagerTest, RecalculateReceivedEntropyHash) {
-  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
-  entropies.push_back(make_pair(1, 12));
-  entropies.push_back(make_pair(2, 1));
-  entropies.push_back(make_pair(3, 33));
-  entropies.push_back(make_pair(4, 3));
-  entropies.push_back(make_pair(5, 34));
-  entropies.push_back(make_pair(6, 29));
-
-  QuicPacketEntropyHash entropy_hash = 0;
-  for (size_t i = 0; i < entropies.size(); ++i) {
-    entropy_manager_.RecordReceivedPacketEntropyHash(entropies[i].first,
-                                                     entropies[i].second);
-    entropy_hash ^= entropies[i].second;
-  }
-  EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
-
-  // Now set the entropy hash up to 4 to be 100.
-  entropy_hash ^= 100;
-  for (size_t i = 0; i < 3; ++i) {
-    entropy_hash ^= entropies[i].second;
-  }
-  entropy_manager_.RecalculateReceivedEntropyHash(4, 100);
-  EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
-
-  // Ensure it doesn't change with an old received sequence number or entropy.
-  entropy_manager_.RecordReceivedPacketEntropyHash(1, 50);
-  EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
-
-  entropy_manager_.RecalculateReceivedEntropyHash(1, 50);
-  EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
-}
-
-TEST_F(QuicPacketEntropyManagerTest, SentEntropyHash) {
-  EXPECT_EQ(0, entropy_manager_.SentEntropyHash(0));
-
-  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
-  entropies.push_back(make_pair(1, 12));
-  entropies.push_back(make_pair(2, 1));
-  entropies.push_back(make_pair(3, 33));
-  entropies.push_back(make_pair(4, 3));
-
-  for (size_t i = 0; i < entropies.size(); ++i) {
-    entropy_manager_.RecordSentPacketEntropyHash(entropies[i].first,
-                                                 entropies[i].second);
-  }
-
-  QuicPacketEntropyHash hash = 0;
-  for (size_t i = 0; i < entropies.size(); ++i) {
-    hash ^= entropies[i].second;
-    EXPECT_EQ(hash, entropy_manager_.SentEntropyHash(i + 1));
-  }
-}
-
-TEST_F(QuicPacketEntropyManagerTest, IsValidEntropy) {
-  QuicPacketEntropyHash entropies[10] =
-      {12, 1, 33, 3, 32, 100, 28, 42, 22, 255};
-  for (size_t i = 0; i < 10; ++i) {
-    entropy_manager_.RecordSentPacketEntropyHash(i + 1, entropies[i]);
-  }
-
-  SequenceNumberSet missing_packets;
-  missing_packets.insert(1);
-  missing_packets.insert(4);
-  missing_packets.insert(7);
-  missing_packets.insert(8);
-
-  QuicPacketEntropyHash entropy_hash = 0;
-  for (size_t i = 0; i < 10; ++i) {
-    if (missing_packets.find(i + 1) == missing_packets.end()) {
-      entropy_hash ^= entropies[i];
-    }
-  }
-
-  EXPECT_TRUE(entropy_manager_.IsValidEntropy(10, missing_packets,
-                                              entropy_hash));
-}
-
-}  // namespace
-}  // namespace test
-}  // namespace net
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index e6aeac7..08bad94 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -112,11 +112,21 @@
   return QuicConsumedData(total_bytes_consumed, fin_consumed);
 }
 
+bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
+  DCHECK(HasPendingFrames());
+  HasRetransmittableData retransmittable =
+      (should_send_ack_ || should_send_feedback_) ? NO_RETRANSMITTABLE_DATA
+                                                  : HAS_RETRANSMITTABLE_DATA;
+  if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
+      DCHECK(!queued_control_frames_.empty());  // These are retransmittable.
+  }
+  return delegate_->CanWrite(NOT_RETRANSMISSION, retransmittable);
+}
+
 void QuicPacketGenerator::SendQueuedFrames() {
   packet_creator_->MaybeStartFEC();
-  while (HasPendingFrames() && delegate_->CanWrite(NOT_RETRANSMISSION,
-             packet_creator_->HasPendingFrames() ?
-                 HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA)) {
+  // Only add pending frames if we are SURE we can then send the whole packet.
+  while (HasPendingFrames() && CanSendWithNextPendingFrameAddition()) {
     if (!AddNextPendingFrame()) {
       // Packet was full, so serialize and send it.
       SerializeAndSendPacket();
@@ -159,28 +169,26 @@
 
 bool QuicPacketGenerator::AddNextPendingFrame() {
   if (should_send_ack_) {
-    pending_ack_frame_.reset(delegate_->CreateAckFrame());
-    if (!AddFrame(QuicFrame(pending_ack_frame_.get()))) {
-      // packet was full
-      return false;
-    }
-    should_send_ack_ = false;
-    return true;
+    pending_ack_frame_.reset((delegate_->CreateAckFrame()));
+    // If we can't this add the frame now, then we still need to do so later.
+    should_send_ack_ = !AddFrame(QuicFrame(pending_ack_frame_.get()));
+    // Return success if we have cleared out this flag (i.e., added the frame).
+    // If we still need to send, then the frame is full, and we have failed.
+    return !should_send_ack_;
   }
 
   if (should_send_feedback_) {
-    pending_feedback_frame_.reset(delegate_->CreateFeedbackFrame());
-    if (!AddFrame(QuicFrame(pending_feedback_frame_.get()))) {
-      // packet was full
-      return false;
-    }
-    should_send_feedback_ = false;
-    return true;
+    pending_feedback_frame_.reset((delegate_->CreateFeedbackFrame()));
+    // If we can't this add the frame now, then we still need to do so later.
+    should_send_feedback_ = !AddFrame(QuicFrame(pending_feedback_frame_.get()));
+    // Return success if we have cleared out this flag (i.e., added the frame).
+    // If we still need to send, then the frame is full, and we have failed.
+    return !should_send_feedback_;
   }
 
   DCHECK(!queued_control_frames_.empty());
   if (!AddFrame(queued_control_frames_.back())) {
-    // packet was full
+    // Packet was full.
     return false;
   }
   queued_control_frames_.pop_back();
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index f47a540..ab0dbe2 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -108,7 +108,13 @@
  private:
   void SendQueuedFrames();
 
+  // Test to see if we have pending ack, feedback, or control frames.
   bool HasPendingFrames() const;
+  // Test to see if the addition of a pending frame (which might be
+  // retransmittable) would still allow the resulting packet to be sent now.
+  bool CanSendWithNextPendingFrameAddition() const;
+  // Add exactly one pending frame, preferring ack over feedback over control
+  // frames.
   bool AddNextPendingFrame();
 
   bool AddFrame(const QuicFrame& frame);
@@ -120,10 +126,15 @@
   QuicPacketCreator* packet_creator_;
   QuicFrames queued_control_frames_;
   bool should_flush_;
+  // Flags to indicate the need for just-in-time construction of a frame.
   bool should_send_ack_;
+  bool should_send_feedback_;
+  // If we put a non-retransmittable frame (namley ack or feedback frame) in
+  // this packet, then we have to hold a reference to it until we flush (and
+  // serialize it). Retransmittable frames are referenced elsewhere so that they
+  // can later be (optionally) retransmitted.
   scoped_ptr<QuicAckFrame> pending_ack_frame_;
   scoped_ptr<QuicCongestionFeedbackFrame> pending_feedback_frame_;
-  bool should_send_feedback_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
 };
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index c3c4fc1..4511251 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -39,9 +39,26 @@
   MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
   MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
 
-  void SetCanWrite(bool can_write) {
+  void SetCanWriteAnything() {
     EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _))
-        .WillRepeatedly(Return(can_write));
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA))
+        .WillRepeatedly(Return(true));
+  }
+
+  void SetCanNotWrite() {
+    EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _))
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA))
+        .WillRepeatedly(Return(false));
+  }
+
+  // Use this when only ack and feedback frames should be allowed to be written.
+  void SetCanWriteOnlyNonRetransmittable() {
+    EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _))
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA))
+        .WillRepeatedly(Return(true));
   }
 
  private:
@@ -77,7 +94,7 @@
 class QuicPacketGeneratorTest : public ::testing::Test {
  protected:
   QuicPacketGeneratorTest()
-      : framer_(kQuicVersion1, QuicTime::Zero(), false),
+      : framer_(QuicVersionMax(), QuicTime::Zero(), false),
         creator_(42, &framer_, &random_, false),
         generator_(&delegate_, NULL, &creator_),
         packet_(0, NULL, 0, NULL),
@@ -194,14 +211,14 @@
 };
 
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
-  delegate_.SetCanWrite(false);
+  delegate_.SetCanNotWrite();
 
   generator_.SetShouldSendAck(false);
   EXPECT_TRUE(generator_.HasQueuedFrames());
 }
 
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteOnlyNonRetransmittable();
   generator_.StartBatchOperations();
 
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
@@ -211,7 +228,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteOnlyNonRetransmittable();
 
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
   EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
@@ -227,7 +244,7 @@
 
 TEST_F(QuicPacketGeneratorTest,
        ShouldSendAckWithFeedback_WritableAndShouldNotFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteOnlyNonRetransmittable();
   generator_.StartBatchOperations();
 
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
@@ -240,7 +257,7 @@
 
 TEST_F(QuicPacketGeneratorTest,
        ShouldSendAckWithFeedback_WritableAndShouldFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteOnlyNonRetransmittable();
 
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
   EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
@@ -259,14 +276,21 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
-  delegate_.SetCanWrite(false);
+  delegate_.SetCanNotWrite();
+
+  generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+  EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) {
+  delegate_.SetCanWriteOnlyNonRetransmittable();
 
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
   EXPECT_TRUE(generator_.HasQueuedFrames());
 }
 
 TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
   generator_.StartBatchOperations();
 
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
@@ -274,7 +298,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
       DoAll(SaveArg<0>(&packet_), Return(true)));
@@ -288,7 +312,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
-  delegate_.SetCanWrite(false);
+  delegate_.SetCanNotWrite();
 
   QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 2, true);
   EXPECT_EQ(0u, consumed.bytes_consumed);
@@ -297,7 +321,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
   generator_.StartBatchOperations();
 
   QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 2, true);
@@ -307,7 +331,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
       DoAll(SaveArg<0>(&packet_), Return(true)));
@@ -323,7 +347,7 @@
 
 TEST_F(QuicPacketGeneratorTest,
        ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
   generator_.StartBatchOperations();
 
   generator_.ConsumeData(1, "foo", 2, true);
@@ -334,7 +358,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
   generator_.StartBatchOperations();
 
   generator_.ConsumeData(1, "foo", 2, true);
@@ -355,7 +379,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeDataFEC) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   // Send FEC every two packets.
   creator_.options()->max_packets_per_fec_group = 2;
@@ -391,7 +415,7 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) {
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   // Send FEC every six packets.
   creator_.options()->max_packets_per_fec_group = 6;
@@ -420,13 +444,13 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
-  delegate_.SetCanWrite(false);
+  delegate_.SetCanNotWrite();
 
   generator_.SetShouldSendAck(true);
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
   EXPECT_TRUE(generator_.HasQueuedFrames());
 
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   generator_.StartBatchOperations();
 
@@ -456,13 +480,13 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
-  delegate_.SetCanWrite(false);
+  delegate_.SetCanNotWrite();
 
   generator_.SetShouldSendAck(true);
   generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
   EXPECT_TRUE(generator_.HasQueuedFrames());
 
-  delegate_.SetCanWrite(true);
+  delegate_.SetCanWriteAnything();
 
   generator_.StartBatchOperations();
 
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 051a640..abbbadf 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "net/quic/quic_protocol.h"
+
 #include "base/stl_util.h"
+#include "net/quic/quic_utils.h"
 
 using base::StringPiece;
 using std::map;
@@ -52,13 +54,6 @@
       kPrivateFlagsSize;
 }
 
-uint32 MakeQuicTag(char a, char b, char c, char d) {
-  return static_cast<uint32>(a) |
-         static_cast<uint32>(b) << 8 |
-         static_cast<uint32>(c) << 16 |
-         static_cast<uint32>(d) << 24;
-}
-
 QuicPacketPublicHeader::QuicPacketPublicHeader()
     : guid(0),
       guid_length(PACKET_8BYTE_GUID),
@@ -119,6 +114,69 @@
       data(data) {
 }
 
+uint32 MakeQuicTag(char a, char b, char c, char d) {
+  return static_cast<uint32>(a) |
+         static_cast<uint32>(b) << 8 |
+         static_cast<uint32>(c) << 16 |
+         static_cast<uint32>(d) << 24;
+}
+
+QuicVersion QuicVersionMax() { return kSupportedQuicVersions[0]; }
+
+QuicTag QuicVersionToQuicTag(const QuicVersion version) {
+  switch (version) {
+    case QUIC_VERSION_6:
+      return MakeQuicTag('Q', '0', '0', '6');
+    // case QUIC_VERSION_7
+      // return MakeQuicTag('Q', '0', '0', '7');
+    default:
+      // This shold be an ERROR because we should never attempt to convert an
+      // invalid QuicVersion to be written to the wire.
+      LOG(ERROR) << "Unsupported QuicVersion: " << version;
+      return 0;
+  }
+}
+
+QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) {
+  const QuicTag quic_tag_v6 = MakeQuicTag('Q', '0', '0', '6');
+  // const QuicTag quic_tag_v7 = MakeQuicTag('Q', '0', '0', '7');
+
+  if (version_tag == quic_tag_v6) {
+    return QUIC_VERSION_6;
+  // } else if (version_tag == quic_tag_v7) {
+    // return QUIC_VERSION_7;
+  } else {
+    // Reading from the client so this should not be considered an ERROR.
+    DLOG(INFO) << "Unsupported QuicTag version: "
+               << QuicUtils::TagToString(version_tag);
+    return QUIC_VERSION_UNSUPPORTED;
+  }
+}
+
+string QuicVersionToString(const QuicVersion version) {
+  // TODO(rjshade): Possibly start using RETURN_STRING_LITERAL here when we
+  //                start supporting a lot of versions.
+  switch (version) {
+    case QUIC_VERSION_6:
+      return "QUIC_VERSION_6";
+    // case QUIC_VERSION_7:
+      // return "QUIC_VERSION_7";
+    default:
+      return "QUIC_VERSION_UNSUPPORTED";
+  }
+}
+
+string QuicVersionArrayToString(const QuicVersion versions[],
+                                int num_versions) {
+  string result = "";
+  for (int i = 0; i < num_versions; ++i) {
+    const QuicVersion& version = versions[i];
+    result.append(QuicVersionToString(version));
+    result.append(",");
+  }
+  return result;
+}
+
 ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
   os << "{ guid: " << header.public_header.guid
      << ", guid_length:" << header.public_header.guid_length
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 4090f4c..93a5333 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -63,9 +63,6 @@
 // Signifies that the QuicPacket will contain version of the protocol.
 const bool kIncludeVersion = true;
 
-// Returns true if |version| is a supported protocol version.
-NET_EXPORT_PRIVATE bool IsSupportedVersion(QuicTag version);
-
 // Index of the first byte in a QUIC packet which is used in hash calculation.
 const size_t kStartOfHashData = 0;
 
@@ -175,6 +172,59 @@
   PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1
 };
 
+// The available versions of QUIC. Guaranteed that the integer value of the enum
+// will match the version number.
+// When adding a new version to this enum you should add it to
+// kSupportedVersions (if appropriate), and also add a new case to the helper
+// methods QuicVersionToQuicTag, and QuicTagToQuicVersion.
+enum QuicVersion {
+  // Special case to indicate unknown/unsupported QUIC version.
+  QUIC_VERSION_UNSUPPORTED = 0,
+
+  QUIC_VERSION_6 = 6,  // Current version.
+};
+
+// This vector contains QUIC versions which we currently support.
+// This should be ordered such that the highest supported version is the first
+// element, with subsequent elements in descending order (versions can be
+// skipped as necessary).
+static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_6};
+
+typedef std::vector<QuicVersion> QuicVersionVector;
+
+// Upper limit on versions we support.
+NET_EXPORT_PRIVATE QuicVersion QuicVersionMax();
+
+// QuicTag is written to and read from the wire, but we prefer to use
+// the more readable QuicVersion at other levels.
+// Helper function which translates from a QuicVersion to a QuicTag. Returns 0
+// if QuicVersion is unsupported.
+NET_EXPORT_PRIVATE QuicTag QuicVersionToQuicTag(const QuicVersion version);
+
+// Returns appropriate QuicVersion from a QuicTag.
+// Returns QUIC_VERSION_UNSUPPORTED if version_tag cannot be understood.
+NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag);
+
+// Helper function which translates from a QuicVersion to a string.
+// Returns strings corresponding to enum names (e.g. QUIC_VERSION_6).
+NET_EXPORT_PRIVATE std::string QuicVersionToString(const QuicVersion version);
+
+// Returns comma separated list of string representations of QuicVersion enum
+// values in the supplied QuicVersionArray.
+NET_EXPORT_PRIVATE std::string QuicVersionArrayToString(
+    const QuicVersion versions[], int num_versions);
+
+// Version and Crypto tags are written to the wire with a big-endian
+// representation of the name of the tag.  For example
+// the client hello tag (CHLO) will be written as the
+// following 4 bytes: 'C' 'H' 'L' 'O'.  Since it is
+// stored in memory as a little endian uint32, we need
+// to reverse the order of the bytes.
+
+// MakeQuicTag returns a value given the four bytes. For example:
+//   MakeQuicTag('C', 'H', 'L', 'O');
+NET_EXPORT_PRIVATE QuicTag MakeQuicTag(char a, char b, char c, char d);
+
 // Size in bytes of the data or fec packet header.
 NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(QuicPacketHeader header);
 
@@ -323,27 +373,6 @@
   QUIC_LAST_ERROR,
 };
 
-// Version and Crypto tags are written to the wire with a big-endian
-// representation of the name of the tag.  For example
-// the client hello tag (CHLO) will be written as the
-// following 4 bytes: 'C' 'H' 'L' 'O'.  Since it is
-// stored in memory as a little endian uint32, we need
-// to reverse the order of the bytes.
-//
-// The TAG macro is used in header files to ensure that we don't create static
-// initialisers. In normal code, the MakeQuicTag function should be used.
-#define TAG(a, b, c, d) ((d << 24) + (c << 16) + (b << 8) + a)
-const QuicTag kUnsupportedVersion = -1;
-// Each time the wire format changes, this need needs to be incremented.
-// At some point, we will actually freeze the wire format and make an official
-// version number, but this works for now.
-const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '6');
-#undef TAG
-
-// MakeQuicTag returns a value given the four bytes. For example:
-//   MakeQuicTag('C', 'H', 'L', 'O');
-uint32 NET_EXPORT_PRIVATE MakeQuicTag(char a, char b, char c, char d);
-
 struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
   QuicPacketPublicHeader();
   explicit QuicPacketPublicHeader(const QuicPacketPublicHeader& other);
@@ -357,7 +386,7 @@
   bool reset_flag;
   bool version_flag;
   QuicSequenceNumberLength sequence_number_length;
-  QuicTagVector versions;
+  QuicVersionVector versions;
 };
 
 // Header for Data or FEC packets.
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
index 271cca6..a22cb62 100644
--- a/net/quic/quic_protocol_test.cc
+++ b/net/quic/quic_protocol_test.cc
@@ -43,6 +43,104 @@
   }
 }
 
+TEST(QuicProtocolTest, QuicVersionToQuicTag) {
+  // If you add a new version to the QuicVersion enum you will need to add a new
+  // case to QuicVersionToQuicTag, otherwise this test will fail.
+
+  // TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+  // Any logs would indicate an unsupported version which we don't expect.
+  ScopedMockLog log(kDoNotCaptureLogsYet);
+  EXPECT_CALL(log, Log(_, _, _)).Times(0);
+  log.StartCapturingLogs();
+#endif
+
+  // Explicitly test a specific version.
+  EXPECT_EQ(MakeQuicTag('Q', '0', '0', '6'),
+            QuicVersionToQuicTag(QUIC_VERSION_6));
+
+  // Loop over all supported versions and make sure that we never hit the
+  // default case (i.e. all supported versions should be successfully converted
+  // to valid QuicTags).
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    const QuicVersion& version = kSupportedQuicVersions[i];
+    EXPECT_LT(0u, QuicVersionToQuicTag(version));
+  }
+}
+
+TEST(QuicProtocolTest, QuicVersionToQuicTagUnsupported) {
+  // TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+  // TODO(rjshade): Change to DFATAL once we actually support multiple versions,
+  // and QuicConnectionTest::SendVersionNegotiationPacket can be changed to use
+  // mis-matched versions rather than relying on QUIC_VERSION_UNSUPPORTED.
+  ScopedMockLog log(kDoNotCaptureLogsYet);
+  EXPECT_CALL(log, Log(ERROR, _, "Unsupported QuicVersion: 0")).Times(1);
+  log.StartCapturingLogs();
+#endif
+
+  EXPECT_EQ(0u, QuicVersionToQuicTag(QUIC_VERSION_UNSUPPORTED));
+}
+
+TEST(QuicProtocolTest, QuicTagToQuicVersion) {
+  // If you add a new version to the QuicVersion enum you will need to add a new
+  // case to QuicTagToQuicVersion, otherwise this test will fail.
+
+  // TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+  // Any logs would indicate an unsupported version which we don't expect.
+  ScopedMockLog log(kDoNotCaptureLogsYet);
+  EXPECT_CALL(log, Log(_, _, _)).Times(0);
+  log.StartCapturingLogs();
+#endif
+
+  // Explicitly test specific versions.
+  EXPECT_EQ(QUIC_VERSION_6,
+            QuicTagToQuicVersion(MakeQuicTag('Q', '0', '0', '6')));
+
+  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+    const QuicVersion& version = kSupportedQuicVersions[i];
+
+    // Get the tag from the version (we can loop over QuicVersions easily).
+    QuicTag tag = QuicVersionToQuicTag(version);
+    EXPECT_LT(0u, tag);
+
+    // Now try converting back.
+    QuicVersion tag_to_quic_version = QuicTagToQuicVersion(tag);
+    EXPECT_EQ(version, tag_to_quic_version);
+    EXPECT_NE(QUIC_VERSION_UNSUPPORTED, tag_to_quic_version);
+  }
+}
+
+TEST(QuicProtocolTest, QuicTagToQuicVersionUnsupported) {
+  // TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+  ScopedMockLog log(kDoNotCaptureLogsYet);
+#ifndef NDEBUG
+  EXPECT_CALL(log, Log(INFO, _, "Unsupported QuicTag version: FAKE")).Times(1);
+#endif
+  log.StartCapturingLogs();
+#endif
+
+  EXPECT_EQ(QUIC_VERSION_UNSUPPORTED,
+            QuicTagToQuicVersion(MakeQuicTag('F', 'A', 'K', 'E')));
+}
+
+TEST(QuicProtocolTest, QuicVersionToString) {
+  EXPECT_EQ("QUIC_VERSION_6",
+            QuicVersionToString(QUIC_VERSION_6));
+  EXPECT_EQ("QUIC_VERSION_UNSUPPORTED",
+            QuicVersionToString(QUIC_VERSION_UNSUPPORTED));
+
+  QuicVersion single_version[] = {QUIC_VERSION_6};
+  EXPECT_EQ("QUIC_VERSION_6,", QuicVersionArrayToString(single_version,
+                                   arraysize(single_version)));
+  // QuicVersion multiple_versions[] = {QUIC_VERSION_7, QUIC_VERSION_6};
+  // EXPECT_EQ("QUIC_VERSION_7,QUIC_VERSION_6,",
+  //           QuicVersionArrayToString(multiple_versions,
+  //                                    arraysize(multiple_versions)));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_received_entropy_manager.cc b/net/quic/quic_received_entropy_manager.cc
index e69de29..57020eb 100644
--- a/net/quic/quic_received_entropy_manager.cc
+++ b/net/quic/quic_received_entropy_manager.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_received_entropy_manager.h"
+
+#include "base/logging.h"
+#include "net/base/linked_hash_map.h"
+
+using std::make_pair;
+using std::max;
+using std::min;
+
+namespace net {
+
+QuicReceivedEntropyManager::QuicReceivedEntropyManager()
+    : packets_entropy_hash_(0),
+      largest_sequence_number_(0) {}
+
+QuicReceivedEntropyManager::~QuicReceivedEntropyManager() {}
+
+QuicPacketSequenceNumber
+QuicReceivedEntropyManager::LargestSequenceNumber() const {
+  if (packets_entropy_.empty()) {
+    return 0;
+  }
+  return packets_entropy_.rbegin()->first;
+}
+
+void QuicReceivedEntropyManager::RecordPacketEntropyHash(
+    QuicPacketSequenceNumber sequence_number,
+    QuicPacketEntropyHash entropy_hash) {
+  if (sequence_number < largest_sequence_number_) {
+    DLOG(INFO) << "Ignoring received packet entropy for sequence_number:"
+               << sequence_number << " less than largest_peer_sequence_number:"
+               << largest_sequence_number_;
+    return;
+  }
+  packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
+  packets_entropy_hash_ ^= entropy_hash;
+  DVLOG(2) << "setting cumulative received entropy hash to: "
+           << static_cast<int>(packets_entropy_hash_)
+           << " updated with sequence number " << sequence_number
+           << " entropy hash: " << static_cast<int>(entropy_hash);
+}
+
+QuicPacketEntropyHash QuicReceivedEntropyManager::EntropyHash(
+    QuicPacketSequenceNumber sequence_number) const {
+  DCHECK_LE(sequence_number, LargestSequenceNumber());
+  DCHECK_GE(sequence_number, largest_sequence_number_);
+  if (sequence_number == LargestSequenceNumber()) {
+    return packets_entropy_hash_;
+  }
+
+  ReceivedEntropyMap::const_iterator it =
+      packets_entropy_.upper_bound(sequence_number);
+  // When this map is empty we should only query entropy for
+  // |largest_received_sequence_number_|.
+  LOG_IF(WARNING, it != packets_entropy_.end())
+      << "largest_received: " << LargestSequenceNumber()
+      << " sequence_number: " << sequence_number;
+
+  // TODO(satyamshekhar): Make this O(1).
+  QuicPacketEntropyHash hash = packets_entropy_hash_;
+  for (; it != packets_entropy_.end(); ++it) {
+    hash ^= it->second;
+  }
+  return hash;
+}
+
+void QuicReceivedEntropyManager::RecalculateEntropyHash(
+    QuicPacketSequenceNumber peer_least_unacked,
+    QuicPacketEntropyHash entropy_hash) {
+  DLOG_IF(WARNING, peer_least_unacked > LargestSequenceNumber())
+      << "Prematurely updating the entropy manager before registering the "
+      << "entropy of the containing packet creates a temporary inconsistency.";
+  if (peer_least_unacked < largest_sequence_number_) {
+    DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked
+               << " less than largest_peer_sequence_number:"
+               << largest_sequence_number_;
+    return;
+  }
+  largest_sequence_number_ = peer_least_unacked;
+  packets_entropy_hash_ = entropy_hash;
+  ReceivedEntropyMap::iterator it =
+      packets_entropy_.lower_bound(peer_least_unacked);
+  // TODO(satyamshekhar): Make this O(1).
+  for (; it != packets_entropy_.end(); ++it) {
+    packets_entropy_hash_ ^= it->second;
+  }
+  // Discard entropies before least unacked.
+  packets_entropy_.erase(
+      packets_entropy_.begin(),
+      packets_entropy_.lower_bound(
+          min(peer_least_unacked, LargestSequenceNumber())));
+}
+
+}  // namespace net
diff --git a/net/quic/quic_received_entropy_manager.h b/net/quic/quic_received_entropy_manager.h
index e69de29..d969834 100644
--- a/net/quic/quic_received_entropy_manager.h
+++ b/net/quic/quic_received_entropy_manager.h
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Manages the packet entropy calculation for both sent and received packets
+// for a connection.
+
+#ifndef NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
+#define NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
+
+#include "net/quic/quic_framer.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+// Records all received packets by a connection to track the cumulative
+// entropy of received packets.  Also, called by the framer when it truncates
+// an ack frame to calculate the correct entropy value for the ack frame being
+// serialized.
+class NET_EXPORT_PRIVATE QuicReceivedEntropyManager :
+    public QuicReceivedEntropyHashCalculatorInterface {
+ public:
+  QuicReceivedEntropyManager();
+  virtual ~QuicReceivedEntropyManager();
+
+  // Record the received entropy hash against |sequence_number|.
+  void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
+                               QuicPacketEntropyHash entropy_hash);
+
+  // QuicReceivedEntropyHashCalculatorInterface
+  // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
+  // the received entropy hash for the truncated ack frame.
+  virtual QuicPacketEntropyHash EntropyHash(
+      QuicPacketSequenceNumber sequence_number) const OVERRIDE;
+
+  QuicPacketSequenceNumber LargestSequenceNumber() const;
+
+  // Recalculate the entropy hash and clears old packet entropies,
+  // now that the sender sent us the |entropy_hash| for packets up to,
+  // but not including, |peer_least_unacked|.
+  void RecalculateEntropyHash(QuicPacketSequenceNumber peer_least_unacked,
+                              QuicPacketEntropyHash entropy_hash);
+
+  QuicPacketEntropyHash packets_entropy_hash() const {
+    return packets_entropy_hash_;
+  }
+
+ private:
+  typedef std::map<QuicPacketSequenceNumber,
+                   QuicPacketEntropyHash> ReceivedEntropyMap;
+
+  // TODO(satyamshekhar): Can be optimized using an interval set like data
+  // structure.
+  // Map of received sequence numbers to their corresponding entropy.
+  // Every received packet has an entry, and packets without the entropy bit set
+  // have an entropy value of 0.
+  // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
+  ReceivedEntropyMap packets_entropy_;
+
+  // Cumulative hash of entropy of all received packets.
+  QuicPacketEntropyHash packets_entropy_hash_;
+
+  // The largest sequence number cleared by RecalculateEntropyHash.
+  // Received entropy cannot be calculated for numbers less than it.
+  QuicPacketSequenceNumber largest_sequence_number_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
diff --git a/net/quic/quic_received_entropy_manager_test.cc b/net/quic/quic_received_entropy_manager_test.cc
index e69de29..c857315 100644
--- a/net/quic/quic_received_entropy_manager_test.cc
+++ b/net/quic/quic_received_entropy_manager_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_received_entropy_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::make_pair;
+using std::pair;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicReceivedEntropyManagerTest : public ::testing::Test {
+ protected:
+  QuicReceivedEntropyManager entropy_manager_;
+};
+
+TEST_F(QuicReceivedEntropyManagerTest, ReceivedPacketEntropyHash) {
+  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
+  entropies.push_back(make_pair(1, 12));
+  entropies.push_back(make_pair(7, 1));
+  entropies.push_back(make_pair(2, 33));
+  entropies.push_back(make_pair(5, 3));
+  entropies.push_back(make_pair(8, 34));
+
+  for (size_t i = 0; i < entropies.size(); ++i) {
+    entropy_manager_.RecordPacketEntropyHash(entropies[i].first,
+                                             entropies[i].second);
+  }
+
+  sort(entropies.begin(), entropies.end());
+
+  QuicPacketEntropyHash hash = 0;
+  size_t index = 0;
+  for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
+    if (entropies[index].first == i) {
+      hash ^= entropies[index].second;
+      ++index;
+    }
+    EXPECT_EQ(hash, entropy_manager_.EntropyHash(i));
+  }
+}
+
+TEST_F(QuicReceivedEntropyManagerTest, EntropyHashBelowLeastObserved) {
+  EXPECT_EQ(0, entropy_manager_.EntropyHash(0));
+  entropy_manager_.RecordPacketEntropyHash(4, 5);
+  EXPECT_EQ(0, entropy_manager_.EntropyHash(3));
+}
+
+TEST_F(QuicReceivedEntropyManagerTest, EntropyHashAboveLargestObserved) {
+  EXPECT_EQ(0, entropy_manager_.EntropyHash(0));
+  entropy_manager_.RecordPacketEntropyHash(4, 5);
+  EXPECT_EQ(0, entropy_manager_.EntropyHash(3));
+}
+
+TEST_F(QuicReceivedEntropyManagerTest, RecalculateEntropyHash) {
+  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
+  entropies.push_back(make_pair(1, 12));
+  entropies.push_back(make_pair(2, 1));
+  entropies.push_back(make_pair(3, 33));
+  entropies.push_back(make_pair(4, 3));
+  entropies.push_back(make_pair(5, 34));
+  entropies.push_back(make_pair(6, 29));
+
+  QuicPacketEntropyHash entropy_hash = 0;
+  for (size_t i = 0; i < entropies.size(); ++i) {
+    entropy_manager_.RecordPacketEntropyHash(entropies[i].first,
+                                             entropies[i].second);
+    entropy_hash ^= entropies[i].second;
+  }
+  EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
+
+  // Now set the entropy hash up to 4 to be 100.
+  entropy_hash ^= 100;
+  for (size_t i = 0; i < 3; ++i) {
+    entropy_hash ^= entropies[i].second;
+  }
+  entropy_manager_.RecalculateEntropyHash(4, 100);
+  EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
+
+  // Ensure it doesn't change with an old received sequence number or entropy.
+  entropy_manager_.RecordPacketEntropyHash(1, 50);
+  EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
+
+  entropy_manager_.RecalculateEntropyHash(1, 50);
+  EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/quic_sent_entropy_manager.cc b/net/quic/quic_sent_entropy_manager.cc
index e69de29..0f33e2d 100644
--- a/net/quic/quic_sent_entropy_manager.cc
+++ b/net/quic/quic_sent_entropy_manager.cc
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_sent_entropy_manager.h"
+
+#include "base/logging.h"
+#include "net/base/linked_hash_map.h"
+
+using std::make_pair;
+using std::max;
+using std::min;
+
+namespace net {
+
+QuicSentEntropyManager::QuicSentEntropyManager()
+    : packets_entropy_hash_(0) {}
+
+QuicSentEntropyManager::~QuicSentEntropyManager() {}
+
+void QuicSentEntropyManager::RecordPacketEntropyHash(
+    QuicPacketSequenceNumber sequence_number,
+    QuicPacketEntropyHash entropy_hash) {
+  // TODO(satyamshekhar): Check this logic again when/if we enable packet
+  // reordering.
+  packets_entropy_hash_ ^= entropy_hash;
+  packets_entropy_.insert(
+      make_pair(sequence_number,
+                make_pair(entropy_hash, packets_entropy_hash_)));
+  DVLOG(2) << "setting cumulative sent entropy hash to: "
+           << static_cast<int>(packets_entropy_hash_)
+           << " updated with sequence number " << sequence_number
+           << " entropy hash: " << static_cast<int>(entropy_hash);
+}
+
+QuicPacketEntropyHash QuicSentEntropyManager::EntropyHash(
+    QuicPacketSequenceNumber sequence_number) const {
+  SentEntropyMap::const_iterator it =
+      packets_entropy_.find(sequence_number);
+  if (it == packets_entropy_.end()) {
+    // Should only happen when we have not received ack for any packet.
+    DCHECK_EQ(0u, sequence_number);
+    return 0;
+  }
+  return it->second.second;
+}
+
+bool QuicSentEntropyManager::IsValidEntropy(
+    QuicPacketSequenceNumber sequence_number,
+    const SequenceNumberSet& missing_packets,
+    QuicPacketEntropyHash entropy_hash) const {
+  SentEntropyMap::const_iterator entropy_it =
+      packets_entropy_.find(sequence_number);
+  if (entropy_it == packets_entropy_.end()) {
+    DCHECK_EQ(0u, sequence_number);
+    // Close connection if something goes wrong.
+    return 0 == sequence_number;
+  }
+  QuicPacketEntropyHash expected_entropy_hash = entropy_it->second.second;
+  for (SequenceNumberSet::const_iterator it = missing_packets.begin();
+       it != missing_packets.end(); ++it) {
+    entropy_it = packets_entropy_.find(*it);
+    DCHECK(entropy_it != packets_entropy_.end());
+    expected_entropy_hash ^= entropy_it->second.first;
+  }
+  DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
+      << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
+      << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
+  return entropy_hash == expected_entropy_hash;
+}
+
+void QuicSentEntropyManager::ClearEntropyBefore(
+    QuicPacketSequenceNumber sequence_number) {
+  if (packets_entropy_.empty()) {
+    return;
+  }
+  SentEntropyMap::iterator it = packets_entropy_.begin();
+  while (it->first < sequence_number) {
+    packets_entropy_.erase(it);
+    it = packets_entropy_.begin();
+    DCHECK(it != packets_entropy_.end());
+  }
+  DVLOG(2) << "Cleared entropy before: "
+           << packets_entropy_.begin()->first;
+}
+
+}  // namespace net
diff --git a/net/quic/quic_sent_entropy_manager.h b/net/quic/quic_sent_entropy_manager.h
index e69de29..4f684fc 100644
--- a/net/quic/quic_sent_entropy_manager.h
+++ b/net/quic/quic_sent_entropy_manager.h
@@ -0,0 +1,62 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Manages the packet entropy calculation for both sent and received packets
+// for a connection.
+
+#ifndef NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
+#define NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
+
+#include "net/base/linked_hash_map.h"
+#include "net/quic/quic_framer.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+// Records all sent packets by a connection to track the cumulative entropy of
+// sent packets.  It is used by the connection to validate an ack
+// frame sent by the peer as a preventive measure against the optimistic ack
+// attack.
+class NET_EXPORT_PRIVATE QuicSentEntropyManager {
+ public:
+  QuicSentEntropyManager();
+  virtual ~QuicSentEntropyManager();
+
+  // Record |entropy_hash| for sent packet corresponding to |sequence_number|.
+  void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
+                               QuicPacketEntropyHash entropy_hash);
+
+  QuicPacketEntropyHash EntropyHash(
+      QuicPacketSequenceNumber sequence_number) const;
+
+  // Returns true if |entropy_hash| matches the expected sent entropy hash
+  // up to |sequence_number| removing sequence numbers from |missing_packets|.
+  bool IsValidEntropy(QuicPacketSequenceNumber sequence_number,
+                      const SequenceNumberSet& missing_packets,
+                      QuicPacketEntropyHash entropy_hash) const;
+
+  // Removes not required entries from |packets_entropy_| before
+  // |sequence_number|.
+  void ClearEntropyBefore(QuicPacketSequenceNumber sequence_number);
+
+  QuicPacketEntropyHash packets_entropy_hash() const {
+    return packets_entropy_hash_;
+  }
+
+ private:
+  typedef linked_hash_map<QuicPacketSequenceNumber,
+                          std::pair<QuicPacketEntropyHash,
+                               QuicPacketEntropyHash> > SentEntropyMap;
+
+  // Linked hash map from sequence numbers to the sent entropy hash up to the
+  // sequence number in the key.
+  SentEntropyMap packets_entropy_;
+
+  // Cumulative hash of entropy of all sent packets.
+  QuicPacketEntropyHash packets_entropy_hash_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
diff --git a/net/quic/quic_sent_entropy_manager_test.cc b/net/quic/quic_sent_entropy_manager_test.cc
index e69de29..e4e9847 100644
--- a/net/quic/quic_sent_entropy_manager_test.cc
+++ b/net/quic/quic_sent_entropy_manager_test.cc
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_sent_entropy_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::make_pair;
+using std::pair;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicSentEntropyManagerTest : public ::testing::Test {
+ protected:
+  QuicSentEntropyManager entropy_manager_;
+};
+
+TEST_F(QuicSentEntropyManagerTest, SentEntropyHash) {
+  EXPECT_EQ(0, entropy_manager_.EntropyHash(0));
+
+  vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
+  entropies.push_back(make_pair(1, 12));
+  entropies.push_back(make_pair(2, 1));
+  entropies.push_back(make_pair(3, 33));
+  entropies.push_back(make_pair(4, 3));
+
+  for (size_t i = 0; i < entropies.size(); ++i) {
+    entropy_manager_.RecordPacketEntropyHash(entropies[i].first,
+                                             entropies[i].second);
+  }
+
+  QuicPacketEntropyHash hash = 0;
+  for (size_t i = 0; i < entropies.size(); ++i) {
+    hash ^= entropies[i].second;
+    EXPECT_EQ(hash, entropy_manager_.EntropyHash(i + 1));
+  }
+}
+
+TEST_F(QuicSentEntropyManagerTest, IsValidEntropy) {
+  QuicPacketEntropyHash entropies[10] =
+      {12, 1, 33, 3, 32, 100, 28, 42, 22, 255};
+  for (size_t i = 0; i < 10; ++i) {
+    entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
+  }
+
+  SequenceNumberSet missing_packets;
+  missing_packets.insert(1);
+  missing_packets.insert(4);
+  missing_packets.insert(7);
+  missing_packets.insert(8);
+
+  QuicPacketEntropyHash entropy_hash = 0;
+  for (size_t i = 0; i < 10; ++i) {
+    if (missing_packets.find(i + 1) == missing_packets.end()) {
+      entropy_hash ^= entropies[i];
+    }
+  }
+
+  EXPECT_TRUE(entropy_manager_.IsValidEntropy(10, missing_packets,
+                                              entropy_hash));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/quic_spdy_decompressor_test.cc b/net/quic/quic_spdy_decompressor_test.cc
index 1e63396..de9156b 100644
--- a/net/quic/quic_spdy_decompressor_test.cc
+++ b/net/quic/quic_spdy_decompressor_test.cc
@@ -38,6 +38,36 @@
   EXPECT_EQ(2u, decompressor_.current_header_id());
 }
 
+TEST_F(QuicSpdyDecompressorTest, DecompressPartial) {
+  SpdyHeaderBlock headers;
+  headers[":host"] = "www.google.com";
+  headers[":path"] = "/index.hml";
+  headers[":scheme"] = "https";
+  string compressed_headers = compressor_.CompressHeaders(headers).substr(4);
+
+  for (size_t i = 0; i < compressed_headers.length(); ++i) {
+    QuicSpdyDecompressor decompressor;
+    TestDecompressorVisitor visitor;
+
+    EXPECT_EQ(1u, decompressor.current_header_id());
+
+    string partial_compressed_headers = compressed_headers.substr(0, i);
+    EXPECT_EQ(partial_compressed_headers.length(),
+              decompressor.DecompressData(partial_compressed_headers,
+                                          &visitor));
+    EXPECT_EQ(1u, decompressor.current_header_id()) << "i: " << i;
+
+    string remaining_compressed_headers =
+        compressed_headers.substr(partial_compressed_headers.length());
+    EXPECT_EQ(remaining_compressed_headers.length(),
+              decompressor.DecompressData(remaining_compressed_headers,
+                                          &visitor));
+    EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers), visitor.data());
+
+    EXPECT_EQ(2u, decompressor.current_header_id());
+  }
+}
+
 TEST_F(QuicSpdyDecompressorTest, DecompressAndIgnoreTrailingData) {
   SpdyHeaderBlock headers;
   headers[":host"] = "www.google.com";
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index af2d881..ceae162 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -440,7 +440,8 @@
       random_generator_,
       socket);
 
-  QuicConnection* connection = new QuicConnection(guid, addr, helper, false);
+  QuicConnection* connection = new QuicConnection(guid, addr, helper, false,
+                                                  QuicVersionMax());
 
   QuicCryptoClientConfig* crypto_config =
       GetOrCreateCryptoConfig(host_port_proxy_pair);
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 383ca9a..2427cf8 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -72,7 +72,7 @@
     feedback.tcp.accumulated_number_of_lost_packets = 0;
     feedback.tcp.receive_window = 16000;
 
-    QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
+    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(QuicFrame(&ack));
     frames.push_back(QuicFrame(&feedback));
@@ -106,7 +106,7 @@
   scoped_ptr<QuicEncryptedPacket> ConstructPacket(
       const QuicPacketHeader& header,
       const QuicFrame& frame) {
-    QuicFramer framer(kQuicVersion1, QuicTime::Zero(), false);
+    QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), false);
     QuicFrames frames;
     frames.push_back(frame);
     scoped_ptr<QuicPacket> packet(
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 146a77c..7cf67d3 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -74,10 +74,19 @@
     return true;
   }
 
+  if (frame.fin) {
+    CloseStreamAtOffset(frame.offset + frame.data.size());
+  }
+
   QuicStreamOffset byte_offset = frame.offset;
   const char* data = frame.data.data();
   size_t data_len = frame.data.size();
 
+  if (data_len == 0) {
+    // TODO(rch): Close the stream if there was no data and no fin.
+    return true;
+  }
+
   if (byte_offset == num_bytes_consumed_) {
     DVLOG(1) << "Processing byte offset " << byte_offset;
     size_t bytes_consumed = stream_->ProcessRawData(data, data_len);
@@ -194,23 +203,32 @@
 
 void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
   size_t end_offset = num_bytes_consumed_ + num_bytes_consumed;
-  while (!frames_.empty()) {
+  while (!frames_.empty() && end_offset != num_bytes_consumed_) {
     FrameMap::iterator it = frames_.begin();
+    if (it->first != num_bytes_consumed_) {
+      LOG(DFATAL) << "Invalid argument to MarkConsumed. "
+                  << " num_bytes_consumed_: " << num_bytes_consumed_
+                  << " end_offset: " << end_offset
+                  << " offset: " << it->first
+                  << " length: " << it->second.length();
+      stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM);
+      return;
+    }
+
     if (it->first + it->second.length() <= end_offset) {
+      num_bytes_consumed_ += it->second.length();
       // This chunk is entirely consumed.
       frames_.erase(it);
       continue;
     }
 
-    if (it->first != end_offset) {
-      // Partially consume this frame.
-      frames_.insert(make_pair(end_offset,
-                               it->second.substr(end_offset - it->first)));
-      frames_.erase(it);
-    }
+    // Partially consume this frame.
+    size_t delta = end_offset - it->first;
+    num_bytes_consumed_ += delta;
+    frames_.insert(make_pair(end_offset, it->second.substr(delta)));
+    frames_.erase(it);
     break;
   }
-  num_bytes_consumed_ = end_offset;
 }
 
 bool QuicStreamSequencer::HasBytesToRead() const {
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index bb5b29e..fe9fba5 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -49,9 +49,6 @@
   // this will return true, or it will be rejected and this will return false.
   bool OnStreamFrame(const QuicStreamFrame& frame);
 
-  // Wait until we've seen 'offset' bytes, and then terminate the stream.
-  void CloseStreamAtOffset(QuicStreamOffset offset);
-
   // Once data is buffered, it's up to the stream to read it when the stream
   // can handle more data.  The following three functions make that possible.
 
@@ -86,6 +83,9 @@
   // TODO(alyssar) use something better than strings.
   typedef map<QuicStreamOffset, string> FrameMap;
 
+  // Wait until we've seen 'offset' bytes, and then terminate the stream.
+  void CloseStreamAtOffset(QuicStreamOffset offset);
+
   bool MaybeCloseStream();
 
   ReliableQuicStream* stream_;  // The stream which owns this sequencer.
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index af8a961..0d40db9 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -32,15 +32,26 @@
   }
 
   QuicStreamSequencerPeer(int32 max_mem, ReliableQuicStream* stream)
-      : QuicStreamSequencer(max_mem, stream) {}
+      : QuicStreamSequencer(max_mem, stream) {
+  }
 
-  virtual bool OnFrame(QuicStreamOffset byte_offset,
-                       const char* data,
-                       uint32 data_len) {
+  virtual bool OnFinFrame(QuicStreamOffset byte_offset,
+                          const char* data) {
     QuicStreamFrame frame;
     frame.stream_id = 1;
     frame.offset = byte_offset;
-    frame.data = StringPiece(data, data_len);
+    frame.data = StringPiece(data);
+    frame.fin = true;
+    return OnStreamFrame(frame);
+  }
+
+  virtual bool OnFrame(QuicStreamOffset byte_offset,
+                       const char* data) {
+    QuicStreamFrame frame;
+    frame.stream_id = 1;
+    frame.offset = byte_offset;
+    frame.data = StringPiece(data);
+    frame.fin = false;
     return OnStreamFrame(frame);
   }
 
@@ -127,55 +138,69 @@
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3))
       .WillOnce(Return(3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(0u, sequencer_->frames()->size());
   EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
   // Ignore this - it matches a past sequence number and we should not see it
   // again.
-  EXPECT_TRUE(sequencer_->OnFrame(0, "def", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "def"));
   EXPECT_EQ(0u, sequencer_->frames()->size());
 }
 
 TEST_F(QuicStreamSequencerTest, RejectOverlyLargeFrame) {
+  // TODO(rch): enable when chromium supports EXPECT_DFATAL.
   /*
   EXPECT_DFATAL(sequencer_.reset(new QuicStreamSequencerPeer(2, &stream_)),
                 "Setting max frame memory to 2.  "
                 "Some frames will be impossible to handle.");
 
-  EXPECT_DEBUG_DEATH(sequencer_->OnFrame(0, "abc", 3), "");
+  EXPECT_DEBUG_DEATH(sequencer_->OnFrame(0, "abc"), "");
   */
 }
 
 TEST_F(QuicStreamSequencerTest, DropFramePastBuffering) {
   sequencer_->SetMemoryLimit(3);
 
-  EXPECT_FALSE(sequencer_->OnFrame(3, "abc", 3));
+  EXPECT_FALSE(sequencer_->OnFrame(3, "abc"));
 }
 
 TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) {
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
   // Ignore this - it matches a buffered frame.
   // Right now there's no checking that the payload is consistent.
-  EXPECT_TRUE(sequencer_->OnFrame(0, "def", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "def"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
 }
 
 TEST_F(QuicStreamSequencerTest, FullFrameConsumed) {
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(0u, sequencer_->frames()->size());
   EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
 }
 
+TEST_F(QuicStreamSequencerTest, EmptyFrame) {
+  EXPECT_TRUE(sequencer_->OnFrame(0, ""));
+  EXPECT_EQ(0u, sequencer_->frames()->size());
+  EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
+}
+
+TEST_F(QuicStreamSequencerTest, EmptyFinFrame) {
+  EXPECT_CALL(stream_, TerminateFromPeer(true));
+  EXPECT_TRUE(sequencer_->OnFinFrame(0, ""));
+  EXPECT_EQ(0u, sequencer_->frames()->size());
+  EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
+}
+
 TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) {
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(2));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
   EXPECT_EQ(2u, sequencer_->num_bytes_consumed());
   EXPECT_EQ("c", sequencer_->frames()->find(2)->second);
@@ -184,14 +209,14 @@
 TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) {
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
   EXPECT_EQ("abc", sequencer_->frames()->find(0)->second);
 }
 
 TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) {
-  EXPECT_TRUE(sequencer_->OnFrame(3, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "abc"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
   EXPECT_EQ("abc", sequencer_->frames()->find(3)->second);
@@ -199,11 +224,11 @@
 
 TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
   // Buffer the first
-  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi"));
   EXPECT_EQ(1u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
   // Buffer the second
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
   EXPECT_EQ(2u, sequencer_->frames()->size());
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
 
@@ -213,7 +238,7 @@
   EXPECT_CALL(stream_, ProcessData(StrEq("ghi"), 3)).WillOnce(Return(3));
 
   // Ack right away
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(9u, sequencer_->num_bytes_consumed());
 
   EXPECT_EQ(0u, sequencer_->frames()->size());
@@ -223,28 +248,28 @@
   sequencer_->SetMemoryLimit(9);
 
   // Too far to buffer.
-  EXPECT_FALSE(sequencer_->OnFrame(9, "jkl", 3));
+  EXPECT_FALSE(sequencer_->OnFrame(9, "jkl"));
 
   // We can afford to buffer this.
-  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi"));
   EXPECT_EQ(0u, sequencer_->num_bytes_consumed());
 
   InSequence s;
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3));
 
   // Ack right away
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
   EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
 
   // We should be willing to buffer this now.
-  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl"));
   EXPECT_EQ(3u, sequencer_->num_bytes_consumed());
 
   EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3));
   EXPECT_CALL(stream_, ProcessData(StrEq("ghi"), 3)).WillOnce(Return(3));
   EXPECT_CALL(stream_, ProcessData(StrEq("jkl"), 3)).WillOnce(Return(3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
   EXPECT_EQ(12u, sequencer_->num_bytes_consumed());
   EXPECT_EQ(0u, sequencer_->frames()->size());
 }
@@ -273,25 +298,25 @@
   EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(0));
   EXPECT_CALL(stream_, ProcessData(StrEq("pqr"), 3)).WillOnce(Return(3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3));
-  EXPECT_FALSE(sequencer_->OnFrame(12, "mno", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
+  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl"));
+  EXPECT_FALSE(sequencer_->OnFrame(12, "mno"));
+  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi"));
 
   // Read 3 bytes.
   EXPECT_EQ(3, sequencer_->Readv(iov, 2));
   EXPECT_EQ(0, strncmp(buffer, "def", 3));
 
   // Now we have space to bufer this.
-  EXPECT_TRUE(sequencer_->OnFrame(12, "mno", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(12, "mno"));
 
   // Read the remaining 9 bytes.
   iov[1].iov_len = 19;
   EXPECT_EQ(9, sequencer_->Readv(iov, 2));
   EXPECT_EQ(0, strncmp(buffer, "ghijklmno", 9));
 
-  EXPECT_TRUE(sequencer_->OnFrame(15, "pqr", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(15, "pqr"));
 }
 
 // Same as above, just using a different method for reading.
@@ -303,11 +328,11 @@
   EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(0));
   EXPECT_CALL(stream_, ProcessData(StrEq("pqr"), 3)).WillOnce(Return(3));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3));
-  EXPECT_FALSE(sequencer_->OnFrame(12, "mno", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
+  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl"));
+  EXPECT_FALSE(sequencer_->OnFrame(12, "mno"));
+  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi"));
 
   // Read 3 bytes.
   const char* expected[] = {"def", "ghi", "jkl"};
@@ -317,7 +342,7 @@
   ASSERT_EQ(3, sequencer_->Readv(&read_iov, 1));
 
   // Now we have space to bufer this.
-  EXPECT_TRUE(sequencer_->OnFrame(12, "mno", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(12, "mno"));
 
   // Read the remaining 9 bytes.
   const char* expected2[] = {"ghi", "jkl", "mno"};
@@ -325,7 +350,7 @@
   read_iov.iov_len = 9;
   ASSERT_EQ(9, sequencer_->Readv(&read_iov, 1));
 
-  EXPECT_TRUE(sequencer_->OnFrame(15, "pqr", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(15, "pqr"));
 }
 
 // Same as above, just using a different method for reading.
@@ -335,9 +360,9 @@
   InSequence s;
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
+  EXPECT_TRUE(sequencer_->OnFrame(6, "ghi"));
 
   // Peek into the data.
   const char* expected[] = {"abc", "def", "ghi"};
@@ -362,49 +387,85 @@
   ASSERT_TRUE(VerifyReadableRegions(expected4, arraysize(expected4)));
 }
 
+TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
+  // TODO(rch): enable when chromium supports EXPECT_DFATAL.
+  /*
+  EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0));
+
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
+  EXPECT_TRUE(sequencer_->OnFrame(9, "jklmnopqrstuvwxyz"));
+
+  // Peek into the data.  Only the first chunk should be readable
+  // because of the missing data.
+  const char* expected[] = {"abc"};
+  ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+
+  // Now, attempt to mark consumed more data than was readable
+  // and expect the stream to be closed.
+  EXPECT_CALL(stream_, Close(QUIC_SERVER_ERROR_PROCESSING_STREAM));
+  EXPECT_DFATAL(sequencer_->MarkConsumed(4),
+                "Invalid argument to MarkConsumed.  num_bytes_consumed_: 3 "
+                "end_offset: 4 offset: 9 length: 17");
+  */
+}
+
+TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
+  InSequence s;
+  EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0));
+
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
+  // Missing packet: 6, ghi
+  EXPECT_TRUE(sequencer_->OnFrame(9, "jkl"));
+
+  const char* expected[] = {"abc", "def"};
+  ASSERT_TRUE(VerifyReadableRegions(expected, arraysize(expected)));
+
+  sequencer_->MarkConsumed(6);
+}
+
 TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
   InSequence s;
 
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3));
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
-
   EXPECT_CALL(stream_, TerminateFromPeer(true));
-  sequencer_->CloseStreamAtOffset(3);
+  EXPECT_TRUE(sequencer_->OnFinFrame(0, "abc"));
+
   EXPECT_EQ(3u, sequencer_->close_offset());
 }
 
 TEST_F(QuicStreamSequencerTest, BasicHalfCloseUnorderedWithFlush) {
-  sequencer_->CloseStreamAtOffset(6);
+  sequencer_->OnFinFrame(6, "");
   EXPECT_EQ(6u, sequencer_->close_offset());
   InSequence s;
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3));
   EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3));
   EXPECT_CALL(stream_, TerminateFromPeer(true));
 
-  EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3));
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(3, "def"));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
 }
 
 TEST_F(QuicStreamSequencerTest, BasicHalfUnordered) {
-  sequencer_->CloseStreamAtOffset(3);
+  sequencer_->OnFinFrame(3, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
   InSequence s;
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3));
   EXPECT_CALL(stream_, TerminateFromPeer(true));
 
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
 }
 
 TEST_F(QuicStreamSequencerTest, TerminateWithReadv) {
   char buffer[3];
 
-  sequencer_->CloseStreamAtOffset(3);
+  sequencer_->OnFinFrame(3, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
 
   EXPECT_FALSE(sequencer_->IsHalfClosed());
 
   EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0));
-  EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3));
+  EXPECT_TRUE(sequencer_->OnFrame(0, "abc"));
 
   iovec iov = { &buffer[0], 3 };
   int bytes_read = sequencer_->Readv(&iov, 1);
@@ -413,18 +474,18 @@
 }
 
 TEST_F(QuicStreamSequencerTest, MutipleOffsets) {
-  sequencer_->CloseStreamAtOffset(3);
+  sequencer_->OnFinFrame(3, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
 
   EXPECT_CALL(stream_, Close(QUIC_MULTIPLE_TERMINATION_OFFSETS));
-  sequencer_->CloseStreamAtOffset(5);
+  sequencer_->OnFinFrame(5, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
 
   EXPECT_CALL(stream_, Close(QUIC_MULTIPLE_TERMINATION_OFFSETS));
-  sequencer_->CloseStreamAtOffset(1);
+  sequencer_->OnFinFrame(1, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
 
-  sequencer_->CloseStreamAtOffset(3);
+  sequencer_->OnFinFrame(3, "");
   EXPECT_EQ(3u, sequencer_->close_offset());
 }
 
@@ -479,9 +540,9 @@
     int index = OneToN(list_.size()) - 1;
     LOG(ERROR) << "Sending index " << index << " "
                << list_[index].second.data();
-    EXPECT_TRUE(sequencer_->OnFrame(
-        list_[index].first, list_[index].second.data(),
-        list_[index].second.size()));
+    EXPECT_TRUE(sequencer_->OnFrame(list_[index].first,
+                                    list_[index].second.data()));
+
     list_.erase(list_.begin() + index);
   }
 }
@@ -502,9 +563,9 @@
     int index = OneToN(list_.size()) - 1;
     LOG(ERROR) << "Sending index " << index << " "
                << list_[index].second.data();
-    bool acked = sequencer_->OnFrame(
-        list_[index].first, list_[index].second.data(),
-        list_[index].second.size());
+    bool acked = sequencer_->OnFrame(list_[index].first,
+                                     list_[index].second.data());
+
     if (acked) {
       list_.erase(list_.begin() + index);
     }
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 0fa5b7a..c2cb3f1 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -22,6 +22,7 @@
       stream_bytes_written_(0),
       headers_decompressed_(false),
       headers_id_(0),
+      decompression_failed_(false),
       stream_error_(QUIC_STREAM_NO_ERROR),
       connection_error_(QUIC_NO_ERROR),
       read_side_closed_(false),
@@ -57,10 +58,6 @@
 
   bool accepted = sequencer_.OnStreamFrame(frame);
 
-  if (frame.fin) {
-    sequencer_.CloseStreamAtOffset(frame.offset + frame.data.size());
-  }
-
   return accepted;
 }
 
@@ -267,6 +264,9 @@
     data_len -= missing_size;
   }
   DCHECK_NE(0u, headers_id_);
+  if (data_len == 0) {
+    return total_bytes_consumed;
+  }
 
   // Once the headers are finished, we simply pass the data through.
   if (headers_decompressed_) {
@@ -274,7 +274,7 @@
     if (!decompressed_headers_.empty()) {
       ProcessHeaderData();
     }
-    if (decompressed_headers_.empty() && data_len > 0) {
+    if (decompressed_headers_.empty()) {
       DVLOG(1) << "Delegating procesing to ProcessData";
       total_bytes_consumed += ProcessData(data, data_len);
     }
@@ -304,20 +304,39 @@
   // Decompressed data will be delivered to decompressed_headers_.
   size_t bytes_consumed = session_->decompressor()->DecompressData(
       StringPiece(data, data_len), this);
+  DCHECK_NE(0u, bytes_consumed);
+  if (bytes_consumed > data_len) {
+    DCHECK(false) << "DecompressData returned illegal value";
+    OnDecompressionError();
+    return total_bytes_consumed;
+  }
   total_bytes_consumed += bytes_consumed;
+  data += bytes_consumed;
+  data_len -= bytes_consumed;
+
+  if (decompression_failed_) {
+    // The session will have been closed in OnDecompressionError.
+    return total_bytes_consumed;
+  }
 
   // Headers are complete if the decompressor has moved on to the
   // next stream.
   headers_decompressed_ =
       session_->decompressor()->current_header_id() != headers_id_;
+  if (!headers_decompressed_) {
+    DCHECK_EQ(0u, data_len);
+  }
 
   ProcessHeaderData();
 
+  if (!headers_decompressed_ || !decompressed_headers_.empty()) {
+    return total_bytes_consumed;
+  }
+
   // We have processed all of the decompressed data but we might
   // have some more raw data to process.
-  if (decompressed_headers_.empty() && bytes_consumed < data_len) {
-    total_bytes_consumed += ProcessData(data + bytes_consumed,
-                                        data_len - bytes_consumed);
+  if (data_len > 0) {
+    total_bytes_consumed += ProcessData(data, data_len);
   }
 
   // The sequencer will push any additional buffered frames if this data
@@ -344,29 +363,30 @@
   DCHECK_EQ(headers_id_,
             session_->decompressor()->current_header_id());
   DCHECK(!headers_decompressed_);
+  DCHECK(!decompression_failed_);
   DCHECK_EQ(0u, decompressed_headers_.length());
 
-  size_t total_bytes_consumed = 0;
-  struct iovec iovecs[5];
   while (!headers_decompressed_) {
-    size_t num_iovecs =
-        sequencer_.GetReadableRegions(iovecs, arraysize(iovecs));
-
-    if (num_iovecs == 0) {
+    struct iovec iovec;
+    if (sequencer_.GetReadableRegions(&iovec, 1) == 0) {
       return;
     }
-    for (size_t i = 0; i < num_iovecs && !headers_decompressed_; i++) {
-      total_bytes_consumed += session_->decompressor()->DecompressData(
-          StringPiece(static_cast<char*>(iovecs[i].iov_base),
-                      iovecs[i].iov_len), this);
 
-      headers_decompressed_ =
-          session_->decompressor()->current_header_id() != headers_id_;
+    size_t bytes_consumed = session_->decompressor()->DecompressData(
+        StringPiece(static_cast<char*>(iovec.iov_base),
+                    iovec.iov_len),
+        this);
+    DCHECK_LE(bytes_consumed, iovec.iov_len);
+    if (decompression_failed_) {
+      return;
     }
+    sequencer_.MarkConsumed(bytes_consumed);
+
+    headers_decompressed_ =
+        session_->decompressor()->current_header_id() != headers_id_;
   }
 
   // Either the headers are complete, or the all data as been consumed.
-  sequencer_.MarkConsumed(total_bytes_consumed);
   ProcessHeaderData();  // Unprocessed headers remain in decompressed_headers_.
   if (IsHalfClosed()) {
     TerminateFromPeer(true);
@@ -381,6 +401,8 @@
 }
 
 void ReliableQuicStream::OnDecompressionError() {
+  DCHECK(!decompression_failed_);
+  decompression_failed_ = true;
   session_->connection()->SendConnectionClose(QUIC_DECOMPRESSION_FAILURE);
 }
 
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 05abaef..3f5150b 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -172,6 +172,8 @@
   // Contains a copy of the decompressed headers_ until they are consumed
   // via ProcessData or Readv.
   string decompressed_headers_;
+  // True if an error was encountered during decompression.
+  bool decompression_failed_;
 
   // Stream error code received from a RstStreamFrame or error code sent by the
   // visitor or sequencer in the RstStreamFrame.
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index dc5c160..5548697 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -44,6 +44,7 @@
   }
 
   virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
+    EXPECT_NE(0u, data_len);
     DVLOG(1) << "ProcessData data_len: " << data_len;
     data_ += string(data, data_len);
     return should_process_data_ ? data_len : 0;
@@ -66,6 +67,30 @@
     headers_[":host"] = "www.google.com";
     headers_[":path"] = "/index.hml";
     headers_[":scheme"] = "https";
+    headers_["cookie"] =
+        "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
+        "__utmc=160408618; "
+        "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
+        "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
+        "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
+        "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
+        "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
+        "1zFMi5vzcns38-8_Sns; "
+        "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
+        "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
+        "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
+        "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
+        "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
+        "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
+        "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
+        "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
+        "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
+        "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
+        "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
+        "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
+        "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
+        "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
+        "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
   }
 
   void Initialize(bool stream_should_process_data) {
@@ -263,6 +288,21 @@
     ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
               stream_->data()) << "fragment_size: " << fragment_size;
   }
+
+  for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) {
+    Initialize(kShouldProcessData);
+
+    StringPiece fragment1(data.data(), split_point);
+    QuicStreamFrame frame1(kStreamId, false, 0, fragment1);
+    stream_->OnStreamFrame(frame1);
+
+    StringPiece fragment2(data.data() + split_point, data.size() - split_point);
+    QuicStreamFrame frame2(kStreamId, false, split_point, fragment2);
+    stream_->OnStreamFrame(frame2);
+
+    ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body,
+              stream_->data()) << "split_point: " << split_point;
+  }
 }
 
 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) {
@@ -279,7 +319,7 @@
   stream_->OnStreamFrame(frame);
   EXPECT_EQ(uncompressed_headers, stream_->data());
 
-  char buffer[1024];
+  char buffer[2048];
   ASSERT_LT(data.length(), arraysize(buffer));
   struct iovec vec;
   vec.iov_base = buffer;
@@ -348,6 +388,93 @@
   }
 }
 
+TEST_F(ReliableQuicStreamTest, ProcessCorruptHeadersEarly) {
+  Initialize(kShouldProcessData);
+
+  string compressed_headers1 = compressor_->CompressHeaders(headers_);
+  QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1);
+  string decompressed_headers1 =
+      SpdyUtils::SerializeUncompressedHeaders(headers_);
+
+  headers_["content-type"] = "text/plain";
+  string compressed_headers2 = compressor_->CompressHeaders(headers_);
+  // Corrupt the compressed data.
+  compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1;
+  QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2);
+  string decompressed_headers2 =
+      SpdyUtils::SerializeUncompressedHeaders(headers_);
+
+  // Deliver frame2 to stream2 out of order.  The decompressor is not
+  // available yet, so no data will be processed.  The compressed data
+  // will be buffered until OnDecompressorAvailable() is called
+  // to process it.
+  stream2_->OnStreamFrame(frame2);
+  EXPECT_EQ("", stream2_->data());
+
+  // Now deliver frame1 to stream1.  The decompressor is available so
+  // the data will be processed, and the decompressor will become
+  // available for stream2.
+  stream_->OnStreamFrame(frame1);
+  EXPECT_EQ(decompressed_headers1, stream_->data());
+
+  // Verify that the decompressor is available, and inform stream2
+  // that it can now decompress the buffered compressed data.    Since
+  // the compressed data is corrupt, the stream will shutdown the session.
+  EXPECT_EQ(2u, session_->decompressor()->current_header_id());
+  EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE));
+  stream2_->OnDecompressorAvailable();
+  EXPECT_EQ("", stream2_->data());
+}
+
+TEST_F(ReliableQuicStreamTest, ProcessPartialHeadersEarly) {
+  Initialize(kShouldProcessData);
+
+  string compressed_headers1 = compressor_->CompressHeaders(headers_);
+  QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1);
+  string decompressed_headers1 =
+      SpdyUtils::SerializeUncompressedHeaders(headers_);
+
+  headers_["content-type"] = "text/plain";
+  string compressed_headers2 = compressor_->CompressHeaders(headers_);
+  string partial_compressed_headers =
+      compressed_headers2.substr(0, compressed_headers2.length() / 2);
+  QuicStreamFrame frame2(stream2_->id(), false, 0, partial_compressed_headers);
+  string decompressed_headers2 =
+      SpdyUtils::SerializeUncompressedHeaders(headers_);
+
+  // Deliver frame2 to stream2 out of order.  The decompressor is not
+  // available yet, so no data will be processed.  The compressed data
+  // will be buffered until OnDecompressorAvailable() is called
+  // to process it.
+  stream2_->OnStreamFrame(frame2);
+  EXPECT_EQ("", stream2_->data());
+
+  // Now deliver frame1 to stream1.  The decompressor is available so
+  // the data will be processed, and the decompressor will become
+  // available for stream2.
+  stream_->OnStreamFrame(frame1);
+  EXPECT_EQ(decompressed_headers1, stream_->data());
+
+  // Verify that the decompressor is available, and inform stream2
+  // that it can now decompress the buffered compressed data.  Since
+  // the compressed data is incomplete it will not be passed to
+  // the stream.
+  EXPECT_EQ(2u, session_->decompressor()->current_header_id());
+  stream2_->OnDecompressorAvailable();
+  EXPECT_EQ("", stream2_->data());
+
+  // Now send remaining data and verify that we have now received the
+  // compressed headers.
+  string remaining_compressed_headers =
+      compressed_headers2.substr(partial_compressed_headers.length());
+
+  QuicStreamFrame frame3(stream2_->id(), false,
+                         partial_compressed_headers.length(),
+                         remaining_compressed_headers);
+  stream2_->OnStreamFrame(frame3);
+  EXPECT_EQ(decompressed_headers2, stream2_->data());
+}
+
 TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) {
   Initialize(kShouldProcessData);
 
@@ -362,12 +489,21 @@
   string decompressed_headers2 =
       SpdyUtils::SerializeUncompressedHeaders(headers_);
 
+  // Deliver frame2 to stream2 out of order.  The decompressor is not
+  // available yet, so no data will be processed.  The compressed data
+  // will be buffered until OnDecompressorAvailable() is called
+  // to process it.
   stream2_->OnStreamFrame(frame2);
-  EXPECT_EQ("", stream_->data());
+  EXPECT_EQ("", stream2_->data());
 
+  // Now deliver frame1 to stream1.  The decompressor is available so
+  // the data will be processed, and the decompressor will become
+  // available for stream2.
   stream_->OnStreamFrame(frame1);
   EXPECT_EQ(decompressed_headers1, stream_->data());
 
+  // Verify that the decompressor is available, and inform stream2
+  // that it can now decompress the buffered compressed data.
   EXPECT_EQ(2u, session_->decompressor()->current_header_id());
   stream2_->OnDecompressorAvailable();
   EXPECT_EQ(decompressed_headers2, stream2_->data());
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 8c4c245..330aa06 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -89,7 +89,7 @@
 QuicPacketEntropyHash QuicConnectionPeer::GetSentEntropyHash(
     QuicConnection* connection,
     QuicPacketSequenceNumber sequence_number) {
-  return connection->entropy_manager_.SentEntropyHash(sequence_number);
+  return connection->sent_entropy_manager_.EntropyHash(sequence_number);
 }
 
 // static
@@ -98,7 +98,7 @@
     QuicPacketSequenceNumber largest_observed,
     const SequenceNumberSet& missing_packets,
     QuicPacketEntropyHash entropy_hash) {
-  return connection->entropy_manager_.IsValidEntropy(
+  return connection->sent_entropy_manager_.IsValidEntropy(
       largest_observed, missing_packets, entropy_hash);
 }
 
@@ -106,7 +106,8 @@
 QuicPacketEntropyHash QuicConnectionPeer::ReceivedEntropyHash(
     QuicConnection* connection,
     QuicPacketSequenceNumber sequence_number) {
-  return connection->entropy_manager_.ReceivedEntropyHash(sequence_number);
+  return connection->received_entropy_manager_.EntropyHash(
+      sequence_number);
 }
 
 // static
diff --git a/net/quic/test_tools/quic_framer_peer.cc b/net/quic/test_tools/quic_framer_peer.cc
index f31299c..5ec52dc 100644
--- a/net/quic/test_tools/quic_framer_peer.cc
+++ b/net/quic/test_tools/quic_framer_peer.cc
@@ -34,7 +34,7 @@
   framer->is_server_ = is_server;
 }
 
-void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicTag version) {
+void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicVersion version) {
   framer->quic_version_ = version;
 }
 
diff --git a/net/quic/test_tools/quic_framer_peer.h b/net/quic/test_tools/quic_framer_peer.h
index 7a2da5c..0508f5c 100644
--- a/net/quic/test_tools/quic_framer_peer.h
+++ b/net/quic/test_tools/quic_framer_peer.h
@@ -24,7 +24,7 @@
       QuicFramer* framer,
       QuicPacketSequenceNumber packet_sequence_number);
   static void SetIsServer(QuicFramer* framer, bool is_server);
-  static void SetVersion(QuicFramer* framer, QuicTag version);
+  static void SetVersion(QuicFramer* framer, QuicVersion version);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 809f28a..3f122ba 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -55,7 +55,7 @@
 MockFramerVisitor::~MockFramerVisitor() {
 }
 
-bool NoOpFramerVisitor::OnProtocolVersionMismatch(QuicTag version) {
+bool NoOpFramerVisitor::OnProtocolVersionMismatch(QuicVersion version) {
   return false;
 }
 
@@ -189,7 +189,7 @@
                                IPEndPoint address,
                                bool is_server)
     : QuicConnection(guid, address, new testing::NiceMock<MockHelper>(),
-                     is_server),
+                     is_server, QuicVersionMax()),
       has_mock_helper_(true) {
 }
 
@@ -197,7 +197,7 @@
                                IPEndPoint address,
                                QuicConnectionHelperInterface* helper,
                                bool is_server)
-    : QuicConnection(guid, address, helper, is_server),
+    : QuicConnection(guid, address, helper, is_server, QuicVersionMax()),
       has_mock_helper_(false) {
 }
 
@@ -354,7 +354,7 @@
     bool should_include_version) {
   CryptoFramer crypto_framer;
   scoped_ptr<QuicData> data(crypto_framer.ConstructHandshakeMessage(message));
-  QuicFramer quic_framer(kQuicVersion1, QuicTime::Zero(), false);
+  QuicFramer quic_framer(QuicVersionMax(), QuicTime::Zero(), false);
 
   QuicPacketHeader header;
   header.public_header.guid = guid;
@@ -403,7 +403,7 @@
           PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
 }
 
-QuicPacketEntropyHash TestEntropyCalculator::ReceivedEntropyHash(
+QuicPacketEntropyHash TestEntropyCalculator::EntropyHash(
     QuicPacketSequenceNumber sequence_number) const {
   return 1u;
 }
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index d67fb9c..d24a2a5 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -53,7 +53,7 @@
 
   MOCK_METHOD1(OnError, void(QuicFramer* framer));
   // The constructor sets this up to return false by default.
-  MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicTag version));
+  MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicVersion version));
   MOCK_METHOD0(OnPacket, void());
   MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
   MOCK_METHOD1(OnVersionNegotiationPacket,
@@ -88,7 +88,7 @@
   virtual void OnVersionNegotiationPacket(
       const QuicVersionNegotiationPacket& packet) OVERRIDE {}
   virtual void OnRevivedPacket() OVERRIDE {}
-  virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE;
+  virtual bool OnProtocolVersionMismatch(QuicVersion version) OVERRIDE;
   virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
   virtual void OnFecProtectedPayload(base::StringPiece payload) OVERRIDE {}
   virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
@@ -245,7 +245,7 @@
     QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE {
+  virtual bool OnProtocolVersionMismatch(QuicVersion version) OVERRIDE {
     return false;
   }
 
@@ -338,6 +338,7 @@
                                               HasRetransmittableData));
   MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void));
   MOCK_METHOD0(SmoothedRtt, QuicTime::Delta(void));
+  MOCK_METHOD0(RetransmissionDelay, QuicTime::Delta(void));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
@@ -349,7 +350,7 @@
   TestEntropyCalculator() { }
   virtual ~TestEntropyCalculator() { }
 
-  virtual QuicPacketEntropyHash ReceivedEntropyHash(
+  virtual QuicPacketEntropyHash EntropyHash(
       QuicPacketSequenceNumber sequence_number) const OVERRIDE;
 };
 
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 7e77b0f..46be3a8 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -25,7 +25,7 @@
     error_ = framer->error();
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicTag version) OVERRIDE {
+  virtual bool OnProtocolVersionMismatch(QuicVersion version) OVERRIDE {
     return false;
   }
 
@@ -128,7 +128,7 @@
 };
 
 SimpleQuicFramer::SimpleQuicFramer()
-    : framer_(kQuicVersion1, QuicTime::Zero(), true) {
+    : framer_(QuicVersionMax(), QuicTime::Zero(), true) {
 }
 
 SimpleQuicFramer::~SimpleQuicFramer() {