Project import generated by Copybara.

PiperOrigin-RevId: 231652158
Change-Id: I80001699b542a5c823722d90d24fcdd014ef99e7
diff --git a/http2/hpack/decoder/hpack_entry_decoder.cc b/http2/hpack/decoder/hpack_entry_decoder.cc
index b227b18..96b9f06 100644
--- a/http2/hpack/decoder/hpack_entry_decoder.cc
+++ b/http2/hpack/decoder/hpack_entry_decoder.cc
@@ -192,7 +192,7 @@
 
 bool HpackEntryDecoder::DispatchOnType(HpackEntryDecoderListener* listener) {
   const HpackEntryType entry_type = entry_type_decoder_.entry_type();
-  const uint64_t varint = entry_type_decoder_.varint();
+  const uint32_t varint = static_cast<uint32_t>(entry_type_decoder_.varint());
   switch (entry_type) {
     case HpackEntryType::kIndexedHeader:
       // The entry consists solely of the entry type and varint. See:
diff --git a/http2/hpack/decoder/hpack_string_decoder.h b/http2/hpack/decoder/hpack_string_decoder.h
index 5e0d220..2128728 100644
--- a/http2/hpack/decoder/hpack_string_decoder.h
+++ b/http2/hpack/decoder/hpack_string_decoder.h
@@ -13,7 +13,6 @@
 
 #include <algorithm>
 #include <cstdint>
-#include <limits>
 
 #include "base/logging.h"
 #include "base/macros.h"
@@ -169,16 +168,8 @@
   // false otherwise, in which case status set.
   template <class Listener>
   void OnStringStart(Listener* cb, DecodeStatus* status) {
-    // HpackVarintDecoder::value() returns uint64_t.
-    const uint64_t value = length_decoder_.value();
-    // |remaining_| is size_t.  Check for truncation on 32-bit platforms.
-    // numeric_limits::max() is constexpr.  On platforms where size_t is at
-    // least 64 bit wide, the compiler should optimize away this branch.
-    if (value > std::numeric_limits<size_t>::max()) {
-      *status = DecodeStatus::kDecodeError;
-      return;
-    }
-    remaining_ = static_cast<size_t>(value);
+    // TODO(vasilvv): fail explicitly in case of truncation.
+    remaining_ = static_cast<size_t>(length_decoder_.value());
     // Make callback so consumer knows what is coming.
     cb->OnStringStart(huffman_encoded_, remaining_);
   }
diff --git a/http2/hpack/varint/hpack_varint_decoder.cc b/http2/hpack/varint/hpack_varint_decoder.cc
index dd64025..ac85247 100644
--- a/http2/hpack/varint/hpack_varint_decoder.cc
+++ b/http2/hpack/varint/hpack_varint_decoder.cc
@@ -4,7 +4,6 @@
 
 #include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h"
 
-#include "net/third_party/quiche/src/http2/platform/api/http2_flag_utils.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
 
 namespace http2 {
@@ -43,96 +42,67 @@
 }
 
 DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) {
-  if (decode_64_bits_) {
-    HTTP2_RELOADABLE_FLAG_COUNT(http2_varint_decode_64_bits);
-    // There can be at most 10 continuation bytes.  Offset is zero for the
-    // first one and increases by 7 for each subsequent one.
-    const uint8_t kMaxOffset = 63;
-    CheckNotDone();
-
-    // Process most extension bytes without the need for overflow checking.
-    while (offset_ < kMaxOffset) {
-      if (db->Empty()) {
-        return DecodeStatus::kDecodeInProgress;
-      }
-
-      uint8_t byte = db->DecodeUInt8();
-      uint64_t summand = byte & 0x7f;
-
-      // Shifting a 7 bit value to the left by at most 56 places can never
-      // overflow on uint64_t.
-      DCHECK_LE(offset_, 56);
-      DCHECK_LE(summand, std::numeric_limits<uint64_t>::max() >> offset_);
-
-      summand <<= offset_;
-
-      // At this point,
-      // |value_| is at most (2^prefix_length - 1) + (2^49 - 1), and
-      // |summand| is at most 255 << 56 (which is smaller than 2^63),
-      // so adding them can never overflow on uint64_t.
-      DCHECK_LE(value_, std::numeric_limits<uint64_t>::max() - summand);
-
-      value_ += summand;
-
-      // Decoding ends if continuation flag is not set.
-      if ((byte & 0x80) == 0) {
-        MarkDone();
-        return DecodeStatus::kDecodeDone;
-      }
-
-      offset_ += 7;
-    }
-
-    if (db->Empty()) {
-      return DecodeStatus::kDecodeInProgress;
-    }
-
-    DCHECK_EQ(kMaxOffset, offset_);
-
-    uint8_t byte = db->DecodeUInt8();
-    // No more extension bytes are allowed after this.
-    if ((byte & 0x80) == 0) {
-      uint64_t summand = byte & 0x7f;
-      // Check for overflow in left shift.
-      if (summand <= std::numeric_limits<uint64_t>::max() >> offset_) {
-        summand <<= offset_;
-        // Check for overflow in addition.
-        if (value_ <= std::numeric_limits<uint64_t>::max() - summand) {
-          value_ += summand;
-          MarkDone();
-          return DecodeStatus::kDecodeDone;
-        }
-      }
-    }
-
-    // Signal error if value is too large or there are too many extension bytes.
-    DLOG(WARNING) << "Variable length int encoding is too large or too long. "
-                  << DebugString();
-    MarkDone();
-    return DecodeStatus::kDecodeError;
-  }
-
-  // Old code path.  TODO(bnc): remove.
-  DCHECK(!decode_64_bits_);
-  const uint8_t kMaxOffset = 28;
+  // There can be at most 10 continuation bytes.  Offset is zero for the
+  // first one and increases by 7 for each subsequent one.
+  const uint8_t kMaxOffset = 63;
   CheckNotDone();
-  do {
+
+  // Process most extension bytes without the need for overflow checking.
+  while (offset_ < kMaxOffset) {
     if (db->Empty()) {
       return DecodeStatus::kDecodeInProgress;
     }
+
     uint8_t byte = db->DecodeUInt8();
-    if (offset_ == kMaxOffset && byte != 0)
-      break;
-    DCHECK(offset_ <= kMaxOffset - 7 || byte == 0);
-    // Shifting a 7 bit value to the left by at most 21 places can never
-    // overflow on uint32_t.  Shifting 0 to the left cannot overflow either.
-    value_ += (byte & 0x7f) << offset_;
+    uint64_t summand = byte & 0x7f;
+
+    // Shifting a 7 bit value to the left by at most 56 places can never
+    // overflow on uint64_t.
+    DCHECK_LE(offset_, 56);
+    DCHECK_LE(summand, std::numeric_limits<uint64_t>::max() >> offset_);
+
+    summand <<= offset_;
+
+    // At this point,
+    // |value_| is at most (2^prefix_length - 1) + (2^49 - 1), and
+    // |summand| is at most 255 << 56 (which is smaller than 2^63),
+    // so adding them can never overflow on uint64_t.
+    DCHECK_LE(value_, std::numeric_limits<uint64_t>::max() - summand);
+
+    value_ += summand;
+
+    // Decoding ends if continuation flag is not set.
     if ((byte & 0x80) == 0) {
       MarkDone();
       return DecodeStatus::kDecodeDone;
     }
+
     offset_ += 7;
-  } while (offset_ <= kMaxOffset);
+  }
+
+  if (db->Empty()) {
+    return DecodeStatus::kDecodeInProgress;
+  }
+
+  DCHECK_EQ(kMaxOffset, offset_);
+
+  uint8_t byte = db->DecodeUInt8();
+  // No more extension bytes are allowed after this.
+  if ((byte & 0x80) == 0) {
+    uint64_t summand = byte & 0x7f;
+    // Check for overflow in left shift.
+    if (summand <= std::numeric_limits<uint64_t>::max() >> offset_) {
+      summand <<= offset_;
+      // Check for overflow in addition.
+      if (value_ <= std::numeric_limits<uint64_t>::max() - summand) {
+        value_ += summand;
+        MarkDone();
+        return DecodeStatus::kDecodeDone;
+      }
+    }
+  }
+
+  // Signal error if value is too large or there are too many extension bytes.
   DLOG(WARNING) << "Variable length int encoding is too large or too long. "
                 << DebugString();
   MarkDone();
diff --git a/http2/hpack/varint/hpack_varint_decoder.h b/http2/hpack/varint/hpack_varint_decoder.h
index c793500..5c99b5c 100644
--- a/http2/hpack/varint/hpack_varint_decoder.h
+++ b/http2/hpack/varint/hpack_varint_decoder.h
@@ -13,23 +13,16 @@
 // For details of the encoding, see:
 //        http://httpwg.org/specs/rfc7541.html#integer.representation
 //
-// If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, then this
-// decoder supports decoding any integer that can be represented on uint64_t,
-// thereby exceeding the requirements for QPACK: "QPACK implementations MUST be
-// able to decode integers up to 62 bits long."  See
+// HpackVarintDecoder supports decoding any integer that can be represented on
+// uint64_t, thereby exceeding the requirements for QPACK: "QPACK
+// implementations MUST be able to decode integers up to 62 bits long."  See
 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.1.1
 //
-// If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is false, then this
-// decoder supports decoding integers up to 2^28 + 2^prefix_length - 2.
-//
 // This decoder supports at most 10 extension bytes (bytes following the prefix,
-// also called continuation bytes) if
-// GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, and at most 5
-// extension bytes if GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is
-// false.  An encoder is allowed to zero pad the encoded integer on the left,
-// thereby increasing the number of extension bytes.  If an encoder uses so much
-// padding that the number of extension bytes exceeds the limit, then this
-// decoder signals an error.
+// also called continuation bytes).  An encoder is allowed to zero pad the
+// encoded integer on the left, thereby increasing the number of extension
+// bytes.  If an encoder uses so much padding that the number of extension bytes
+// exceeds the limit, then this decoder signals an error.
 
 #ifndef QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
 #define QUICHE_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
@@ -41,7 +34,6 @@
 #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_status.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
-#include "net/third_party/quiche/src/http2/platform/api/http2_flags.h"
 #include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
 
 namespace http2 {
@@ -119,12 +111,6 @@
 #endif
   }
 
-  // If true, decode integers up to 2^64 - 1, and accept at most 10 extension
-  // bytes (some of which might be padding).
-  // If false, decode integers up to 2^28 + 2^prefix_length - 2, and accept at
-  // most 5 extension bytes (some of which might be padding).
-  bool decode_64_bits_ = GetHttp2ReloadableFlag(http2_varint_decode_64_bits);
-
   // These fields are initialized just to keep ASAN happy about reading
   // them from DebugString().
 
diff --git a/http2/hpack/varint/hpack_varint_decoder_test.cc b/http2/hpack/varint/hpack_varint_decoder_test.cc
index e36ad07..32a4a30 100644
--- a/http2/hpack/varint/hpack_varint_decoder_test.cc
+++ b/http2/hpack/varint/hpack_varint_decoder_test.cc
@@ -22,32 +22,13 @@
 namespace test {
 namespace {
 
-// Save previous value of flag and restore on destruction.
-class FlagSaver {
- public:
-  FlagSaver() = delete;
-  explicit FlagSaver(bool decode_64_bits)
-      : saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
-  }
-  ~FlagSaver() {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
-  }
-
- private:
-  const bool saved_value_;
-};
-
-class HpackVarintDecoderTest
-    : public RandomDecoderTest,
-      public ::testing::WithParamInterface<
-          ::testing::tuple<bool, uint8_t, const char*>> {
+class HpackVarintDecoderTest : public RandomDecoderTest,
+                               public ::testing::WithParamInterface<
+                                   ::testing::tuple<uint8_t, const char*>> {
  protected:
   HpackVarintDecoderTest()
-      : decode_64_bits_(::testing::get<0>(GetParam())),
-        high_bits_(::testing::get<1>(GetParam())),
-        suffix_(Http2HexDecode(::testing::get<2>(GetParam()))),
-        flag_saver_(decode_64_bits_),
+      : high_bits_(::testing::get<0>(GetParam())),
+        suffix_(Http2HexDecode(::testing::get<1>(GetParam()))),
         prefix_length_(0) {}
 
   void DecodeExpectSuccess(Http2StringPiece data,
@@ -81,8 +62,6 @@
     EXPECT_TRUE(Decode(data, prefix_length, validator));
   }
 
-  bool decode_64_bits() const { return decode_64_bits_; }
-
  private:
   AssertionResult Decode(Http2StringPiece data,
                          uint32_t prefix_length,
@@ -119,16 +98,11 @@
     return decoder_.Resume(b);
   }
 
-  // Test new or old behavior.
-  const bool decode_64_bits_;
   // Bits of the first byte not part of the prefix.
   const uint8_t high_bits_;
   // Extra bytes appended to the input.
   const Http2String suffix_;
 
-  // |flag_saver_| must preceed |decoder_| so that the flag is already set when
-  // |decoder_| is constructed.
-  FlagSaver flag_saver_;
   HpackVarintDecoder decoder_;
   uint8_t prefix_length_;
 };
@@ -137,15 +111,11 @@
     HpackVarintDecoderTest,
     HpackVarintDecoderTest,
     ::testing::Combine(
-        // Test both the new version (supporting 64 bit integers) and the old
-        // one (only supporting up to 2^28 + 2^prefix_length - 2.
-        ::testing::Bool(),
         // Bits of the first byte not part of the prefix should be ignored.
         ::testing::Values(0b00000000, 0b11111111, 0b10101010),
         // Extra bytes appended to the input should be ignored.
         ::testing::Values("", "00", "666f6f")));
 
-// Test data used when decode_64_bits() == true.
 struct {
   const char* data;
   uint32_t prefix_length;
@@ -289,124 +259,14 @@
     {"1f9a0a", 5, 1337},
 };
 
-// Test data used when decode_64_bits() == false.
-struct {
-  const char* data;
-  uint32_t prefix_length;
-  uint64_t expected_value;
-} kSuccessTestDataOld[] = {
-    // Zero value with different prefix lengths.
-    {"00", 3, 0},
-    {"00", 4, 0},
-    {"00", 5, 0},
-    {"00", 6, 0},
-    {"00", 7, 0},
-    // Small values that fit in the prefix.
-    {"06", 3, 6},
-    {"0d", 4, 13},
-    {"10", 5, 16},
-    {"29", 6, 41},
-    {"56", 7, 86},
-    // Values of 2^n-1, which have an all-zero extension byte.
-    {"0700", 3, 7},
-    {"0f00", 4, 15},
-    {"1f00", 5, 31},
-    {"3f00", 6, 63},
-    {"7f00", 7, 127},
-    // Values of 2^n-1, plus one extra byte of padding.
-    {"078000", 3, 7},
-    {"0f8000", 4, 15},
-    {"1f8000", 5, 31},
-    {"3f8000", 6, 63},
-    {"7f8000", 7, 127},
-    // Values requiring one extension byte.
-    {"0760", 3, 103},
-    {"0f2a", 4, 57},
-    {"1f7f", 5, 158},
-    {"3f02", 6, 65},
-    {"7f49", 7, 200},
-    // Values requiring one extension byte, plus one byte of padding.
-    {"07e000", 3, 103},
-    {"0faa00", 4, 57},
-    {"1fff00", 5, 158},
-    {"3f8200", 6, 65},
-    {"7fc900", 7, 200},
-    // Values requiring one extension byte, plus two bytes of padding.
-    {"07e08000", 3, 103},
-    {"0faa8000", 4, 57},
-    {"1fff8000", 5, 158},
-    {"3f828000", 6, 65},
-    {"7fc98000", 7, 200},
-    // Values requiring one extension byte, plus the maximum amount of padding.
-    {"07e080808000", 3, 103},
-    {"0faa80808000", 4, 57},
-    {"1fff80808000", 5, 158},
-    {"3f8280808000", 6, 65},
-    {"7fc980808000", 7, 200},
-    // Values requiring two extension bytes.
-    {"07b260", 3, 12345},
-    {"0f8a2a", 4, 5401},
-    {"1fa87f", 5, 16327},
-    {"3fd002", 6, 399},
-    {"7fff49", 7, 9598},
-    // Values requiring two extension bytes, plus one byte of padding.
-    {"07b2e000", 3, 12345},
-    {"0f8aaa00", 4, 5401},
-    {"1fa8ff00", 5, 16327},
-    {"3fd08200", 6, 399},
-    {"7fffc900", 7, 9598},
-    // Values requiring two extension bytes, plus the maximum amount of padding.
-    {"07b2e0808000", 3, 12345},
-    {"0f8aaa808000", 4, 5401},
-    {"1fa8ff808000", 5, 16327},
-    {"3fd082808000", 6, 399},
-    {"7fffc9808000", 7, 9598},
-    // Values requiring three extension bytes.
-    {"078ab260", 3, 1579281},
-    {"0fc18a2a", 4, 689488},
-    {"1fada87f", 5, 2085964},
-    {"3fa0d002", 6, 43103},
-    {"7ffeff49", 7, 1212541},
-    // Values requiring three extension bytes, plus one byte of padding.
-    {"078ab2e000", 3, 1579281},
-    {"0fc18aaa00", 4, 689488},
-    {"1fada8ff00", 5, 2085964},
-    {"3fa0d08200", 6, 43103},
-    {"7ffeffc900", 7, 1212541},
-    // Values requiring four extension bytes.
-    {"079f8ab260", 3, 202147110},
-    {"0fa2c18a2a", 4, 88252593},
-    {"1fd0ada87f", 5, 266999535},
-    {"3ff9a0d002", 6, 5509304},
-    {"7f9efeff49", 7, 155189149},
-    // Values requiring four extension bytes, plus one byte of padding.
-    {"079f8ab2e000", 3, 202147110},
-    {"0fa2c18aaa00", 4, 88252593},
-    {"1fd0ada8ff00", 5, 266999535},
-    {"3ff9a0d08200", 6, 5509304},
-    {"7f9efeffc900", 7, 155189149},
-    // Examples from RFC7541 C.1.
-    {"0a", 5, 10},
-    {"1f9a0a", 5, 1337},
-};
-
 TEST_P(HpackVarintDecoderTest, Success) {
-  if (decode_64_bits()) {
     for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestData); ++i) {
       DecodeExpectSuccess(Http2HexDecode(kSuccessTestData[i].data),
                           kSuccessTestData[i].prefix_length,
                           kSuccessTestData[i].expected_value);
     }
-  } else {
-    for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestDataOld); ++i) {
-      DecodeExpectSuccess(Http2HexDecode(kSuccessTestDataOld[i].data),
-                          kSuccessTestDataOld[i].prefix_length,
-                          kSuccessTestDataOld[i].expected_value);
-    }
-  }
 }
 
-// Test data used when decode_64_bits() == true.
 struct {
   const char* data;
   uint32_t prefix_length;
@@ -440,45 +300,11 @@
     {"7f80ffffffffffffffff8100", 7},
     {"ff80feffffffffffffff8100", 8}};
 
-// Test data used when decode_64_bits() == false.
-// In this mode, HpackVarintDecoder allows at most five extension bytes,
-// and fifth extension byte must be zero.
-struct {
-  const char* data;
-  uint32_t prefix_length;
-} kErrorTestDataOld[] = {
-    // Maximum number of extension bytes but last byte is non-zero.
-    {"078080808001", 3},
-    {"0f8080808001", 4},
-    {"1f8080808001", 5},
-    {"3f8080808001", 6},
-    {"7f8080808001", 7},
-    // Too many extension bytes, all 0s (except for extension bit in each byte).
-    {"078080808080", 3},
-    {"0f8080808080", 4},
-    {"1f8080808080", 5},
-    {"3f8080808080", 6},
-    {"7f8080808080", 7},
-    // Too many extension bytes, all 1s.
-    {"07ffffffffff", 3},
-    {"0fffffffffff", 4},
-    {"1fffffffffff", 5},
-    {"3fffffffffff", 6},
-    {"7fffffffffff", 7},
-};
-
 TEST_P(HpackVarintDecoderTest, Error) {
-  if (decode_64_bits()) {
     for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestData); ++i) {
       DecodeExpectError(Http2HexDecode(kErrorTestData[i].data),
                         kErrorTestData[i].prefix_length);
     }
-  } else {
-    for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestDataOld); ++i) {
-      DecodeExpectError(Http2HexDecode(kErrorTestDataOld[i].data),
-                        kErrorTestDataOld[i].prefix_length);
-    }
-  }
 }
 
 }  // namespace
diff --git a/http2/hpack/varint/hpack_varint_round_trip_test.cc b/http2/hpack/varint/hpack_varint_round_trip_test.cc
index 3299d5e..cd26553 100644
--- a/http2/hpack/varint/hpack_varint_round_trip_test.cc
+++ b/http2/hpack/varint/hpack_varint_round_trip_test.cc
@@ -22,29 +22,11 @@
 
 using ::testing::AssertionFailure;
 using ::testing::AssertionSuccess;
-using ::testing::Bool;
-using ::testing::WithParamInterface;
 
 namespace http2 {
 namespace test {
 namespace {
 
-// Save previous value of flag and restore on destruction.
-class FlagSaver {
- public:
-  FlagSaver() = delete;
-  explicit FlagSaver(bool decode_64_bits)
-      : saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
-  }
-  ~FlagSaver() {
-    SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
-  }
-
- private:
-  const bool saved_value_;
-};
-
 // Returns the highest value with the specified number of extension bytes
 // and the specified prefix length (bits).
 uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
@@ -53,13 +35,9 @@
          (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
 }
 
-class HpackVarintRoundTripTest : public RandomDecoderTest,
-                                 public WithParamInterface<bool> {
+class HpackVarintRoundTripTest : public RandomDecoderTest {
  protected:
-  HpackVarintRoundTripTest()
-      : decode_64_bits_(GetParam()),
-        flag_saver_(decode_64_bits_),
-        prefix_length_(0) {}
+  HpackVarintRoundTripTest() : prefix_length_(0) {}
 
   DecodeStatus StartDecoding(DecodeBuffer* b) override {
     CHECK_LT(0u, b->Remaining());
@@ -260,22 +238,14 @@
     EncodeAndDecodeValues(values, prefix_length, expected_bytes);
   }
 
-  // |flag_saver_| must preceed |decoder_| so that the flag is already set when
-  // |decoder_| is constructed.
-  const bool decode_64_bits_;
-  FlagSaver flag_saver_;
   HpackVarintDecoder decoder_;
   Http2String buffer_;
   uint8_t prefix_length_;
 };
 
-INSTANTIATE_TEST_CASE_P(HpackVarintRoundTripTest,
-                        HpackVarintRoundTripTest,
-                        Bool());
-
 // To help me and future debuggers of varint encodings, this LOGs out the
 // transition points where a new extension byte is added.
-TEST_P(HpackVarintRoundTripTest, Encode) {
+TEST_F(HpackVarintRoundTripTest, Encode) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
     const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
@@ -300,19 +270,13 @@
         b - 1, b, b + 1, b + 2, b + 3,  // Force line break.
         c - 1, c, c + 1, c + 2, c + 3,  // Force line break.
         d - 1, d, d + 1, d + 2, d + 3,  // Force line break.
-        e - 1, e, e + 1, e + 2, e + 3   // Force line break.
+        e - 1, e, e + 1, e + 2, e + 3,  // Force line break.
+        f - 1, f, f + 1, f + 2, f + 3,  // Force line break.
+        g - 1, g, g + 1, g + 2, g + 3,  // Force line break.
+        h - 1, h, h + 1, h + 2, h + 3,  // Force line break.
+        i - 1, i, i + 1, i + 2, i + 3,  // Force line break.
+        j - 1, j, j + 1, j + 2, j + 3,  // Force line break.
     };
-    if (decode_64_bits_) {
-      for (auto value : {
-               f - 1, f, f + 1, f + 2, f + 3,  // Force line break.
-               g - 1, g, g + 1, g + 2, g + 3,  // Force line break.
-               h - 1, h, h + 1, h + 2, h + 3,  // Force line break.
-               i - 1, i, i + 1, i + 2, i + 3,  // Force line break.
-               j - 1, j, j + 1, j + 2, j + 3,  // Force line break.
-           }) {
-        values.push_back(value);
-      }
-    }
 
     for (uint64_t value : values) {
       EncodeNoRandom(value, prefix_length);
@@ -323,7 +287,7 @@
   }
 }
 
-TEST_P(HpackVarintRoundTripTest, FromSpec1337) {
+TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
   DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a"));
   uint32_t prefix_length = 5;
   uint8_t p = b.DecodeUInt8();
@@ -340,7 +304,7 @@
 }
 
 // Test all the values that fit into the prefix (one less than the mask).
-TEST_P(HpackVarintRoundTripTest, ValidatePrefixOnly) {
+TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint8_t prefix_mask = (1 << prefix_length) - 1;
     EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
@@ -348,7 +312,7 @@
 }
 
 // Test all values that require exactly 1 extension byte.
-TEST_P(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
+TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
     EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
@@ -356,7 +320,7 @@
 }
 
 // Test *some* values that require exactly 2 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
     const uint64_t range = 127 << 7;
@@ -366,7 +330,7 @@
 }
 
 // Test *some* values that require 3 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
     const uint64_t range = 127 << 14;
@@ -376,7 +340,7 @@
 }
 
 // Test *some* values that require 4 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
+TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
     const uint64_t range = 127 << 21;
@@ -386,11 +350,7 @@
 }
 
 // Test *some* values that require 5 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
     const uint64_t range = 127llu << 28;
@@ -400,11 +360,7 @@
 }
 
 // Test *some* values that require 6 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
     const uint64_t range = 127llu << 35;
@@ -414,11 +370,7 @@
 }
 
 // Test *some* values that require 7 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
     const uint64_t range = 127llu << 42;
@@ -428,11 +380,7 @@
 }
 
 // Test *some* values that require 8 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
     const uint64_t range = 127llu << 49;
@@ -442,11 +390,7 @@
 }
 
 // Test *some* values that require 9 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
     const uint64_t range = 127llu << 56;
@@ -456,11 +400,7 @@
 }
 
 // Test *some* values that require 10 extension bytes.
-TEST_P(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
-  if (!decode_64_bits_) {
-    return;
-  }
-
+TEST_F(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
   for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
     const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
     const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
@@ -469,45 +409,6 @@
   }
 }
 
-// Test the value one larger than the largest that can be decoded.
-TEST_P(HpackVarintRoundTripTest, ValueTooLarge) {
-  // New implementation can decode any integer that HpackVarintEncoder can
-  // encode.
-  if (decode_64_bits_) {
-    return;
-  }
-
-  for (prefix_length_ = 3; prefix_length_ <= 8; ++prefix_length_) {
-    const uint64_t too_large = (1 << 28) + (1 << prefix_length_) - 1;
-    const uint32_t expected_offset = 6;
-    HpackBlockBuilder bb;
-    bb.AppendHighBitsAndVarint(0, prefix_length_, too_large);
-    buffer_ = bb.buffer();
-
-    // The validator is called after each of the several times that the input
-    // DecodeBuffer is decoded, each with a different segmentation of the input.
-    // Validate that decoder_.value() matches the expected value.
-    bool validated = false;
-    Validator validator = [&validated, expected_offset](
-                              const DecodeBuffer& db,
-                              DecodeStatus status) -> AssertionResult {
-      validated = true;
-      VERIFY_EQ(DecodeStatus::kDecodeError, status);
-      VERIFY_EQ(expected_offset, db.Offset());
-      return AssertionSuccess();
-    };
-
-    // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
-    // can call Start with the prefix byte.
-    bool return_non_zero_on_first = true;
-    DecodeBuffer b(buffer_);
-    EXPECT_TRUE(
-        DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
-    EXPECT_EQ(expected_offset, b.Offset());
-    EXPECT_TRUE(validated);
-  }
-}
-
 }  // namespace
 }  // namespace test
 }  // namespace http2
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc
index b1c470c..d16050b 100644
--- a/quic/core/chlo_extractor_test.cc
+++ b/quic/core/chlo_extractor_test.cc
@@ -52,7 +52,7 @@
     header_.version = AllSupportedVersions().front();
     header_.reset_flag = false;
     header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
-    header_.packet_number = 1;
+    header_.packet_number = QuicPacketNumber(1);
   }
 
   void MakePacket(const QuicStreamFrame& stream_frame) {
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc
index 47d55d6..c60eaa2 100644
--- a/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -18,9 +18,7 @@
       total_bytes_sent_at_last_acked_packet_(0),
       last_acked_packet_sent_time_(QuicTime::Zero()),
       last_acked_packet_ack_time_(QuicTime::Zero()),
-      last_sent_packet_(0),
       is_app_limited_(false),
-      end_of_app_limited_phase_(0),
       connection_state_map_() {}
 
 BandwidthSampler::~BandwidthSampler() {}
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc
index 4203686..e9b74c7 100644
--- a/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -40,54 +40,55 @@
   BandwidthSampler sampler_;
   QuicByteCount bytes_in_flight_;
 
-  void SendPacketInner(QuicPacketNumber packet_number,
+  void SendPacketInner(uint64_t packet_number,
                        QuicByteCount bytes,
                        HasRetransmittableData has_retransmittable_data) {
-    sampler_.OnPacketSent(clock_.Now(), packet_number, bytes, bytes_in_flight_,
-                          has_retransmittable_data);
+    sampler_.OnPacketSent(clock_.Now(), QuicPacketNumber(packet_number), bytes,
+                          bytes_in_flight_, has_retransmittable_data);
     if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA) {
       bytes_in_flight_ += bytes;
     }
   }
 
-  void SendPacket(QuicPacketNumber packet_number) {
+  void SendPacket(uint64_t packet_number) {
     SendPacketInner(packet_number, kRegularPacketSize,
                     HAS_RETRANSMITTABLE_DATA);
   }
 
-  BandwidthSample AckPacketInner(QuicPacketNumber packet_number) {
-    QuicByteCount size =
-        BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
+  BandwidthSample AckPacketInner(uint64_t packet_number) {
+    QuicByteCount size = BandwidthSamplerPeer::GetPacketSize(
+        sampler_, QuicPacketNumber(packet_number));
     bytes_in_flight_ -= size;
-    return sampler_.OnPacketAcknowledged(clock_.Now(), packet_number);
+    return sampler_.OnPacketAcknowledged(clock_.Now(),
+                                         QuicPacketNumber(packet_number));
   }
 
   // Acknowledge receipt of a packet and expect it to be not app-limited.
-  QuicBandwidth AckPacket(QuicPacketNumber packet_number) {
+  QuicBandwidth AckPacket(uint64_t packet_number) {
     BandwidthSample sample = AckPacketInner(packet_number);
     EXPECT_FALSE(sample.is_app_limited);
     return sample.bandwidth;
   }
 
-  void LosePacket(QuicPacketNumber packet_number) {
-    QuicByteCount size =
-        BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
+  void LosePacket(uint64_t packet_number) {
+    QuicByteCount size = BandwidthSamplerPeer::GetPacketSize(
+        sampler_, QuicPacketNumber(packet_number));
     bytes_in_flight_ -= size;
-    sampler_.OnPacketLost(packet_number);
+    sampler_.OnPacketLost(QuicPacketNumber(packet_number));
   }
 
   // Sends one packet and acks it.  Then, send 20 packets.  Finally, send
   // another 20 packets while acknowledging previous 20.
   void Send40PacketsAndAckFirst20(QuicTime::Delta time_between_packets) {
     // Send 20 packets at a constant inter-packet time.
-    for (QuicPacketNumber i = 1; i <= 20; i++) {
+    for (int i = 1; i <= 20; i++) {
       SendPacket(i);
       clock_.AdvanceTime(time_between_packets);
     }
 
     // Ack packets 1 to 20, while sending new packets at the same rate as
     // before.
-    for (QuicPacketNumber i = 1; i <= 20; i++) {
+    for (int i = 1; i <= 20; i++) {
       AckPacket(i);
       SendPacket(i + 20);
       clock_.AdvanceTime(time_between_packets);
@@ -102,7 +103,7 @@
       QuicBandwidth::FromBytesPerSecond(kRegularPacketSize * 100);
 
   // Send packets at the constant bandwidth.
-  for (QuicPacketNumber i = 1; i < 20; i++) {
+  for (int i = 1; i < 20; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
     QuicBandwidth current_sample = AckPacket(i);
@@ -110,7 +111,7 @@
   }
 
   // Send packets at the exponentially decreasing bandwidth.
-  for (QuicPacketNumber i = 20; i < 25; i++) {
+  for (int i = 20; i < 25; i++) {
     time_between_packets = time_between_packets * 2;
     expected_bandwidth = expected_bandwidth * 0.5;
 
@@ -135,7 +136,7 @@
 
   // Ack the packets 21 to 40, arriving at the correct bandwidth.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -152,14 +153,14 @@
       QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize) * 0.5;
 
   // Send 20 packets, each 1 ms apart.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
 
   // Ack packets 1 to 20, losing every even-numbered packet, while sending new
   // packets at the same rate as before.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     if (i % 2 == 0) {
       AckPacket(i);
     } else {
@@ -171,7 +172,7 @@
 
   // Ack the packets 21 to 40 with the same loss pattern.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     if (i % 2 == 0) {
       last_bandwidth = AckPacket(i);
       EXPECT_EQ(expected_bandwidth, last_bandwidth);
@@ -196,7 +197,7 @@
 
   // Send 20 packets, each 1 ms apart. Every even packet is not congestion
   // controlled.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     SendPacketInner(
         i, kRegularPacketSize,
         i % 2 == 0 ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA);
@@ -208,7 +209,7 @@
 
   // Ack packets 2 to 21, ignoring every even-numbered packet, while sending new
   // packets at the same rate as before.
-  for (QuicPacketNumber i = 1; i <= 20; i++) {
+  for (int i = 1; i <= 20; i++) {
     if (i % 2 == 0) {
       AckPacket(i);
     }
@@ -220,7 +221,7 @@
 
   // Ack the packets 22 to 41 with the same congestion controlled pattern.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     if (i % 2 == 0) {
       last_bandwidth = AckPacket(i);
       EXPECT_EQ(expected_bandwidth, last_bandwidth);
@@ -251,7 +252,7 @@
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
   QuicTime::Delta ridiculously_small_time_delta =
       QuicTime::Delta::FromMicroseconds(20);
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     last_bandwidth = AckPacket(i);
     clock_.AdvanceTime(ridiculously_small_time_delta);
   }
@@ -272,7 +273,7 @@
   // Ack the packets 21 to 40 in the reverse order, while sending packets 41 to
   // 60.
   QuicBandwidth last_bandwidth = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 0; i < 20; i++) {
+  for (int i = 0; i < 20; i++) {
     last_bandwidth = AckPacket(40 - i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     SendPacket(41 + i);
@@ -280,7 +281,7 @@
   }
 
   // Ack the packets 41 to 60, now in the regular order.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -301,7 +302,7 @@
   // We are now app-limited. Ack 21 to 40 as usual, but do not send anything for
   // now.
   sampler_.OnAppLimited();
-  for (QuicPacketNumber i = 21; i <= 40; i++) {
+  for (int i = 21; i <= 40; i++) {
     QuicBandwidth current_sample = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, current_sample);
     clock_.AdvanceTime(time_between_packets);
@@ -311,14 +312,14 @@
   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
 
   // Send packets 41 to 60, all of which would be marked as app-limited.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
 
   // Ack packets 41 to 60, while sending packets 61 to 80.  41 to 60 should be
   // app-limited and underestimate the bandwidth due to that.
-  for (QuicPacketNumber i = 41; i <= 60; i++) {
+  for (int i = 41; i <= 60; i++) {
     BandwidthSample sample = AckPacketInner(i);
     EXPECT_TRUE(sample.is_app_limited);
     EXPECT_LT(sample.bandwidth, 0.7f * expected_bandwidth);
@@ -329,7 +330,7 @@
 
   // Run out of packets, and then ack packet 61 to 80, all of which should have
   // correct non-app-limited samples.
-  for (QuicPacketNumber i = 61; i <= 80; i++) {
+  for (int i = 61; i <= 80; i++) {
     QuicBandwidth last_bandwidth = AckPacket(i);
     EXPECT_EQ(expected_bandwidth, last_bandwidth);
     clock_.AdvanceTime(time_between_packets);
@@ -349,7 +350,7 @@
   const QuicBandwidth real_bandwidth =
       QuicBandwidth::FromBytesAndTimeDelta(num_bytes, rtt);
 
-  for (QuicPacketNumber i = 1; i <= 10; i++) {
+  for (int i = 1; i <= 10; i++) {
     SendPacket(i);
     clock_.AdvanceTime(time_between_packets);
   }
@@ -357,7 +358,7 @@
   clock_.AdvanceTime(rtt - num_packets * time_between_packets);
 
   QuicBandwidth last_sample = QuicBandwidth::Zero();
-  for (QuicPacketNumber i = 1; i <= 10; i++) {
+  for (int i = 1; i <= 10; i++) {
     QuicBandwidth sample = AckPacket(i);
     EXPECT_GT(sample, last_sample);
     last_sample = sample;
@@ -385,9 +386,9 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
 
   EXPECT_EQ(5u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
-  sampler_.RemoveObsoletePackets(4);
+  sampler_.RemoveObsoletePackets(QuicPacketNumber(4));
   EXPECT_EQ(2u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
-  sampler_.OnPacketLost(4);
+  sampler_.OnPacketLost(QuicPacketNumber(4));
   EXPECT_EQ(1u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
   AckPacket(5);
   EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index 81931a1..6a7fe2b 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -87,8 +87,6 @@
       random_(random),
       mode_(STARTUP),
       round_trip_count_(0),
-      last_sent_packet_(0),
-      current_round_trip_end_(0),
       max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0),
       max_ack_height_(kBandwidthWindowSize, 0, 0),
       aggregation_epoch_start_time_(QuicTime::Zero()),
@@ -122,14 +120,12 @@
       has_non_app_limited_sample_(false),
       flexible_app_limited_(false),
       recovery_state_(NOT_IN_RECOVERY),
-      end_recovery_at_(0),
       recovery_window_(max_congestion_window_),
       is_app_limited_recovery_(false),
       slower_startup_(false),
       rate_based_startup_(false),
       startup_rate_reduction_multiplier_(0),
       startup_bytes_lost_(0),
-      initial_conservation_in_startup_(CONSERVATION),
       enable_ack_aggregation_during_startup_(false),
       expire_ack_aggregation_in_startup_(false),
       drain_to_target_(false),
@@ -263,12 +259,6 @@
   if (config.HasClientRequestedIndependentOption(kBBS1, perspective)) {
     rate_based_startup_ = true;
   }
-  if (config.HasClientRequestedIndependentOption(kBBS2, perspective)) {
-    initial_conservation_in_startup_ = MEDIUM_GROWTH;
-  }
-  if (config.HasClientRequestedIndependentOption(kBBS3, perspective)) {
-    initial_conservation_in_startup_ = GROWTH;
-  }
   if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) &&
       config.HasClientRequestedIndependentOption(kBBS4, perspective)) {
     rate_based_startup_ = true;
@@ -467,7 +457,8 @@
 }
 
 bool BbrSender::UpdateRoundTripCounter(QuicPacketNumber last_acked_packet) {
-  if (last_acked_packet > current_round_trip_end_) {
+  if (!current_round_trip_end_.IsInitialized() ||
+      last_acked_packet > current_round_trip_end_) {
     round_trip_count_++;
     current_round_trip_end_ = last_sent_packet_;
     return true;
@@ -677,9 +668,6 @@
       // Enter conservation on the first loss.
       if (has_losses) {
         recovery_state_ = CONSERVATION;
-        if (mode_ == STARTUP) {
-          recovery_state_ = initial_conservation_in_startup_;
-        }
         // This will cause the |recovery_window_| to be set to the correct
         // value in CalculateRecoveryWindow().
         recovery_window_ = 0;
@@ -695,7 +683,6 @@
       break;
 
     case CONSERVATION:
-    case MEDIUM_GROWTH:
       if (is_round_start) {
         recovery_state_ = GROWTH;
       }
@@ -759,7 +746,7 @@
     return;
   }
   // Slow the pacing rate in STARTUP once loss has ever been detected.
-  const bool has_ever_detected_loss = end_recovery_at_ > 0;
+  const bool has_ever_detected_loss = end_recovery_at_.IsInitialized();
   if (slower_startup_ && has_ever_detected_loss &&
       has_non_app_limited_sample_) {
     pacing_rate_ = kStartupAfterLossGain * BandwidthEstimate();
@@ -848,11 +835,8 @@
 
   // In CONSERVATION mode, just subtracting losses is sufficient.  In GROWTH,
   // release additional |bytes_acked| to achieve a slow-start-like behavior.
-  // In MEDIUM_GROWTH, release |bytes_acked| / 2 to split the difference.
   if (recovery_state_ == GROWTH) {
     recovery_window_ += bytes_acked;
-  } else if (recovery_state_ == MEDIUM_GROWTH) {
-    recovery_window_ += bytes_acked / 2;
   }
 
   // Sanity checks.  Ensure that we always allow to send at least an MSS or
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h
index 0ee730c..37e2695 100644
--- a/quic/core/congestion_control/bbr_sender.h
+++ b/quic/core/congestion_control/bbr_sender.h
@@ -58,8 +58,6 @@
     NOT_IN_RECOVERY,
     // Allow an extra outstanding byte for each byte acknowledged.
     CONSERVATION,
-    // Allow 1.5 extra outstanding bytes for each byte acknowledged.
-    MEDIUM_GROWTH,
     // Allow two extra outstanding bytes for each byte acknowledged (slow
     // start).
     GROWTH
@@ -265,7 +263,7 @@
   QuicPacketNumber last_sent_packet_;
   // Acknowledgement of any packet after |current_round_trip_end_| will cause
   // the round trip counter to advance.
-  QuicPacketCount current_round_trip_end_;
+  QuicPacketNumber current_round_trip_end_;
 
   // The filter that tracks the maximum bandwidth over the multiple recent
   // round-trips.
@@ -375,8 +373,6 @@
   // Sum of bytes lost in STARTUP.
   QuicByteCount startup_bytes_lost_;
 
-  // Used as the initial packet conservation mode when first entering recovery.
-  RecoveryState initial_conservation_in_startup_;
   // When true, add the most recent ack aggregation measurement during STARTUP.
   bool enable_ack_aggregation_during_startup_;
   // When true, expire the windowed ack aggregation values in STARTUP when
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc
index bc7fc76..e0d5867 100644
--- a/quic/core/congestion_control/bbr_sender_test.cc
+++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -515,97 +515,6 @@
   ASSERT_TRUE(simulator_result);
 }
 
-// Ensures the code transitions loss recovery states correctly when in STARTUP
-// and the BBS2 connection option is used.
-// (NOT_IN_RECOVERY -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY).
-TEST_F(BbrSenderTest, StartupMediumRecoveryStates) {
-  // Set seed to the position where the gain cycling causes the sender go
-  // into conservation upon entering PROBE_BW.
-  //
-  // TODO(vasilvv): there should be a better way to test this.
-  random_.set_seed(UINT64_C(14719894707049085006));
-
-  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
-  bool simulator_result;
-  CreateSmallBufferSetup();
-  SetConnectionOption(kBBS2);
-
-  bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::NOT_IN_RECOVERY;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::MEDIUM_GROWTH,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::MEDIUM_GROWTH;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH;
-      },
-      timeout);
-
-  ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-  ASSERT_TRUE(simulator_result);
-}
-
-// Ensures the code transitions loss recovery states correctly when in STARTUP
-// and the BBS3 connection option is used.
-// (NOT_IN_RECOVERY -> GROWTH -> NOT_IN_RECOVERY).
-TEST_F(BbrSenderTest, StartupGrowthRecoveryStates) {
-  // Set seed to the position where the gain cycling causes the sender go
-  // into conservation upon entering PROBE_BW.
-  //
-  // TODO(vasilvv): there should be a better way to test this.
-  random_.set_seed(UINT64_C(14719894707049085006));
-
-  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
-  bool simulator_result;
-  CreateSmallBufferSetup();
-  SetConnectionOption(kBBS3);
-
-  bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state !=
-               BbrSender::NOT_IN_RECOVERY;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state);
-
-  simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() {
-        return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH;
-      },
-      timeout);
-  ASSERT_TRUE(simulator_result);
-
-  ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
-  ASSERT_TRUE(simulator_result);
-}
-
 // Verify the behavior of the algorithm in the case when the connection sends
 // small bursts of data after sending continuously for a while.
 TEST_F(BbrSenderTest, ApplicationLimitedBursts) {
@@ -1185,7 +1094,7 @@
   QuicBandwidth pacing_rate = original_pacing_rate;
   const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(0, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(), kMaxPacketSize));
   QuicPacketNumber largest_sent =
       bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
   for (QuicPacketNumber packet_number =
@@ -1235,7 +1144,7 @@
   QuicBandwidth pacing_rate = original_pacing_rate;
   const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(0, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(), kMaxPacketSize));
   QuicPacketNumber largest_sent =
       bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
   for (QuicPacketNumber packet_number =
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 7250940..27a3ab8 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -31,7 +31,6 @@
 
 GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
     : loss_detection_timeout_(QuicTime::Zero()),
-      largest_lost_(0),
       least_in_flight_(1),
       faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) {
   SetLossDetectionType(loss_type);
@@ -39,7 +38,7 @@
 
 void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) {
   loss_detection_timeout_ = QuicTime::Zero();
-  largest_sent_on_spurious_retransmit_ = kInvalidPacketNumber;
+  largest_sent_on_spurious_retransmit_.Clear();
   loss_type_ = loss_type;
   reordering_shift_ = loss_type == kAdaptiveTime
                           ? kDefaultAdaptiveLossDelayShift
@@ -49,7 +48,7 @@
     QUIC_RELOADABLE_FLAG_COUNT(quic_eighth_rtt_loss_detection);
     reordering_shift_ = 3;
   }
-  largest_previously_acked_ = kInvalidPacketNumber;
+  largest_previously_acked_.Clear();
 }
 
 LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const {
@@ -91,7 +90,7 @@
   QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
   auto it = unacked_packets.begin();
   if (faster_detect_loss_) {
-    if (least_in_flight_ >= packet_number) {
+    if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
       if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) {
         QUIC_BUG << "least_in_flight: " << least_in_flight_
                  << " is greater than largest_sent_packet + 1: "
@@ -103,9 +102,9 @@
       }
     }
     // Clear least_in_flight_.
-    least_in_flight_ = kInvalidPacketNumber;
+    least_in_flight_.Clear();
   } else {
-    if (largest_lost_ >= packet_number) {
+    if (largest_lost_.IsInitialized() && largest_lost_ >= packet_number) {
       if (largest_lost_ > unacked_packets.largest_sent_packet()) {
         QUIC_BUG << "largest_lost: " << largest_lost_
                  << " is greater than largest_sent_packet: "
@@ -132,7 +131,8 @@
     } else if (loss_type_ == kLazyFack) {
       // Require two in order acks to invoke FACK, which avoids spuriously
       // retransmitting packets when one packet is reordered by a large amount.
-      if (largest_newly_acked > largest_previously_acked_ &&
+      if (largest_previously_acked_.IsInitialized() &&
+          largest_newly_acked > largest_previously_acked_ &&
           largest_previously_acked_ > packet_number &&
           largest_previously_acked_ - packet_number >=
               (kNumberOfNacksBeforeRetransmission - 1)) {
@@ -150,7 +150,7 @@
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
         loss_detection_timeout_ = when_lost;
-        if (least_in_flight_ == kInvalidPacketNumber) {
+        if (!least_in_flight_.IsInitialized()) {
           // At this point, packet_number is in flight and not detected as lost.
           least_in_flight_ = packet_number;
         }
@@ -166,18 +166,19 @@
       packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
       continue;
     }
-    if (least_in_flight_ == kInvalidPacketNumber) {
+    if (!least_in_flight_.IsInitialized()) {
       // At this point, packet_number is in flight and not detected as lost.
       least_in_flight_ = packet_number;
     }
   }
-  if (least_in_flight_ == kInvalidPacketNumber) {
+  if (!least_in_flight_.IsInitialized()) {
     // There is no in flight packet.
     least_in_flight_ = largest_newly_acked + 1;
   }
   largest_previously_acked_ = largest_newly_acked;
   if (!packets_lost->empty()) {
-    DCHECK_LT(largest_lost_, packets_lost->back().packet_number);
+    DCHECK(!largest_lost_.IsInitialized() ||
+           largest_lost_ < packets_lost->back().packet_number);
     largest_lost_ = packets_lost->back().packet_number;
   }
 }
@@ -212,7 +213,8 @@
     return;
   }
 
-  if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
+  if (largest_sent_on_spurious_retransmit_.IsInitialized() &&
+      spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
     return;
   }
   largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet();
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 7a8ec67..2cd19a7 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -31,37 +31,43 @@
 
   ~GeneralLossAlgorithmTest() override {}
 
-  void SendDataPacket(QuicPacketNumber packet_number) {
+  void SendDataPacket(uint64_t packet_number) {
     QuicStreamFrame frame;
     frame.stream_id = QuicUtils::GetHeadersStreamId(
         CurrentSupportedVersions()[0].transport_version);
-    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, false, false);
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            false, false);
     packet.retransmittable_frames.push_back(QuicFrame(frame));
-    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
-                                   true);
+    unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                   NOT_RETRANSMISSION, clock_.Now(), true);
   }
 
-  void SendAckPacket(QuicPacketNumber packet_number) {
-    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, true, false);
-    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
-                                   false);
+  void SendAckPacket(uint64_t packet_number) {
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            true, false);
+    unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                   NOT_RETRANSMISSION, clock_.Now(), false);
   }
 
-  void VerifyLosses(QuicPacketNumber largest_newly_acked,
+  void VerifyLosses(uint64_t largest_newly_acked,
                     const AckedPacketVector& packets_acked,
-                    const std::vector<QuicPacketNumber>& losses_expected) {
-    if (largest_newly_acked > unacked_packets_.largest_acked()) {
-      unacked_packets_.IncreaseLargestAcked(largest_newly_acked);
+                    const std::vector<uint64_t>& losses_expected) {
+    if (!unacked_packets_.largest_acked().IsInitialized() ||
+        QuicPacketNumber(largest_newly_acked) >
+            unacked_packets_.largest_acked()) {
+      unacked_packets_.IncreaseLargestAcked(
+          QuicPacketNumber(largest_newly_acked));
     }
     LostPacketVector lost_packets;
     loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
-                                 largest_newly_acked, packets_acked,
-                                 &lost_packets);
+                                 QuicPacketNumber(largest_newly_acked),
+                                 packets_acked, &lost_packets);
     ASSERT_EQ(losses_expected.size(), lost_packets.size());
     for (size_t i = 0; i < losses_expected.size(); ++i) {
-      EXPECT_EQ(lost_packets[i].packet_number, losses_expected[i]);
+      EXPECT_EQ(lost_packets[i].packet_number,
+                QuicPacketNumber(losses_expected[i]));
     }
   }
 
@@ -79,18 +85,21 @@
   }
   AckedPacketVector packets_acked;
   // No loss on one ack.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // No loss on two acks.
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Loss on three acks.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -105,12 +114,15 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -124,8 +136,9 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -138,9 +151,10 @@
   }
   AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
@@ -162,9 +176,9 @@
   AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and 1.25 RTTs have
   // elapsed since the packets were sent.
-  unacked_packets_.RemoveFromInFlight(kNumSentPackets);
-  packets_acked.push_back(
-      AckedPacket(kNumSentPackets, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(kNumSentPackets));
+  packets_acked.push_back(AckedPacket(QuicPacketNumber(kNumSentPackets),
+                                      kMaxPacketSize, QuicTime::Zero()));
   // This simulates a single ack following multiple missing packets with FACK.
   VerifyLosses(kNumSentPackets, packets_acked, {1, 2});
   packets_acked.clear();
@@ -190,14 +204,15 @@
   }
   AckedPacketVector packets_acked;
   // Neuter packet 1.
-  unacked_packets_.RemoveRetransmittability(1);
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(1));
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
 
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 }
@@ -211,10 +226,11 @@
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
 
   // Early retransmit when the final packet gets acked and the first is nacked.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
@@ -237,9 +253,10 @@
   AckedPacketVector packets_acked;
   // Wait another RTT and ack 2.
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(2, packets_acked, {1});
 }
 
@@ -253,18 +270,21 @@
   }
   AckedPacketVector packets_acked;
   // No loss on one ack.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // No loss on two acks.
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Loss on three acks.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -281,19 +301,23 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(3);
-  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(3), kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 will be lost.
-  unacked_packets_.RemoveFromInFlight(5);
-  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(5), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(5, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -308,15 +332,17 @@
   }
   AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
-  unacked_packets_.RemoveFromInFlight(4);
-  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(4), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 and 2 will be lost.
-  unacked_packets_.RemoveFromInFlight(5);
-  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(5), kMaxPacketSize, QuicTime::Zero()));
   VerifyLosses(5, packets_acked, {1, 2});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -330,10 +356,11 @@
     SendDataPacket(i);
   }
   AckedPacketVector packets_acked;
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
   for (size_t i = 1; i < 500; ++i) {
-    VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+    VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
     packets_acked.clear();
   }
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
@@ -357,9 +384,10 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -370,7 +398,7 @@
     EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
               loss_algorithm_.GetLossTimeout() - clock_.Now());
   }
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -388,16 +416,17 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost without a nack.
-  unacked_packets_.RemoveFromInFlight(1);
-  packets_acked.push_back(AckedPacket(1, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(1), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // The timer should still not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<uint64_t>{});
 
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -414,9 +443,10 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(10);
-  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(10));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(10), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -445,9 +475,10 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
 
-  unacked_packets_.RemoveFromInFlight(10);
-  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(10));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(10), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
@@ -461,10 +492,11 @@
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets
   // are lost.
-  for (QuicPacketNumber i = 1; i <= 9; ++i) {
-    unacked_packets_.RemoveFromInFlight(i);
-    packets_acked.push_back(AckedPacket(i, kMaxPacketSize, QuicTime::Zero()));
-    VerifyLosses(i, packets_acked, std::vector<QuicPacketNumber>{});
+  for (uint64_t i = 1; i <= 9; ++i) {
+    unacked_packets_.RemoveFromInFlight(QuicPacketNumber(i));
+    packets_acked.push_back(
+        AckedPacket(QuicPacketNumber(i), kMaxPacketSize, QuicTime::Zero()));
+    VerifyLosses(i, packets_acked, std::vector<uint64_t>{});
     packets_acked.clear();
     EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   }
@@ -484,14 +516,15 @@
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Packet 1 should not be lost until 1/16 RTTs pass.
-  unacked_packets_.RemoveFromInFlight(2);
-  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  packets_acked.push_back(
+      AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   packets_acked.clear();
   // Expect the timer to be set to 1/16 RTT's in the future.
   EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16),
             loss_algorithm_.GetLossTimeout() - clock_.Now());
-  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16));
   VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -508,13 +541,13 @@
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
   }
   loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
-                                             rtt_stats_, 11);
+                                             rtt_stats_, QuicPacketNumber(11));
   EXPECT_EQ(1, loss_algorithm_.reordering_shift());
 
   // Detect another spurious retransmit and ensure the threshold doesn't
   // increase again.
   loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
-                                             rtt_stats_, 12);
+                                             rtt_stats_, QuicPacketNumber(12));
   EXPECT_EQ(1, loss_algorithm_.reordering_shift());
 }
 
diff --git a/quic/core/congestion_control/hybrid_slow_start.cc b/quic/core/congestion_control/hybrid_slow_start.cc
index 11a14e6..28963b1 100644
--- a/quic/core/congestion_control/hybrid_slow_start.cc
+++ b/quic/core/congestion_control/hybrid_slow_start.cc
@@ -24,8 +24,6 @@
 HybridSlowStart::HybridSlowStart()
     : started_(false),
       hystart_found_(NOT_FOUND),
-      last_sent_packet_number_(0),
-      end_packet_number_(0),
       rtt_sample_count_(0),
       current_min_rtt_(QuicTime::Delta::Zero()) {}
 
@@ -56,7 +54,7 @@
 }
 
 bool HybridSlowStart::IsEndOfRound(QuicPacketNumber ack) const {
-  return end_packet_number_ <= ack;
+  return !end_packet_number_.IsInitialized() || end_packet_number_ <= ack;
 }
 
 bool HybridSlowStart::ShouldExitSlowStart(QuicTime::Delta latest_rtt,
diff --git a/quic/core/congestion_control/hybrid_slow_start_test.cc b/quic/core/congestion_control/hybrid_slow_start_test.cc
index c97c616..aa2f849 100644
--- a/quic/core/congestion_control/hybrid_slow_start_test.cc
+++ b/quic/core/congestion_control/hybrid_slow_start_test.cc
@@ -24,8 +24,8 @@
 };
 
 TEST_F(HybridSlowStartTest, Simple) {
-  QuicPacketNumber packet_number = 1;
-  QuicPacketNumber end_packet_number = 3;
+  QuicPacketNumber packet_number(1);
+  QuicPacketNumber end_packet_number(3);
   slow_start_->StartReceiveRound(end_packet_number);
 
   EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
@@ -39,7 +39,7 @@
   // Test without a new registered end_packet_number;
   EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
 
-  end_packet_number = 20;
+  end_packet_number = QuicPacketNumber(20);
   slow_start_->StartReceiveRound(end_packet_number);
   while (packet_number < end_packet_number) {
     EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
@@ -52,7 +52,7 @@
   // RTT of 60ms the detection will happen at 67.5 ms.
   const int kHybridStartMinSamples = 8;  // Number of acks required to trigger.
 
-  QuicPacketNumber end_packet_number = 1;
+  QuicPacketNumber end_packet_number(1);
   slow_start_->StartReceiveRound(end_packet_number++);
 
   // Will not trigger since our lowest RTT in our burst is the same as the long
diff --git a/quic/core/congestion_control/pacing_sender_test.cc b/quic/core/congestion_control/pacing_sender_test.cc
index 904fb8d..0bb9258 100644
--- a/quic/core/congestion_control/pacing_sender_test.cc
+++ b/quic/core/congestion_control/pacing_sender_test.cc
@@ -50,7 +50,7 @@
     if (burst_size == 0) {
       EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _, _));
       LostPacketVector lost_packets;
-      lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+      lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
       AckedPacketVector empty;
       pacing_sender_->OnCongestionEvent(true, 1234, clock_.Now(), empty,
                                         lost_packets);
@@ -320,7 +320,7 @@
 
   // Losing a packet will set clear burst tokens.
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
   AckedPacketVector empty_acked;
   EXPECT_CALL(*mock_sender_,
               OnCongestionEvent(true, kMaxPacketSize, _, IsEmpty(), _));
diff --git a/quic/core/congestion_control/rtt_stats_test.cc b/quic/core/congestion_control/rtt_stats_test.cc
index 4d154a6..83cb155 100644
--- a/quic/core/congestion_control/rtt_stats_test.cc
+++ b/quic/core/congestion_control/rtt_stats_test.cc
@@ -192,9 +192,9 @@
   for (QuicTime::Delta bad_send_delta : bad_send_deltas) {
     SCOPED_TRACE(Message() << "bad_send_delta = "
                            << bad_send_delta.ToMicroseconds());
-#if QUIC_LOG_WARNING_IS_ON
-    EXPECT_QUIC_LOG_CALL_CONTAINS(log, WARNING, "Ignoring");
-#endif
+    if (QUIC_LOG_WARNING_IS_ON()) {
+      EXPECT_QUIC_LOG_CALL_CONTAINS(log, WARNING, "Ignoring");
+    }
     rtt_stats_.UpdateRtt(bad_send_delta, QuicTime::Delta::Zero(),
                          QuicTime::Zero());
     EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
index 1d903ea..5b843eb 100644
--- a/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
+++ b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -38,9 +38,6 @@
       stats_(stats),
       reno_(reno),
       num_connections_(kDefaultNumConnections),
-      largest_sent_packet_number_(kInvalidPacketNumber),
-      largest_acked_packet_number_(kInvalidPacketNumber),
-      largest_sent_at_last_cutback_(kInvalidPacketNumber),
       min4_mode_(false),
       last_cutback_exited_slowstart_(false),
       slow_start_large_reduction_(false),
@@ -151,8 +148,12 @@
                                         QuicByteCount acked_bytes,
                                         QuicByteCount prior_in_flight,
                                         QuicTime event_time) {
-  largest_acked_packet_number_ =
-      std::max(acked_packet_number, largest_acked_packet_number_);
+  if (largest_acked_packet_number_.IsInitialized()) {
+    largest_acked_packet_number_ =
+        std::max(acked_packet_number, largest_acked_packet_number_);
+  } else {
+    largest_acked_packet_number_ = acked_packet_number;
+  }
   if (InRecovery()) {
     if (!no_prr_) {
       // PRR is used when in recovery.
@@ -184,7 +185,8 @@
     // PRR is used when in recovery.
     prr_.OnPacketSent(bytes);
   }
-  DCHECK_LT(largest_sent_packet_number_, packet_number);
+  DCHECK(!largest_sent_packet_number_.IsInitialized() ||
+         largest_sent_packet_number_ < packet_number);
   largest_sent_packet_number_ = packet_number;
   hybrid_slow_start_.OnPacketSent(packet_number);
 }
@@ -240,8 +242,9 @@
 }
 
 bool TcpCubicSenderBytes::InRecovery() const {
-  return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ &&
-         largest_acked_packet_number_ != kInvalidPacketNumber;
+  return largest_acked_packet_number_.IsInitialized() &&
+         largest_sent_at_last_cutback_.IsInitialized() &&
+         largest_acked_packet_number_ <= largest_sent_at_last_cutback_;
 }
 
 bool TcpCubicSenderBytes::ShouldSendProbingPacket() const {
@@ -249,7 +252,7 @@
 }
 
 void TcpCubicSenderBytes::OnRetransmissionTimeout(bool packets_retransmitted) {
-  largest_sent_at_last_cutback_ = kInvalidPacketNumber;
+  largest_sent_at_last_cutback_.Clear();
   if (!packets_retransmitted) {
     return;
   }
@@ -298,7 +301,8 @@
                                        QuicByteCount prior_in_flight) {
   // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
   // already sent should be treated as a single loss event, since it's expected.
-  if (packet_number <= largest_sent_at_last_cutback_) {
+  if (largest_sent_at_last_cutback_.IsInitialized() &&
+      packet_number <= largest_sent_at_last_cutback_) {
     if (last_cutback_exited_slowstart_) {
       ++stats_->slowstart_packets_lost;
       stats_->slowstart_bytes_lost += lost_bytes;
@@ -414,9 +418,9 @@
 void TcpCubicSenderBytes::OnConnectionMigration() {
   hybrid_slow_start_.Restart();
   prr_ = PrrSender();
-  largest_sent_packet_number_ = kInvalidPacketNumber;
-  largest_acked_packet_number_ = kInvalidPacketNumber;
-  largest_sent_at_last_cutback_ = kInvalidPacketNumber;
+  largest_sent_packet_number_.Clear();
+  largest_acked_packet_number_.Clear();
+  largest_sent_at_last_cutback_.Clear();
   last_cutback_exited_slowstart_ = false;
   cubic_.ResetCubicState();
   num_acked_packets_ = 0;
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
index b7234bc..5eb6226 100644
--- a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -69,8 +69,9 @@
     int packets_sent = 0;
     bool can_send = sender_->CanSend(bytes_in_flight_);
     while (can_send) {
-      sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
-                            kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
+      sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+                            QuicPacketNumber(packet_number_++), kDefaultTCPMSS,
+                            HAS_RETRANSMITTABLE_DATA);
       ++packets_sent;
       bytes_in_flight_ += kDefaultTCPMSS;
       can_send = sender_->CanSend(bytes_in_flight_);
@@ -87,7 +88,8 @@
     for (int i = 0; i < n; ++i) {
       ++acked_packet_number_;
       acked_packets.push_back(
-          AckedPacket(acked_packet_number_, kDefaultTCPMSS, QuicTime::Zero()));
+          AckedPacket(QuicPacketNumber(acked_packet_number_), kDefaultTCPMSS,
+                      QuicTime::Zero()));
     }
     sender_->OnCongestionEvent(true, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
@@ -102,7 +104,8 @@
     LostPacketVector lost_packets;
     for (int i = 0; i < n; ++i) {
       ++acked_packet_number_;
-      lost_packets.push_back(LostPacket(acked_packet_number_, packet_length));
+      lost_packets.push_back(
+          LostPacket(QuicPacketNumber(acked_packet_number_), packet_length));
     }
     sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
@@ -110,10 +113,11 @@
   }
 
   // Does not increment acked_packet_number_.
-  void LosePacket(QuicPacketNumber packet_number) {
+  void LosePacket(uint64_t packet_number) {
     AckedPacketVector acked_packets;
     LostPacketVector lost_packets;
-    lost_packets.push_back(LostPacket(packet_number, kDefaultTCPMSS));
+    lost_packets.push_back(
+        LostPacket(QuicPacketNumber(packet_number), kDefaultTCPMSS));
     sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(),
                                acked_packets, lost_packets);
     bytes_in_flight_ -= kDefaultTCPMSS;
@@ -122,8 +126,8 @@
   const QuicTime::Delta one_ms_;
   MockClock clock_;
   std::unique_ptr<TcpCubicSenderBytesPeer> sender_;
-  QuicPacketNumber packet_number_;
-  QuicPacketNumber acked_packet_number_;
+  uint64_t packet_number_;
+  uint64_t acked_packet_number_;
   QuicByteCount bytes_in_flight_;
 };
 
@@ -779,7 +783,8 @@
   LostPacketVector missing_packets;
   for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
     acked_packets.clear();
-    acked_packets.push_back(AckedPacket(i, 1350, QuicTime::Zero()));
+    acked_packets.push_back(
+        AckedPacket(QuicPacketNumber(i), 1350, QuicTime::Zero()));
     sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(),
                               acked_packets, missing_packets);
   }
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc
index f5ec25c..51cfa26 100644
--- a/quic/core/crypto/aead_base_decrypter.cc
+++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -142,7 +142,7 @@
 }
 
 bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/,
-                                      QuicPacketNumber packet_number,
+                                      uint64_t packet_number,
                                       QuicStringPiece associated_data,
                                       QuicStringPiece ciphertext,
                                       char* output,
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h
index 494d6c2..b4906b8 100644
--- a/quic/core/crypto/aead_base_decrypter.h
+++ b/quic/core/crypto/aead_base_decrypter.h
@@ -36,7 +36,7 @@
   bool SetPreliminaryKey(QuicStringPiece key) override;
   bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.cc b/quic/core/crypto/aead_base_encrypter.cc
index cbe07e3..199851e 100644
--- a/quic/core/crypto/aead_base_encrypter.cc
+++ b/quic/core/crypto/aead_base_encrypter.cc
@@ -124,7 +124,7 @@
 }
 
 bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/,
-                                      QuicPacketNumber packet_number,
+                                      uint64_t packet_number,
                                       QuicStringPiece associated_data,
                                       QuicStringPiece plaintext,
                                       char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.h b/quic/core/crypto/aead_base_encrypter.h
index d3ee016..255bd87 100644
--- a/quic/core/crypto/aead_base_encrypter.h
+++ b/quic/core/crypto/aead_base_encrypter.h
@@ -34,7 +34,7 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
   bool SetIV(QuicStringPiece iv) override;
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
index 7ffbf6e..eb2fa5e 100644
--- a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -203,7 +203,7 @@
                            QuicStringPiece nonce,
                            QuicStringPiece associated_data,
                            QuicStringPiece ciphertext) {
-  QuicPacketNumber packet_number;
+  uint64_t packet_number;
   QuicStringPiece nonce_prefix(nonce.data(),
                                nonce.size() - sizeof(packet_number));
   decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
index 68f56d0..79276ca 100644
--- a/quic/core/crypto/aes_128_gcm_encrypter_test.cc
+++ b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -220,7 +220,7 @@
 TEST_F(Aes128GcmEncrypterTest, EncryptPacket) {
   QuicString key = QuicTextUtils::HexDecode("d95a145250826c25a77b6a84fd4d34fc");
   QuicString iv = QuicTextUtils::HexDecode("50c4431ebb18283448e276e2");
-  QuicPacketNumber packet_num = 0x13278f44;
+  uint64_t packet_num = 0x13278f44;
   QuicString aad =
       QuicTextUtils::HexDecode("875d49f64a70c9cbe713278f44ff000005");
   QuicString pt = QuicTextUtils::HexDecode("aa0003a250bd000000000001");
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
index ba72027..a0c3cbe 100644
--- a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -116,7 +116,7 @@
                            QuicStringPiece nonce,
                            QuicStringPiece associated_data,
                            QuicStringPiece ciphertext) {
-  QuicPacketNumber packet_number;
+  uint64_t packet_number;
   QuicStringPiece nonce_prefix(nonce.data(),
                                nonce.size() - sizeof(packet_number));
   decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
index b5b43fb..8d9a900 100644
--- a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -96,7 +96,7 @@
   ASSERT_TRUE(encrypter.SetNoncePrefix("abcd"));
   ASSERT_TRUE(decrypter.SetNoncePrefix("abcd"));
 
-  QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+  uint64_t packet_number = UINT64_C(0x123456789ABC);
   QuicString associated_data = "associated_data";
   QuicString plaintext = "plaintext";
   char encrypted[1024];
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
index 4a9ecf8..bc7c6c4 100644
--- a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
+++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -95,7 +95,7 @@
   ASSERT_TRUE(encrypter.SetIV("abcdefghijkl"));
   ASSERT_TRUE(decrypter.SetIV("abcdefghijkl"));
 
-  QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+  uint64_t packet_number = UINT64_C(0x123456789ABC);
   QuicString associated_data = "associated_data";
   QuicString plaintext = "plaintext";
   char encrypted[1024];
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index a97b829..c2c4041 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -107,7 +107,7 @@
   CryptoServerTest()
       : rand_(QuicRandom::GetInstance()),
         client_address_(QuicIpAddress::Loopback4(), 1234),
-        client_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        client_version_(UnsupportedQuicVersion()),
         config_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
@@ -723,6 +723,26 @@
   CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons));
 }
 
+TEST_P(CryptoServerTest, CorruptSourceAddressTokenIsStillAccepted) {
+  // This tests corrupted source address token.
+  CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
+      {{"PDMD", "X509"},
+       {"AEAD", "AESG"},
+       {"KEXS", "C255"},
+       {"SCID", scid_hex_},
+       {"#004b5453", (QuicString(1, 'X') + srct_hex_)},
+       {"PUBS", pub_hex_},
+       {"NONC", nonce_hex_},
+       {"XLCT", XlctHexString()},
+       {"VER\0", client_version_string_}},
+      kClientHelloMinimumSize);
+
+  config_.set_validate_source_address_token(false);
+
+  ShouldSucceed(msg);
+  EXPECT_EQ(kSHLO, out_.tag());
+}
+
 TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
   // This test corrupts client nonce and source address token.
   CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 72fbdd9..46d172f 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -95,11 +95,13 @@
 
 // static
 void CryptoUtils::CreateTlsInitialCrypters(Perspective perspective,
+                                           QuicTransportVersion version,
                                            QuicConnectionId connection_id,
                                            CrypterPair* crypters) {
-  QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength)
-      << "CreateTlsInitialCrypters called with connection ID " << connection_id
-      << " of unsupported length " << connection_id.length();
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id, version))
+      << "CreateTlsInitialCrypters: attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version);
   const EVP_MD* hash = EVP_sha256();
 
   std::vector<uint8_t> handshake_secret;
diff --git a/quic/core/crypto/crypto_utils.h b/quic/core/crypto/crypto_utils.h
index 713822a..511bae9 100644
--- a/quic/core/crypto/crypto_utils.h
+++ b/quic/core/crypto/crypto_utils.h
@@ -90,6 +90,7 @@
   // decrypter (put in |*crypters|) to use for this packet protection, as well
   // as setting the key and IV on those crypters.
   static void CreateTlsInitialCrypters(Perspective perspective,
+                                       QuicTransportVersion version,
                                        QuicConnectionId connection_id,
                                        CrypterPair* crypters);
 
diff --git a/quic/core/crypto/ephemeral_key_source.h b/quic/core/crypto/ephemeral_key_source.h
deleted file mode 100644
index e494310..0000000
--- a/quic/core/crypto/ephemeral_key_source.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 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.
-
-#ifndef QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-#define QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
-#include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-
-namespace quic {
-
-class QuicRandom;
-
-// EphemeralKeySource manages and rotates ephemeral keys as they can be reused
-// for several connections in a short space of time. Since the implementation
-// of this may involve locking or thread-local data, this interface abstracts
-// that away.
-class QUIC_EXPORT_PRIVATE EphemeralKeySource {
- public:
-  virtual ~EphemeralKeySource() {}
-
-  // CalculateForwardSecureKey generates an ephemeral public/private key pair
-  // using the algorithm represented by |key_exchange_factory|, sets
-  // |*public_value| to the public key and returns the shared key between
-  // |peer_public_value| and the private key. |*public_value| will be sent to
-  // the peer to be used with the peer's private key.
-  virtual QuicString CalculateForwardSecureKey(
-      const KeyExchange::Factory& key_exchange_factory,
-      QuicRandom* rand,
-      QuicTime now,
-      QuicStringPiece peer_public_value,
-      QuicString* public_value) = 0;
-};
-
-}  // namespace quic
-
-#endif  // QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc
index ba470f5..0c108b6 100644
--- a/quic/core/crypto/null_decrypter.cc
+++ b/quic/core/crypto/null_decrypter.cc
@@ -39,7 +39,7 @@
 }
 
 bool NullDecrypter::DecryptPacket(QuicTransportVersion version,
-                                  QuicPacketNumber /*packet_number*/,
+                                  uint64_t /*packet_number*/,
                                   QuicStringPiece associated_data,
                                   QuicStringPiece ciphertext,
                                   char* output,
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h
index 275228c..3996eb7 100644
--- a/quic/core/crypto/null_decrypter.h
+++ b/quic/core/crypto/null_decrypter.h
@@ -36,7 +36,7 @@
   bool SetPreliminaryKey(QuicStringPiece key) override;
   bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
diff --git a/quic/core/crypto/null_encrypter.cc b/quic/core/crypto/null_encrypter.cc
index 524caef..e4a165f 100644
--- a/quic/core/crypto/null_encrypter.cc
+++ b/quic/core/crypto/null_encrypter.cc
@@ -27,7 +27,7 @@
 }
 
 bool NullEncrypter::EncryptPacket(QuicTransportVersion version,
-                                  QuicPacketNumber /*packet_number*/,
+                                  uint64_t /*packet_number*/,
                                   QuicStringPiece associated_data,
                                   QuicStringPiece plaintext,
                                   char* output,
diff --git a/quic/core/crypto/null_encrypter.h b/quic/core/crypto/null_encrypter.h
index d826202..01ecd45 100644
--- a/quic/core/crypto/null_encrypter.h
+++ b/quic/core/crypto/null_encrypter.h
@@ -30,7 +30,7 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override;
   bool SetIV(QuicStringPiece iv) override;
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index 0a37be8..56447bb 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -13,6 +13,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
 #include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
 #include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
@@ -88,8 +89,8 @@
 
   const CryptoHandshakeMessage* scfg = GetServerConfig();
   if (!scfg) {
-    RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
     // Should be impossible short of cache corruption.
+    RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
     DCHECK(false);
     return false;
   }
@@ -441,7 +442,11 @@
     CryptoHandshakeMessage* out) const {
   out->set_tag(kCHLO);
   // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag.
-  out->set_minimum_size(kClientHelloMinimumSize);
+  if (pad_inchoate_hello_) {
+    out->set_minimum_size(kClientHelloMinimumSize);
+  } else {
+    out->set_minimum_size(1);
+  }
 
   // Server name indication. We only send SNI if it's a valid domain name, as
   // per the spec.
@@ -517,13 +522,21 @@
     CryptoHandshakeMessage* out,
     QuicString* error_details) const {
   DCHECK(error_details != nullptr);
-  QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength)
-      << "FillClientHello called with connection ID " << connection_id
-      << " of unsupported length " << connection_id.length();
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, preferred_version.transport_version))
+      << "FillClientHello: attempted to use connection ID " << connection_id
+      << " which is invalid with version "
+      << QuicVersionToString(preferred_version.transport_version);
 
   FillInchoateClientHello(server_id, preferred_version, cached, rand,
                           /* demand_x509_proof= */ true, out_params, out);
 
+  if (pad_full_hello_) {
+    out->set_minimum_size(kClientHelloMinimumSize);
+  } else {
+    out->set_minimum_size(1);
+  }
+
   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
   if (!scfg) {
     // This should never happen as our caller should have checked
@@ -860,10 +873,9 @@
       }
       connection_id = QuicConnectionId(connection_id_bytes.data(),
                                        connection_id_bytes.length());
-      if (connection_id.length() != kQuicDefaultConnectionIdLength) {
+      if (!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) {
         QUIC_PEER_BUG << "Received server-designated connection ID "
-                      << connection_id << " of bad length "
-                      << connection_id.length() << " with version "
+                      << connection_id << " which is invalid with version "
                       << QuicVersionToString(version);
         *error_details = "Bad kRCID length";
         return QUIC_CRYPTO_INTERNAL_ERROR;
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index c7e46a9..32df726 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "third_party/boringssl/src/include/openssl/base.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -351,6 +352,14 @@
     pre_shared_key_ = QuicString(psk);
   }
 
+  bool pad_inchoate_hello() const { return pad_inchoate_hello_; }
+  void set_pad_inchoate_hello(bool new_value) {
+    pad_inchoate_hello_ = new_value;
+  }
+
+  bool pad_full_hello() const { return pad_full_hello_; }
+  void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; }
+
  private:
   // Sets the members to reasonable, default values.
   void SetDefaults();
@@ -402,6 +411,20 @@
   // If non-empty, the client will operate in the pre-shared key mode by
   // incorporating |pre_shared_key_| into the key schedule.
   QuicString pre_shared_key_;
+
+  // In QUIC, technically, client hello should be fully padded.
+  // However, fully padding on slow network connection (e.g. 50kbps) can add
+  // 150ms latency to one roundtrip. Therefore, you can disable padding of
+  // individual messages. It is recommend to leave at least one message in
+  // each direction fully padded (e.g. full CHLO and SHLO), but if you know
+  // the lower-bound MTU, you don't need to pad all of them (keep in mind that
+  // it's not OK to do it according to the standard).
+  //
+  // Also, if you disable padding, you must disable (change) the
+  // anti-amplification protection. You should only do so if you have some
+  // other means of verifying the client.
+  bool pad_inchoate_hello_ = true;
+  bool pad_full_hello_ = true;
 };
 
 }  // namespace quic
diff --git a/quic/core/crypto/quic_crypto_client_config_test.cc b/quic/core/crypto/quic_crypto_client_config_test.cc
index 8cc0420..5e0ca6e 100644
--- a/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -113,9 +113,11 @@
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
   QuicCryptoClientConfig::CachedState state;
   EXPECT_FALSE(state.has_server_designated_connection_id());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
   EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(),
                      "Attempting to consume a connection id "
                      "that was never designated.");
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
 }
 
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
@@ -152,9 +154,11 @@
 TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) {
   QuicCryptoClientConfig::CachedState state;
   EXPECT_FALSE(state.has_server_nonce());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
   EXPECT_DEBUG_DEATH(state.GetNextServerNonce(),
                      "Attempting to consume a server nonce "
                      "that was never designated.");
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
 }
 
 TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
@@ -197,6 +201,26 @@
   QuicStringPiece alpn;
   EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn));
   EXPECT_EQ("hq", alpn);
+
+  EXPECT_EQ(msg.minimum_size(), 1024u);
+}
+
+TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) {
+  QuicCryptoClientConfig::CachedState state;
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
+                                TlsClientHandshaker::CreateSslCtx());
+  config.set_pad_inchoate_hello(false);
+  config.set_user_agent_id("quic-tester");
+  config.set_alpn("hq");
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
+      new QuicCryptoNegotiatedParameters);
+  CryptoHandshakeMessage msg;
+  QuicServerId server_id("www.google.com", 443, false);
+  MockRandom rand;
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+                                 /* demand_x509_proof= */ true, params, &msg);
+
+  EXPECT_EQ(msg.minimum_size(), 1u);
 }
 
 // Make sure AES-GCM is the preferred encryption algorithm if it has hardware
@@ -307,6 +331,30 @@
   EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
 }
 
+TEST_F(QuicCryptoClientConfigTest, FillClientHelloNoPadding) {
+  QuicCryptoClientConfig::CachedState state;
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
+                                TlsClientHandshaker::CreateSslCtx());
+  config.set_pad_full_hello(false);
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
+      new QuicCryptoNegotiatedParameters);
+  QuicConnectionId kConnectionId = TestConnectionId(1234);
+  QuicString error_details;
+  MockRandom rand;
+  CryptoHandshakeMessage chlo;
+  QuicServerId server_id("www.google.com", 443, false);
+  config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state,
+                         QuicWallTime::Zero(), &rand,
+                         nullptr,  // channel_id_key
+                         params, &chlo, &error_details);
+
+  // Verify that the version label has been set correctly in the CHLO.
+  QuicVersionLabel cver;
+  EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver));
+  EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
+  EXPECT_EQ(chlo.minimum_size(), 1u);
+}
+
 TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
   ParsedQuicVersionVector supported_versions = AllSupportedVersions();
   if (supported_versions.size() == 1) {
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 1004236..851f8e3 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -20,7 +20,6 @@
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
 #include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h"
-#include "net/third_party/quiche/src/quic/core/crypto/ephemeral_key_source.h"
 #include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
 #include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
@@ -35,6 +34,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_cert_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
@@ -220,7 +220,11 @@
       source_address_token_future_secs_(3600),
       source_address_token_lifetime_secs_(86400),
       enable_serving_sct_(false),
-      rejection_observer_(nullptr) {
+      rejection_observer_(nullptr),
+      pad_rej_(true),
+      pad_shlo_(true),
+      validate_chlo_size_(true),
+      validate_source_address_token_(true) {
   DCHECK(proof_source_.get());
   source_address_token_boxer_.SetKeys(
       {DeriveSourceAddressTokenKey(source_address_token_secret)});
@@ -507,13 +511,11 @@
   QuicReferenceCountedPointer<Config> primary_config;
   {
     QuicReaderMutexLock locked(&configs_lock_);
-
     if (!primary_config_.get()) {
       result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
       result->error_details = "No configurations loaded";
     } else {
-      if (!next_config_promotion_time_.IsZero() &&
-          next_config_promotion_time_.IsAfter(now)) {
+      if (IsNextConfigReady(now)) {
         configs_lock_.ReaderUnlock();
         configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
@@ -678,6 +680,7 @@
           validate_chlo_result,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
+      ParsedQuicVersion version,
       const ParsedQuicVersionVector& supported_versions,
       const QuicClock* clock,
       QuicRandom* rand,
@@ -694,6 +697,7 @@
         validate_chlo_result_(std::move(validate_chlo_result)),
         connection_id_(connection_id),
         client_address_(client_address),
+        version_(version),
         supported_versions_(supported_versions),
         clock_(clock),
         rand_(rand),
@@ -707,7 +711,7 @@
     config_->ProcessClientHelloAfterCalculateSharedKeys(
         !ok, std::move(proof_source_details_), key_exchange_factory_,
         std::move(out_), public_value_, *validate_chlo_result_, connection_id_,
-        client_address_, supported_versions_, clock_, rand_, params_,
+        client_address_, version_, supported_versions_, clock_, rand_, params_,
         signed_config_, requested_config_, primary_config_,
         std::move(done_cb_));
   }
@@ -722,6 +726,7 @@
       validate_chlo_result_;
   QuicConnectionId connection_id_;
   const QuicSocketAddress client_address_;
+  ParsedQuicVersion version_;
   const ParsedQuicVersionVector supported_versions_;
   const QuicClock* clock_;
   QuicRandom* rand_;
@@ -780,8 +785,7 @@
     if (!primary_config_) {
       no_primary_config = true;
     } else {
-      if (!next_config_promotion_time_.IsZero() &&
-          next_config_promotion_time_.IsAfter(now)) {
+      if (IsNextConfigReady(now)) {
         configs_lock_.ReaderUnlock();
         configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
@@ -867,11 +871,11 @@
     const QuicReferenceCountedPointer<Config>& requested_config,
     const QuicReferenceCountedPointer<Config>& primary_config,
     std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
-  if (connection_id.length() != kQuicDefaultConnectionIdLength) {
-    QUIC_BUG << "ProcessClientHelloAfterGetProof called with connection ID "
-             << connection_id << " of unsupported length "
-             << connection_id.length();
-  }
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, version.transport_version))
+      << "ProcessClientHelloAfterGetProof: attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version.transport_version);
   if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) {
     connection_id = QuicConnectionIdFromUInt64(
         QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)));
@@ -965,25 +969,13 @@
   // TODO(rch): Would it be better to implement a move operator and just
   // std::move(helper) instead of done_cb?
   helper.DetachCallback();
-  if (GetQuicRestartFlag(quic_use_async_key_exchange)) {
-    QUIC_RESTART_FLAG_COUNT(quic_use_async_key_exchange);
-    auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
-        this, std::move(proof_source_details), key_exchange->GetFactory(),
-        std::move(out), public_value, validate_chlo_result, connection_id,
-        client_address, supported_versions, clock, rand, params, signed_config,
-        requested_config, primary_config, std::move(done_cb));
-    key_exchange->CalculateSharedKey(
-        public_value, &params->initial_premaster_secret, std::move(cb));
-  } else {
-    found_error = !key_exchange->CalculateSharedKey(
-        public_value, &params->initial_premaster_secret);
-    ProcessClientHelloAfterCalculateSharedKeys(
-        found_error, std::move(proof_source_details),
-        key_exchange->GetFactory(), std::move(out), public_value,
-        *validate_chlo_result, connection_id, client_address,
-        supported_versions, clock, rand, params, signed_config,
-        requested_config, primary_config, std::move(done_cb));
-  }
+  auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>(
+      this, std::move(proof_source_details), key_exchange->GetFactory(),
+      std::move(out), public_value, validate_chlo_result, connection_id,
+      client_address, version, supported_versions, clock, rand, params,
+      signed_config, requested_config, primary_config, std::move(done_cb));
+  key_exchange->CalculateSharedKey(
+      public_value, &params->initial_premaster_secret, std::move(cb));
 }
 
 void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys(
@@ -995,6 +987,7 @@
     const ValidateClientHelloResultCallback::Result& validate_chlo_result,
     QuicConnectionId connection_id,
     const QuicSocketAddress& client_address,
+    ParsedQuicVersion version,
     const ParsedQuicVersionVector& supported_versions,
     const QuicClock* clock,
     QuicRandom* rand,
@@ -1003,12 +996,12 @@
     const QuicReferenceCountedPointer<Config>& requested_config,
     const QuicReferenceCountedPointer<Config>& primary_config,
     std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
-  if (connection_id.length() != kQuicDefaultConnectionIdLength) {
-    QUIC_BUG << "ProcessClientHelloAfterCalculateSharedKeys called with "
-                "connection ID "
-             << connection_id << " of unsupported length "
-             << connection_id.length();
-  }
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      connection_id, version.transport_version))
+      << "ProcessClientHelloAfterCalculateSharedKeys:"
+         " attempted to use connection ID "
+      << connection_id << " which is invalid with version "
+      << QuicVersionToString(version.transport_version);
   ProcessClientHelloHelper helper(&done_cb);
 
   if (found_error) {
@@ -1140,30 +1133,14 @@
   }
 
   QuicString forward_secure_public_value;
-  if (GetQuicRestartFlag(quic_no_ephemeral_key_source)) {
-    if (ephemeral_key_source_) {
-      QUIC_BUG << "quic_no_ephemeral_key_source flag is on, but "
-                  "ephemeral_key_source is present";
-    } else {
-      QUIC_RESTART_FLAG_COUNT(quic_no_ephemeral_key_source);
-    }
-  }
-  if (ephemeral_key_source_) {
-    params->forward_secure_premaster_secret =
-        ephemeral_key_source_->CalculateForwardSecureKey(
-            key_exchange_factory, rand, clock->ApproximateNow(), public_value,
-            &forward_secure_public_value);
-  } else {
-    std::unique_ptr<KeyExchange> forward_secure_key_exchange =
-        key_exchange_factory.Create(rand);
-    forward_secure_public_value =
-        QuicString(forward_secure_key_exchange->public_value());
-    if (!forward_secure_key_exchange->CalculateSharedKey(
-            public_value, &params->forward_secure_premaster_secret)) {
-      helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
-                  "Invalid public value");
-      return;
-    }
+  std::unique_ptr<KeyExchange> forward_secure_key_exchange =
+      key_exchange_factory.Create(rand);
+  forward_secure_public_value =
+      QuicString(forward_secure_key_exchange->public_value());
+  if (!forward_secure_key_exchange->CalculateSharedKey(
+          public_value, &params->forward_secure_premaster_secret)) {
+    helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Invalid public value");
+    return;
   }
 
   QuicString forward_secure_hkdf_input;
@@ -1332,7 +1309,6 @@
           requested_config,
       QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
           primary_config,
-      bool use_get_cert_chain,
       QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
       QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
           client_hello_state,
@@ -1342,7 +1318,6 @@
         version_(version),
         requested_config_(std::move(requested_config)),
         primary_config_(std::move(primary_config)),
-        use_get_cert_chain_(use_get_cert_chain),
         signed_config_(signed_config),
         client_hello_state_(std::move(client_hello_state)),
         done_cb_(std::move(done_cb)) {}
@@ -1357,8 +1332,8 @@
     }
     config_.EvaluateClientHelloAfterGetProof(
         server_ip_, version_, requested_config_, primary_config_,
-        signed_config_, std::move(details), use_get_cert_chain_, !ok,
-        client_hello_state_, std::move(done_cb_));
+        signed_config_, std::move(details), !ok, client_hello_state_,
+        std::move(done_cb_));
   }
 
  private:
@@ -1369,7 +1344,6 @@
       requested_config_;
   const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
       primary_config_;
-  const bool use_get_cert_chain_;
   QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
   QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
       client_hello_state_;
@@ -1392,7 +1366,7 @@
   const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
   ClientHelloInfo* info = &(client_hello_state->info);
 
-  if (client_hello.size() < kClientHelloMinimumSize) {
+  if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) {
     helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
                               "Client hello too small", nullptr);
     return;
@@ -1408,22 +1382,27 @@
   client_hello.GetStringPiece(kUAID, &info->user_agent_id);
 
   HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
-  QuicStringPiece srct;
-  if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
-    Config& config =
-        requested_config != nullptr ? *requested_config : *primary_config;
-    source_address_token_error =
-        ParseSourceAddressToken(config, srct, &info->source_address_tokens);
+  if (validate_source_address_token_) {
+    QuicStringPiece srct;
+    if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
+      Config& config =
+          requested_config != nullptr ? *requested_config : *primary_config;
+      source_address_token_error =
+          ParseSourceAddressToken(config, srct, &info->source_address_tokens);
 
-    if (source_address_token_error == HANDSHAKE_OK) {
-      source_address_token_error = ValidateSourceAddressTokens(
-          info->source_address_tokens, info->client_ip, info->now,
-          &client_hello_state->cached_network_params);
+      if (source_address_token_error == HANDSHAKE_OK) {
+        source_address_token_error = ValidateSourceAddressTokens(
+            info->source_address_tokens, info->client_ip, info->now,
+            &client_hello_state->cached_network_params);
+      }
+      info->valid_source_address_token =
+          (source_address_token_error == HANDSHAKE_OK);
+    } else {
+      source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
     }
-    info->valid_source_address_token =
-        (source_address_token_error == HANDSHAKE_OK);
   } else {
-    source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
+    source_address_token_error = HANDSHAKE_OK;
+    info->valid_source_address_token = true;
   }
 
   if (!requested_config.get()) {
@@ -1450,28 +1429,6 @@
     // No valid source address token.
   }
 
-  const bool use_get_cert_chain =
-      GetQuicReloadableFlag(quic_use_get_cert_chain);
-  if (!use_get_cert_chain) {
-    QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 1, 2);
-    QuicString serialized_config = primary_config->serialized;
-    QuicString chlo_hash;
-    CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash,
-                                      Perspective::IS_SERVER);
-    // Make an async call to GetProof and setup the callback to trampoline
-    // back into EvaluateClientHelloAfterGetProof
-    auto cb = QuicMakeUnique<EvaluateClientHelloCallback>(
-        *this, server_address.host(), version, requested_config, primary_config,
-        use_get_cert_chain, signed_config, client_hello_state,
-        std::move(done_cb));
-    proof_source_->GetProof(server_address, QuicString(info->sni),
-                            serialized_config, version, chlo_hash,
-                            std::move(cb));
-    helper.DetachCallback();
-    return;
-  }
-
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 2, 2);
   QuicReferenceCountedPointer<ProofSource::Chain> chain =
       proof_source_->GetCertChain(server_address, QuicString(info->sni));
   if (!chain) {
@@ -1481,7 +1438,7 @@
   }
   EvaluateClientHelloAfterGetProof(
       server_address.host(), version, requested_config, primary_config,
-      signed_config, /*proof_source_details=*/nullptr, use_get_cert_chain,
+      signed_config, /*proof_source_details=*/nullptr,
       /*get_proof_failed=*/false, client_hello_state, std::move(done_cb));
   helper.DetachCallback();
 }
@@ -1493,7 +1450,6 @@
     QuicReferenceCountedPointer<Config> primary_config,
     QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
     std::unique_ptr<ProofSource::Details> proof_source_details,
-    bool use_get_cert_chain,
     bool get_proof_failed,
     QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
         client_hello_state,
@@ -1502,18 +1458,6 @@
   const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
   ClientHelloInfo* info = &(client_hello_state->info);
 
-  if (!use_get_cert_chain) {
-    if (get_proof_failed) {
-      info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
-    }
-
-    if (signed_config->chain != nullptr &&
-        !ValidateExpectedLeafCertificate(client_hello,
-                                         signed_config->chain->certs)) {
-      info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
-    }
-  }
-
   if (info->client_nonce.size() != kNonceSize) {
     info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
     // Invalid client nonce.
@@ -1673,12 +1617,11 @@
       out->SetValue(kRCID, QuicEndian::HostToNet64(QuicConnectionIdToUInt64(
                                server_designated_connection_id)));
     } else {
-      if (server_designated_connection_id.length() !=
-              kQuicDefaultConnectionIdLength &&
-          version < QUIC_VERSION_99) {
-        QUIC_BUG << "Tried to send connection ID "
-                 << server_designated_connection_id << " of bad length "
-                 << server_designated_connection_id.length() << " with version "
+      if (!QuicUtils::IsConnectionIdValidForVersion(
+              server_designated_connection_id, version)) {
+        QUIC_BUG << "Tried to send server designated connection ID "
+                 << server_designated_connection_id
+                 << " which is invalid with version "
                  << QuicVersionToString(version);
         return;
       }
@@ -1754,8 +1697,22 @@
     out->SetStringPiece(kPROF, signed_config.proof.signature);
     if (should_return_sct) {
       if (cert_sct.empty()) {
-        QUIC_LOG_EVERY_N_SEC(WARNING, 60)
-            << "SCT is expected but it is empty. sni :" << params->sni;
+        if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) {
+          QUIC_LOG_EVERY_N_SEC(WARNING, 60)
+              << "SCT is expected but it is empty. sni :" << params->sni;
+        } else {
+          // Log SNI and subject name for the leaf cert if its SCT is empty.
+          // This is for debugging b/28342827.
+          const std::vector<quic::QuicString>& certs =
+              signed_config.chain->certs;
+          QuicStringPiece ca_subject;
+          if (!certs.empty()) {
+            QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject);
+          }
+          QUIC_LOG_EVERY_N_SEC(WARNING, 60)
+              << "SCT is expected but it is empty. sni: '" << params->sni
+              << "' cert subject: '" << ca_subject << "'";
+        }
       } else {
         out->SetStringPiece(kCertificateSCTTag, cert_sct);
       }
@@ -1855,7 +1812,7 @@
   static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size");
   memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
 
-  if (kexs_tags.size() != protobuf->key_size()) {
+  if (kexs_tags.size() != static_cast<size_t>(protobuf->key_size())) {
     QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size()
                       << " key exchange methods configured, but "
                       << protobuf->key_size() << " private keys";
@@ -1878,7 +1835,7 @@
 
     config->kexs.push_back(tag);
 
-    for (size_t j = 0; j < protobuf->key_size(); j++) {
+    for (int j = 0; j < protobuf->key_size(); j++) {
       const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
       if (key.tag() == tag) {
         private_key = key.private_key();
@@ -1911,11 +1868,6 @@
   return config;
 }
 
-void QuicCryptoServerConfig::SetEphemeralKeySource(
-    std::unique_ptr<EphemeralKeySource> ephemeral_key_source) {
-  ephemeral_key_source_ = std::move(ephemeral_key_source);
-}
-
 void QuicCryptoServerConfig::set_replay_protection(bool on) {
   replay_protection_ = on;
 }
@@ -2124,6 +2076,15 @@
   return false;
 }
 
+bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const {
+  if (GetQuicReloadableFlag(quic_fix_config_rotation)) {
+    return !next_config_promotion_time_.IsZero() &&
+           !next_config_promotion_time_.IsAfter(now);
+  }
+  return !next_config_promotion_time_.IsZero() &&
+         next_config_promotion_time_.IsAfter(now);
+}
+
 QuicCryptoServerConfig::Config::Config()
     : channel_id_enabled(false),
       is_primary(false),
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index b10786d..3561844 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -34,7 +34,6 @@
 namespace quic {
 
 class CryptoHandshakeMessage;
-class EphemeralKeySource;
 class ProofSource;
 class QuicClock;
 class QuicRandom;
@@ -370,12 +369,6 @@
       const CachedNetworkParameters* cached_network_params,
       std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
 
-  // SetEphemeralKeySource installs an object that can cache ephemeral keys for
-  // a short period of time. If not set, ephemeral keys will be generated
-  // per-connection.
-  void SetEphemeralKeySource(
-      std::unique_ptr<EphemeralKeySource> ephemeral_key_source);
-
   // set_replay_protection controls whether replay protection is enabled. If
   // replay protection is disabled then no strike registers are needed and
   // frontends can share an orbit value without a shared strike-register.
@@ -388,6 +381,19 @@
   // valid source-address token.
   void set_chlo_multiplier(size_t multiplier);
 
+  // When sender is allowed to not pad client hello (not standards compliant),
+  // we need to disable the client hello check.
+  void set_validate_chlo_size(bool new_value) {
+    validate_chlo_size_ = new_value;
+  }
+
+  // When QUIC is tunneled through some other mechanism, source token validation
+  // may be disabled. Do not disable it if you are not providing other
+  // protection. (|true| protects against UDP amplification attack.).
+  void set_validate_source_address_token(bool new_value) {
+    validate_source_address_token_ = new_value;
+  }
+
   // set_source_address_token_future_secs sets the number of seconds into the
   // future that source-address tokens will be accepted from. Since
   // source-address tokens are authenticated, this should only happen if
@@ -423,6 +429,12 @@
     pre_shared_key_ = QuicString(psk);
   }
 
+  bool pad_rej() const { return pad_rej_; }
+  void set_pad_rej(bool new_value) { pad_rej_ = new_value; }
+
+  bool pad_shlo() const { return pad_shlo_; }
+  void set_pad_shlo(bool new_value) { pad_shlo_ = new_value; }
+
  private:
   friend class test::QuicCryptoServerConfigPeer;
   friend struct QuicSignedServerConfig;
@@ -539,7 +551,6 @@
       QuicReferenceCountedPointer<Config> primary_config,
       QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof,
       std::unique_ptr<ProofSource::Details> proof_source_details,
-      bool use_get_cert_chain,
       bool get_proof_failed,
       QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
           client_hello_state,
@@ -589,6 +600,7 @@
       const ValidateClientHelloResultCallback::Result& validate_chlo_result,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
+      ParsedQuicVersion version,
       const ParsedQuicVersionVector& supported_versions,
       const QuicClock* clock,
       QuicRandom* rand,
@@ -754,6 +766,10 @@
       CryptoHandshakeMessage message,
       std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
 
+  // Returns true if the next config promotion should happen now.
+  bool IsNextConfigReady(QuicWallTime now) const
+      SHARED_LOCKS_REQUIRED(configs_lock_);
+
   // replay_protection_ controls whether the server enforces that handshakes
   // aren't replays.
   bool replay_protection_;
@@ -805,10 +821,6 @@
   // ssl_ctx_ contains the server configuration for doing TLS handshakes.
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
-  // ephemeral_key_source_ contains an object that caches ephemeral keys for a
-  // short period of time.
-  std::unique_ptr<EphemeralKeySource> ephemeral_key_source_;
-
   // These fields store configuration values. See the comments for their
   // respective setter functions.
   uint32_t source_address_token_future_secs_;
@@ -823,6 +835,23 @@
   // If non-empty, the server will operate in the pre-shared key mode by
   // incorporating |pre_shared_key_| into the key schedule.
   QuicString pre_shared_key_;
+
+  // Whether REJ message should be padded to max packet size.
+  bool pad_rej_;
+
+  // Whether SHLO message should be padded to max packet size.
+  bool pad_shlo_;
+
+  // If client is allowed to send a small client hello (by disabling padding),
+  // server MUST not check for the client hello size.
+  // DO NOT disable this unless you have some other way of validating client.
+  // (e.g. in realtime scenarios, where quic is tunneled through ICE, ICE will
+  // do its own peer validation using STUN pings with ufrag/upass).
+  bool validate_chlo_size_;
+
+  // When source address is validated by some other means (e.g. when using ICE),
+  // source address token validation may be disabled.
+  bool validate_source_address_token_;
 };
 
 struct QUIC_EXPORT_PRIVATE QuicSignedServerConfig
diff --git a/quic/core/crypto/quic_crypto_server_config_test.cc b/quic/core/crypto/quic_crypto_server_config_test.cc
index 15de28b..81e6951 100644
--- a/quic/core/crypto/quic_crypto_server_config_test.cc
+++ b/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -258,12 +258,12 @@
       NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input);
 
   CachedNetworkParameters cached_network_params_output;
-  EXPECT_NE(cached_network_params_output.DebugString(),
-            cached_network_params_input.DebugString());
+  EXPECT_NE(cached_network_params_output.SerializeAsString(),
+            cached_network_params_input.SerializeAsString());
   ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_,
                               &cached_network_params_output);
-  EXPECT_EQ(cached_network_params_output.DebugString(),
-            cached_network_params_input.DebugString());
+  EXPECT_EQ(cached_network_params_output.SerializeAsString(),
+            cached_network_params_input.SerializeAsString());
 }
 
 // Test the ability for a source address token to be valid for multiple
@@ -457,6 +457,33 @@
   test_peer_.CheckConfigs({{"a", false}, {"b", true}});
 }
 
+class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+  void Run(QuicReferenceCountedPointer<Result> result,
+           std::unique_ptr<ProofSource::Details> /* details */) override {}
+};
+
+TEST_F(CryptoServerConfigsTest, AdvancePrimaryViaValidate) {
+  SetQuicReloadableFlag(quic_fix_config_rotation, true);
+  // Check that a new primary config is enabled at the right time.
+  SetConfigs({{"a", 900, 1}, {"b", 1100, 1}});
+  test_peer_.SelectNewPrimaryConfig(1000);
+  test_peer_.CheckConfigs({{"a", true}, {"b", false}});
+  CryptoHandshakeMessage client_hello;
+  QuicIpAddress client_ip;
+  QuicSocketAddress server_address;
+  QuicTransportVersion version = QUIC_VERSION_99;
+  MockClock clock;
+  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config(
+      new QuicSignedServerConfig);
+  std::unique_ptr<ValidateClientHelloResultCallback> done_cb(
+      new ValidateCallback);
+  clock.AdvanceTime(QuicTime::Delta::FromSeconds(1100));
+  config_.ValidateClientHello(client_hello, client_ip, server_address, version,
+                              &clock, signed_config, std::move(done_cb));
+  test_peer_.CheckConfigs({{"a", false}, {"b", true}});
+}
+
 TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
   // Ensure that invalid configs don't change anything.
   SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}});
diff --git a/quic/core/crypto/quic_decrypter.h b/quic/core/crypto/quic_decrypter.h
index f61f621..892504c 100644
--- a/quic/core/crypto/quic_decrypter.h
+++ b/quic/core/crypto/quic_decrypter.h
@@ -54,7 +54,7 @@
   // TODO(wtc): add a way for DecryptPacket to report decryption failure due
   // to non-authentic inputs, as opposed to other reasons for failure.
   virtual bool DecryptPacket(QuicTransportVersion version,
-                             QuicPacketNumber packet_number,
+                             uint64_t packet_number,
                              QuicStringPiece associated_data,
                              QuicStringPiece ciphertext,
                              char* output,
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h
index ea1cee8..591021e 100644
--- a/quic/core/crypto/quic_encrypter.h
+++ b/quic/core/crypto/quic_encrypter.h
@@ -35,7 +35,7 @@
   // |associated_data|. If |output| overlaps with |plaintext| then
   // |plaintext| must be <= |output|.
   virtual bool EncryptPacket(QuicTransportVersion version,
-                             QuicPacketNumber packet_number,
+                             uint64_t packet_number,
                              QuicStringPiece associated_data,
                              QuicStringPiece plaintext,
                              char* output,
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc
index 3493f97..5f47b3f 100644
--- a/quic/core/frames/quic_ack_frame.cc
+++ b/quic/core/frames/quic_ack_frame.cc
@@ -12,19 +12,29 @@
 namespace quic {
 
 namespace {
-const QuicPacketNumber kMaxPrintRange = 128;
+
+const QuicPacketCount kMaxPrintRange = 128;
+
+uint64_t PacketNumberIntervalLength(
+    const QuicInterval<QuicPacketNumber>& interval) {
+  if (interval.Empty()) {
+    return 0u;
+  }
+  return interval.max() - interval.min();
+}
 }  // namespace
 
 bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
                       QuicPacketNumber packet_number,
                       QuicPacketNumber peer_least_packet_awaiting_ack) {
-  return packet_number >= peer_least_packet_awaiting_ack &&
+  DCHECK(packet_number.IsInitialized());
+  return (!peer_least_packet_awaiting_ack.IsInitialized() ||
+          packet_number >= peer_least_packet_awaiting_ack) &&
          !ack_frame.packets.Contains(packet_number);
 }
 
 QuicAckFrame::QuicAckFrame()
-    : largest_acked(kInvalidPacketNumber),
-      ack_delay_time(QuicTime::Delta::Infinite()),
+    : ack_delay_time(QuicTime::Delta::Infinite()),
       ecn_counters_populated(false),
       ect_0_count(0),
       ect_1_count(0),
@@ -56,7 +66,7 @@
 }
 
 void QuicAckFrame::Clear() {
-  largest_acked = kInvalidPacketNumber;
+  largest_acked.Clear();
   ack_delay_time = QuicTime::Delta::Infinite();
   received_packet_times.clear();
   packets.Clear();
@@ -73,6 +83,9 @@
     default;
 
 void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
+  if (!packet_number.IsInitialized()) {
+    return;
+  }
   // Check if the deque is empty
   if (packet_number_deque_.empty()) {
     packet_number_deque_.push_front(
@@ -148,7 +161,7 @@
 
 void PacketNumberQueue::AddRange(QuicPacketNumber lower,
                                  QuicPacketNumber higher) {
-  if (lower >= higher) {
+  if (!lower.IsInitialized() || !higher.IsInitialized() || lower >= higher) {
     return;
   }
   if (packet_number_deque_.empty()) {
@@ -187,7 +200,7 @@
 }
 
 bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
-  if (Empty()) {
+  if (!higher.IsInitialized() || Empty()) {
     return false;
   }
   const QuicPacketNumber old_min = Min();
@@ -221,7 +234,7 @@
 }
 
 bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
-  if (packet_number_deque_.empty()) {
+  if (!packet_number.IsInitialized() || packet_number_deque_.empty()) {
     return false;
   }
   if (packet_number_deque_.front().min() > packet_number ||
@@ -253,7 +266,7 @@
 QuicPacketCount PacketNumberQueue::NumPacketsSlow() const {
   QuicPacketCount n_packets = 0;
   for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) {
-    n_packets += interval.Length();
+    n_packets += PacketNumberIntervalLength(interval);
   }
   return n_packets;
 }
@@ -278,9 +291,9 @@
   return packet_number_deque_.rend();
 }
 
-QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
+QuicPacketCount PacketNumberQueue::LastIntervalLength() const {
   DCHECK(!Empty());
-  return packet_number_deque_.back().Length();
+  return PacketNumberIntervalLength(packet_number_deque_.back());
 }
 
 // Largest min...max range for packet numbers where we print the numbers
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h
index 29d511e..4dcfc3d 100644
--- a/quic/core/frames/quic_ack_frame.h
+++ b/quic/core/frames/quic_ack_frame.h
@@ -73,7 +73,7 @@
   size_t NumIntervals() const;
 
   // Returns the length of last interval.
-  QuicPacketNumber LastIntervalLength() const;
+  QuicPacketCount LastIntervalLength() const;
 
   // Returns iterators over the packet number intervals.
   const_iterator begin() const;
diff --git a/quic/core/frames/quic_blocked_frame.h b/quic/core/frames/quic_blocked_frame.h
index 3203c67..a4be664 100644
--- a/quic/core/frames/quic_blocked_frame.h
+++ b/quic/core/frames/quic_blocked_frame.h
@@ -37,6 +37,9 @@
   // BLOCKED or STREAM_BLOCKED frame is generated.
   // If stream_id is 0 then a BLOCKED frame is generated and transmitted,
   // if non-0, a STREAM_BLOCKED.
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   QuicStreamId stream_id;
 
   // For Google QUIC, the offset is ignored.
diff --git a/quic/core/frames/quic_crypto_frame.cc b/quic/core/frames/quic_crypto_frame.cc
index c7f500a..9d602bc 100644
--- a/quic/core/frames/quic_crypto_frame.cc
+++ b/quic/core/frames/quic_crypto_frame.cc
@@ -8,15 +8,27 @@
 
 namespace quic {
 
-QuicCryptoFrame::QuicCryptoFrame() : QuicCryptoFrame(0, nullptr, 0) {}
+QuicCryptoFrame::QuicCryptoFrame()
+    : QuicCryptoFrame(ENCRYPTION_NONE, 0, nullptr, 0) {}
 
-QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data)
-    : QuicCryptoFrame(offset, data.data(), data.length()) {}
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicPacketLength data_length)
+    : QuicCryptoFrame(level, offset, nullptr, data_length) {}
 
-QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset,
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
+                                 QuicStringPiece data)
+    : QuicCryptoFrame(level, offset, data.data(), data.length()) {}
+
+QuicCryptoFrame::QuicCryptoFrame(EncryptionLevel level,
+                                 QuicStreamOffset offset,
                                  const char* data_buffer,
                                  QuicPacketLength data_length)
-    : data_length(data_length), data_buffer(data_buffer), offset(offset) {}
+    : level(level),
+      data_length(data_length),
+      data_buffer(data_buffer),
+      offset(offset) {}
 
 QuicCryptoFrame::~QuicCryptoFrame() {}
 
diff --git a/quic/core/frames/quic_crypto_frame.h b/quic/core/frames/quic_crypto_frame.h
index bbf8ea0..a3968fe 100644
--- a/quic/core/frames/quic_crypto_frame.h
+++ b/quic/core/frames/quic_crypto_frame.h
@@ -17,20 +17,29 @@
 
 struct QUIC_EXPORT_PRIVATE QuicCryptoFrame {
   QuicCryptoFrame();
-  QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data);
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicPacketLength data_length);
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
+                  QuicStringPiece data);
   ~QuicCryptoFrame();
 
   friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                                       const QuicCryptoFrame& s);
 
+  // When writing a crypto frame to a packet, the packet must be encrypted at
+  // |level|. When a crypto frame is read, the encryption level of the packet it
+  // was received in is put in |level|.
+  EncryptionLevel level;
   QuicPacketLength data_length;
   // When reading, |data_buffer| points to the data that was received in the
-  // frame. When writing, |data_buffer| must be a valid pointer for the lifetime
-  // of the frame, which may get serialized some time after creation.
+  // frame. |data_buffer| is not used when writing.
   const char* data_buffer;
   QuicStreamOffset offset;  // Location of this data in the stream.
 
-  QuicCryptoFrame(QuicStreamOffset offset,
+  QuicCryptoFrame(EncryptionLevel level,
+                  QuicStreamOffset offset,
                   const char* data_buffer,
                   QuicPacketLength data_length);
 };
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc
index a951ce6..2e6a303 100644
--- a/quic/core/frames/quic_frame.cc
+++ b/quic/core/frames/quic_frame.cc
@@ -246,15 +246,15 @@
     case PING_FRAME:
       copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
       break;
+    case STOP_SENDING_FRAME:
+      copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
+      break;
     case STREAM_ID_BLOCKED_FRAME:
       copy = QuicFrame(QuicStreamIdBlockedFrame(frame.stream_id_blocked_frame));
       break;
     case MAX_STREAM_ID_FRAME:
       copy = QuicFrame(QuicMaxStreamIdFrame(frame.max_stream_id_frame));
       break;
-    case STOP_SENDING_FRAME:
-      copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
-      break;
     default:
       QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame;
       copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 725ce83..af9c40b 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -27,12 +27,13 @@
 
 TEST_F(QuicFramesTest, AckFrameToString) {
   QuicAckFrame frame;
-  frame.largest_acked = 5;
+  frame.largest_acked = QuicPacketNumber(5);
   frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
-  frame.packets.Add(4);
-  frame.packets.Add(5);
+  frame.packets.Add(QuicPacketNumber(4));
+  frame.packets.Add(QuicPacketNumber(5));
   frame.received_packet_times = {
-      {6, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+      {QuicPacketNumber(6),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ(
@@ -45,11 +46,12 @@
 
 TEST_F(QuicFramesTest, BigAckFrameToString) {
   QuicAckFrame frame;
-  frame.largest_acked = 500;
+  frame.largest_acked = QuicPacketNumber(500);
   frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
-  frame.packets.AddRange(4, 501);
+  frame.packets.AddRange(QuicPacketNumber(4), QuicPacketNumber(501));
   frame.received_packet_times = {
-      {500, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+      {QuicPacketNumber(500),
+       QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ(
@@ -213,7 +215,7 @@
 
 TEST_F(QuicFramesTest, StopWaitingFrameToString) {
   QuicStopWaitingFrame frame;
-  frame.least_unacked = 2;
+  frame.least_unacked = QuicPacketNumber(2);
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ("{ least_unacked: 2 }\n", stream.str());
@@ -223,69 +225,84 @@
 
 TEST_F(QuicFramesTest, IsAwaitingPacket) {
   QuicAckFrame ack_frame1;
-  ack_frame1.largest_acked = 10u;
-  ack_frame1.packets.AddRange(1, 11);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u));
+  ack_frame1.largest_acked = QuicPacketNumber(10u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(11));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
+  EXPECT_FALSE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(1u), QuicPacketNumber()));
 
-  ack_frame1.packets.Add(12);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
+  ack_frame1.packets.Add(QuicPacketNumber(12));
+  EXPECT_TRUE(
+      IsAwaitingPacket(ack_frame1, QuicPacketNumber(11u), QuicPacketNumber()));
 
   QuicAckFrame ack_frame2;
-  ack_frame2.largest_acked = 100u;
-  ack_frame2.packets.AddRange(21, 100);
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u));
-  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u));
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
+  ack_frame2.largest_acked = QuicPacketNumber(100u);
+  ack_frame2.packets.AddRange(QuicPacketNumber(21), QuicPacketNumber(100));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(11u),
+                                QuicPacketNumber(20u)));
+  EXPECT_FALSE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(80u),
+                                QuicPacketNumber(20u)));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
 
-  ack_frame2.packets.AddRange(102, 200);
-  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
+  ack_frame2.packets.AddRange(QuicPacketNumber(102), QuicPacketNumber(200));
+  EXPECT_TRUE(IsAwaitingPacket(ack_frame2, QuicPacketNumber(101u),
+                               QuicPacketNumber(20u)));
 }
 
 TEST_F(QuicFramesTest, AddPacket) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.Add(1);
-  ack_frame1.packets.Add(99);
+  ack_frame1.packets.Add(QuicPacketNumber(1));
+  ack_frame1.packets.Add(QuicPacketNumber(99));
 
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(1u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   EXPECT_EQ(expected_intervals, actual_intervals);
 
-  ack_frame1.packets.Add(20);
+  ack_frame1.packets.Add(QuicPacketNumber(20));
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(20, 21));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals2.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
   EXPECT_EQ(expected_intervals2, actual_intervals2);
 
-  ack_frame1.packets.Add(19);
-  ack_frame1.packets.Add(21);
+  ack_frame1.packets.Add(QuicPacketNumber(19));
+  ack_frame1.packets.Add(QuicPacketNumber(21));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals3(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals3;
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(1, 2));
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(19, 22));
-  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(99, 100));
+  expected_intervals3.emplace_back(
+      QuicInterval<QuicPacketNumber>(QuicPacketNumber(1), QuicPacketNumber(2)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(19), QuicPacketNumber(22)));
+  expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(99), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals3, actual_intervals3);
 
-  ack_frame1.packets.Add(20);
+  ack_frame1.packets.Add(QuicPacketNumber(20));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals4(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -293,37 +310,44 @@
   EXPECT_EQ(expected_intervals3, actual_intervals4);
 
   QuicAckFrame ack_frame2;
-  ack_frame2.packets.Add(20);
-  ack_frame2.packets.Add(40);
-  ack_frame2.packets.Add(60);
-  ack_frame2.packets.Add(10);
-  ack_frame2.packets.Add(80);
+  ack_frame2.packets.Add(QuicPacketNumber(20));
+  ack_frame2.packets.Add(QuicPacketNumber(40));
+  ack_frame2.packets.Add(QuicPacketNumber(60));
+  ack_frame2.packets.Add(QuicPacketNumber(10));
+  ack_frame2.packets.Add(QuicPacketNumber(80));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals5(
       ack_frame2.packets.begin(), ack_frame2.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals5;
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(10, 11));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(20, 21));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(40, 41));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(60, 61));
-  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(80, 81));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(11)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(21)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(41)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(61)));
+  expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(81)));
 
   EXPECT_EQ(expected_intervals5, actual_intervals5);
 }
 
 TEST_F(QuicFramesTest, AddInterval) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.AddRange(1, 10);
-  ack_frame1.packets.AddRange(50, 100);
+  ack_frame1.packets.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
 
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(1u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 10));
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(50, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -331,48 +355,58 @@
   EXPECT_EQ(expected_intervals, actual_intervals);
 
   // Ensure adding a range within the existing ranges fails.
-  EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), "");
+  EXPECT_QUIC_BUG(
+      ack_frame1.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(30)),
+      "");
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2;
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 10));
-  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(50, 100));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(10)));
+  expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(50), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals());
   EXPECT_EQ(expected_intervals2, actual_intervals2);
 
   // Add ranges at both ends.
   QuicAckFrame ack_frame2;
-  ack_frame2.packets.AddRange(20, 25);
-  ack_frame2.packets.AddRange(40, 45);
-  ack_frame2.packets.AddRange(60, 65);
-  ack_frame2.packets.AddRange(10, 15);
-  ack_frame2.packets.AddRange(80, 85);
+  ack_frame2.packets.AddRange(QuicPacketNumber(20), QuicPacketNumber(25));
+  ack_frame2.packets.AddRange(QuicPacketNumber(40), QuicPacketNumber(45));
+  ack_frame2.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(65));
+  ack_frame2.packets.AddRange(QuicPacketNumber(10), QuicPacketNumber(15));
+  ack_frame2.packets.AddRange(QuicPacketNumber(80), QuicPacketNumber(85));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals8(
       ack_frame2.packets.begin(), ack_frame2.packets.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals8;
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(10, 15));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(20, 25));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(40, 45));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(60, 65));
-  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(80, 85));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(10), QuicPacketNumber(15)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(20), QuicPacketNumber(25)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(40), QuicPacketNumber(45)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(60), QuicPacketNumber(65)));
+  expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(80), QuicPacketNumber(85)));
 
   EXPECT_EQ(expected_intervals8, actual_intervals8);
 }
 
 TEST_F(QuicFramesTest, AddAdjacentForward) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.Add(49);
-  ack_frame1.packets.AddRange(50, 60);
-  ack_frame1.packets.AddRange(60, 70);
-  ack_frame1.packets.AddRange(70, 100);
+  ack_frame1.packets.Add(QuicPacketNumber(49));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -382,13 +416,14 @@
 
 TEST_F(QuicFramesTest, AddAdjacentReverse) {
   QuicAckFrame ack_frame1;
-  ack_frame1.packets.AddRange(70, 100);
-  ack_frame1.packets.AddRange(60, 70);
-  ack_frame1.packets.AddRange(50, 60);
-  ack_frame1.packets.Add(49);
+  ack_frame1.packets.AddRange(QuicPacketNumber(70), QuicPacketNumber(100));
+  ack_frame1.packets.AddRange(QuicPacketNumber(60), QuicPacketNumber(70));
+  ack_frame1.packets.AddRange(QuicPacketNumber(50), QuicPacketNumber(60));
+  ack_frame1.packets.Add(QuicPacketNumber(49));
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(49), QuicPacketNumber(100)));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       ack_frame1.packets.begin(), ack_frame1.packets.end());
@@ -398,19 +433,19 @@
 
 TEST_F(QuicFramesTest, RemoveSmallestInterval) {
   QuicAckFrame ack_frame1;
-  ack_frame1.largest_acked = 100u;
-  ack_frame1.packets.AddRange(51, 60);
-  ack_frame1.packets.AddRange(71, 80);
-  ack_frame1.packets.AddRange(91, 100);
+  ack_frame1.largest_acked = QuicPacketNumber(100u);
+  ack_frame1.packets.AddRange(QuicPacketNumber(51), QuicPacketNumber(60));
+  ack_frame1.packets.AddRange(QuicPacketNumber(71), QuicPacketNumber(80));
+  ack_frame1.packets.AddRange(QuicPacketNumber(91), QuicPacketNumber(100));
   ack_frame1.packets.RemoveSmallestInterval();
   EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(71u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(71u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 
   ack_frame1.packets.RemoveSmallestInterval();
   EXPECT_EQ(1u, ack_frame1.packets.NumIntervals());
-  EXPECT_EQ(91u, ack_frame1.packets.Min());
-  EXPECT_EQ(99u, ack_frame1.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(91u), ack_frame1.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), ack_frame1.packets.Max());
 }
 
 class PacketNumberQueueTest : public QuicTest {};
@@ -418,85 +453,85 @@
 // Tests that a queue contains the expected data after calls to Add().
 TEST_F(PacketNumberQueueTest, AddRange) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 51);
-  queue.Add(53);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(51));
+  queue.Add(QuicPacketNumber(53));
 
-  EXPECT_FALSE(queue.Contains(0));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
-  EXPECT_FALSE(queue.Contains(51));
-  EXPECT_FALSE(queue.Contains(52));
-  EXPECT_TRUE(queue.Contains(53));
-  EXPECT_FALSE(queue.Contains(54));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(52)));
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(53)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(54)));
   EXPECT_EQ(51u, queue.NumPacketsSlow());
-  EXPECT_EQ(1u, queue.Min());
-  EXPECT_EQ(53u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(1u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(53u), queue.Max());
 
-  queue.Add(70);
-  EXPECT_EQ(70u, queue.Max());
+  queue.Add(QuicPacketNumber(70));
+  EXPECT_EQ(QuicPacketNumber(70u), queue.Max());
 }
 
 // Tests Contains function
 TEST_F(PacketNumberQueueTest, Contains) {
   PacketNumberQueue queue;
-  EXPECT_FALSE(queue.Contains(0));
-  queue.AddRange(5, 10);
-  queue.Add(20);
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
+  queue.AddRange(QuicPacketNumber(5), QuicPacketNumber(10));
+  queue.Add(QuicPacketNumber(20));
 
   for (int i = 1; i < 5; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
 
   for (int i = 5; i < 10; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
   for (int i = 10; i < 20; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
-  EXPECT_TRUE(queue.Contains(20));
-  EXPECT_FALSE(queue.Contains(21));
+  EXPECT_TRUE(queue.Contains(QuicPacketNumber(20)));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(21)));
 
   PacketNumberQueue queue2;
-  EXPECT_FALSE(queue2.Contains(1));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(1)));
   for (int i = 1; i < 51; ++i) {
-    queue2.Add(2 * i);
+    queue2.Add(QuicPacketNumber(2 * i));
   }
-  EXPECT_FALSE(queue2.Contains(0));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
     if (i % 2 == 0) {
-      EXPECT_TRUE(queue2.Contains(i));
+      EXPECT_TRUE(queue2.Contains(QuicPacketNumber(i)));
     } else {
-      EXPECT_FALSE(queue2.Contains(i));
+      EXPECT_FALSE(queue2.Contains(QuicPacketNumber(i)));
     }
   }
-  EXPECT_FALSE(queue2.Contains(101));
+  EXPECT_FALSE(queue2.Contains(QuicPacketNumber(101)));
 }
 
 // Tests that a queue contains the expected data after calls to RemoveUpTo().
 TEST_F(PacketNumberQueueTest, Removal) {
   PacketNumberQueue queue;
-  EXPECT_FALSE(queue.Contains(51));
-  queue.AddRange(0, 100);
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber(51)));
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
 
-  EXPECT_TRUE(queue.RemoveUpTo(51));
-  EXPECT_FALSE(queue.RemoveUpTo(51));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(51)));
+  EXPECT_FALSE(queue.RemoveUpTo(QuicPacketNumber(51)));
 
-  EXPECT_FALSE(queue.Contains(0));
+  EXPECT_FALSE(queue.Contains(QuicPacketNumber()));
   for (int i = 1; i < 51; ++i) {
-    EXPECT_FALSE(queue.Contains(i));
+    EXPECT_FALSE(queue.Contains(QuicPacketNumber(i)));
   }
   for (int i = 51; i < 100; ++i) {
-    EXPECT_TRUE(queue.Contains(i));
+    EXPECT_TRUE(queue.Contains(QuicPacketNumber(i)));
   }
   EXPECT_EQ(49u, queue.NumPacketsSlow());
-  EXPECT_EQ(51u, queue.Min());
-  EXPECT_EQ(99u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(51u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(99u), queue.Max());
 
   PacketNumberQueue queue2;
-  queue2.AddRange(0, 5);
-  EXPECT_TRUE(queue2.RemoveUpTo(3));
-  EXPECT_TRUE(queue2.RemoveUpTo(50));
+  queue2.AddRange(QuicPacketNumber(1), QuicPacketNumber(5));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(3)));
+  EXPECT_TRUE(queue2.RemoveUpTo(QuicPacketNumber(50)));
   EXPECT_TRUE(queue2.Empty());
 }
 
@@ -506,8 +541,8 @@
   EXPECT_TRUE(queue.Empty());
   EXPECT_EQ(0u, queue.NumPacketsSlow());
 
-  queue.AddRange(1, 100);
-  EXPECT_TRUE(queue.RemoveUpTo(100));
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(100)));
   EXPECT_TRUE(queue.Empty());
   EXPECT_EQ(0u, queue.NumPacketsSlow());
 }
@@ -518,29 +553,30 @@
   PacketNumberQueue queue;
   oss << queue;
 
-  queue.Add(1);
-  queue.AddRange(50, 100);
+  queue.Add(QuicPacketNumber(1));
+  queue.AddRange(QuicPacketNumber(50), QuicPacketNumber(100));
   oss << queue;
 }
 
 // Tests that the iterators returned from a packet queue iterate over the queue.
 TEST_F(PacketNumberQueueTest, Iterators) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 100);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       queue.begin(), queue.end());
 
   PacketNumberQueue queue2;
   for (int i = 1; i < 100; i++) {
-    queue2.AddRange(i, i + 1);
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
   }
 
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2(
       queue2.begin(), queue2.end());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
   EXPECT_EQ(expected_intervals, actual_intervals);
   EXPECT_EQ(expected_intervals, actual_intervals2);
   EXPECT_EQ(actual_intervals, actual_intervals2);
@@ -548,10 +584,10 @@
 
 TEST_F(PacketNumberQueueTest, ReversedIterators) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 100);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(100));
   PacketNumberQueue queue2;
   for (int i = 1; i < 100; i++) {
-    queue2.AddRange(i, i + 1);
+    queue2.AddRange(QuicPacketNumber(i), QuicPacketNumber(i + 1));
   }
   const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals(
       queue.rbegin(), queue.rend());
@@ -559,7 +595,8 @@
       queue2.rbegin(), queue2.rend());
 
   std::vector<QuicInterval<QuicPacketNumber>> expected_intervals;
-  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100));
+  expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(
+      QuicPacketNumber(1), QuicPacketNumber(100)));
 
   EXPECT_EQ(expected_intervals, actual_intervals);
   EXPECT_EQ(expected_intervals, actual_intervals2);
@@ -567,7 +604,7 @@
 
   PacketNumberQueue queue3;
   for (int i = 1; i < 20; i++) {
-    queue3.Add(2 * i);
+    queue3.Add(QuicPacketNumber(2 * i));
   }
 
   auto begin = queue3.begin();
@@ -583,17 +620,17 @@
 
 TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
   PacketNumberQueue queue;
-  queue.AddRange(1, 10);
-  queue.AddRange(20, 30);
-  queue.AddRange(40, 50);
+  queue.AddRange(QuicPacketNumber(1), QuicPacketNumber(10));
+  queue.AddRange(QuicPacketNumber(20), QuicPacketNumber(30));
+  queue.AddRange(QuicPacketNumber(40), QuicPacketNumber(50));
   EXPECT_EQ(3u, queue.NumIntervals());
   EXPECT_EQ(10u, queue.LastIntervalLength());
 
-  EXPECT_TRUE(queue.RemoveUpTo(25));
+  EXPECT_TRUE(queue.RemoveUpTo(QuicPacketNumber(25)));
   EXPECT_EQ(2u, queue.NumIntervals());
   EXPECT_EQ(10u, queue.LastIntervalLength());
-  EXPECT_EQ(25u, queue.Min());
-  EXPECT_EQ(49u, queue.Max());
+  EXPECT_EQ(QuicPacketNumber(25u), queue.Min());
+  EXPECT_EQ(QuicPacketNumber(49u), queue.Max());
 }
 
 }  // namespace
diff --git a/quic/core/frames/quic_stop_waiting_frame.cc b/quic/core/frames/quic_stop_waiting_frame.cc
index 696bed4..0674e8f 100644
--- a/quic/core/frames/quic_stop_waiting_frame.cc
+++ b/quic/core/frames/quic_stop_waiting_frame.cc
@@ -8,7 +8,7 @@
 
 namespace quic {
 
-QuicStopWaitingFrame::QuicStopWaitingFrame() : least_unacked(0) {}
+QuicStopWaitingFrame::QuicStopWaitingFrame() {}
 
 QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
 
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 55c72ff..132da8e 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -22,6 +22,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -62,8 +63,6 @@
 #include "net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h"
 #include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h"
 
-using gfe2::EpollEvent;
-using gfe2::EpollServer;
 using spdy::kV3LowestPriority;
 using spdy::SETTINGS_MAX_HEADER_LIST_SIZE;
 using spdy::SpdyFramer;
@@ -260,7 +259,7 @@
   explicit ClientDelegate(QuicClient* client) : client_(client) {}
   ~ClientDelegate() override = default;
   void OnCanWrite() override {
-    EpollEvent event(EPOLLOUT);
+    QuicEpollEvent event(EPOLLOUT);
     client_->epoll_network_helper()->OnEvent(client_->GetLatestFD(), &event);
   }
 
@@ -278,10 +277,11 @@
         server_hostname_("test.example.com"),
         client_writer_(nullptr),
         server_writer_(nullptr),
-        negotiated_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        negotiated_version_(UnsupportedQuicVersion()),
         chlo_multiplier_(0),
         stream_factory_(nullptr),
-        support_server_push_(false) {
+        support_server_push_(false),
+        override_connection_id_(nullptr) {
     FLAGS_quic_supports_tls_handshake = true;
     SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, true);
     SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true);
@@ -330,6 +330,9 @@
     if (!pre_shared_key_client_.empty()) {
       client->client()->SetPreSharedKey(pre_shared_key_client_);
     }
+    if (override_connection_id_ != nullptr) {
+      client->UseConnectionId(*override_connection_id_);
+    }
     client->Connect();
     return client;
   }
@@ -419,14 +422,14 @@
     }
 
     CreateClientWithWriter();
-    static EpollEvent event(EPOLLOUT);
+    static QuicEpollEvent event(EPOLLOUT);
     if (client_writer_ != nullptr) {
       client_writer_->Initialize(
           QuicConnectionPeer::GetHelper(
               client_->client()->client_session()->connection()),
           QuicConnectionPeer::GetAlarmFactory(
               client_->client()->client_session()->connection()),
-          absl::make_unique<ClientDelegate>(client_->client()));
+          QuicMakeUnique<ClientDelegate>(client_->client()));
     }
     initialized_ = true;
     return client_->client()->connected();
@@ -470,7 +473,7 @@
 
     server_writer_->Initialize(QuicDispatcherPeer::GetHelper(dispatcher),
                                QuicDispatcherPeer::GetAlarmFactory(dispatcher),
-                               absl::make_unique<ServerDelegate>(dispatcher));
+                               QuicMakeUnique<ServerDelegate>(dispatcher));
     if (stream_factory_ != nullptr) {
       down_cast<QuicTestServer*>(server_thread_->server())
           ->SetSpdyStreamFactory(stream_factory_);
@@ -632,6 +635,7 @@
   bool support_server_push_;
   QuicString pre_shared_key_client_;
   QuicString pre_shared_key_server_;
+  QuicConnectionId* override_connection_id_;
 };
 
 // Run all end to end tests with all supported versions.
@@ -724,6 +728,28 @@
             client_->client()->GetNumSentClientHellos());
 }
 
+TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) {
+  QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId(
+      GetParam().negotiated_version.transport_version);
+  override_connection_id_ = &connection_id;
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+  EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+  int expected_num_client_hellos = 2;
+  if (ServerSendsVersionNegotiation()) {
+    ++expected_num_client_hellos;
+    if (BothSidesSupportStatelessRejects()) {
+      ++expected_num_client_hellos;
+    }
+  }
+  EXPECT_EQ(expected_num_client_hellos,
+            client_->client()->GetNumSentClientHellos());
+  EXPECT_EQ(client_->client()->client_session()->connection()->connection_id(),
+            QuicUtils::CreateZeroConnectionId(
+                GetParam().negotiated_version.transport_version));
+}
+
 // TODO(dschinazi) remove this test once the flags are deprecated
 TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDServer) {
   SetQuicRestartFlag(quic_variable_length_connection_ids_client, false);
@@ -1870,7 +1896,7 @@
 
   // Register the new FD for epoll events.
   int new_fd = client_->client()->GetLatestFD();
-  EpollServer* eps = client_->epoll_server();
+  QuicEpollServer* eps = client_->epoll_server();
   eps->RegisterFD(new_fd, client_->client()->epoll_network_helper(),
                   EPOLLIN | EPOLLOUT | EPOLLET);
 
@@ -3132,13 +3158,13 @@
   client->UseWriter(client_writer_);
   client->Connect();
   client_.reset(client);
-  static EpollEvent event(EPOLLOUT);
+  static QuicEpollEvent event(EPOLLOUT);
   client_writer_->Initialize(
       QuicConnectionPeer::GetHelper(
           client_->client()->client_session()->connection()),
       QuicConnectionPeer::GetAlarmFactory(
           client_->client()->client_session()->connection()),
-      absl::make_unique<ClientDelegate>(client_->client()));
+      QuicMakeUnique<ClientDelegate>(client_->client()));
   initialized_ = true;
   ASSERT_TRUE(client_->client()->connected());
 
@@ -3695,6 +3721,32 @@
   EXPECT_EQ(kStopSendingTestCode, client_stream->last_stop_sending_code());
 }
 
+TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) {
+  ASSERT_TRUE(Initialize());
+
+  // Send a request without a fin, to keep the stream open
+  SpdyHeaderBlock headers;
+  headers[":method"] = "POST";
+  headers[":path"] = "/foo";
+  headers[":scheme"] = "https";
+  headers[":authority"] = server_hostname_;
+  client_->SendMessage(headers, "", /*fin=*/false);
+  // Stream should be open
+  ASSERT_NE(nullptr, client_->latest_created_stream());
+  EXPECT_FALSE(
+      QuicStreamPeer::write_side_closed(client_->latest_created_stream()));
+  EXPECT_FALSE(
+      QuicStreamPeer::read_side_closed(client_->latest_created_stream()));
+
+  // Send a RST_STREAM+STOP_SENDING on the stream
+  // Code is not important.
+  client_->latest_created_stream()->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+  client_->WaitForResponse();
+
+  // Stream should be gone.
+  ASSERT_EQ(nullptr, client_->latest_created_stream());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index f1d6de0..345f2cb 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -262,6 +262,24 @@
       }
       return;
     }
+
+    case 0xE: {  // DUPLICATE_PUSH
+      BufferFramePayload(reader);
+      if (remaining_frame_length_ != 0) {
+        return;
+      }
+      QuicDataReader reader(buffer_.data(), current_frame_length_,
+                            NETWORK_BYTE_ORDER);
+      DuplicatePushFrame frame;
+      if (!reader.ReadVarInt62(&frame.push_id)) {
+        RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+        return;
+      }
+      visitor_->OnDuplicatePushFrame(frame);
+      state_ = STATE_READING_FRAME_LENGTH;
+      current_length_field_size_ = 0;
+      return;
+    }
     // Reserved frame types.
     // TODO(rch): Since these are actually the same behavior as the
     // default, we probably don't need to special case them here?
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h
index 730bbe3..a5f41b5 100644
--- a/quic/core/http/http_decoder.h
+++ b/quic/core/http/http_decoder.h
@@ -58,7 +58,10 @@
     // Called when a SETTINGS frame has been successfully parsed.
     virtual void OnSettingsFrame(const SettingsFrame& frame) = 0;
 
-    // Called when a DATA frame has been recevied, |frame_lengths| will be
+    // Called when a DUPLICATE_PUSH frame has been successfully parsed.
+    virtual void OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0;
+
+    // Called when a DATA frame has been received, |frame_lengths| will be
     // passed to inform header length and payload length of the frame.
     virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0;
     // Called when the payload of a DATA frame has read. May be called
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index 5261d65..c2b303c 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -23,6 +23,7 @@
   MOCK_METHOD1(OnMaxPushIdFrame, void(const MaxPushIdFrame& frame));
   MOCK_METHOD1(OnGoAwayFrame, void(const GoAwayFrame& frame));
   MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame& frame));
+  MOCK_METHOD1(OnDuplicatePushFrame, void(const DuplicatePushFrame& frame));
 
   MOCK_METHOD1(OnDataFrameStart, void(Http3FrameLengths frame_lengths));
   MOCK_METHOD1(OnDataFramePayload, void(QuicStringPiece payload));
@@ -134,7 +135,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("Headers"));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("Headers")));
   EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -143,13 +144,13 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("H"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("a"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("d"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("r"));
-  EXPECT_CALL(visitor_, OnPushPromiseFramePayload("s"));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("H")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("d")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("r")));
+  EXPECT_CALL(visitor_, OnPushPromiseFramePayload(QuicStringPiece("s")));
   EXPECT_CALL(visitor_, OnPushPromiseFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
@@ -182,6 +183,29 @@
   EXPECT_EQ("", decoder_.error_detail());
 }
 
+TEST_F(HttpDecoderTest, DuplicatePush) {
+  char input[] = {// length
+                  0x1,
+                  // type (DUPLICATE_PUSH)
+                  0x0E,
+                  // Push Id
+                  0x01};
+  // Process the full frame.
+  EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1})));
+  EXPECT_EQ(QUIC_ARRAYSIZE(input),
+            decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
+  EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+  EXPECT_EQ("", decoder_.error_detail());
+
+  // Process the frame incremently.
+  EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1})));
+  for (char c : input) {
+    EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
+  }
+  EXPECT_EQ(QUIC_NO_ERROR, decoder_.error());
+  EXPECT_EQ("", decoder_.error_detail());
+}
+
 TEST_F(HttpDecoderTest, PriorityFrame) {
   char input[] = {// length
                   0x4,
@@ -273,7 +297,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
-  EXPECT_CALL(visitor_, OnDataFramePayload("Data!"));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("Data!")));
   EXPECT_CALL(visitor_, OnDataFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -282,11 +306,11 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5)));
-  EXPECT_CALL(visitor_, OnDataFramePayload("D"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("a"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("t"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("a"));
-  EXPECT_CALL(visitor_, OnDataFramePayload("!"));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("D")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("t")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece("!")));
   EXPECT_CALL(visitor_, OnDataFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
@@ -358,7 +382,7 @@
   // Process the full frame.
   InSequence s;
   EXPECT_CALL(visitor_, OnHeadersFrameStart());
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("Headers"));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers")));
   EXPECT_CALL(visitor_, OnHeadersFrameEnd());
   EXPECT_EQ(QUIC_ARRAYSIZE(input),
             decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input)));
@@ -367,13 +391,13 @@
 
   // Process the frame incremently.
   EXPECT_CALL(visitor_, OnHeadersFrameStart());
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("H"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("e"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("a"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("d"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("e"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("r"));
-  EXPECT_CALL(visitor_, OnHeadersFramePayload("s"));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("H")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("a")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("d")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("r")));
+  EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("s")));
   EXPECT_CALL(visitor_, OnHeadersFrameEnd());
   for (char c : input) {
     EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1));
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc
index 6e2487b..7c07838 100644
--- a/quic/core/http/http_encoder.cc
+++ b/quic/core/http/http_encoder.cc
@@ -59,33 +59,32 @@
 HttpEncoder::~HttpEncoder() {}
 
 QuicByteCount HttpEncoder::SerializeDataFrameHeader(
-    QuicByteCount length,
+    QuicByteCount payload_length,
     std::unique_ptr<char[]>* output) {
-  DCHECK_NE(0u, length);
+  DCHECK_NE(0u, payload_length);
   QuicByteCount header_length =
-      QuicDataWriter::GetVarInt62Len(length) + kFrameTypeLength;
+      QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
 
   output->reset(new char[header_length]);
   QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
 
-  if (WriteFrameHeader(length, HttpFrameType::DATA, &writer)) {
+  if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) {
     return header_length;
   }
   return 0;
 }
 
 QuicByteCount HttpEncoder::SerializeHeadersFrameHeader(
-    const HeadersFrame& headers,
+    QuicByteCount payload_length,
     std::unique_ptr<char[]>* output) {
+  DCHECK_NE(0u, payload_length);
   QuicByteCount header_length =
-      QuicDataWriter::GetVarInt62Len(headers.headers.length()) +
-      kFrameTypeLength;
+      QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength;
 
   output->reset(new char[header_length]);
   QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
 
-  if (WriteFrameHeader(headers.headers.length(), HttpFrameType::HEADERS,
-                       &writer)) {
+  if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) {
     return header_length;
   }
   return 0;
@@ -225,6 +224,24 @@
   return 0;
 }
 
+QuicByteCount HttpEncoder::SerializeDuplicatePushFrame(
+    const DuplicatePushFrame& duplicate_push,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      QuicDataWriter::GetVarInt62Len(duplicate_push.push_id);
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH,
+                       &writer) &&
+      writer.WriteVarInt62(duplicate_push.push_id)) {
+    return total_length;
+  }
+  return 0;
+}
+
 bool HttpEncoder::WriteFrameHeader(QuicByteCount length,
                                    HttpFrameType type,
                                    QuicDataWriter* writer) {
diff --git a/quic/core/http/http_encoder.h b/quic/core/http/http_encoder.h
index 79b76e9..f04e6e4 100644
--- a/quic/core/http/http_encoder.h
+++ b/quic/core/http/http_encoder.h
@@ -24,14 +24,14 @@
 
   ~HttpEncoder();
 
-  // Serializes the header of a DATA frame into a new buffer stored in |output|.
+  // Serializes a DATA frame header into a new buffer stored in |output|.
   // Returns the length of the buffer on success, or 0 otherwise.
-  QuicByteCount SerializeDataFrameHeader(QuicByteCount length,
+  QuicByteCount SerializeDataFrameHeader(QuicByteCount payload_length,
                                          std::unique_ptr<char[]>* output);
 
-  // Serializes the header of a HEADERS frame into a new buffer stored in
-  // |output|. Returns the length of the buffer on success, or 0 otherwise.
-  QuicByteCount SerializeHeadersFrameHeader(const HeadersFrame& headers,
+  // Serializes a HEADERS frame header into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeHeadersFrameHeader(QuicByteCount payload_length,
                                             std::unique_ptr<char[]>* output);
 
   // Serializes a PRIORITY frame into a new buffer stored in |output|.
@@ -66,6 +66,12 @@
   QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id,
                                         std::unique_ptr<char[]>* output);
 
+  // Serialize a DUPLICATE_PUSH frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeDuplicatePushFrame(
+      const DuplicatePushFrame& duplicate_push,
+      std::unique_ptr<char[]>* output);
+
  private:
   bool WriteFrameHeader(QuicByteCount length,
                         HttpFrameType type,
diff --git a/quic/core/http/http_encoder_test.cc b/quic/core/http/http_encoder_test.cc
index 70cfd6a..a484aed 100644
--- a/quic/core/http/http_encoder_test.cc
+++ b/quic/core/http/http_encoder_test.cc
@@ -18,11 +18,9 @@
 };
 
 TEST_F(HttpEncoderTest, SerializeDataFrameHeader) {
-  DataFrame data;
-  data.data = "Data!";
   std::unique_ptr<char[]> buffer;
   uint64_t length =
-      encoder_.SerializeDataFrameHeader(data.data.length(), &buffer);
+      encoder_.SerializeDataFrameHeader(/* payload_length = */ 5, &buffer);
   char output[] = {// length
                    0x05,
                    // type (DATA)
@@ -33,10 +31,9 @@
 }
 
 TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) {
-  HeadersFrame headers;
-  headers.headers = "Headers";
   std::unique_ptr<char[]> buffer;
-  uint64_t length = encoder_.SerializeHeadersFrameHeader(headers, &buffer);
+  uint64_t length =
+      encoder_.SerializeHeadersFrameHeader(/* payload_length = */ 7, &buffer);
   char output[] = {// length
                    0x07,
                    // type (HEADERS)
@@ -167,5 +164,22 @@
                                 QUIC_ARRAYSIZE(output));
 }
 
+TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) {
+  DuplicatePushFrame duplicate_push;
+  duplicate_push.push_id = 0x1;
+  char output[] = {// length
+                   0x1,
+                   // type (DUPLICATE_PUSH)
+                   0x0E,
+                   // Push Id
+                   0x01};
+  std::unique_ptr<char[]> buffer;
+  uint64_t length =
+      encoder_.SerializeDuplicatePushFrame(duplicate_push, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("DUPLICATE_PUSH", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/http/http_frames.h b/quic/core/http/http_frames.h
index 6b6aa41..ea11557 100644
--- a/quic/core/http/http_frames.h
+++ b/quic/core/http/http_frames.h
@@ -21,10 +21,11 @@
   SETTINGS = 0x4,
   PUSH_PROMISE = 0x5,
   GOAWAY = 0x7,
-  MAX_PUSH_ID = 0xD
+  MAX_PUSH_ID = 0xD,
+  DUPLICATE_PUSH = 0xE
 };
 
-// 4.2.2.  DATA
+// 4.2.1.  DATA
 //
 //   DATA frames (type=0x0) convey arbitrary, variable-length sequences of
 //   octets associated with an HTTP request or response payload.
@@ -32,7 +33,7 @@
   QuicStringPiece data;
 };
 
-// 4.2.3.  HEADERS
+// 4.2.2.  HEADERS
 //
 //   The HEADERS frame (type=0x1) is used to carry a header block,
 //   compressed using QPACK.
@@ -40,7 +41,7 @@
   QuicStringPiece headers;
 };
 
-// 4.2.4.  PRIORITY
+// 4.2.3.  PRIORITY
 //
 //   The PRIORITY (type=0x02) frame specifies the sender-advised priority
 //   of a stream
@@ -69,7 +70,7 @@
   }
 };
 
-// 4.2.5.  CANCEL_PUSH
+// 4.2.4.  CANCEL_PUSH
 //
 //   The CANCEL_PUSH frame (type=0x3) is used to request cancellation of
 //   server push prior to the push stream being created.
@@ -83,7 +84,7 @@
   }
 };
 
-// 4.2.6.  SETTINGS
+// 4.2.5.  SETTINGS
 //
 //   The SETTINGS frame (type=0x4) conveys configuration parameters that
 //   affect how endpoints communicate, such as preferences and constraints
@@ -100,7 +101,7 @@
   }
 };
 
-// 4.2.7.  PUSH_PROMISE
+// 4.2.6.  PUSH_PROMISE
 //
 //   The PUSH_PROMISE frame (type=0x05) is used to carry a request header
 //   set from server to client, as in HTTP/2.
@@ -113,7 +114,7 @@
   }
 };
 
-// 4.2.8.  GOAWAY
+// 4.2.7.  GOAWAY
 //
 //   The GOAWAY frame (type=0x7) is used to initiate graceful shutdown of
 //   a connection by a server.
@@ -125,7 +126,7 @@
   }
 };
 
-// 4.2.9.  MAX_PUSH_ID
+// 4.2.8.  MAX_PUSH_ID
 //
 //   The MAX_PUSH_ID frame (type=0xD) is used by clients to control the
 //   number of server pushes that the server can initiate.
@@ -137,6 +138,19 @@
   }
 };
 
+// 4.2.9.  DUPLICATE_PUSH
+//
+//  The DUPLICATE_PUSH frame (type=0xE) is used by servers to indicate
+//  that an existing pushed resource is related to multiple client
+//  requests.
+struct DuplicatePushFrame {
+  PushId push_id;
+
+  bool operator==(const DuplicatePushFrame& rhs) const {
+    return push_id == rhs.push_id;
+  }
+};
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_HTTP_HTTP_FRAMES_H_
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc
index 47e3a27..40b43dc 100644
--- a/quic/core/http/quic_server_session_base.cc
+++ b/quic/core/http/quic_server_session_base.cc
@@ -30,8 +30,7 @@
       helper_(helper),
       bandwidth_resumption_enabled_(false),
       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
-      last_scup_time_(QuicTime::Zero()),
-      last_scup_packet_number_(0) {}
+      last_scup_time_(QuicTime::Zero()) {}
 
 QuicServerSessionBase::~QuicServerSessionBase() {}
 
@@ -112,9 +111,15 @@
   int64_t srtt_ms =
       sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
   int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
-  int64_t packets_since_last_scup =
-      connection()->sent_packet_manager().GetLargestSentPacket() -
-      last_scup_packet_number_;
+  int64_t packets_since_last_scup = 0;
+  const QuicPacketNumber largest_sent_packet =
+      connection()->sent_packet_manager().GetLargestSentPacket();
+  if (largest_sent_packet.IsInitialized()) {
+    packets_since_last_scup =
+        last_scup_packet_number_.IsInitialized()
+            ? largest_sent_packet - last_scup_packet_number_
+            : largest_sent_packet.ToUint64();
+  }
   if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
       now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
       packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
diff --git a/quic/core/http/quic_server_session_base.h b/quic/core/http/quic_server_session_base.h
index 7495253..55a8d60 100644
--- a/quic/core/http/quic_server_session_base.h
+++ b/quic/core/http/quic_server_session_base.h
@@ -126,7 +126,7 @@
   QuicTime last_scup_time_;
 
   // Number of packets sent to the peer, at the time we last sent a SCUP.
-  int64_t last_scup_packet_number_;
+  QuicPacketNumber last_scup_packet_number_;
 
   // Converts QuicBandwidth to an int32 bytes/second that can be
   // stored in CachedNetworkParameters.  TODO(jokulik): This function
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index 6a8fb37..9f36e37 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -170,6 +170,28 @@
     return connection_->transport_version();
   }
 
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close. This method can be used to inject a STOP_SENDING, which
+  // would cause a close in the opposite direction. This allows tests to do the
+  // extra work to get a two-way (full) close where desired. Also sets up
+  // expects needed to ensure that the STOP_SENDING worked as expected.
+  void InjectStopSendingFrame(QuicStreamId stream_id,
+                              QuicRstStreamErrorCode rst_stream_code) {
+    if (transport_version() != QUIC_VERSION_99) {
+      // Only needed for version 99/IETF QUIC. Noop otherwise.
+      return;
+    }
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_id,
+        static_cast<QuicApplicationErrorCode>(rst_stream_code));
+    EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+    session_->OnStopSendingFrame(stop_sending);
+  }
+
   StrictMock<MockQuicSessionVisitor> owner_;
   StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
   MockQuicConnectionHelper helper_;
@@ -221,6 +243,12 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send the same two bytes of payload in a new packet.
@@ -242,6 +270,12 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send two bytes of payload.
@@ -275,6 +309,11 @@
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst);
 
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   // If we were tracking, we'd probably want to reject this because it's data
   // past the reset point of stream 3.  As it's a closed stream we just drop the
   // data on the floor, but accept the packet because it has data for stream 5.
@@ -499,10 +538,11 @@
 
   // Bandwidth estimate has now changed sufficiently, enough time has passed,
   // and enough packets have been sent.
-  SerializedPacket packet(1 + kMinPacketsBetweenServerConfigUpdates,
-                          PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false,
-                          false);
-  sent_packet_manager->OnPacketSent(&packet, 0, now, NOT_RETRANSMISSION,
+  SerializedPacket packet(
+      QuicPacketNumber(1) + kMinPacketsBetweenServerConfigUpdates,
+      PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false);
+  sent_packet_manager->OnPacketSent(&packet, QuicPacketNumber(), now,
+                                    NOT_RETRANSMISSION,
                                     HAS_RETRANSMITTABLE_DATA);
 
   // Verify that the proto has exactly the values we expect.
@@ -655,7 +695,7 @@
 
   EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_))
+  EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_, _))
       .WillOnce(testing::Return(TestConnectionId(12345)));
 
   // Set the current packet
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index 579870a..a9d6c62 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -454,7 +454,7 @@
   QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
   // Close connection shouldn't be called.
   EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  if (connection_->transport_version() == QUIC_VERSION_99) {
+  if (connection_->transport_version() > QUIC_VERSION_46) {
     // Illegal fixed bit value.
     EXPECT_CALL(*connection_, OnError(_)).Times(1);
   }
diff --git a/quic/core/http/quic_spdy_server_stream_base_test.cc b/quic/core/http/quic_spdy_server_stream_base_test.cc
index ab13943..51abf0c 100644
--- a/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -62,6 +62,14 @@
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
   stream_->OnStreamReset(rst_frame);
+  if (session_.connection()->transport_version() == QUIC_VERSION_99) {
+    // Create and inject a STOP SENDING frame to complete the close
+    // of the stream. This is only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
 
   EXPECT_TRUE(stream_->reading_stopped());
   EXPECT_TRUE(stream_->write_side_closed());
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 00fb10f..affa07a 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1001,6 +1001,23 @@
                           GetNthClientInitiatedBidirectionalId(0),
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   session_.OnRstStream(rst1);
+
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0),
+        static_cast<QuicApplicationErrorCode>(QUIC_ERROR_PROCESSING_STREAM));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_ERROR_PROCESSING_STREAM));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
   // Connection should remain alive.
   EXPECT_TRUE(connection_->connected());
@@ -1219,15 +1236,31 @@
         .Times(2)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   } else {
-    // V99 has an additional, STOP_SENDING, frame.
+    // V99 has an additional, STOP_SENDING, frame and an additional RST_STREAM
+    // (the response to the STOP_SENDING) frame.
     EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(3)
+        .Times(4)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   }
   EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
                                QUIC_STREAM_CANCELLED, kByteOffset);
   session_.OnRstStream(rst_frame);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream->id(), QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
 }
 
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc
index 9a5d024..eb8135a 100644
--- a/quic/core/http/quic_spdy_stream.cc
+++ b/quic/core/http/quic_spdy_stream.cc
@@ -59,6 +59,10 @@
     CloseConnectionOnWrongFrame("Settings");
   }
 
+  void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
+    CloseConnectionOnWrongFrame("Duplicate Push");
+  }
+
   void OnDataFrameStart(Http3FrameLengths frame_lengths) override {
     stream_->OnDataFrameStart(frame_lengths);
   }
@@ -176,19 +180,23 @@
     QuicStringPiece data,
     bool fin,
     QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
-  if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99 &&
-      data.length() > 0) {
-    std::unique_ptr<char[]> buffer;
-    QuicByteCount header_length =
-        encoder_.SerializeDataFrameHeader(data.length(), &buffer);
-    WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
-                      nullptr);
-    QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
-                    << header_length;
-    total_header_bytes_written_ += header_length;
+  if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 ||
+      data.length() == 0) {
+    WriteOrBufferData(data, fin, std::move(ack_listener));
+    return;
   }
+  QuicConnection::ScopedPacketFlusher flusher(
+      spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+  std::unique_ptr<char[]> buffer;
+  QuicByteCount header_length =
+      encoder_.SerializeDataFrameHeader(data.length(), &buffer);
+  WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false,
+                    nullptr);
+  QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length "
+                  << header_length;
+  total_header_bytes_written_ += header_length;
   WriteOrBufferData(data, fin, std::move(ack_listener));
-  QUIC_DLOG(INFO) << "Stream" << id() << " is writing body of length "
+  QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length "
                   << data.length();
 }
 
@@ -254,6 +262,8 @@
     return {0, false};
   }
 
+  QuicConnection::ScopedPacketFlusher flusher(
+      spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
   struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length};
   QuicMemSliceStorage storage(
       &header_iov, 1,
diff --git a/quic/core/http/quic_spdy_stream_body_buffer.h b/quic/core/http/quic_spdy_stream_body_buffer.h
index acd4985..2485aac 100644
--- a/quic/core/http/quic_spdy_stream_body_buffer.h
+++ b/quic/core/http/quic_spdy_stream_body_buffer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
-#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
+#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
+#define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
 
 #include "net/third_party/quiche/src/quic/core/http/http_decoder.h"
 #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
@@ -72,4 +72,4 @@
 
 }  // namespace quic
 
-#endif  // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H
+#endif  // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_BODY_BUFFER_H_
diff --git a/quic/core/http/spdy_utils_test.cc b/quic/core/http/spdy_utils_test.cc
index b8edf49..6cd2f1d 100644
--- a/quic/core/http/spdy_utils_test.cc
+++ b/quic/core/http/spdy_utils_test.cc
@@ -327,6 +327,24 @@
   EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
 }
 
+TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "user@www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "/";
+  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
+TEST_F(GetPromisedUrlFromHeaders, InvalidPath) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "";
+  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
 using GetPromisedHostNameFromHeaders = QuicTest;
 
 TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) {
diff --git a/quic/core/legacy_quic_stream_id_manager.cc b/quic/core/legacy_quic_stream_id_manager.cc
index 000d0cb..6fb662a 100644
--- a/quic/core/legacy_quic_stream_id_manager.cc
+++ b/quic/core/legacy_quic_stream_id_manager.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
diff --git a/quic/core/legacy_quic_stream_id_manager.h b/quic/core/legacy_quic_stream_id_manager.h
index 79a4d47..78d4545 100644
--- a/quic/core/legacy_quic_stream_id_manager.h
+++ b/quic/core/legacy_quic_stream_id_manager.h
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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.
 #ifndef QUICHE_QUIC_CORE_LEGACY_QUIC_STREAM_ID_MANAGER_H_
 #define QUICHE_QUIC_CORE_LEGACY_QUIC_STREAM_ID_MANAGER_H_
 
diff --git a/quic/core/legacy_quic_stream_id_manager_test.cc b/quic/core/legacy_quic_stream_id_manager_test.cc
index 643ff5b..823cdc0 100644
--- a/quic/core/legacy_quic_stream_id_manager_test.cc
+++ b/quic/core/legacy_quic_stream_id_manager_test.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
diff --git a/quic/core/packet_number_indexed_queue.h b/quic/core/packet_number_indexed_queue.h
index 97d93de..ab2e20b 100644
--- a/quic/core/packet_number_indexed_queue.h
+++ b/quic/core/packet_number_indexed_queue.h
@@ -5,8 +5,9 @@
 #ifndef QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
 #define QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
 
-#include "base/logging.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
 
 namespace quic {
@@ -35,8 +36,7 @@
 template <typename T>
 class PacketNumberIndexedQueue {
  public:
-  PacketNumberIndexedQueue()
-      : number_of_present_entries_(0), first_packet_(0) {}
+  PacketNumberIndexedQueue() : number_of_present_entries_(0) {}
 
   // Retrieve the entry associated with the packet number.  Returns the pointer
   // to the entry in case of success, or nullptr if the entry does not exist.
@@ -65,15 +65,15 @@
   // proportional to the memory usage of the queue.
   size_t entry_slots_used() const { return entries_.size(); }
 
-  // Packet number of the first entry in the queue.  Zero if the queue is empty.
-  size_t first_packet() const { return first_packet_; }
+  // Packet number of the first entry in the queue.
+  QuicPacketNumber first_packet() const { return first_packet_; }
 
   // Packet number of the last entry ever inserted in the queue.  Note that the
   // entry in question may have already been removed.  Zero if the queue is
   // empty.
-  size_t last_packet() const {
+  QuicPacketNumber last_packet() const {
     if (IsEmpty()) {
-      return 0;
+      return QuicPacketNumber();
     }
     return first_packet_ + entries_.size() - 1;
   }
@@ -127,9 +127,14 @@
 template <typename... Args>
 bool PacketNumberIndexedQueue<T>::Emplace(QuicPacketNumber packet_number,
                                           Args&&... args) {
+  if (!packet_number.IsInitialized()) {
+    QUIC_BUG << "Try to insert an uninitialized packet number";
+    return false;
+  }
+
   if (IsEmpty()) {
     DCHECK(entries_.empty());
-    DCHECK_EQ(0u, first_packet_);
+    DCHECK(!first_packet_.IsInitialized());
 
     entries_.emplace_back(std::forward<Args>(args)...);
     number_of_present_entries_ = 1;
@@ -176,18 +181,19 @@
     first_packet_++;
   }
   if (entries_.empty()) {
-    first_packet_ = 0;
+    first_packet_.Clear();
   }
 }
 
 template <typename T>
-auto PacketNumberIndexedQueue<T>::GetEntryWrapper(QuicPacketNumber offset) const
-    -> const EntryWrapper* {
-  if (offset < first_packet_) {
+auto PacketNumberIndexedQueue<T>::GetEntryWrapper(
+    QuicPacketNumber packet_number) const -> const EntryWrapper* {
+  if (!packet_number.IsInitialized() || IsEmpty() ||
+      packet_number < first_packet_) {
     return nullptr;
   }
 
-  offset -= first_packet_;
+  uint64_t offset = packet_number - first_packet_;
   if (offset >= entries_.size()) {
     return nullptr;
   }
diff --git a/quic/core/packet_number_indexed_queue_test.cc b/quic/core/packet_number_indexed_queue_test.cc
index 0190df2..294d2a4 100644
--- a/quic/core/packet_number_indexed_queue_test.cc
+++ b/quic/core/packet_number_indexed_queue_test.cc
@@ -23,156 +23,156 @@
 
 TEST_F(PacketNumberIndexedQueueTest, InitialState) {
   EXPECT_TRUE(queue_.IsEmpty());
-  EXPECT_EQ(0u, queue_.first_packet());
-  EXPECT_EQ(0u, queue_.last_packet());
+  EXPECT_FALSE(queue_.first_packet().IsInitialized());
+  EXPECT_FALSE(queue_.last_packet().IsInitialized());
   EXPECT_EQ(0u, queue_.number_of_present_entries());
   EXPECT_EQ(0u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingContinuousElements) {
-  ASSERT_TRUE(queue_.Emplace(1001, "one"));
-  EXPECT_EQ("one", *queue_.GetEntry(1001));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1001), "one"));
+  EXPECT_EQ("one", *queue_.GetEntry(QuicPacketNumber(1001)));
 
-  ASSERT_TRUE(queue_.Emplace(1002, "two"));
-  EXPECT_EQ("two", *queue_.GetEntry(1002));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1002), "two"));
+  EXPECT_EQ("two", *queue_.GetEntry(QuicPacketNumber(1002)));
 
   EXPECT_FALSE(queue_.IsEmpty());
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1002u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1002u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(2u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingOutOfOrder) {
-  queue_.Emplace(1001, "one");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
 
-  ASSERT_TRUE(queue_.Emplace(1003, "three"));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
-  EXPECT_EQ("three", *queue_.GetEntry(1003));
+  ASSERT_TRUE(queue_.Emplace(QuicPacketNumber(1003), "three"));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1002)));
+  EXPECT_EQ("three", *queue_.GetEntry(QuicPacketNumber(1003)));
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(3u, queue_.entry_slots_used());
 
-  ASSERT_FALSE(queue_.Emplace(1002, "two"));
+  ASSERT_FALSE(queue_.Emplace(QuicPacketNumber(1002), "two"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingIntoPast) {
-  queue_.Emplace(1001, "one");
-  EXPECT_FALSE(queue_.Emplace(1000, "zero"));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1000), "zero"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, InsertingDuplicate) {
-  queue_.Emplace(1001, "one");
-  EXPECT_FALSE(queue_.Emplace(1001, "one"));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1001), "one"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveInTheMiddle) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "two");
-  queue_.Emplace(1003, "three");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "two");
+  queue_.Emplace(QuicPacketNumber(1003), "three");
 
-  ASSERT_TRUE(queue_.Remove(1002));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1002));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1002)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1002)));
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(3u, queue_.entry_slots_used());
 
-  EXPECT_FALSE(queue_.Emplace(1002, "two"));
-  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+  EXPECT_FALSE(queue_.Emplace(QuicPacketNumber(1002), "two"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(1004), "four"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtImmediateEdges) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "two");
-  queue_.Emplace(1003, "three");
-  ASSERT_TRUE(queue_.Remove(1001));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1001));
-  ASSERT_TRUE(queue_.Remove(1003));
-  EXPECT_EQ(nullptr, queue_.GetEntry(1003));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "two");
+  queue_.Emplace(QuicPacketNumber(1003), "three");
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1001)));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1003)));
+  EXPECT_EQ(nullptr, queue_.GetEntry(QuicPacketNumber(1003)));
 
-  EXPECT_EQ(1002u, queue_.first_packet());
-  EXPECT_EQ(1003u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1002u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(1003u), queue_.last_packet());
   EXPECT_EQ(1u, queue_.number_of_present_entries());
   EXPECT_EQ(2u, queue_.entry_slots_used());
 
-  EXPECT_TRUE(queue_.Emplace(1004, "four"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(1004), "four"));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantFront) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(1002, "one (kinda)");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(1002), "one (kinda)");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(3u, queue_.number_of_present_entries());
   EXPECT_EQ(1001u, queue_.entry_slots_used());
 
-  ASSERT_TRUE(queue_.Remove(1002));
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1002)));
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(2u, queue_.number_of_present_entries());
   EXPECT_EQ(1001u, queue_.entry_slots_used());
 
-  ASSERT_TRUE(queue_.Remove(1001));
-  EXPECT_EQ(2001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
   EXPECT_EQ(1u, queue_.number_of_present_entries());
   EXPECT_EQ(1u, queue_.entry_slots_used());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, RemoveAtDistantBack) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
 
-  ASSERT_TRUE(queue_.Remove(2001));
-  EXPECT_EQ(1001u, queue_.first_packet());
-  EXPECT_EQ(2001u, queue_.last_packet());
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(2001)));
+  EXPECT_EQ(QuicPacketNumber(1001u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(2001u), queue_.last_packet());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, ClearAndRepopulate) {
-  queue_.Emplace(1001, "one");
-  queue_.Emplace(2001, "two");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  queue_.Emplace(QuicPacketNumber(2001), "two");
 
-  ASSERT_TRUE(queue_.Remove(1001));
-  ASSERT_TRUE(queue_.Remove(2001));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(2001)));
   EXPECT_TRUE(queue_.IsEmpty());
-  EXPECT_EQ(0u, queue_.first_packet());
-  EXPECT_EQ(0u, queue_.last_packet());
+  EXPECT_FALSE(queue_.first_packet().IsInitialized());
+  EXPECT_FALSE(queue_.last_packet().IsInitialized());
 
-  EXPECT_TRUE(queue_.Emplace(101, "one"));
-  EXPECT_TRUE(queue_.Emplace(201, "two"));
-  EXPECT_EQ(101u, queue_.first_packet());
-  EXPECT_EQ(201u, queue_.last_packet());
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(101), "one"));
+  EXPECT_TRUE(queue_.Emplace(QuicPacketNumber(201), "two"));
+  EXPECT_EQ(QuicPacketNumber(101u), queue_.first_packet());
+  EXPECT_EQ(QuicPacketNumber(201u), queue_.last_packet());
 }
 
 TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsThatNeverExisted) {
-  ASSERT_FALSE(queue_.Remove(1000));
-  queue_.Emplace(1001, "one");
-  ASSERT_FALSE(queue_.Remove(1000));
-  ASSERT_FALSE(queue_.Remove(1002));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1000)));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1000)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1002)));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, FailToRemoveElementsTwice) {
-  queue_.Emplace(1001, "one");
-  ASSERT_TRUE(queue_.Remove(1001));
-  ASSERT_FALSE(queue_.Remove(1001));
-  ASSERT_FALSE(queue_.Remove(1001));
+  queue_.Emplace(QuicPacketNumber(1001), "one");
+  ASSERT_TRUE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1001)));
+  ASSERT_FALSE(queue_.Remove(QuicPacketNumber(1001)));
 }
 
 TEST_F(PacketNumberIndexedQueueTest, ConstGetter) {
-  queue_.Emplace(1001, "one");
+  queue_.Emplace(QuicPacketNumber(1001), "one");
   const auto& const_queue = queue_;
 
-  EXPECT_EQ("one", *const_queue.GetEntry(1001));
-  EXPECT_EQ(nullptr, const_queue.GetEntry(1002));
+  EXPECT_EQ("one", *const_queue.GetEntry(QuicPacketNumber(1001)));
+  EXPECT_EQ(nullptr, const_queue.GetEntry(QuicPacketNumber(1002)));
 }
 
 }  // namespace
diff --git a/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
index e61c973..980889d 100644
--- a/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_encoder_stream_receiver_fuzzer.cc
@@ -28,7 +28,7 @@
   void OnInsertWithoutNameReference(QuicStringPiece name,
                                     QuicStringPiece value) override {}
   void OnDuplicate(uint64_t index) override {}
-  void OnDynamicTableSizeUpdate(uint64_t max_size) override {}
+  void OnSetDynamicTableCapacity(uint64_t capacity) override {}
   void OnErrorDetected(QuicStringPiece error_message) override {
     error_detected_ = true;
   }
diff --git a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
index f404a76..501a69f 100644
--- a/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
+++ b/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
@@ -8,6 +8,7 @@
 #include <cstdint>
 #include <limits>
 
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -15,22 +16,12 @@
 namespace quic {
 namespace test {
 
-// A QpackEncoderStreamSender::Delegate implementation that ignores encoded
-// data.
-class NoOpDelegate : public QpackEncoderStreamSender::Delegate {
- public:
-  NoOpDelegate() = default;
-  ~NoOpDelegate() override = default;
-
-  void Write(QuicStringPiece data) override {}
-};
-
 // This fuzzer exercises QpackEncoderStreamSender.
 // TODO(bnc): Encoded data could be fed into QpackEncoderStreamReceiver and
 // decoded instructions directly compared to input.  Figure out how to get gMock
 // enabled for cc_fuzz_target target types.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  NoOpDelegate delegate;
+  NoopEncoderStreamSenderDelegate delegate;
   QpackEncoderStreamSender sender(&delegate);
 
   QuicFuzzedDataProvider provider(data, size);
@@ -65,8 +56,8 @@
         break;
       }
       case 3: {
-        uint64_t max_size = provider.ConsumeIntegral<uint64_t>();
-        sender.SendDynamicTableSizeUpdate(max_size);
+        uint64_t capacity = provider.ConsumeIntegral<uint64_t>();
+        sender.SendSetDynamicTableCapacity(capacity);
         break;
       }
     }
diff --git a/quic/core/qpack/offline/qpack_offline_decoder.cc b/quic/core/qpack/offline/qpack_offline_decoder.cc
index c3ad1f9..2b02edd 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder.cc
+++ b/quic/core/qpack/offline/qpack_offline_decoder.cc
@@ -44,7 +44,7 @@
   return true;
 }
 
-void QpackOfflineDecoder::OnError(QuicStringPiece error_message) {
+void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) {
   QUIC_LOG(ERROR) << "Encoder stream error: " << error_message;
   encoder_stream_error_detected_ = true;
 }
diff --git a/quic/core/qpack/offline/qpack_offline_decoder.h b/quic/core/qpack/offline/qpack_offline_decoder.h
index faa64bc..922fd64 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder.h
+++ b/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
 #define QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
 
+#include <list>
+
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -30,7 +32,7 @@
                                   QuicStringPiece expected_headers_filename);
 
   // QpackDecoder::EncoderStreamErrorDelegate implementation:
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 
  private:
   // Parse decoder parameters from |input_filename| and set up |decoder_|
diff --git a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
index 2068f52..499c9fd 100644
--- a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
+++ b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
@@ -20,7 +20,7 @@
     return 1;
   }
 
-  size_t i;
+  int i;
   for (i = 0; 2 * i + 1 < argc; ++i) {
     const quic::QuicStringPiece input_filename(argv[2 * i + 1]);
     const quic::QuicStringPiece expected_headers_filename(argv[2 * i + 2]);
diff --git a/quic/core/qpack/qpack_constants.cc b/quic/core/qpack/qpack_constants.cc
index eda1ef4..b9144e0 100644
--- a/quic/core/qpack/qpack_constants.cc
+++ b/quic/core/qpack/qpack_constants.cc
@@ -4,7 +4,6 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 
-#include <cstddef>
 #include <limits>
 
 #include "base/logging.h"
@@ -17,8 +16,9 @@
 //  * in each instruction, the bits of |value| that are zero in |mask| are zero;
 //  * every byte matches exactly one opcode.
 void ValidateLangague(const QpackLanguage* language) {
+#ifndef NDEBUG
   for (const auto* instruction : *language) {
-    DCHECK_EQ(0u, instruction->opcode.value & ~instruction->opcode.mask);
+    DCHECK_EQ(0, instruction->opcode.value & ~instruction->opcode.mask);
   }
 
   for (uint8_t byte = 0; byte < std::numeric_limits<uint8_t>::max(); ++byte) {
@@ -30,6 +30,7 @@
     }
     DCHECK_EQ(1u, match_count) << static_cast<int>(byte);
   }
+#endif
 }
 
 }  // namespace
@@ -68,7 +69,7 @@
   return instruction;
 }
 
-const QpackInstruction* DynamicTableSizeUpdateInstruction() {
+const QpackInstruction* SetDynamicTableCapacityInstruction() {
   static const QpackInstructionOpcode* const opcode =
       new QpackInstructionOpcode{0b00100000, 0b11100000};
   static const QpackInstruction* const instruction =
@@ -80,14 +81,12 @@
   static const QpackLanguage* const language = new QpackLanguage{
       InsertWithNameReferenceInstruction(),
       InsertWithoutNameReferenceInstruction(), DuplicateInstruction(),
-      DynamicTableSizeUpdateInstruction()};
-#ifndef NDEBUG
+      SetDynamicTableCapacityInstruction()};
   ValidateLangague(language);
-#endif
   return language;
 }
 
-const QpackInstruction* TableStateSynchronizeInstruction() {
+const QpackInstruction* InsertCountIncrementInstruction() {
   static const QpackInstructionOpcode* const opcode =
       new QpackInstructionOpcode{0b00000000, 0b11000000};
   static const QpackInstruction* const instruction =
@@ -113,11 +112,9 @@
 
 const QpackLanguage* QpackDecoderStreamLanguage() {
   static const QpackLanguage* const language = new QpackLanguage{
-      TableStateSynchronizeInstruction(), HeaderAcknowledgementInstruction(),
+      InsertCountIncrementInstruction(), HeaderAcknowledgementInstruction(),
       StreamCancellationInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
@@ -136,9 +133,7 @@
 const QpackLanguage* QpackPrefixLanguage() {
   static const QpackLanguage* const language =
       new QpackLanguage{QpackPrefixInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
@@ -198,9 +193,7 @@
                         QpackLiteralHeaderFieldNameReferenceInstruction(),
                         QpackLiteralHeaderFieldPostBaseInstruction(),
                         QpackLiteralHeaderFieldInstruction()};
-#ifndef NDEBUG
   ValidateLangague(language);
-#endif
   return language;
 }
 
diff --git a/quic/core/qpack/qpack_constants.h b/quic/core/qpack/qpack_constants.h
index 4fce3dd..7b7eb47 100644
--- a/quic/core/qpack/qpack_constants.h
+++ b/quic/core/qpack/qpack_constants.h
@@ -30,14 +30,14 @@
 // literal consumes all bytes containing the field value.
 enum class QpackInstructionFieldType {
   // A single bit indicating whether the index refers to the static table, or
-  // indicating the sign of Delta Base Index.  Called "S" bit because both
-  // "static" and "sign" start with the letter "S".
+  // indicating the sign of Delta Base.  Called "S" bit because both "static"
+  // and "sign" start with the letter "S".
   kSbit,
   // An integer encoded with variable length encoding.  This could be an index,
-  // stream ID, maximum size, or Largest Reference.
+  // stream ID, maximum size, or Encoded Required Insert Count.
   kVarint,
   // A second integer encoded with variable length encoding.  This could be
-  // Delta Base Index.
+  // Delta Base.
   kVarint2,
   // A header name or header value encoded as:
   //   a bit indicating whether it is Huffman encoded;
@@ -97,15 +97,15 @@
 const QpackInstruction* DuplicateInstruction();
 
 // 5.2.4 Dynamic Table Size Update
-const QpackInstruction* DynamicTableSizeUpdateInstruction();
+const QpackInstruction* SetDynamicTableCapacityInstruction();
 
 // Encoder stream language.
 const QpackLanguage* QpackEncoderStreamLanguage();
 
 // 5.3 Decoder stream instructions
 
-// 5.3.1 Table State Synchronize
-const QpackInstruction* TableStateSynchronizeInstruction();
+// 5.3.1 Insert Count Increment
+const QpackInstruction* InsertCountIncrementInstruction();
 
 // 5.3.2 Header Acknowledgement
 const QpackInstruction* HeaderAcknowledgementInstruction();
diff --git a/quic/core/qpack/qpack_decoder.cc b/quic/core/qpack/qpack_decoder.cc
index 9ae883f..fd0867a 100644
--- a/quic/core/qpack/qpack_decoder.cc
+++ b/quic/core/qpack/qpack_decoder.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 
+#include <limits>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 
@@ -40,33 +42,36 @@
   if (is_static) {
     auto entry = header_table_.LookupEntry(/* is_static = */ true, name_index);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError("Invalid static table entry.");
+      encoder_stream_error_delegate_->OnEncoderStreamError(
+          "Invalid static table entry.");
       return;
     }
 
     entry = header_table_.InsertEntry(entry->name(), value);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError(
+      encoder_stream_error_delegate_->OnEncoderStreamError(
           "Error inserting entry with name reference.");
     }
     return;
   }
 
-  uint64_t real_index;
-  if (!EncoderStreamRelativeIndexToRealIndex(name_index, &real_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+  uint64_t absolute_index;
+  if (!EncoderStreamRelativeIndexToAbsoluteIndex(name_index, &absolute_index)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
-      header_table_.LookupEntry(/* is_static = */ false, real_index);
+      header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError(
+    encoder_stream_error_delegate_->OnEncoderStreamError(
         "Error inserting entry with name reference.");
   }
 }
@@ -75,50 +80,54 @@
                                                 QuicStringPiece value) {
   const QpackEntry* entry = header_table_.InsertEntry(name, value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting literal entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting literal entry.");
   }
 }
 
 void QpackDecoder::OnDuplicate(uint64_t index) {
-  uint64_t real_index;
-  if (!EncoderStreamRelativeIndexToRealIndex(index, &real_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+  uint64_t absolute_index;
+  if (!EncoderStreamRelativeIndexToAbsoluteIndex(index, &absolute_index)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
-      header_table_.LookupEntry(/* is_static = */ false, real_index);
+      header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), entry->value());
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting duplicate entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting duplicate entry.");
   }
 }
 
-void QpackDecoder::OnDynamicTableSizeUpdate(uint64_t max_size) {
-  if (!header_table_.UpdateTableSize(max_size)) {
-    encoder_stream_error_delegate_->OnError(
-        "Error updating dynamic table size.");
+void QpackDecoder::OnSetDynamicTableCapacity(uint64_t capacity) {
+  if (!header_table_.SetDynamicTableCapacity(capacity)) {
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error updating dynamic table capacity.");
   }
 }
 
 void QpackDecoder::OnErrorDetected(QuicStringPiece error_message) {
-  encoder_stream_error_delegate_->OnError(error_message);
+  encoder_stream_error_delegate_->OnEncoderStreamError(error_message);
 }
 
-bool QpackDecoder::EncoderStreamRelativeIndexToRealIndex(
+bool QpackDecoder::EncoderStreamRelativeIndexToAbsoluteIndex(
     uint64_t relative_index,
-    uint64_t* real_index) const {
+    uint64_t* absolute_index) const {
   if (relative_index == std::numeric_limits<uint64_t>::max() ||
       relative_index + 1 > std::numeric_limits<uint64_t>::max() -
                                header_table_.inserted_entry_count()) {
     return false;
   }
 
-  *real_index = header_table_.inserted_entry_count() - relative_index - 1;
+  *absolute_index = header_table_.inserted_entry_count() - relative_index - 1;
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_decoder.h b/quic/core/qpack/qpack_decoder.h
index ffb2e88..c3b28a3 100644
--- a/quic/core/qpack/qpack_decoder.h
+++ b/quic/core/qpack/qpack_decoder.h
@@ -31,7 +31,7 @@
    public:
     virtual ~EncoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnEncoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackDecoder(
@@ -79,18 +79,17 @@
   void OnInsertWithoutNameReference(QuicStringPiece name,
                                     QuicStringPiece value) override;
   void OnDuplicate(uint64_t index) override;
-  void OnDynamicTableSizeUpdate(uint64_t max_size) override;
+  void OnSetDynamicTableCapacity(uint64_t capacity) override;
   void OnErrorDetected(QuicStringPiece error_message) override;
 
  private:
   // The encoder stream uses relative index (but different from the kind of
-  // relative index used on a request stream).
-  // The spec describes how to convert these into absolute index (one based).
-  // QpackHeaderTable uses real index (zero based, one less than the absolute
-  // index).  This method converts relative index to real index.  It returns
-  // true on success, or false if conversion fails due to overflow/underflow.
-  bool EncoderStreamRelativeIndexToRealIndex(uint64_t relative_index,
-                                             uint64_t* real_index) const;
+  // relative index used on a request stream).  This method converts relative
+  // index to absolute index (zero based).  It returns true on success, or false
+  // if conversion fails due to overflow/underflow.
+  bool EncoderStreamRelativeIndexToAbsoluteIndex(
+      uint64_t relative_index,
+      uint64_t* absolute_index) const;
 
   EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
   QpackEncoderStreamReceiver encoder_stream_receiver_;
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver.cc b/quic/core/qpack/qpack_decoder_stream_receiver.cc
index b38aedf..559ce43 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver.cc
+++ b/quic/core/qpack/qpack_decoder_stream_receiver.cc
@@ -27,8 +27,8 @@
 
 bool QpackDecoderStreamReceiver::OnInstructionDecoded(
     const QpackInstruction* instruction) {
-  if (instruction == TableStateSynchronizeInstruction()) {
-    delegate_->OnTableStateSynchronize(instruction_decoder_.varint());
+  if (instruction == InsertCountIncrementInstruction()) {
+    delegate_->OnInsertCountIncrement(instruction_decoder_.varint());
     return true;
   }
 
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver.h b/quic/core/qpack/qpack_decoder_stream_receiver.h
index 003be12..61c2773 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver.h
+++ b/quic/core/qpack/qpack_decoder_stream_receiver.h
@@ -25,8 +25,8 @@
    public:
     virtual ~Delegate() = default;
 
-    // 5.3.1 Table State Synchronize
-    virtual void OnTableStateSynchronize(uint64_t insert_count) = 0;
+    // 5.3.1 Insert Count Increment
+    virtual void OnInsertCountIncrement(uint64_t increment) = 0;
     // 5.3.2 Header Acknowledgement
     virtual void OnHeaderAcknowledgement(QuicStreamId stream_id) = 0;
     // 5.3.3 Stream Cancellation
diff --git a/quic/core/qpack/qpack_decoder_stream_receiver_test.cc b/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
index e9b3124..fc7225f 100644
--- a/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
+++ b/quic/core/qpack/qpack_decoder_stream_receiver_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using testing::Eq;
 using testing::StrictMock;
 
 namespace quic {
@@ -19,7 +20,7 @@
  public:
   ~MockDelegate() override = default;
 
-  MOCK_METHOD1(OnTableStateSynchronize, void(uint64_t insert_count));
+  MOCK_METHOD1(OnInsertCountIncrement, void(uint64_t increment));
   MOCK_METHOD1(OnHeaderAcknowledgement, void(QuicStreamId stream_id));
   MOCK_METHOD1(OnStreamCancellation, void(QuicStreamId stream_id));
   MOCK_METHOD1(OnErrorDetected, void(QuicStringPiece error_message));
@@ -34,20 +35,20 @@
   StrictMock<MockDelegate> delegate_;
 };
 
-TEST_F(QpackDecoderStreamReceiverTest, TableStateSynchronize) {
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(0));
+TEST_F(QpackDecoderStreamReceiverTest, InsertCountIncrement) {
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(0));
   stream_.Decode(QuicTextUtils::HexDecode("00"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(10));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(10));
   stream_.Decode(QuicTextUtils::HexDecode("0a"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(63));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(63));
   stream_.Decode(QuicTextUtils::HexDecode("3f00"));
 
-  EXPECT_CALL(delegate_, OnTableStateSynchronize(200));
+  EXPECT_CALL(delegate_, OnInsertCountIncrement(200));
   stream_.Decode(QuicTextUtils::HexDecode("3f8901"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
 
@@ -64,7 +65,7 @@
   EXPECT_CALL(delegate_, OnHeaderAcknowledgement(503));
   stream_.Decode(QuicTextUtils::HexDecode("fff802"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
 }
 
@@ -81,7 +82,7 @@
   EXPECT_CALL(delegate_, OnStreamCancellation(110));
   stream_.Decode(QuicTextUtils::HexDecode("7f2f"));
 
-  EXPECT_CALL(delegate_, OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(delegate_, OnErrorDetected(Eq("Encoded integer too large.")));
   stream_.Decode(QuicTextUtils::HexDecode("7fffffffffffffffffffff"));
 }
 
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.cc b/quic/core/qpack/qpack_decoder_stream_sender.cc
index 48d0e0e..141b64a 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -18,18 +18,17 @@
   DCHECK(delegate_);
 }
 
-void QpackDecoderStreamSender::SendTableStateSynchronize(
-    uint64_t insert_count) {
-  instruction_encoder_.set_varint(insert_count);
+void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
+  instruction_encoder_.set_varint(increment);
 
-  instruction_encoder_.Encode(TableStateSynchronizeInstruction());
+  instruction_encoder_.Encode(InsertCountIncrementInstruction());
 
   QuicString output;
 
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendHeaderAcknowledgement(
@@ -43,7 +42,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
@@ -56,7 +55,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.h b/quic/core/qpack/qpack_decoder_stream_sender.h
index 0522042..a791173 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -24,9 +24,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the decoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteDecoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteDecoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackDecoderStreamSender(Delegate* delegate);
@@ -37,8 +38,8 @@
   // Methods for sending instructions, see
   // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.3
 
-  // 5.3.1 Table State Synchronize
-  void SendTableStateSynchronize(uint64_t insert_count);
+  // 5.3.1 Insert Count Increment
+  void SendInsertCountIncrement(uint64_t increment);
   // 5.3.2 Header Acknowledgement
   void SendHeaderAcknowledgement(QuicStreamId stream_id);
   // 5.3.3 Stream Cancellation
diff --git a/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index ab65c8c..cc95759 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using ::testing::Eq;
 using ::testing::StrictMock;
 
 namespace quic {
@@ -19,7 +20,7 @@
  public:
   ~MockSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 class QpackDecoderStreamSenderTest : public QuicTest {
@@ -31,45 +32,57 @@
   QpackDecoderStreamSender stream_;
 };
 
-TEST_F(QpackDecoderStreamSenderTest, TableStateSynchronize) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("00")));
-  stream_.SendTableStateSynchronize(0);
+TEST_F(QpackDecoderStreamSenderTest, InsertCountIncrement) {
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("00"))));
+  stream_.SendInsertCountIncrement(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("0a")));
-  stream_.SendTableStateSynchronize(10);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("0a"))));
+  stream_.SendInsertCountIncrement(10);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("3f00")));
-  stream_.SendTableStateSynchronize(63);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f00"))));
+  stream_.SendInsertCountIncrement(63);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("3f8901")));
-  stream_.SendTableStateSynchronize(200);
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f8901"))));
+  stream_.SendInsertCountIncrement(200);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, HeaderAcknowledgement) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("80")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("80"))));
   stream_.SendHeaderAcknowledgement(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("a5")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("a5"))));
   stream_.SendHeaderAcknowledgement(37);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("ff00")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("ff00"))));
   stream_.SendHeaderAcknowledgement(127);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("fff802")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("fff802"))));
   stream_.SendHeaderAcknowledgement(503);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, StreamCancellation) {
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("40")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("40"))));
   stream_.SendStreamCancellation(0);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("53")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("53"))));
   stream_.SendStreamCancellation(19);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("7f00")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f00"))));
   stream_.SendStreamCancellation(63);
 
-  EXPECT_CALL(delegate_, Write(QuicTextUtils::HexDecode("7f2f")));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f2f"))));
   stream_.SendStreamCancellation(110);
 }
 
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc
index 5f68213..52f739c 100644
--- a/quic/core/qpack/qpack_decoder_test.cc
+++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
@@ -66,8 +68,8 @@
                                FragmentMode::kOctetByOctet));
 
 TEST_P(QpackDecoderTest, NoPrefix) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Incomplete header data prefix.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header data prefix.")));
 
   // Header Data Prefix is at least two bytes long.
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00"));
@@ -76,60 +78,54 @@
 TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyName) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece(""), QuicStringPiece("foo")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyValue) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
 }
 
 TEST_P(QpackDecoderTest, LiteralEntryEmptyNameAndValue) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece(""), QuicStringPiece("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
 }
 
 TEST_P(QpackDecoderTest, SimpleLiteralEntry) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
 }
 
 TEST_P(QpackDecoderTest, MultipleLiteralEntries) {
-  EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   QuicString str(127, 'a');
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("foobaar"),
-                                        QuicStringPiece(str)));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                // prefix
@@ -146,24 +142,24 @@
 
 // Name Length value is too large for varint decoder to decode.
 TEST_P(QpackDecoderTest, NameLenTooLargeForVarintDecoder) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffffffffffffffffffff"));
 }
 
 // Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_P(QpackDecoderTest, NameLenExceedsLimit) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000027ffff7f"));
 }
 
 // Value Length value is too large for varint decoder to decode.
 TEST_P(QpackDecoderTest, ValueLenTooLargeForVarintDecoder) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Encoded integer too large.")));
 
   DecodeHeaderBlock(
       QuicTextUtils::HexDecode("000023666f6f7fffffffffffffffffffff"));
@@ -171,37 +167,35 @@
 
 // Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_P(QpackDecoderTest, ValueLenExceedsLimit) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("String literal too long.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f7fffff7f"));
 }
 
 TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Incomplete header block.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Incomplete header block.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002366"));
 }
 
 TEST_P(QpackDecoderTest, HuffmanSimple) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("custom-key"),
-                                        QuicStringPiece("custom-value")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
-  DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      QuicStringPiece("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf")));
+  DecodeHeaderBlock(
+      QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
 }
 
 TEST_P(QpackDecoderTest, AlternatingHuffmanNonHuffman) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("custom-key"),
-                                        QuicStringPiece("custom-value")))
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")))
       .Times(4);
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                        // Prefix.
@@ -212,8 +206,7 @@
       "2f0125a849e95ba97d7f"        // Huffman-encoded name.
       "0c637573746f6d2d76616c7565"  // Non-Huffman encoded value.
       "2703637573746f6d2d6b6579"    // Non-Huffman encoded name.
-      "8925a849e95bb8e8b4bf"        // Huffman-encoded value.
-      ));
+      "8925a849e95bb8e8b4bf"));     // Huffman-encoded value.
 }
 
 TEST_P(QpackDecoderTest, HuffmanNameDoesNotHaveEOSPrefix) {
@@ -260,30 +253,23 @@
 
 TEST_P(QpackDecoderTest, StaticTable) {
   // A header name that has multiple entries with different values.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("GET")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("POST")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("TRACE")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("POST")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("TRACE")));
 
   // A header name that has a single entry with non-empty value.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("gzip, deflate, br")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("compress")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("")));
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("accept-encoding"), Eq("gzip, deflate, br")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("compress")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("accept-encoding"), Eq("")));
 
   // A header name that has a single entry with empty value.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
-                                        QuicStringPiece("")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
-                                        QuicStringPiece("foo")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("")));
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("location"), Eq("foo")));
 
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
@@ -291,12 +277,12 @@
 
 TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
   // This is the last entry in the static table with index 98.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("x-frame-options"),
-                                        QuicStringPiece("sameorigin")));
+  EXPECT_CALL(handler_,
+              OnHeaderDecoded(Eq("x-frame-options"), Eq("sameorigin")));
 
   // Addressing entry 99 should trigger an error.
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Static table entry not found.")));
+  EXPECT_CALL(handler_,
+              OnDecodingErrorDetected(Eq("Static table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000ff23ff24"));
 }
@@ -311,11 +297,10 @@
       "01"));           // Duplicate entry with relative index 1.
 
   // Now there are four entries in the dynamic table.
-  // Note that absolute indices start with 1.
-  // Entry 1: "foo", "bar"
-  // Entry 2: "foo", "ZZZ"
-  // Entry 3: ":method", "foo"
-  // Entry 4: "foo", "ZZZ"
+  // Entry 0: "foo", "bar"
+  // Entry 1: "foo", "ZZZ"
+  // Entry 2: ":method", "foo"
+  // Entry 3: "foo", "ZZZ"
 
   // Use a Sequence to test that mock methods are called in order.
   Sequence s;
@@ -327,17 +312,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"  // Largest Reference 4 and Delta Base Index 0.
-              // Base Index is 4 + 0 = 4.
-      "83"    // Dynamic table entry with relative index 3, absolute index 1.
-      "82"    // Dynamic table entry with relative index 2, absolute index 2.
-      "81"    // Dynamic table entry with relative index 1, absolute index 3.
-      "80"    // Dynamic table entry with relative index 0, absolute index 4.
+      "0500"  // Required Insert Count 4 and Delta Base 0.
+              // Base is 4 + 0 = 4.
+      "83"    // Dynamic table entry with relative index 3, absolute index 0.
+      "82"    // Dynamic table entry with relative index 2, absolute index 1.
+      "81"    // Dynamic table entry with relative index 1, absolute index 2.
+      "80"    // Dynamic table entry with relative index 0, absolute index 3.
       "41025a5a"));  // Name of entry 1 (relative index) from dynamic table,
                      // with value "ZZ".
 
@@ -348,17 +333,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0502"  // Largest Reference 4 and Delta Base Index 2.
-              // Base Index is 4 + 2 = 6.
-      "85"    // Dynamic table entry with relative index 5, absolute index 1.
-      "84"    // Dynamic table entry with relative index 4, absolute index 2.
-      "83"    // Dynamic table entry with relative index 3, absolute index 3.
-      "82"    // Dynamic table entry with relative index 2, absolute index 4.
+      "0502"  // Required Insert Count 4 and Delta Base 2.
+              // Base is 4 + 2 = 6.
+      "85"    // Dynamic table entry with relative index 5, absolute index 0.
+      "84"    // Dynamic table entry with relative index 4, absolute index 1.
+      "83"    // Dynamic table entry with relative index 3, absolute index 2.
+      "82"    // Dynamic table entry with relative index 2, absolute index 3.
       "43025a5a"));  // Name of entry 3 (relative index) from dynamic table,
                      // with value "ZZ".
 
@@ -369,17 +354,17 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0582"  // Largest Reference 4 and Delta Base Index 2 with sign bit set.
-              // Base Index is 4 - 2 - 1 = 1.
-      "80"    // Dynamic table entry with relative index 0, absolute index 1.
-      "10"    // Dynamic table entry with post-base index 0, absolute index 2.
-      "11"    // Dynamic table entry with post-base index 1, absolute index 3.
-      "12"    // Dynamic table entry with post-base index 2, absolute index 4.
+      "0582"  // Required Insert Count 4 and Delta Base 2 with sign bit set.
+              // Base is 4 - 2 - 1 = 1.
+      "80"    // Dynamic table entry with relative index 0, absolute index 0.
+      "10"    // Dynamic table entry with post-base index 0, absolute index 1.
+      "11"    // Dynamic table entry with post-base index 1, absolute index 2.
+      "12"    // Dynamic table entry with post-base index 2, absolute index 3.
       "01025a5a"));  // Name of entry 1 (post-base index) from dynamic table,
                      // with value "ZZ".
 }
@@ -391,12 +376,12 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
-      "80"));  // Dynamic table entry with relative index 0, absolute index 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
 
   // Change dynamic table capacity to 32 bytes, smaller than the entry.
   // This must cause the entry to be evicted.
@@ -406,14 +391,14 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
-      "80"));  // Dynamic table entry with relative index 0, absolute index 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
+      "80"));  // Dynamic table entry with relative index 0, absolute index 0.
 }
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorEntryTooLarge) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error inserting literal entry.")));
+              OnEncoderStreamError(Eq("Error inserting literal entry.")));
 
   // Set dynamic table capacity to 34.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f03"));
@@ -423,7 +408,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Invalid static table entry.")));
+              OnEncoderStreamError(Eq("Invalid static table entry.")));
 
   // Address invalid static table entry index 99.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("ff2400"));
@@ -431,7 +416,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -442,7 +427,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -453,27 +438,25 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Encoded integer too large.")));
+              OnEncoderStreamError(Eq("Encoded integer too large.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
 
-TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIndexIsZero) {
+TEST_P(QpackDecoderTest, InvalidDynamicEntryWhenBaseIsZero) {
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0280"  // Largest Reference is 1.  Base Index 1 - 1 - 0 = 0 is explicitly
-              // permitted by the spec.
+      "0280"   // Required Insert Count is 1.  Base 1 - 1 - 0 = 0 is explicitly
+               // permitted by the spec.
       "80"));  // However, addressing entry with relative index 0 would point to
-               // absolute index 0, which is invalid (absolute index is one
-               // based).
+               // absolute index -1, which is invalid.
 }
 
-TEST_P(QpackDecoderTest, InvalidNegativeBaseIndex) {
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Error calculating Base Index.")));
+TEST_P(QpackDecoderTest, InvalidNegativeBase) {
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Error calculating Base.")));
 
-  // Largest reference 1, Delta Base Index 1 with sign bit set, Base Index would
+  // Required Insert Count 1, Delta Base 1 with sign bit set, Base would
   // be 1 - 1 - 1 = -1, but it is not allowed to be negative.
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0281"));
 }
@@ -486,38 +469,37 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"   // Largest Reference 4 and Delta Base Index 0.
-               // Base Index is 4 + 0 = 4.
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
       "82"));  // Indexed Header Field instruction addressing relative index 2.
-               // This is absolute index 2. Such entry does not exist.
+               // This is absolute index 1. Such entry does not exist.
 
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"   // Largest Reference 4 and Delta Base Index 0.
-               // Base Index is 4 + 0 = 4.
+      "0500"   // Required Insert Count 4 and Delta Base 0.
+               // Base is 4 + 0 = 4.
       "84"));  // Indexed Header Field instruction addressing relative index 4.
-               // This is absolute index 0, which is invalid, because absolute
-               // indexing starts from 1.
+               // This is absolute index -1, which is invalid.
 
   EXPECT_CALL(handler_,
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"     // Largest Reference 4 and Delta Base Index 0.
-                 // Base Index is 4 + 0 = 4.
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
       "4200"));  // Literal Header Field with Name Reference instruction
-                 // addressing relative index 2.  This is absolute index 2. Such
+                 // addressing relative index 2.  This is absolute index 1. Such
                  // entry does not exist.
 
   EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0500"     // Largest Reference 4 and Delta Base Index 0.
-                 // Base Index is 4 + 0 = 4.
+      "0500"     // Required Insert Count 4 and Delta Base 0.
+                 // Base is 4 + 0 = 4.
       "4400"));  // Literal Header Field with Name Reference instruction
-                 // addressing relative index 4.  This is absolute index 0,
-                 // which is invalid, because absolute indexing starts from 1.
+                 // addressing relative index 4.  This is absolute index -1,
+                 // which is invalid.
 }
 
 TEST_P(QpackDecoderTest, InvalidDynamicEntryByPostBaseIndex) {
@@ -528,26 +510,27 @@
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0380"   // Largest Reference 2 and Delta Base Index 0 with sign bit set.
-               // Base Index is 2 - 0 - 1 = 1
+      "0380"   // Required Insert Count 2 and Delta Base 0 with sign bit set.
+               // Base is 2 - 0 - 1 = 1
       "10"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with post-base index 0, absolute index 2.  Such entry
+               // entry with post-base index 0, absolute index 1.  Such entry
                // does not exist.
 
   EXPECT_CALL(handler_,
               OnDecodingErrorDetected(Eq("Dynamic table entry not found.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0380"  // Largest Reference 2 and Delta Base Index 0 with sign bit set.
-              // Base Index is 2 - 0 - 1 = 1
+      "0380"     // Required Insert Count 2 and Delta Base 0 with sign bit set.
+                 // Base is 2 - 0 - 1 = 1
       "0000"));  // Literal Header Field With Name Reference instruction
                  // addressing dynamic table entry with post-base index 0,
-                 // absolute index 2.  Such entry does not exist.
+                 // absolute index 1.  Such entry does not exist.
 }
 
 TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
-  EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error updating dynamic table size.")));
+  EXPECT_CALL(
+      encoder_stream_error_delegate_,
+      OnEncoderStreamError(Eq("Error updating dynamic table capacity.")));
 
   // Try to update dynamic table capacity to 2048, which exceeds the maximum.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe10f"));
@@ -558,17 +541,17 @@
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f61"));
 }
 
-TEST_P(QpackDecoderTest, LargestReferenceOutOfRange) {
+TEST_P(QpackDecoderTest, InvalidEncodedRequiredInsertCount) {
   // Maximum dynamic table capacity is 1024.
   // MaxEntries is 1024 / 32 = 32.
-  // Largest Reference is decoded modulo 2 * MaxEntries, that is, modulo 64.
+  // Required Insert Count is decoded modulo 2 * MaxEntries, that is, modulo 64.
   // A value of 1 cannot be encoded as 65 even though it has the same remainder.
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Error decoding Largest Reference.")));
+  EXPECT_CALL(handler_, OnDecodingErrorDetected(
+                            Eq("Error decoding Required Insert Count.")));
   DecodeHeaderBlock(QuicTextUtils::HexDecode("4100"));
 }
 
-TEST_P(QpackDecoderTest, WrappedLargestReference) {
+TEST_P(QpackDecoderTest, WrappedRequiredInsertCount) {
   // Maximum dynamic table capacity is 1024.
   // MaxEntries is 1024 / 32 = 32.
 
@@ -583,131 +566,136 @@
   // Duplicate most recent entry 200 times.
   DecodeEncoderStreamData(QuicString(200, '\x00'));
 
-  // Now there is only one entry in the dynamic table, with absolute index 201.
+  // Now there is only one entry in the dynamic table, with absolute index 200.
 
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
-  // Send header block with Largest Reference = 201.
+  // Send header block with Required Insert Count = 201.
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0a00"   // Wire Largest Reference 10, Largest Reference 201,
-               // Delta Base Index 0, Base Index 201.
+      "0a00"   // Encoded Required Insert Count 10, Required Insert Count 201,
+               // Delta Base 0, Base 201.
       "80"));  // Emit dynamic table entry with relative index 0.
 }
 
-TEST_P(QpackDecoderTest, NonZeroLargestReferenceButNoDynamicEntries) {
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("GET")));
+TEST_P(QpackDecoderTest, NonZeroRequiredInsertCountButNoDynamicEntries) {
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
   EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference is 1.
+      "0200"   // Required Insert Count is 1.
       "d1"));  // But the only instruction references the static table.
 }
 
-TEST_P(QpackDecoderTest, AddressEntryBeyondLargestReference) {
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+TEST_P(QpackDecoderTest, AddressEntryNotAllowedByRequiredInsertCount) {
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0201"   // Largest Reference 1 and Delta Base Index 1.
-               // Base Index is 1 + 1 = 2.
+      "0201"   // Required Insert Count 1 and Delta Base 1.
+               // Base is 1 + 1 = 2.
       "80"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with relative index 0, absolute index 2.  This is beyond
-               // Largest Reference.
+               // entry with relative index 0, absolute index 1.  This is not
+               // allowed by Required Insert Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0201"     // Largest Reference 1 and Delta Base Index 1.
-                 // Base Index is 1 + 1 = 2.
+      "0201"     // Required Insert Count 1 and Delta Base 1.
+                 // Base is 1 + 1 = 2.
       "4000"));  // Literal Header Field with Name Reference instruction
                  // addressing dynamic table entry with relative index 0,
-                 // absolute index 2.  This is beyond Largest Reference.
+                 // absolute index 1.  This is not allowed by Required Index
+                 // Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"   // Largest Reference 1 and Delta Base Index 0.
-               // Base Index is 1 + 0 = 1.
+      "0200"   // Required Insert Count 1 and Delta Base 0.
+               // Base is 1 + 0 = 1.
       "10"));  // Indexed Header Field with Post-Base Index instruction
                // addressing dynamic table entry with post-base index 0,
-               // absolute index 2.  This is beyond Largest Reference.
+               // absolute index 1.  This is not allowed by Required Insert
+               // Count.
 
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            Eq("Index larger than Largest Reference.")));
+  EXPECT_CALL(
+      handler_,
+      OnDecodingErrorDetected(
+          Eq("Absolute Index must be smaller than Required Insert Count.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0200"     // Largest Reference 1 and Delta Base Index 0.
-                 // Base Index is 1 + 0 = 1.
+      "0200"     // Required Insert Count 1 and Delta Base 0.
+                 // Base is 1 + 0 = 1.
       "0000"));  // Literal Header Field with Post-Base Name Reference
                  // instruction addressing dynamic table entry with post-base
-                 // index 0, absolute index 2.  This is beyond Largest
-                 // Reference.
+                 // index 0, absolute index 1.  This is not allowed by Required
+                 // Index Count.
 }
 
-TEST_P(QpackDecoderTest, PromisedLargestReferenceLargerThanLargestActualIndex) {
+TEST_P(QpackDecoderTest, PromisedRequiredInsertCountLargerThanActual) {
   // Add literal entry with name "foo" and value "bar".
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
   // Duplicate entry.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("00"));
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0300"   // Largest Reference 2 and Delta Base Index 0.
-               // Base Index is 2 + 0 = 2.
+      "0300"   // Required Insert Count 2 and Delta Base 0.
+               // Base is 2 + 0 = 2.
       "81"));  // Indexed Header Field instruction addressing dynamic table
-               // entry with relative index 1, absolute index 1.  This is the
-               // largest reference in this header block, even though Largest
-               // Reference is 2.
+               // entry with relative index 1, absolute index 0.  Header block
+               // requires insert count of 1, even though Required Insert Count
+               // is 2.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0300"     // Largest Reference 2 and Delta Base Index 0.
-                 // Base Index is 2 + 0 = 2.
+      "0300"     // Required Insert Count 2 and Delta Base 0.
+                 // Base is 2 + 0 = 2.
       "4100"));  // Literal Header Field with Name Reference instruction
                  // addressing dynamic table entry with relative index 1,
-                 // absolute index 1.  This is the largest reference in this
-                 // header block, even though Largest Reference is 2.
+                 // absolute index 0.  Header block requires insert count of 1,
+                 // even though Required Insert Count is 2.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("bar")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0481"   // Largest Reference 3 and Delta Base Index 1 with sign bit set.
-               // Base Index is 3 - 1 - 1 = 1.
+      "0481"   // Required Insert Count 3 and Delta Base 1 with sign bit set.
+               // Base is 3 - 1 - 1 = 1.
       "10"));  // Indexed Header Field with Post-Base Index instruction
                // addressing dynamic table entry with post-base index 0,
-               // absolute index 2.  This is the largest reference in this
-               // header block, even though Largest Reference is 3.
+               // absolute index 1.  Header block requires insert count of 2,
+               // even though Required Insert Count is 3.
 
+  EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_,
-              OnHeaderDecoded(QuicStringPiece("foo"), QuicStringPiece("")));
-  EXPECT_CALL(handler_,
-              OnDecodingErrorDetected(Eq("Largest Reference too large.")));
+              OnDecodingErrorDetected(Eq("Required Insert Count too large.")));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
-      "0481"  // Largest Reference 3 and Delta Base Index 1 with sign bit set.
-              // Base Index is 3 - 1 - 1 = 1.
+      "0481"     // Required Insert Count 3 and Delta Base 1 with sign bit set.
+                 // Base is 3 - 1 - 1 = 1.
       "0000"));  // Literal Header Field with Post-Base Name Reference
                  // instruction addressing dynamic table entry with post-base
-                 // index 0, absolute index 2.  This is the largest reference in
-                 // this header block, even though Largest Reference is 3.
+                 // index 0, absolute index 1.  Header block requires insert
+                 // count of 2, even though Required Insert Count is 3.
 }
 
 }  // namespace
diff --git a/quic/core/qpack/qpack_decoder_test_utils.cc b/quic/core/qpack/qpack_decoder_test_utils.cc
index 21a4606..e8bbd17 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.cc
+++ b/quic/core/qpack/qpack_decoder_test_utils.cc
@@ -4,16 +4,20 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
 
+#include <algorithm>
 #include <cstddef>
+#include <utility>
 
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace quic {
 namespace test {
 
-void NoopEncoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopEncoderStreamErrorDelegate::OnEncoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopDecoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopDecoderStreamSenderDelegate::WriteDecoderStreamData(
+    QuicStringPiece data) {}
 
 TestHeadersHandler::TestHeadersHandler()
     : decoding_completed_(false), decoding_error_detected_(false) {}
diff --git a/quic/core/qpack/qpack_decoder_test_utils.h b/quic/core/qpack/qpack_decoder_test_utils.h
index 4896ce0..937ecfc 100644
--- a/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/quic/core/qpack/qpack_decoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopEncoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackDecoder::EncoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockEncoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackDecoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,7 @@
  public:
   ~NoopDecoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteDecoderStreamData(QuicStringPiece data) override;
 };
 
 // Mock QpackDecoderStreamSender::Delegate implementation.
@@ -48,7 +48,7 @@
  public:
   ~MockDecoderStreamSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 // HeadersHandlerInterface implementation that collects decoded headers
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index 86f1785..6019229 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -35,7 +35,7 @@
   decoder_stream_receiver_.Decode(data);
 }
 
-void QpackEncoder::OnTableStateSynchronize(uint64_t insert_count) {
+void QpackEncoder::OnInsertCountIncrement(uint64_t increment) {
   // TODO(bnc): Implement dynamic table management for encoding.
 }
 
@@ -48,7 +48,7 @@
 }
 
 void QpackEncoder::OnErrorDetected(QuicStringPiece error_message) {
-  decoder_stream_error_delegate_->OnError(error_message);
+  decoder_stream_error_delegate_->OnDecoderStreamError(error_message);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index b7d7f20..4e65532 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -36,7 +36,7 @@
    public:
     virtual ~DecoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnDecoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackEncoder(
@@ -55,7 +55,7 @@
   void DecodeDecoderStreamData(QuicStringPiece data);
 
   // QpackDecoderStreamReceiver::Delegate implementation
-  void OnTableStateSynchronize(uint64_t insert_count) override;
+  void OnInsertCountIncrement(uint64_t increment) override;
   void OnHeaderAcknowledgement(QuicStreamId stream_id) override;
   void OnStreamCancellation(QuicStreamId stream_id) override;
   void OnErrorDetected(QuicStringPiece error_message) override;
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver.cc b/quic/core/qpack/qpack_encoder_stream_receiver.cc
index 008e357..3f8ef08 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver.cc
+++ b/quic/core/qpack/qpack_encoder_stream_receiver.cc
@@ -45,8 +45,8 @@
     return true;
   }
 
-  DCHECK_EQ(instruction, DynamicTableSizeUpdateInstruction());
-  delegate_->OnDynamicTableSizeUpdate(instruction_decoder_.varint());
+  DCHECK_EQ(instruction, SetDynamicTableCapacityInstruction());
+  delegate_->OnSetDynamicTableCapacity(instruction_decoder_.varint());
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver.h b/quic/core/qpack/qpack_encoder_stream_receiver.h
index 7ce4f15..66a2985 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver.h
+++ b/quic/core/qpack/qpack_encoder_stream_receiver.h
@@ -33,8 +33,8 @@
                                               QuicStringPiece value) = 0;
     // 5.2.3. Duplicate
     virtual void OnDuplicate(uint64_t index) = 0;
-    // 5.2.4. Dynamic Table Size Update
-    virtual void OnDynamicTableSizeUpdate(uint64_t max_size) = 0;
+    // 5.2.4. Set Dynamic Table Capacity
+    virtual void OnSetDynamicTableCapacity(uint64_t capacity) = 0;
     // Decoding error
     virtual void OnErrorDetected(QuicStringPiece error_message) = 0;
   };
diff --git a/quic/core/qpack/qpack_encoder_stream_receiver_test.cc b/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
index f9fce00..5685981 100644
--- a/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
+++ b/quic/core/qpack/qpack_encoder_stream_receiver_test.cc
@@ -9,6 +9,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using testing::Eq;
 using testing::StrictMock;
 
 namespace quic {
@@ -26,7 +27,7 @@
   MOCK_METHOD2(OnInsertWithoutNameReference,
                void(QuicStringPiece name, QuicStringPiece value));
   MOCK_METHOD1(OnDuplicate, void(uint64_t index));
-  MOCK_METHOD1(OnDynamicTableSizeUpdate, void(uint64_t max_size));
+  MOCK_METHOD1(OnSetDynamicTableCapacity, void(uint64_t capacity));
   MOCK_METHOD1(OnErrorDetected, void(QuicStringPiece error_message));
 };
 
@@ -45,15 +46,15 @@
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 5, ""));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 5, Eq("")));
   // Static, index fits in prefix, Huffman encoded value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 2, "foo"));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(true, 2, Eq("foo")));
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(*delegate(), OnInsertWithNameReference(false, 137, "bar"));
+  EXPECT_CALL(*delegate(), OnInsertWithNameReference(false, 137, Eq("bar")));
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(*delegate(),
-              OnInsertWithNameReference(false, 42, QuicString(127, 'Z')));
+              OnInsertWithNameReference(false, 42, Eq(QuicString(127, 'Z'))));
 
   Decode(QuicTextUtils::HexDecode(
       "c500"
@@ -66,29 +67,29 @@
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceIndexTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("bfffffffffffffffffffffff"));
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithNameReferenceValueTooLong) {
-  EXPECT_CALL(*delegate(),
-              OnErrorDetected(QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("c57fffffffffffffffffffff"));
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("", ""));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq(""), Eq("")));
   // Huffman encoded short strings.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("bar", "bar"));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("bar"), Eq("bar")));
   // Not Huffman encoded short strings.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference("foo", "foo"));
+  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(Eq("foo"), Eq("foo")));
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
-  EXPECT_CALL(*delegate(), OnInsertWithoutNameReference(QuicString(31, 'Z'),
-                                                        QuicString(127, 'Z')));
+  EXPECT_CALL(*delegate(),
+              OnInsertWithoutNameReference(Eq(QuicString(31, 'Z')),
+                                           Eq(QuicString(127, 'Z'))));
 
   Decode(QuicTextUtils::HexDecode(
       "4000"
@@ -104,7 +105,7 @@
 // Name Length value is too large for varint decoder to decode.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceNameTooLongForVarintDecoder) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("5fffffffffffffffffffff"));
 }
@@ -112,8 +113,7 @@
 // Name Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceNameExceedsLimit) {
-  EXPECT_CALL(*delegate(),
-              OnErrorDetected(QuicStringPiece("String literal too long.")));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("String literal too long.")));
 
   Decode(QuicTextUtils::HexDecode("5fffff7f"));
 }
@@ -121,7 +121,7 @@
 // Value Length value is too large for varint decoder to decode.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceValueTooLongForVarintDecoder) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("436261727fffffffffffffffffffff"));
 }
@@ -129,7 +129,7 @@
 // Value Length value can be decoded by varint decoder but exceeds 1 MB limit.
 TEST_F(QpackEncoderStreamReceiverTest,
        InsertWithoutNameReferenceValueExceedsLimit) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("String literal too long."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("String literal too long.")));
 
   Decode(QuicTextUtils::HexDecode("436261727fffff7f"));
 }
@@ -144,22 +144,22 @@
 }
 
 TEST_F(QpackEncoderStreamReceiverTest, DuplicateIndexTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("1fffffffffffffffffffff"));
 }
 
-TEST_F(QpackEncoderStreamReceiverTest, DynamicTableSizeUpdate) {
-  // Small max size fits in prefix.
-  EXPECT_CALL(*delegate(), OnDynamicTableSizeUpdate(17));
-  // Large max size requires two extension bytes.
-  EXPECT_CALL(*delegate(), OnDynamicTableSizeUpdate(500));
+TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacity) {
+  // Small capacity fits in prefix.
+  EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(17));
+  // Large capacity requires two extension bytes.
+  EXPECT_CALL(*delegate(), OnSetDynamicTableCapacity(500));
 
   Decode(QuicTextUtils::HexDecode("313fd503"));
 }
 
-TEST_F(QpackEncoderStreamReceiverTest, DynamicTableSizeUpdateMaxSizeTooLarge) {
-  EXPECT_CALL(*delegate(), OnErrorDetected("Encoded integer too large."));
+TEST_F(QpackEncoderStreamReceiverTest, SetDynamicTableCapacityTooLarge) {
+  EXPECT_CALL(*delegate(), OnErrorDetected(Eq("Encoded integer too large.")));
 
   Decode(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.cc b/quic/core/qpack/qpack_encoder_stream_sender.cc
index c7ee503..fb43046 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -33,7 +33,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendInsertWithoutNameReference(
@@ -49,7 +49,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
@@ -62,20 +62,20 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
-void QpackEncoderStreamSender::SendDynamicTableSizeUpdate(uint64_t max_size) {
-  instruction_encoder_.set_varint(max_size);
+void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
+  instruction_encoder_.set_varint(capacity);
 
-  instruction_encoder_.Encode(DynamicTableSizeUpdateInstruction());
+  instruction_encoder_.Encode(SetDynamicTableCapacityInstruction());
 
   QuicString output;
 
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.h b/quic/core/qpack/qpack_encoder_stream_sender.h
index 0c8d4dd..ad34568 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -22,9 +22,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the encoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteEncoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteEncoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackEncoderStreamSender(Delegate* delegate);
@@ -44,8 +45,8 @@
                                       QuicStringPiece value);
   // 5.2.3. Duplicate
   void SendDuplicate(uint64_t index);
-  // 5.2.4. Dynamic Table Size Update
-  void SendDynamicTableSizeUpdate(uint64_t max_size);
+  // 5.2.4. Set Dynamic Table Capacity
+  void SendSetDynamicTableCapacity(uint64_t capacity);
 
  private:
   Delegate* const delegate_;
diff --git a/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 46e5c46..a850f18 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
@@ -16,40 +17,36 @@
 namespace test {
 namespace {
 
-class MockSenderDelegate : public QpackEncoderStreamSender::Delegate {
- public:
-  ~MockSenderDelegate() override = default;
-
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
-};
-
 class QpackEncoderStreamSenderTest : public QuicTest {
  protected:
   QpackEncoderStreamSenderTest() : stream_(&delegate_) {}
   ~QpackEncoderStreamSenderTest() override = default;
 
-  StrictMock<MockSenderDelegate> delegate_;
+  StrictMock<MockEncoderStreamSenderDelegate> delegate_;
   QpackEncoderStreamSender stream_;
 };
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c500"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c500"))));
   stream_.SendInsertWithNameReference(true, 5, "");
 
   // Static, index fits in prefix, Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c28294e7"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c28294e7"))));
   stream_.SendInsertWithNameReference(true, 2, "foo");
 
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
   stream_.SendInsertWithNameReference(false, 137, "bar");
 
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -59,23 +56,25 @@
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("4000"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("4000"))));
   stream_.SendInsertWithoutNameReference("", "");
 
   // Huffman encoded short strings.
-  EXPECT_CALL(delegate_,
-              Write(Eq(QuicTextUtils::HexDecode("4362617203626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("4362617203626172"))));
   stream_.SendInsertWithoutNameReference("bar", "bar");
 
   // Not Huffman encoded short strings.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
   stream_.SendInsertWithoutNameReference("foo", "foo");
 
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f"
           "005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -87,22 +86,26 @@
 
 TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
   // Small index fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("11"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("11"))));
   stream_.SendDuplicate(17);
 
   // Large index requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("1fd503"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("1fd503"))));
   stream_.SendDuplicate(500);
 }
 
-TEST_F(QpackEncoderStreamSenderTest, DynamicTableSizeUpdate) {
-  // Small max size fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("31"))));
-  stream_.SendDynamicTableSizeUpdate(17);
+TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
+  // Small capacity fits in prefix.
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("31"))));
+  stream_.SendSetDynamicTableCapacity(17);
 
-  // Large max size requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("3fd503"))));
-  stream_.SendDynamicTableSizeUpdate(500);
+  // Large capacity requires two extension bytes.
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("3fd503"))));
+  stream_.SendSetDynamicTableCapacity(500);
 }
 
 }  // namespace
diff --git a/quic/core/qpack/qpack_encoder_test.cc b/quic/core/qpack/qpack_encoder_test.cc
index 04e4dd6..e3dba00 100644
--- a/quic/core/qpack/qpack_encoder_test.cc
+++ b/quic/core/qpack/qpack_encoder_test.cc
@@ -11,6 +11,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
+using ::testing::Eq;
 using ::testing::StrictMock;
 using ::testing::Values;
 
@@ -153,7 +154,7 @@
 
 TEST_P(QpackEncoderTest, DecoderStreamError) {
   EXPECT_CALL(decoder_stream_error_delegate_,
-              OnError("Encoded integer too large."));
+              OnDecoderStreamError(Eq("Encoded integer too large.")));
 
   QpackEncoder encoder(&decoder_stream_error_delegate_,
                        &encoder_stream_sender_delegate_);
diff --git a/quic/core/qpack/qpack_encoder_test_utils.cc b/quic/core/qpack/qpack_encoder_test_utils.cc
index 606db4e..b9a3263 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.cc
+++ b/quic/core/qpack/qpack_encoder_test_utils.cc
@@ -9,9 +9,11 @@
 namespace quic {
 namespace test {
 
-void NoopDecoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopDecoderStreamErrorDelegate::OnDecoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopEncoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopEncoderStreamSenderDelegate::WriteEncoderStreamData(
+    QuicStringPiece data) {}
 
 QuicString QpackEncode(
     QpackEncoder::DecoderStreamErrorDelegate* decoder_stream_error_delegate,
diff --git a/quic/core/qpack/qpack_encoder_test_utils.h b/quic/core/qpack/qpack_encoder_test_utils.h
index b000868..03d05cb 100644
--- a/quic/core/qpack/qpack_encoder_test_utils.h
+++ b/quic/core/qpack/qpack_encoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopDecoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnDecoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackEncoder::DecoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockDecoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackEncoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,16 @@
  public:
   ~NoopEncoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteEncoderStreamData(QuicStringPiece data) override;
+};
+
+// Mock QpackEncoderStreamSender::Delegate implementation.
+class MockEncoderStreamSenderDelegate
+    : public QpackEncoderStreamSender::Delegate {
+ public:
+  ~MockEncoderStreamSenderDelegate() override = default;
+
+  MOCK_METHOD1(WriteEncoderStreamData, void(QuicStringPiece data));
 };
 
 QuicString QpackEncode(
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index 4a4c9fa..4ba3ee3 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -143,12 +143,12 @@
   return new_entry;
 }
 
-bool QpackHeaderTable::UpdateTableSize(uint64_t max_size) {
-  if (max_size > maximum_dynamic_table_capacity_) {
+bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) {
+  if (capacity > maximum_dynamic_table_capacity_) {
     return false;
   }
 
-  dynamic_table_capacity_ = max_size;
+  dynamic_table_capacity_ = capacity;
   EvictDownToCurrentCapacity();
 
   DCHECK_LE(dynamic_table_size_, dynamic_table_capacity_);
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index b98e7eb..eda7ab5 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -56,9 +56,9 @@
   // is larger than the capacity of the dynamic table.
   const QpackEntry* InsertEntry(QuicStringPiece name, QuicStringPiece value);
 
-  // Change dynamic table capacity to |max_size|.  Returns true on success.
-  // Returns false is |max_size| exceeds maximum dynamic table capacity.
-  bool UpdateTableSize(uint64_t max_size);
+  // Change dynamic table capacity to |capacity|.  Returns true on success.
+  // Returns false is |capacity| exceeds maximum dynamic table capacity.
+  bool SetDynamicTableCapacity(uint64_t capacity);
 
   // Set |maximum_dynamic_table_capacity_|.  The initial value is zero.  The
   // final value is determined by the decoder and is sent to the encoder as
@@ -68,7 +68,7 @@
   // This method must only be called at most once.
   void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
 
-  // Used by request streams to decode Largest Reference.
+  // Used on request streams to encode and decode Required Insert Count.
   uint64_t max_entries() const { return max_entries_; }
 
   // The number of entries inserted to the dynamic table (including ones that
diff --git a/quic/core/qpack/qpack_header_table_test.cc b/quic/core/qpack/qpack_header_table_test.cc
index 95df41d..f3ac5b5 100644
--- a/quic/core/qpack/qpack_header_table_test.cc
+++ b/quic/core/qpack/qpack_header_table_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_static_table.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h"
@@ -76,8 +75,8 @@
     EXPECT_FALSE(table_.InsertEntry(name, value));
   }
 
-  bool UpdateTableSize(uint64_t max_size) {
-    return table_.UpdateTableSize(max_size);
+  bool SetDynamicTableCapacity(uint64_t capacity) {
+    return table_.SetDynamicTableCapacity(capacity);
   }
 
   uint64_t max_entries() const { return table_.max_entries(); }
@@ -237,20 +236,21 @@
   EXPECT_EQ(15u, table2.max_entries());
 }
 
-TEST_F(QpackHeaderTableTest, UpdateTableSize) {
+TEST_F(QpackHeaderTableTest, SetDynamicTableCapacity) {
   // Dynamic table capacity does not affect MaxEntries.
-  EXPECT_TRUE(UpdateTableSize(1024));
+  EXPECT_TRUE(SetDynamicTableCapacity(1024));
   EXPECT_EQ(32u * 1024, max_entries());
 
-  EXPECT_TRUE(UpdateTableSize(500));
+  EXPECT_TRUE(SetDynamicTableCapacity(500));
   EXPECT_EQ(32u * 1024, max_entries());
 
   // Dynamic table capacity cannot exceed maximum dynamic table capacity.
-  EXPECT_FALSE(UpdateTableSize(2 * kMaximumDynamicTableCapacityForTesting));
+  EXPECT_FALSE(
+      SetDynamicTableCapacity(2 * kMaximumDynamicTableCapacityForTesting));
 }
 
 TEST_F(QpackHeaderTableTest, EvictByInsertion) {
-  EXPECT_TRUE(UpdateTableSize(40));
+  EXPECT_TRUE(SetDynamicTableCapacity(40));
 
   // Entry size is 3 + 3 + 32 = 38.
   InsertEntry("foo", "bar");
@@ -285,7 +285,7 @@
   ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
               /* expected_is_static = */ false, 1u);
 
-  EXPECT_TRUE(UpdateTableSize(40));
+  EXPECT_TRUE(SetDynamicTableCapacity(40));
   EXPECT_EQ(2u, inserted_entry_count());
   EXPECT_EQ(1u, dropped_entry_count());
 
@@ -293,7 +293,7 @@
   ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
               /* expected_is_static = */ false, 1u);
 
-  EXPECT_TRUE(UpdateTableSize(20));
+  EXPECT_TRUE(SetDynamicTableCapacity(20));
   EXPECT_EQ(2u, inserted_entry_count());
   EXPECT_EQ(2u, dropped_entry_count());
 
@@ -302,7 +302,7 @@
 }
 
 TEST_F(QpackHeaderTableTest, EvictOldestOfIdentical) {
-  EXPECT_TRUE(UpdateTableSize(80));
+  EXPECT_TRUE(SetDynamicTableCapacity(80));
 
   // Entry size is 3 + 3 + 32 = 38.
   // Insert same entry twice.
@@ -327,7 +327,7 @@
 }
 
 TEST_F(QpackHeaderTableTest, EvictOldestOfSameName) {
-  EXPECT_TRUE(UpdateTableSize(80));
+  EXPECT_TRUE(SetDynamicTableCapacity(80));
 
   // Entry size is 3 + 3 + 32 = 38.
   // Insert two entries with same name but different values.
diff --git a/quic/core/qpack/qpack_instruction_decoder.cc b/quic/core/qpack/qpack_instruction_decoder.cc
index 9623dfb..dbb2076 100644
--- a/quic/core/qpack/qpack_instruction_decoder.cc
+++ b/quic/core/qpack/qpack_instruction_decoder.cc
@@ -4,6 +4,9 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h"
 
+#include <algorithm>
+#include <utility>
+
 #include "base/logging.h"
 
 namespace quic {
diff --git a/quic/core/qpack/qpack_instruction_decoder_test.cc b/quic/core/qpack/qpack_instruction_decoder_test.cc
index 99be5a0..d1fe9b5 100644
--- a/quic/core/qpack/qpack_instruction_decoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -13,6 +15,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
 using ::testing::_;
+using ::testing::Eq;
 using ::testing::Expectation;
 using ::testing::Return;
 using ::testing::StrictMock;
@@ -140,14 +143,12 @@
 }
 
 TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) {
-  EXPECT_CALL(delegate_,
-              OnError(QuicStringPiece("Error in Huffman-encoded string.")));
+  EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string.")));
   decoder_.Decode(QuicTextUtils::HexDecode("c1ff"));
 }
 
 TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) {
-  EXPECT_CALL(delegate_,
-              OnError(QuicStringPiece("Encoded integer too large.")));
+  EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large.")));
   decoder_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
 }
 
diff --git a/quic/core/qpack/qpack_progressive_decoder.cc b/quic/core/qpack/qpack_progressive_decoder.cc
index 409c910..430e707 100644
--- a/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/quic/core/qpack/qpack_progressive_decoder.cc
@@ -4,6 +4,9 @@
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h"
 
+#include <algorithm>
+#include <limits>
+
 #include "base/logging.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
@@ -23,21 +26,21 @@
       header_table_(header_table),
       decoder_stream_sender_(decoder_stream_sender),
       handler_(handler),
-      largest_reference_(0),
-      base_index_(0),
-      largest_reference_seen_(0),
+      required_insert_count_(0),
+      base_(0),
+      required_insert_count_so_far_(0),
       prefix_decoded_(false),
       decoding_(true),
       error_detected_(false) {}
 
 // static
-bool QpackProgressiveDecoder::DecodeLargestReference(
-    uint64_t wire_largest_reference,
+bool QpackProgressiveDecoder::DecodeRequiredInsertCount(
+    uint64_t encoded_required_insert_count,
     uint64_t max_entries,
     uint64_t total_number_of_inserts,
-    uint64_t* largest_reference) {
-  if (wire_largest_reference == 0) {
-    *largest_reference = 0;
+    uint64_t* required_insert_count) {
+  if (encoded_required_insert_count == 0) {
+    *required_insert_count = 0;
     return true;
   }
 
@@ -45,37 +48,37 @@
   // precluding all calculations in this method from overflowing.
   DCHECK_LE(max_entries, std::numeric_limits<uint64_t>::max() / 32);
 
-  if (wire_largest_reference > 2 * max_entries) {
+  if (encoded_required_insert_count > 2 * max_entries) {
     return false;
   }
 
-  *largest_reference = wire_largest_reference - 1;
-  DCHECK_LT(*largest_reference, std::numeric_limits<uint64_t>::max() / 16);
+  *required_insert_count = encoded_required_insert_count - 1;
+  DCHECK_LT(*required_insert_count, std::numeric_limits<uint64_t>::max() / 16);
 
   uint64_t current_wrapped = total_number_of_inserts % (2 * max_entries);
   DCHECK_LT(current_wrapped, std::numeric_limits<uint64_t>::max() / 16);
 
-  if (current_wrapped >= *largest_reference + max_entries) {
-    // Largest Reference wrapped around 1 extra time.
-    *largest_reference += 2 * max_entries;
-  } else if (current_wrapped + max_entries < *largest_reference) {
+  if (current_wrapped >= *required_insert_count + max_entries) {
+    // Required Insert Count wrapped around 1 extra time.
+    *required_insert_count += 2 * max_entries;
+  } else if (current_wrapped + max_entries < *required_insert_count) {
     // Decoder wrapped around 1 extra time.
     current_wrapped += 2 * max_entries;
   }
 
-  if (*largest_reference >
+  if (*required_insert_count >
       std::numeric_limits<uint64_t>::max() - total_number_of_inserts) {
     return false;
   }
 
-  *largest_reference += total_number_of_inserts;
+  *required_insert_count += total_number_of_inserts;
 
-  // Prevent underflow, but also disallow invalid value 0 for Largest Reference.
-  if (current_wrapped >= *largest_reference) {
+  // Prevent underflow, also disallow invalid value 0 for Required Insert Count.
+  if (current_wrapped >= *required_insert_count) {
     return false;
   }
 
-  *largest_reference -= current_wrapped;
+  *required_insert_count -= current_wrapped;
 
   return true;
 }
@@ -118,8 +121,8 @@
     return;
   }
 
-  if (largest_reference_ != largest_reference_seen_) {
-    OnError("Largest Reference too large.");
+  if (required_insert_count_ != required_insert_count_so_far_) {
+    OnError("Required Insert Count too large.");
     return;
   }
 
@@ -164,17 +167,17 @@
       return false;
     }
 
-    if (absolute_index > largest_reference_) {
-      OnError("Index larger than Largest Reference.");
+    if (absolute_index >= required_insert_count_) {
+      OnError("Absolute Index must be smaller than Required Insert Count.");
       return false;
     }
 
-    largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+    DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+    required_insert_count_so_far_ =
+        std::max(required_insert_count_so_far_, absolute_index + 1);
 
-    DCHECK_NE(0u, absolute_index);
-    const uint64_t real_index = absolute_index - 1;
     auto entry =
-        header_table_->LookupEntry(/* is_static = */ false, real_index);
+        header_table_->LookupEntry(/* is_static = */ false, absolute_index);
     if (!entry) {
       OnError("Dynamic table entry not found.");
       return false;
@@ -203,16 +206,17 @@
     return false;
   }
 
-  if (absolute_index > largest_reference_) {
-    OnError("Index larger than Largest Reference.");
+  if (absolute_index >= required_insert_count_) {
+    OnError("Absolute Index must be smaller than Required Insert Count.");
     return false;
   }
 
-  largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+  DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+  required_insert_count_so_far_ =
+      std::max(required_insert_count_so_far_, absolute_index + 1);
 
-  DCHECK_NE(0u, absolute_index);
-  const uint64_t real_index = absolute_index - 1;
-  auto entry = header_table_->LookupEntry(/* is_static = */ false, real_index);
+  auto entry =
+      header_table_->LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
     OnError("Dynamic table entry not found.");
     return false;
@@ -231,17 +235,17 @@
       return false;
     }
 
-    if (absolute_index > largest_reference_) {
-      OnError("Index larger than Largest Reference.");
+    if (absolute_index >= required_insert_count_) {
+      OnError("Absolute Index must be smaller than Required Insert Count.");
       return false;
     }
 
-    largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+    DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+    required_insert_count_so_far_ =
+        std::max(required_insert_count_so_far_, absolute_index + 1);
 
-    DCHECK_NE(0u, absolute_index);
-    const uint64_t real_index = absolute_index - 1;
     auto entry =
-        header_table_->LookupEntry(/* is_static = */ false, real_index);
+        header_table_->LookupEntry(/* is_static = */ false, absolute_index);
     if (!entry) {
       OnError("Dynamic table entry not found.");
       return false;
@@ -270,16 +274,17 @@
     return false;
   }
 
-  if (absolute_index > largest_reference_) {
-    OnError("Index larger than Largest Reference.");
+  if (absolute_index >= required_insert_count_) {
+    OnError("Absolute Index must be smaller than Required Insert Count.");
     return false;
   }
 
-  largest_reference_seen_ = std::max(largest_reference_seen_, absolute_index);
+  DCHECK_LT(absolute_index, std::numeric_limits<uint64_t>::max());
+  required_insert_count_so_far_ =
+      std::max(required_insert_count_so_far_, absolute_index + 1);
 
-  DCHECK_NE(0u, absolute_index);
-  const uint64_t real_index = absolute_index - 1;
-  auto entry = header_table_->LookupEntry(/* is_static = */ false, real_index);
+  auto entry =
+      header_table_->LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
     OnError("Dynamic table entry not found.");
     return false;
@@ -299,17 +304,17 @@
 bool QpackProgressiveDecoder::DoPrefixInstruction() {
   DCHECK(!prefix_decoded_);
 
-  if (!DecodeLargestReference(
+  if (!DecodeRequiredInsertCount(
           prefix_decoder_->varint(), header_table_->max_entries(),
-          header_table_->inserted_entry_count(), &largest_reference_)) {
-    OnError("Error decoding Largest Reference.");
+          header_table_->inserted_entry_count(), &required_insert_count_)) {
+    OnError("Error decoding Required Insert Count.");
     return false;
   }
 
   const bool sign = prefix_decoder_->s_bit();
-  const uint64_t delta_base_index = prefix_decoder_->varint2();
-  if (!DeltaBaseIndexToBaseIndex(sign, delta_base_index, &base_index_)) {
-    OnError("Error calculating Base Index.");
+  const uint64_t delta_base = prefix_decoder_->varint2();
+  if (!DeltaBaseToBase(sign, delta_base, &base_)) {
+    OnError("Error calculating Base.");
     return false;
   }
 
@@ -318,24 +323,23 @@
   return true;
 }
 
-bool QpackProgressiveDecoder::DeltaBaseIndexToBaseIndex(
-    bool sign,
-    uint64_t delta_base_index,
-    uint64_t* base_index) {
+bool QpackProgressiveDecoder::DeltaBaseToBase(bool sign,
+                                              uint64_t delta_base,
+                                              uint64_t* base) {
   if (sign) {
-    if (delta_base_index == std::numeric_limits<uint64_t>::max() ||
-        largest_reference_ < delta_base_index + 1) {
+    if (delta_base == std::numeric_limits<uint64_t>::max() ||
+        required_insert_count_ < delta_base + 1) {
       return false;
     }
-    *base_index = largest_reference_ - delta_base_index - 1;
+    *base = required_insert_count_ - delta_base - 1;
     return true;
   }
 
-  if (delta_base_index >
-      std::numeric_limits<uint64_t>::max() - largest_reference_) {
+  if (delta_base >
+      std::numeric_limits<uint64_t>::max() - required_insert_count_) {
     return false;
   }
-  *base_index = largest_reference_ + delta_base_index;
+  *base = required_insert_count_ + delta_base;
   return true;
 }
 
@@ -343,22 +347,22 @@
     uint64_t relative_index,
     uint64_t* absolute_index) const {
   if (relative_index == std::numeric_limits<uint64_t>::max() ||
-      relative_index + 1 > base_index_) {
+      relative_index + 1 > base_) {
     return false;
   }
 
-  *absolute_index = base_index_ - relative_index;
+  *absolute_index = base_ - 1 - relative_index;
   return true;
 }
 
 bool QpackProgressiveDecoder::PostBaseIndexToAbsoluteIndex(
     uint64_t post_base_index,
     uint64_t* absolute_index) const {
-  if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_index_) {
+  if (post_base_index >= std::numeric_limits<uint64_t>::max() - base_) {
     return false;
   }
 
-  *absolute_index = base_index_ + post_base_index + 1;
+  *absolute_index = base_ + post_base_index;
   return true;
 }
 
diff --git a/quic/core/qpack/qpack_progressive_decoder.h b/quic/core/qpack/qpack_progressive_decoder.h
index 7524411..7988861 100644
--- a/quic/core/qpack/qpack_progressive_decoder.h
+++ b/quic/core/qpack/qpack_progressive_decoder.h
@@ -56,14 +56,14 @@
   QpackProgressiveDecoder& operator=(const QpackProgressiveDecoder&) = delete;
   ~QpackProgressiveDecoder() override = default;
 
-  // Calculate actual Largest Reference from largest reference value sent on
-  // wire, MaxEntries, and total number of dynamic table insertions according to
-  // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#largest-reference
+  // Calculate Required Insert Count from Encoded Required Insert Count,
+  // MaxEntries, and total number of dynamic table insertions according to
+  // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#ric.
   // Returns true on success, false on invalid input or overflow/underflow.
-  static bool DecodeLargestReference(uint64_t wire_largest_reference,
-                                     uint64_t max_entries,
-                                     uint64_t total_number_of_inserts,
-                                     uint64_t* largest_reference);
+  static bool DecodeRequiredInsertCount(uint64_t encoded_required_insert_count,
+                                        uint64_t max_entries,
+                                        uint64_t total_number_of_inserts,
+                                        uint64_t* required_insert_count);
 
   // Provide a data fragment to decode.
   void Decode(QuicStringPiece data);
@@ -84,19 +84,18 @@
   bool DoLiteralHeaderFieldInstruction();
   bool DoPrefixInstruction();
 
-  // Calculates Base Index from |largest_reference_|, which must be set before
-  // calling this method, and sign bit and Delta Base Index in the Header Data
-  // Prefix, which are passed in as arguments.  Returns true on success, false
-  // on failure due to overflow/underflow.
-  bool DeltaBaseIndexToBaseIndex(bool sign,
-                                 uint64_t delta_base_index,
-                                 uint64_t* base_index);
+  // Calculates Base from |required_insert_count_|, which must be set before
+  // calling this method, and sign bit and Delta Base in the Header Data Prefix,
+  // which are passed in as arguments.  Returns true on success, false on
+  // failure due to overflow/underflow.
+  bool DeltaBaseToBase(bool sign, uint64_t delta_base, uint64_t* base);
 
   // The request stream can use relative index (but different from the kind of
   // relative index used on the encoder stream), and post-base index.
   // These methods convert relative index and post-base index to absolute index
   // (one based).  They return true on success, or false if conversion fails due
-  // to overflow/underflow.
+  // to overflow/underflow.  On success, |*absolute_index| is guaranteed to be
+  // strictly less than std::numeric_limits<uint64_t>::max().
   bool RequestStreamRelativeIndexToAbsoluteIndex(
       uint64_t relative_index,
       uint64_t* absolute_index) const;
@@ -115,14 +114,16 @@
   QpackDecoderStreamSender* const decoder_stream_sender_;
   HeadersHandlerInterface* const handler_;
 
-  // Largest Reference and Base Index are parsed from the Header Data Prefix.
-  // They are both absolute indices, that is, one based.
-  uint64_t largest_reference_;
-  uint64_t base_index_;
+  // Required Insert Count and Base are decoded from the Header Data Prefix.
+  uint64_t required_insert_count_;
+  uint64_t base_;
 
-  // Keep track of largest reference seen in this header block.
-  // After decoding is completed, this can be compared to |largest_reference_|.
-  uint64_t largest_reference_seen_;
+  // Required Insert Count is one larger than the largest absolute index of all
+  // referenced dynamic table entries, or zero if no dynamic table entries are
+  // referenced.  |required_insert_count_so_far_| starts out as zero and keeps
+  // track of the Required Insert Count based on entries decoded so far.
+  // After decoding is completed, it is compared to |required_insert_count_|.
+  uint64_t required_insert_count_so_far_;
 
   // False until prefix is fully read and decoded.
   bool prefix_decoded_;
diff --git a/quic/core/qpack/qpack_progressive_decoder_test.cc b/quic/core/qpack/qpack_progressive_decoder_test.cc
index c1722e5..b306702 100644
--- a/quic/core/qpack/qpack_progressive_decoder_test.cc
+++ b/quic/core/qpack/qpack_progressive_decoder_test.cc
@@ -11,12 +11,12 @@
 namespace test {
 namespace {
 
-// For testing valid decodings, the encoded (wire) largest reference value is
-// calculated for actual Largest Reference values, so that there is an expected
-// value to comparte the decoded value against, and so that intricate
-// inequalities can be documented.
+// For testing valid decodings, the Encoded Required Insert Count is calculated
+// from Required Insert Count, so that there is an expected value to compare
+// the decoded value against, and so that intricate inequalities can be
+// documented.
 struct {
-  uint64_t largest_reference;
+  uint64_t required_insert_count;
   uint64_t max_entries;
   uint64_t total_number_of_inserts;
 } kTestData[] = {
@@ -25,70 +25,72 @@
     // No dynamic entries in header.
     {0, 100, 0},
     {0, 100, 500},
-    // Largest Reference has not wrapped around yet, no entries evicted.
+    // Required Insert Count has not wrapped around yet, no entries evicted.
     {15, 100, 25},
     {20, 100, 10},
-    // Largest Reference has not wrapped around yet, some entries evicted.
+    // Required Insert Count has not wrapped around yet, some entries evicted.
     {90, 100, 110},
-    // Largest Reference has wrapped around.
+    // Required Insert Count has wrapped around.
     {234, 100, 180},
-    // Largest Reference has wrapped around many times.
+    // Required Insert Count has wrapped around many times.
     {5678, 100, 5701},
-    // Lowest and highest possible Largest Reference values
+    // Lowest and highest possible Required Insert Count values
     // for given MaxEntries and total number of insertions.
     {401, 100, 500},
     {600, 100, 500}};
 
-uint64_t EncodeLargestReference(uint64_t largest_reference,
-                                uint64_t max_entries) {
-  if (largest_reference == 0) {
+uint64_t EncodeRequiredInsertCount(uint64_t required_insert_count,
+                                   uint64_t max_entries) {
+  if (required_insert_count == 0) {
     return 0;
   }
 
-  return largest_reference % (2 * max_entries) + 1;
+  return required_insert_count % (2 * max_entries) + 1;
 }
 
-TEST(QpackProgressiveDecoderTest, DecodeLargestReference) {
+TEST(QpackProgressiveDecoderTest, DecodeRequiredInsertCount) {
   for (size_t i = 0; i < QUIC_ARRAYSIZE(kTestData); ++i) {
-    const uint64_t largest_reference = kTestData[i].largest_reference;
+    const uint64_t required_insert_count = kTestData[i].required_insert_count;
     const uint64_t max_entries = kTestData[i].max_entries;
     const uint64_t total_number_of_inserts =
         kTestData[i].total_number_of_inserts;
 
-    if (largest_reference != 0) {
+    if (required_insert_count != 0) {
       // Dynamic entries cannot be referenced if dynamic table capacity is zero.
       ASSERT_LT(0u, max_entries) << i;
-      // Entry |total_number_of_inserts - max_entries| and earlier entries are
-      // evicted.  Entry |largest_reference| is referenced.  No evicted entry
-      // can be referenced.
-      ASSERT_LT(total_number_of_inserts, largest_reference + max_entries) << i;
-      // Entry |largest_reference - max_entries| and earlier entries are
-      // evicted, entry |total_number_of_inserts| is the last acknowledged
+      // Entry |total_number_of_inserts - 1 - max_entries| and earlier entries
+      // are evicted.  Entry |required_insert_count - 1| is referenced.  No
+      // evicted entry can be referenced.
+      ASSERT_LT(total_number_of_inserts, required_insert_count + max_entries)
+          << i;
+      // Entry |required_insert_count - 1 - max_entries| and earlier entries are
+      // evicted, entry |total_number_of_inserts - 1| is the last acknowledged
       // entry.  Every evicted entry must be acknowledged.
-      ASSERT_LE(largest_reference, total_number_of_inserts + max_entries) << i;
+      ASSERT_LE(required_insert_count, total_number_of_inserts + max_entries)
+          << i;
     }
 
-    uint64_t wire_largest_reference =
-        EncodeLargestReference(largest_reference, max_entries);
+    uint64_t encoded_required_insert_count =
+        EncodeRequiredInsertCount(required_insert_count, max_entries);
 
     // Initialize to a value different from the expected output to confirm that
-    // DecodeLargestReference() modifies the value of
-    // |decoded_largest_reference|.
-    uint64_t decoded_largest_reference = largest_reference + 1;
-    EXPECT_TRUE(QpackProgressiveDecoder::DecodeLargestReference(
-        wire_largest_reference, max_entries, total_number_of_inserts,
-        &decoded_largest_reference))
+    // DecodeRequiredInsertCount() modifies the value of
+    // |decoded_required_insert_count|.
+    uint64_t decoded_required_insert_count = required_insert_count + 1;
+    EXPECT_TRUE(QpackProgressiveDecoder::DecodeRequiredInsertCount(
+        encoded_required_insert_count, max_entries, total_number_of_inserts,
+        &decoded_required_insert_count))
         << i;
 
-    EXPECT_EQ(decoded_largest_reference, largest_reference) << i;
+    EXPECT_EQ(decoded_required_insert_count, required_insert_count) << i;
   }
 }
 
-// Failures are tested with hardcoded values for the on-the-wire largest
-// reference field, to provide test coverage for values that would never be
-// produced by a well behaved encoding function.
+// Failures are tested with hardcoded values for encoded required insert count,
+// to provide test coverage for values that would never be produced by a well
+// behaved encoding function.
 struct {
-  uint64_t wire_largest_reference;
+  uint64_t encoded_required_insert_count;
   uint64_t max_entries;
   uint64_t total_number_of_inserts;
 } kInvalidTestData[] = {
@@ -100,19 +102,19 @@
     // https://github.com/quicwg/base-drafts/issues/2112#issue-389626872.
     {1, 10, 2},
     {18, 10, 2},
-    // Largest Reference value too small or too large
+    // Encoded Required Insert Count value too small or too large
     // for given MaxEntries and total number of insertions.
     {400, 100, 500},
     {601, 100, 500}};
 
-TEST(QpackProgressiveDecoderTest, DecodeLargestReferenceError) {
+TEST(QpackProgressiveDecoderTest, DecodeRequiredInsertCountError) {
   for (size_t i = 0; i < QUIC_ARRAYSIZE(kInvalidTestData); ++i) {
-    uint64_t decoded_largest_reference = 0;
-    EXPECT_FALSE(QpackProgressiveDecoder::DecodeLargestReference(
-        kInvalidTestData[i].wire_largest_reference,
+    uint64_t decoded_required_insert_count = 0;
+    EXPECT_FALSE(QpackProgressiveDecoder::DecodeRequiredInsertCount(
+        kInvalidTestData[i].encoded_required_insert_count,
         kInvalidTestData[i].max_entries,
         kInvalidTestData[i].total_number_of_inserts,
-        &decoded_largest_reference))
+        &decoded_required_insert_count))
         << i;
   }
 }
diff --git a/quic/core/qpack/qpack_progressive_encoder.cc b/quic/core/qpack/qpack_progressive_encoder.cc
index 4d2a3cf..41433ff 100644
--- a/quic/core/qpack/qpack_progressive_encoder.cc
+++ b/quic/core/qpack/qpack_progressive_encoder.cc
@@ -48,8 +48,8 @@
   DCHECK_LT(output->size(), max_length);
 
   if (!prefix_encoded_ && !instruction_encoder_.HasNext()) {
-    // TODO(bnc): Implement dynamic entries and set Largest Reference and
-    // Delta Base Index accordingly.
+    // TODO(bnc): Implement dynamic entries and set Required Insert Count and
+    // Delta Base accordingly.
     instruction_encoder_.set_varint(0);
     instruction_encoder_.set_varint2(0);
     instruction_encoder_.set_s_bit(false);
diff --git a/quic/core/quic_buffered_packet_store_test.cc b/quic/core/quic_buffered_packet_store_test.cc
index 027a26c..e214ff1 100644
--- a/quic/core/quic_buffered_packet_store_test.cc
+++ b/quic/core/quic_buffered_packet_store_test.cc
@@ -6,6 +6,7 @@
 
 #include <list>
 
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -53,7 +54,7 @@
         packet_content_("some encrypted content"),
         packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
         packet_(packet_content_.data(), packet_content_.size(), packet_time_),
-        invalid_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        invalid_version_(UnsupportedQuicVersion()),
         valid_version_(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44) {}
 
  protected:
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index f3a6767..d4c13c4 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -23,6 +23,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_config.h"
 #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h"
 #include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
@@ -42,10 +43,6 @@
 
 namespace {
 
-// The largest gap in packets we'll accept without closing the connection.
-// This will likely have to be tuned.
-const QuicPacketNumber kMaxPacketGap = 5000;
-
 // Maximum number of acks received before sending an ack in response.
 // TODO(fayang): Remove this constant when deprecating QUIC_VERSION_35.
 const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
@@ -74,7 +71,7 @@
 const int kMinReleaseTimeIntoFutureMs = 1;
 
 bool Near(QuicPacketNumber a, QuicPacketNumber b) {
-  QuicPacketNumber delta = (a > b) ? a - b : b - a;
+  QuicPacketCount delta = (a > b) ? a - b : b - a;
   return delta <= kMaxPacketGap;
 }
 
@@ -244,15 +241,12 @@
       peer_address_(initial_peer_address),
       direct_peer_address_(initial_peer_address),
       active_effective_peer_migration_type_(NO_CHANGE),
-      highest_packet_sent_before_effective_peer_migration_(0),
       last_packet_decrypted_(false),
       last_size_(0),
       current_packet_data_(nullptr),
       last_decrypted_packet_level_(ENCRYPTION_NONE),
       should_last_packet_instigate_acks_(false),
       was_last_packet_missing_(false),
-      largest_seen_packet_with_ack_(0),
-      largest_seen_packet_with_stop_waiting_(0),
       max_undecryptable_packets_(0),
       max_tracked_packets_(kMaxTrackedPackets),
       pending_version_negotiation_packet_(false),
@@ -344,10 +338,9 @@
       processing_ack_frame_(false),
       supports_release_time_(false),
       release_time_into_future_(QuicTime::Delta::Zero()),
-      donot_retransmit_old_window_updates_(false),
       no_version_negotiation_(supported_versions.size() == 1),
-      decrypt_packets_on_key_change_(
-          GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
+      clear_probing_mark_after_packet_processing_(GetQuicReloadableFlag(
+          quic_clear_probing_mark_after_packet_processing)) {
   if (ack_mode_ == ACK_DECIMATION) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation);
   }
@@ -359,10 +352,12 @@
                   << "Created connection with connection_id: " << connection_id
                   << " and version: "
                   << QuicVersionToString(transport_version());
-  QUIC_BUG_IF(connection_id.length() != sizeof(uint64_t) &&
-              transport_version() < QUIC_VERSION_99)
-      << "Cannot use connection ID of length " << connection_id.length()
-      << " with version " << QuicVersionToString(transport_version());
+
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(connection_id,
+                                                        transport_version()))
+      << "QuicConnection: attempted to use connection ID " << connection_id
+      << " which is invalid with version "
+      << QuicVersionToString(transport_version());
 
   framer_.set_visitor(this);
   stats_.connection_creation_time = clock_->ApproximateNow();
@@ -441,16 +436,24 @@
   if (config.HasClientSentConnectionOption(kACKD, perspective_)) {
     ack_mode_ = ACK_DECIMATION;
   }
-  if (!GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+  if ((!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+       GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) &&
       config.HasClientSentConnectionOption(kAKD2, perspective_)) {
+    if (GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_keep_ack_decimation_reordering, 1, 2);
+    }
     ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
   }
   if (config.HasClientSentConnectionOption(kAKD3, perspective_)) {
     ack_mode_ = ACK_DECIMATION;
     ack_decimation_delay_ = kShortAckDecimationDelay;
   }
-  if (!GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+  if ((!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+       GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) &&
       config.HasClientSentConnectionOption(kAKD4, perspective_)) {
+    if (GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_keep_ack_decimation_reordering, 2, 2);
+    }
     ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
     ack_decimation_delay_ = kShortAckDecimationDelay;
   }
@@ -782,7 +785,7 @@
       // Packets should have the version flag till version negotiation is
       // done.
       QuicString error_details =
-          QuicStrCat(ENDPOINT, "Packet ", header.packet_number,
+          QuicStrCat(ENDPOINT, "Packet ", header.packet_number.ToUint64(),
                      " without version flag before version negotiated.");
       QUIC_DLOG(WARNING) << error_details;
       CloseConnection(QUIC_INVALID_VERSION, error_details,
@@ -840,7 +843,8 @@
   current_effective_peer_migration_type_ = NO_CHANGE;
 
   if (perspective_ == Perspective::IS_CLIENT) {
-    if (header.packet_number > received_packet_manager_.GetLargestObserved()) {
+    if (!received_packet_manager_.GetLargestObserved().IsInitialized() ||
+        header.packet_number > received_packet_manager_.GetLargestObserved()) {
       // Update peer_address_ and effective_peer_address_ immediately for
       // client connections.
       direct_peer_address_ = last_packet_source_address_;
@@ -944,22 +948,25 @@
   QUIC_DVLOG(1) << ENDPOINT
                 << "OnAckFrameStart, largest_acked: " << largest_acked;
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
 
-  if (largest_acked > sent_packet_manager_.GetLargestSentPacket()) {
+  if (!sent_packet_manager_.GetLargestSentPacket().IsInitialized() ||
+      largest_acked > sent_packet_manager_.GetLargestSentPacket()) {
     QUIC_DLOG(WARNING) << ENDPOINT
                        << "Peer's observed unsent packet:" << largest_acked
                        << " vs " << sent_packet_manager_.GetLargestSentPacket();
-    // We got an error for data we have not sent.
+    // We got an ack for data we have not sent.
     CloseConnection(QUIC_INVALID_ACK_DATA, "Largest observed too high.",
                     ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
     return false;
   }
 
-  if (largest_acked > sent_packet_manager_.GetLargestObserved()) {
+  if (!sent_packet_manager_.GetLargestObserved().IsInitialized() ||
+      largest_acked > sent_packet_manager_.GetLargestObserved()) {
     visitor_->OnForwardProgressConfirmed();
   } else if (largest_acked < sent_packet_manager_.GetLargestObserved()) {
     QUIC_LOG(INFO) << ENDPOINT << "Peer's largest_observed packet decreased:"
@@ -984,7 +991,8 @@
   DCHECK(connected_);
   QUIC_DVLOG(1) << ENDPOINT << "OnAckRange: [" << start << ", " << end << ")";
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -999,7 +1007,8 @@
   QUIC_DVLOG(1) << ENDPOINT << "OnAckTimestamp: [" << packet_number << ", "
                 << timestamp.ToDebuggingValue() << ")";
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -1012,7 +1021,8 @@
   DCHECK(connected_);
   QUIC_DVLOG(1) << ENDPOINT << "OnAckFrameEnd, start: " << start;
 
-  if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+  if (largest_seen_packet_with_ack_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_ack_) {
     QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
     return true;
   }
@@ -1051,7 +1061,8 @@
   if (no_stop_waiting_frames_) {
     return true;
   }
-  if (last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
+  if (largest_seen_packet_with_stop_waiting_.IsInitialized() &&
+      last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
     QUIC_DLOG(INFO) << ENDPOINT
                     << "Received an old stop waiting frame: ignoring";
     return true;
@@ -1129,8 +1140,10 @@
 
 const char* QuicConnection::ValidateStopWaitingFrame(
     const QuicStopWaitingFrame& stop_waiting) {
-  if (stop_waiting.least_unacked <
-      received_packet_manager_.peer_least_packet_awaiting_ack()) {
+  if (received_packet_manager_.peer_least_packet_awaiting_ack()
+          .IsInitialized() &&
+      stop_waiting.least_unacked <
+          received_packet_manager_.peer_least_packet_awaiting_ack()) {
     QUIC_DLOG(ERROR)
         << ENDPOINT
         << "Peer's sent low least_unacked: " << stop_waiting.least_unacked
@@ -1179,7 +1192,22 @@
 }
 
 bool QuicConnection::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
-  return visitor_->OnStopSendingFrame(frame);
+  DCHECK(connected_);
+
+  // Since a reset stream frame was received, this is not a connectivity probe.
+  // A probe only contains a PING and full padding.
+  UpdatePacketContent(NOT_PADDED_PING);
+
+  if (debug_visitor_ != nullptr) {
+    debug_visitor_->OnStopSendingFrame(frame);
+  }
+
+  QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: "
+                  << frame.stream_id
+                  << " with error: " << frame.application_error_code;
+
+  visitor_->OnStopSendingFrame(frame);
+  return connected_;
 }
 
 bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
@@ -1439,8 +1467,10 @@
   if (was_missing) {
     // Only ack immediately if an ACK frame was sent with a larger
     // largest acked than the newly received packet number.
-    if (last_header_.packet_number <
-        sent_packet_manager_.unacked_packets().largest_sent_largest_acked()) {
+    const QuicPacketNumber largest_sent_largest_acked =
+        sent_packet_manager_.unacked_packets().largest_sent_largest_acked();
+    if (largest_sent_largest_acked.IsInitialized() &&
+        last_header_.packet_number < largest_sent_largest_acked) {
       ack_queued_ = true;
     }
   }
@@ -1448,7 +1478,10 @@
   if (should_last_packet_instigate_acks_ && !ack_queued_) {
     ++num_retransmittable_packets_received_since_last_ack_sent_;
     if (ack_mode_ != TCP_ACKING &&
-        last_header_.packet_number > min_received_before_ack_decimation_) {
+        // TODO(fayang): Fix this as this check assumes the first received
+        // packet is 1.
+        last_header_.packet_number >
+            QuicPacketNumber(min_received_before_ack_decimation_)) {
       // Ack up to 10 packets at once unless ack decimation is unlimited.
       if (!unlimited_ack_decimation_ &&
           num_retransmittable_packets_received_since_last_ack_sent_ >=
@@ -1497,7 +1530,8 @@
     // If there are new missing packets to report, send an ack immediately.
     if (received_packet_manager_.HasNewMissingPackets()) {
       if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
-        DCHECK(!GetQuicReloadableFlag(quic_enable_ack_decimation));
+        DCHECK(!GetQuicReloadableFlag(quic_enable_ack_decimation) ||
+               GetQuicReloadableFlag(quic_keep_ack_decimation_reordering));
         // Wait the minimum of an eighth min_rtt and the existing ack time.
         QuicTime ack_time =
             clock_->ApproximateNow() +
@@ -1527,8 +1561,9 @@
 void QuicConnection::CloseIfTooManyOutstandingSentPackets() {
   // This occurs if we don't discard old packets we've seen fast enough. It's
   // possible largest observed is less than leaset unacked.
-  if (sent_packet_manager_.GetLargestObserved() >
-      sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) {
+  if (sent_packet_manager_.GetLargestObserved().IsInitialized() &&
+      sent_packet_manager_.GetLargestObserved() >
+          sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) {
     CloseConnection(
         QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
         QuicStrCat("More than ", max_tracked_packets_, " outstanding."),
@@ -1602,9 +1637,9 @@
     OnWriteError(result.error_code);
     return;
   }
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     visitor_->OnWriteBlocked();
-    if (writer_->IsWriteBlockedDataBuffered()) {
+    if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       pending_version_negotiation_packet_ = false;
     }
     return;
@@ -1676,6 +1711,8 @@
       ++packet_iterator;
       continue;
     }
+    // NOTE THAT RemoveFramesForStream removes only STREAM frames
+    // for the specified stream.
     RemoveFramesForStream(retransmittable_frames, id);
     if (!retransmittable_frames->empty()) {
       ++packet_iterator;
@@ -1776,6 +1813,13 @@
                   << "Unable to process packet.  Last packet processed: "
                   << last_header_.packet_number;
     current_packet_data_ = nullptr;
+    if (clear_probing_mark_after_packet_processing_) {
+      if (is_current_packet_connectivity_probing_) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(
+            quic_clear_probing_mark_after_packet_processing, 1, 2);
+      }
+      is_current_packet_connectivity_probing_ = false;
+    }
     return;
   }
 
@@ -1787,8 +1831,10 @@
       << ", highest_packet_sent_before_effective_peer_migration_ = "
       << highest_packet_sent_before_effective_peer_migration_;
   if (active_effective_peer_migration_type_ != NO_CHANGE &&
-      sent_packet_manager_.GetLargestObserved() >
-          highest_packet_sent_before_effective_peer_migration_) {
+      sent_packet_manager_.GetLargestObserved().IsInitialized() &&
+      (!highest_packet_sent_before_effective_peer_migration_.IsInitialized() ||
+       sent_packet_manager_.GetLargestObserved() >
+           highest_packet_sent_before_effective_peer_migration_)) {
     if (perspective_ == Perspective::IS_SERVER) {
       OnEffectivePeerMigrationValidated();
     }
@@ -1798,6 +1844,13 @@
   MaybeSendInResponseToPacket();
   SetPingAlarm();
   current_packet_data_ = nullptr;
+  if (clear_probing_mark_after_packet_processing_) {
+    if (is_current_packet_connectivity_probing_) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(
+          quic_clear_probing_mark_after_packet_processing, 2, 2);
+    }
+    is_current_packet_connectivity_probing_ = false;
+  }
 }
 
 void QuicConnection::OnBlockedWriterCanWrite() {
@@ -1883,7 +1936,7 @@
     QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 2, 2);
     // Configured to accept any packet number in range 1...0x7fffffff
     // as initial packet number.
-    if (last_header_.packet_number != kInvalidPacketNumber) {
+    if (last_header_.packet_number.IsInitialized()) {
       // The last packet's number is not 0. Ensure that this packet
       // is reasonably close to where it should be.
       if (!Near(header.packet_number, last_header_.packet_number)) {
@@ -1896,10 +1949,9 @@
       }
     } else {
       // The "last packet's number" is 0, meaning that this packet is the first
-      // one received. Ensure it is in range 1..kMaxRandomInitialPacketNumber,
+      // one received. Ensure it is in range 1..MaxRandomInitialPacketNumber(),
       // inclusive.
-      if ((header.packet_number == kInvalidPacketNumber) ||
-          (header.packet_number > kMaxRandomInitialPacketNumber)) {
+      if ((header.packet_number > MaxRandomInitialPacketNumber())) {
         // packet number is bad.
         QUIC_DLOG(INFO) << ENDPOINT << "Initial packet " << header.packet_number
                         << " out of bounds.  Discarding";
@@ -1913,21 +1965,29 @@
     // Count those that would have been accepted if FLAGS..random_ipn
     // were true -- to detect/diagnose potential issues prior to
     // enabling the flag.
-    if ((header.packet_number > 1) &&
-        (header.packet_number <= kMaxRandomInitialPacketNumber)) {
+    if ((header.packet_number > QuicPacketNumber(1)) &&
+        (header.packet_number <= MaxRandomInitialPacketNumber())) {
       QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2);
     }
-
-    if (!Near(header.packet_number, last_header_.packet_number)) {
+    bool out_of_bound =
+        last_header_.packet_number.IsInitialized()
+            ? !Near(header.packet_number, last_header_.packet_number)
+            // TODO(fayang): Fix this as this check assume the first received
+            // packet is 1.
+            : header.packet_number > QuicPacketNumber(kMaxPacketGap);
+    if (out_of_bound) {
       QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number
                       << " out of bounds.  Discarding";
       QuicStringPiece packet_data = GetCurrentPacket();
       const size_t kMaxPacketLengthInErrorDetails = 64;
       CloseConnection(
           QUIC_INVALID_PACKET_HEADER,
-          QuicStrCat("Packet number out of bounds. last_pkn=",
-                     last_header_.packet_number,
-                     ", current_pkn=", header.packet_number,
+          QuicStrCat("Packet number out of bounds. ",
+                     last_header_.packet_number.IsInitialized()
+                         ? QuicStrCat("last_pkn=",
+                                      last_header_.packet_number.ToUint64())
+                         : "first received packet",
+                     ", current_pkn=", header.packet_number.ToUint64(),
                      ", current_pkt_len=", packet_data.length(),
                      ", current_hdr=",
                      QuicTextUtils::HexEncode(
@@ -2127,7 +2187,8 @@
     ++stats_.packets_discarded;
     return true;
   }
-  if (packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
+  if (sent_packet_manager_.GetLargestSentPacket().IsInitialized() &&
+      packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) {
     QUIC_BUG << "Attempt to write packet:" << packet->packet_number
              << " after:" << sent_packet_manager_.GetLargestSentPacket();
     CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.",
@@ -2198,7 +2259,7 @@
       WRITE_STATUS_NUM_VALUES,
       "Status code returned by writer_->WritePacket() in QuicConnection.");
 
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     // Ensure the writer is still write blocked, otherwise QUIC may continue
     // trying to write when it will not be able to.
     DCHECK(writer_->IsWriteBlocked());
@@ -2207,7 +2268,7 @@
     // be queued and sent again, which would result in an unnecessary
     // duplicate packet being sent.  The helper must call OnCanWrite
     // when the write completes, and OnWriteError if an error occurs.
-    if (!writer_->IsWriteBlockedDataBuffered()) {
+    if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       return false;
     }
   }
@@ -2314,6 +2375,14 @@
   }
 
   WriteResult result = writer_->Flush();
+
+  if (HandleWriteBlocked()) {
+    DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status)
+        << "Unexpected flush result:" << result;
+    QUIC_DLOG(INFO) << ENDPOINT << "Write blocked in FlushPackets.";
+    return;
+  }
+
   if (IsWriteError(result.status)) {
     OnWriteError(result.error_code);
   }
@@ -2402,7 +2471,7 @@
 
   if (transport_version() != QUIC_VERSION_35) {
     if (serialized_packet->retransmittable_frames.empty() &&
-        serialized_packet->original_packet_number == kInvalidPacketNumber) {
+        !serialized_packet->original_packet_number.IsInitialized()) {
       // Increment consecutive_num_packets_with_no_retransmittable_frames_ if
       // this packet is a new transmission with no retransmittable frames.
       ++consecutive_num_packets_with_no_retransmittable_frames_;
@@ -2496,8 +2565,7 @@
   }
   consecutive_num_packets_with_no_retransmittable_frames_ = 0;
   if (packet_generator_.HasRetransmittableFrames() ||
-      (donot_retransmit_old_window_updates_ &&
-       visitor_->WillingAndAbleToWrite())) {
+      visitor_->WillingAndAbleToWrite()) {
     // There are pending retransmittable frames.
     return;
   }
@@ -2569,11 +2637,7 @@
 void QuicConnection::SetDecrypter(EncryptionLevel level,
                                   std::unique_ptr<QuicDecrypter> decrypter) {
   framer_.SetDecrypter(level, std::move(decrypter));
-  if (!decrypt_packets_on_key_change_) {
-    return;
-  }
 
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 1, 3);
   if (!undecryptable_packets_.empty() &&
       !process_undecryptable_packets_alarm_->IsSet()) {
     process_undecryptable_packets_alarm_->Set(clock_->ApproximateNow());
@@ -2585,11 +2649,7 @@
     std::unique_ptr<QuicDecrypter> decrypter,
     bool latch_once_used) {
   framer_.SetAlternativeDecrypter(level, std::move(decrypter), latch_once_used);
-  if (!decrypt_packets_on_key_change_) {
-    return;
-  }
 
-  QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 2, 3);
   if (!undecryptable_packets_.empty() &&
       !process_undecryptable_packets_alarm_->IsSet()) {
     process_undecryptable_packets_alarm_->Set(clock_->ApproximateNow());
@@ -2611,10 +2671,7 @@
 }
 
 void QuicConnection::MaybeProcessUndecryptablePackets() {
-  if (decrypt_packets_on_key_change_) {
-    QUIC_RELOADABLE_FLAG_COUNT_N(quic_decrypt_packets_on_key_change, 3, 3);
-    process_undecryptable_packets_alarm_->Cancel();
-  }
+  process_undecryptable_packets_alarm_->Cancel();
 
   if (undecryptable_packets_.empty() || encryption_level_ == ENCRYPTION_NONE) {
     return;
@@ -3071,6 +3128,9 @@
   packet_generator_.GenerateMtuDiscoveryPacket(target_mtu);
 }
 
+// TODO(zhongyi): change this method to generate a connectivity probing packet
+// and let the caller to call writer to write the packet and handle write
+// status.
 bool QuicConnection::SendConnectivityProbingPacket(
     QuicPacketWriter* probing_writer,
     const QuicSocketAddress& peer_address) {
@@ -3186,13 +3246,13 @@
       packet_send_time, probing_packet->transmission_type,
       NO_RETRANSMITTABLE_DATA);
 
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     if (probing_writer == writer_) {
       // Visitor should not be write blocked if the probing writer is not the
       // default packet writer.
       visitor_->OnWriteBlocked();
     }
-    if (probing_writer->IsWriteBlockedDataBuffered()) {
+    if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
       QUIC_DLOG(INFO) << ENDPOINT << "Write probing packet blocked";
     }
   }
@@ -3228,7 +3288,7 @@
     QUIC_BUG << "No migration underway.";
     return;
   }
-  highest_packet_sent_before_effective_peer_migration_ = 0;
+  highest_packet_sent_before_effective_peer_migration_.Clear();
   active_effective_peer_migration_type_ = NO_CHANGE;
 }
 
@@ -3382,8 +3442,9 @@
   }
 
   current_packet_content_ = NOT_PADDED_PING;
-  if (last_header_.packet_number ==
-      received_packet_manager_.GetLargestObserved()) {
+  if (received_packet_manager_.GetLargestObserved().IsInitialized() &&
+      last_header_.packet_number ==
+          received_packet_manager_.GetLargestObserved()) {
     direct_peer_address_ = last_packet_source_address_;
     if (current_effective_peer_migration_type_ != NO_CHANGE) {
       // Start effective peer migration immediately when the current packet is
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 0f50e96..221754f 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -297,6 +297,9 @@
   // Called when RTT may have changed, including when an RTT is read from
   // the config.
   virtual void OnRttChanged(QuicTime::Delta rtt) const {}
+
+  // Called when a StopSendingFrame has been parsed.
+  virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) {}
 };
 
 class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
@@ -792,6 +795,20 @@
     fill_up_link_during_probing_ = new_value;
   }
 
+  // This setting may be changed during the crypto handshake in order to
+  // enable/disable padding of different packets in the crypto handshake.
+  //
+  // This setting should never be set to false in public facing endpoints. It
+  // can only be set to false if there is some other mechanism of preventing
+  // amplification attacks, such as ICE (plus its a non-standard quic).
+  void set_fully_pad_crypto_hadshake_packets(bool new_value) {
+    packet_generator_.set_fully_pad_crypto_hadshake_packets(new_value);
+  }
+
+  bool fully_pad_during_crypto_handshake() const {
+    return packet_generator_.fully_pad_crypto_handshake_packets();
+  }
+
   size_t min_received_before_ack_decimation() const {
     return min_received_before_ack_decimation_;
   }
@@ -803,7 +820,7 @@
     return ack_frequency_before_ack_decimation_;
   }
   void set_ack_frequency_before_ack_decimation(size_t new_value) {
-    DCHECK_GT(new_value, 0);
+    DCHECK_GT(new_value, 0u);
     ack_frequency_before_ack_decimation_ = new_value;
   }
 
@@ -827,20 +844,9 @@
 
   bool IsPathDegrading() const { return is_path_degrading_; }
 
-  // TODO(wub): Remove this function once
-  // quic_donot_retransmit_old_window_update flag is deprecated.
-  void set_donot_retransmit_old_window_updates(bool value) {
-    donot_retransmit_old_window_updates_ = value;
-  }
-
   // Attempts to process any queued undecryptable packets.
   void MaybeProcessUndecryptablePackets();
 
-  // Whether the handshake is confirmed from this connection's perspective.
-  bool IsHandshakeConfirmed() const {
-    return sent_packet_manager_.handshake_confirmed();
-  }
-
   enum PacketContent : uint8_t {
     NO_FRAMES_RECEIVED,
     // TODO(fkastenholz): Change name when we get rid of padded ping/
@@ -851,6 +857,11 @@
     NOT_PADDED_PING,  // Set if the packet is not {PING, PADDING}.
   };
 
+  // Whether the handshake is confirmed from this connection's perspective.
+  bool IsHandshakeConfirmed() const {
+    return sent_packet_manager_.handshake_confirmed();
+  }
+
  protected:
   // Calls cancel() on all the alarms owned by this connection.
   void CancelAllAlarms();
@@ -1076,10 +1087,9 @@
   // Contents received in the current packet, especially used to identify
   // whether the current packet is a padded PING packet.
   PacketContent current_packet_content_;
-  // True if the packet currently being processed is a connectivity probing
-  // packet. Is set to false when a new packet is received, and will be set to
-  // true as soon as |current_packet_content_| is set to
-  // SECOND_FRAME_IS_PADDING.
+  // Set to true as soon as the packet currently being processed has been
+  // detected as a connectivity probing.
+  // Always false outside the context of ProcessUdpPacket().
   bool is_current_packet_connectivity_probing_;
 
   // Caches the current effective peer migration type if a effective peer
@@ -1385,16 +1395,13 @@
   // Time this connection can release packets into the future.
   QuicTime::Delta release_time_into_future_;
 
-  // Latched value of quic_donot_retransmit_old_window_update flag.
-  bool donot_retransmit_old_window_updates_;
-
   // Indicates whether server connection does version negotiation. Server
   // connection does not support version negotiation if a single version is
   // provided in constructor.
   const bool no_version_negotiation_;
 
-  // Latched value of quic_decrypt_packets_on_key_change flag.
-  const bool decrypt_packets_on_key_change_;
+  // Latched value of --quic_clear_probing_mark_after_packet_processing.
+  const bool clear_probing_mark_after_packet_processing_;
 
   // Payload of most recently transmitted QUIC_VERSION_99 connectivity
   // probe packet (the PATH_CHALLENGE payload). This implementation transmits
diff --git a/quic/core/quic_connection_stats.h b/quic/core/quic_connection_stats.h
index 07ca80f..8123fb0 100644
--- a/quic/core/quic_connection_stats.h
+++ b/quic/core/quic_connection_stats.h
@@ -73,7 +73,7 @@
   // Number of packets received out of packet number order.
   QuicPacketCount packets_reordered;
   // Maximum reordering observed in packet number space.
-  QuicPacketNumber max_sequence_reordering;
+  QuicPacketCount max_sequence_reordering;
   // Maximum reordering observed in microseconds
   int64_t max_time_reordering_us;
 
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 63f4453..fe851fd 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -17,6 +17,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -102,7 +103,7 @@
   bool SetIV(QuicStringPiece iv) override { return true; }
 
   bool EncryptPacket(QuicTransportVersion /*version*/,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
@@ -167,7 +168,7 @@
   }
 
   bool DecryptPacket(QuicTransportVersion /*version*/,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
@@ -288,6 +289,7 @@
         last_packet_size_(0),
         write_blocked_(false),
         write_should_fail_(false),
+        block_on_next_flush_(false),
         block_on_next_write_(false),
         next_packet_too_large_(false),
         always_get_packet_too_large_(false),
@@ -336,11 +338,14 @@
       return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE);
     }
     if (IsWriteBlocked()) {
-      return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+      return WriteResult(is_write_blocked_data_buffered_
+                             ? WRITE_STATUS_BLOCKED_DATA_BUFFERED
+                             : WRITE_STATUS_BLOCKED,
+                         0);
     }
 
     if (ShouldWriteFail()) {
-      return WriteResult(WRITE_STATUS_ERROR, EAGAIN);
+      return WriteResult(WRITE_STATUS_ERROR, 0);
     }
 
     last_packet_size_ = packet.length();
@@ -380,7 +385,16 @@
     return nullptr;
   }
 
-  WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+  WriteResult Flush() override {
+    if (block_on_next_flush_) {
+      block_on_next_flush_ = false;
+      SetWriteBlocked();
+      return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
+    }
+    return WriteResult(WRITE_STATUS_OK, 0);
+  }
+
+  void BlockOnNextFlush() { block_on_next_flush_ = true; }
 
   void BlockOnNextWrite() { block_on_next_write_ = true; }
 
@@ -493,6 +507,8 @@
     supports_release_time_ = supports_release_time;
   }
 
+  SimpleQuicFramer* framer() { return &framer_; }
+
  private:
   ParsedQuicVersion version_;
   SimpleQuicFramer framer_;
@@ -500,6 +516,7 @@
   QuicPacketHeader last_packet_header_;
   bool write_blocked_;
   bool write_should_fail_;
+  bool block_on_next_flush_;
   bool block_on_next_write_;
   bool next_packet_too_large_;
   bool always_get_packet_too_large_;
@@ -554,7 +571,7 @@
   }
 
   void SendPacket(EncryptionLevel level,
-                  QuicPacketNumber packet_number,
+                  uint64_t packet_number,
                   std::unique_ptr<QuicPacket> packet,
                   HasRetransmittableData retransmittable,
                   bool has_ack,
@@ -562,10 +579,11 @@
     char buffer[kMaxPacketSize];
     size_t encrypted_length =
         QuicConnectionPeer::GetFramer(this)->EncryptPayload(
-            ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize);
+            ENCRYPTION_NONE, QuicPacketNumber(packet_number), *packet, buffer,
+            kMaxPacketSize);
     SerializedPacket serialized_packet(
-        packet_number, PACKET_4BYTE_PACKET_NUMBER, buffer, encrypted_length,
-        has_ack, has_pending_frames);
+        QuicPacketNumber(packet_number), PACKET_4BYTE_PACKET_NUMBER, buffer,
+        encrypted_length, has_ack, has_pending_frames);
     if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
       serialized_packet.retransmittable_frames.push_back(
           QuicFrame(QuicStreamFrame()));
@@ -580,7 +598,7 @@
                                          QuicStreamOffset offset,
                                          StreamSendingState state) {
     ScopedPacketFlusher flusher(this, NO_ACK);
-    producer_.SaveStreamData(id, iov, iov_count, 0u, offset, total_length);
+    producer_.SaveStreamData(id, iov, iov_count, 0u, total_length);
     if (notifier_ != nullptr) {
       return notifier_->WriteOrBufferData(id, total_length, state);
     }
@@ -902,14 +920,14 @@
 
   QuicPacketNumber least_unacked() {
     if (writer_->stop_waiting_frames().empty()) {
-      return 0;
+      return QuicPacketNumber();
     }
     return writer_->stop_waiting_frames()[0].least_unacked;
   }
 
   void use_tagging_decrypter() { writer_->use_tagging_decrypter(); }
 
-  void ProcessPacket(QuicPacketNumber number) {
+  void ProcessPacket(uint64_t number) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacket(number);
     if (connection_.GetSendAlarm()->IsSet()) {
@@ -984,7 +1002,7 @@
         QuicReceivedPacket(encrypted_buffer, encrypted_length, clock_.Now()));
   }
 
-  size_t ProcessFramePacketAtLevel(QuicPacketNumber number,
+  size_t ProcessFramePacketAtLevel(uint64_t number,
                                    QuicFrame frame,
                                    EncryptionLevel level) {
     QuicPacketHeader header;
@@ -995,32 +1013,43 @@
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
     }
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
     QuicFrames frames;
     frames.push_back(frame);
     std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
 
     char buffer[kMaxPacketSize];
-    size_t encrypted_length =
-        framer_.EncryptPayload(level, number, *packet, buffer, kMaxPacketSize);
+    size_t encrypted_length = framer_.EncryptPayload(
+        level, QuicPacketNumber(number), *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
     return encrypted_length;
   }
 
-  size_t ProcessDataPacket(QuicPacketNumber number) {
+  size_t ProcessDataPacket(uint64_t number) {
     return ProcessDataPacketAtLevel(number, false, ENCRYPTION_NONE);
   }
 
-  size_t ProcessDataPacketAtLevel(QuicPacketNumber number,
+  size_t ProcessDataPacket(QuicPacketNumber packet_number) {
+    return ProcessDataPacketAtLevel(packet_number, false, ENCRYPTION_NONE);
+  }
+
+  size_t ProcessDataPacketAtLevel(QuicPacketNumber packet_number,
+                                  bool has_stop_waiting,
+                                  EncryptionLevel level) {
+    return ProcessDataPacketAtLevel(packet_number.ToUint64(), has_stop_waiting,
+                                    level);
+  }
+
+  size_t ProcessDataPacketAtLevel(uint64_t number,
                                   bool has_stop_waiting,
                                   EncryptionLevel level) {
     std::unique_ptr<QuicPacket> packet(
         ConstructDataPacket(number, has_stop_waiting));
     char buffer[kMaxPacketSize];
     size_t encrypted_length = peer_framer_.EncryptPayload(
-        level, number, *packet, buffer, kMaxPacketSize);
+        level, QuicPacketNumber(number), *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
@@ -1030,11 +1059,12 @@
     return encrypted_length;
   }
 
-  void ProcessClosePacket(QuicPacketNumber number) {
+  void ProcessClosePacket(uint64_t number) {
     std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number));
     char buffer[kMaxPacketSize];
-    size_t encrypted_length = peer_framer_.EncryptPayload(
-        ENCRYPTION_NONE, number, *packet, buffer, kMaxPacketSize);
+    size_t encrypted_length =
+        peer_framer_.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(number),
+                                    *packet, buffer, kMaxPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
         QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
@@ -1084,8 +1114,12 @@
     connection_.OnStreamReset(id, error);
   }
 
-  void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) {
-    QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
+  void ProcessAckPacket(uint64_t packet_number, QuicAckFrame* frame) {
+    if (packet_number > 1) {
+      QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
+    } else {
+      QuicPacketCreatorPeer::ClearPacketNumber(&peer_creator_);
+    }
     ProcessFramePacket(QuicFrame(frame));
   }
 
@@ -1097,7 +1131,7 @@
     ProcessFramePacket(QuicFrame(frame));
   }
 
-  size_t ProcessStopWaitingPacketAtLevel(QuicPacketNumber number,
+  size_t ProcessStopWaitingPacketAtLevel(uint64_t number,
                                          QuicStopWaitingFrame* frame,
                                          EncryptionLevel level) {
     return ProcessFramePacketAtLevel(number, QuicFrame(frame),
@@ -1108,8 +1142,9 @@
     ProcessFramePacket(QuicFrame(frame));
   }
 
-  bool IsMissing(QuicPacketNumber number) {
-    return IsAwaitingPacket(*outgoing_ack(), number, 0);
+  bool IsMissing(uint64_t number) {
+    return IsAwaitingPacket(*outgoing_ack(), QuicPacketNumber(number),
+                            QuicPacketNumber());
   }
 
   std::unique_ptr<QuicPacket> ConstructPacket(const QuicPacketHeader& header,
@@ -1119,7 +1154,7 @@
     return packet;
   }
 
-  std::unique_ptr<QuicPacket> ConstructDataPacket(QuicPacketNumber number,
+  std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number,
                                                   bool has_stop_waiting) {
     QuicPacketHeader header;
     // Set connection_id to peer's in memory representation as this data packet
@@ -1131,7 +1166,7 @@
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
     }
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
 
     QuicFrames frames;
     frames.push_back(QuicFrame(frame1_));
@@ -1153,12 +1188,12 @@
         &peer_creator_);
   }
 
-  std::unique_ptr<QuicPacket> ConstructClosePacket(QuicPacketNumber number) {
+  std::unique_ptr<QuicPacket> ConstructClosePacket(uint64_t number) {
     QuicPacketHeader header;
     // Set connection_id to peer's in memory representation as this connection
     // close packet is created by peer_framer.
     header.destination_connection_id = connection_id_;
-    header.packet_number = number;
+    header.packet_number = QuicPacketNumber(number);
     if (peer_framer_.transport_version() > QUIC_VERSION_43 &&
         peer_framer_.perspective() == Perspective::IS_SERVER) {
       header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
@@ -1180,22 +1215,27 @@
     return QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
   }
 
-  const QuicStopWaitingFrame InitStopWaitingFrame(
-      QuicPacketNumber least_unacked) {
+  const QuicStopWaitingFrame InitStopWaitingFrame(uint64_t least_unacked) {
     QuicStopWaitingFrame frame;
-    frame.least_unacked = least_unacked;
+    frame.least_unacked = QuicPacketNumber(least_unacked);
     return frame;
   }
 
   // Construct a ack_frame that acks all packet numbers between 1 and
   // |largest_acked|, except |missing|.
   // REQUIRES: 1 <= |missing| < |largest_acked|
+  QuicAckFrame ConstructAckFrame(uint64_t largest_acked, uint64_t missing) {
+    return ConstructAckFrame(QuicPacketNumber(largest_acked),
+                             QuicPacketNumber(missing));
+  }
+
   QuicAckFrame ConstructAckFrame(QuicPacketNumber largest_acked,
                                  QuicPacketNumber missing) {
-    if (missing == 1) {
+    if (missing == QuicPacketNumber(1)) {
       return InitAckFrame({{missing + 1, largest_acked + 1}});
     }
-    return InitAckFrame({{1, missing}, {missing + 1, largest_acked + 1}});
+    return InitAckFrame(
+        {{QuicPacketNumber(1), missing}, {missing + 1, largest_acked + 1}});
   }
 
   // Undo nacking a packet within the frame.
@@ -1211,7 +1251,7 @@
     // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
     // packet call to the visitor.
     if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
-      ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000);
+      ProcessDataPacket(MaxRandomInitialPacketNumber() + 6000);
     } else {
       ProcessDataPacket(6000);
     }
@@ -1256,8 +1296,8 @@
       const QuicPacketCount packets_between_probes_base) {
     QuicConnectionPeer::SetPacketsBetweenMtuProbes(&connection_,
                                                    packets_between_probes_base);
-    QuicConnectionPeer::SetNextMtuProbeAt(&connection_,
-                                          packets_between_probes_base);
+    QuicConnectionPeer::SetNextMtuProbeAt(
+        &connection_, QuicPacketNumber(packets_between_probes_base));
   }
 
   bool IsDefaultTestConfiguration() {
@@ -1577,9 +1617,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
 
-  EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1673,9 +1719,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 
@@ -1730,9 +1782,15 @@
                           probing_packet->encrypted_length),
       clock_.Now()));
 
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1819,9 +1877,15 @@
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
       clock_.Now()));
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received);
 
-  EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1861,9 +1925,15 @@
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
       clock_.Now()));
+  uint64_t num_probing_received =
+      connection_.GetStats().num_connectivity_probing_received;
   ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received);
 
-  EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) {
+    EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing());
+  }
+  EXPECT_EQ(num_probing_received + 1,
+            connection_.GetStats().num_connectivity_probing_received);
   EXPECT_EQ(kPeerAddress, connection_.peer_address());
   EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
 }
@@ -1923,7 +1993,7 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
 
   QuicFrames frames;
   QuicPaddingFrame padding;
@@ -1932,7 +2002,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   EXPECT_EQ(kMaxPacketSize, encrypted_length);
 
   framer_.set_version(version());
@@ -1956,7 +2026,7 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
 
   QuicFrames frames;
   QuicPaddingFrame padding;
@@ -1965,7 +2035,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   EXPECT_EQ(kMaxPacketSize, encrypted_length);
 
   framer_.set_version(version());
@@ -2005,15 +2075,15 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(1);
-  EXPECT_EQ(1u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(1u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 
   ProcessPacket(2);
-  EXPECT_EQ(2u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
 }
 
@@ -2021,17 +2091,17 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(2);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_FALSE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(1);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_FALSE(IsMissing(2));
   EXPECT_FALSE(IsMissing(1));
 }
@@ -2040,14 +2110,14 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   // Send packet 3 again, but do not set the expectation that
   // the visitor OnStreamFrame() will be called.
   ProcessDataPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 }
@@ -2056,16 +2126,16 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
 
   ProcessPacket(3);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(2));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(2);
-  EXPECT_EQ(3u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(1));
 
   ProcessPacket(5);
-  EXPECT_EQ(5u, LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(QuicPacketNumber(5u), LargestAcked(*outgoing_ack()));
   EXPECT_TRUE(IsMissing(1));
   EXPECT_TRUE(IsMissing(4));
 
@@ -2089,7 +2159,7 @@
   // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
   // packet call to the visitor.
   if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
-    ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000);
+    ProcessDataPacket(MaxRandomInitialPacketNumber() + 6000);
   } else {
     ProcessDataPacket(6000);
   }
@@ -2264,7 +2334,8 @@
 }
 
 TEST_P(QuicConnectionTest, AckDecimationReducesAcks) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
 
@@ -2435,45 +2506,39 @@
   ProcessAckPacket(&frame);
 }
 
-TEST_P(QuicConnectionTest, AckAll) {
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  ProcessPacket(1);
-
-  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
-  QuicAckFrame frame1;
-  ProcessAckPacket(&frame1);
-}
-
 TEST_P(QuicConnectionTest, BasicSending) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);  // Packet 1
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   SendAckPacketToPeer();  // Packet 2
 
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   SendAckPacketToPeer();  // Packet 3
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   SendStreamDataToPeer(1, "bar", 3, NO_FIN, &last_packet);  // Packet 4
-  EXPECT_EQ(4u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(4u), last_packet);
   SendAckPacketToPeer();  // Packet 5
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(1u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(1u), least_unacked());
   }
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -2487,9 +2552,9 @@
   // ack for 4.
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -2499,34 +2564,34 @@
   ProcessAckPacket(&frame2);  // Acks don't instigate acks.
 
   // Verify that we did not send an ack.
-  EXPECT_EQ(6u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(6u), writer_->header().packet_number);
 
   // So the last ack has not changed.
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   // If we force an ack, we shouldn't change our retransmit state.
   SendAckPacketToPeer();  // Packet 7
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(7u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(7u), least_unacked());
   }
 
   // But if we send more data it should.
   SendStreamDataToPeer(1, "eep", 6, NO_FIN, &last_packet);  // Packet 8
-  EXPECT_EQ(8u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(8u), last_packet);
   SendAckPacketToPeer();  // Packet 9
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(7u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(7u), least_unacked());
   }
 }
 
@@ -2643,6 +2708,10 @@
   // Process a data packet to queue up a pending ack.
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacket(1);
+  QuicPacketNumber last_packet;
+  SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
+  // Verify ack is bundled with outging packet.
+  EXPECT_FALSE(writer_->ack_frames().empty());
 
   EXPECT_CALL(visitor_, OnCanWrite())
       .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
@@ -2652,9 +2721,9 @@
 
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
 
-  // Process an ack to cause the visitor's OnCanWrite to be invoked.
-  QuicAckFrame ack_one;
-  ProcessAckPacket(3, &ack_one);
+  // Process a data packet to cause the visitor's OnCanWrite to be invoked.
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(2);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -2839,7 +2908,7 @@
   // Lose a packet and ensure it triggers retransmission.
   QuicAckFrame nack_two = ConstructAckFrame(3, 2);
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(2, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(2), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -3088,7 +3157,7 @@
   BlockOnNextWrite();
 
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(2, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(2), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -3103,7 +3172,8 @@
 
   // Unblock the socket and attempt to send the queued packets. We will always
   // send the retransmission.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
+      .Times(1);
 
   writer_->SetWritable();
   connection_.OnCanWrite();
@@ -3260,14 +3330,15 @@
   // Process packet number 1. Can not call ProcessPacket or ProcessDataPacket
   // here, because they will fire the alarm after QuicConnection::ProcessPacket
   // is returned.
-  const QuicPacketNumber received_packet_num = 1;
+  const uint64_t received_packet_num = 1;
   const bool has_stop_waiting = false;
   const EncryptionLevel level = ENCRYPTION_NONE;
   std::unique_ptr<QuicPacket> packet(
       ConstructDataPacket(received_packet_num, has_stop_waiting));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = peer_framer_.EncryptPayload(
-      level, received_packet_num, *packet, buffer, kMaxPacketSize);
+  size_t encrypted_length =
+      peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num),
+                                  *packet, buffer, kMaxPacketSize);
   connection_.ProcessUdpPacket(
       kSelfAddress, kPeerAddress,
       QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
@@ -3313,6 +3384,19 @@
   }
 }
 
+TEST_P(QuicConnectionTest, AddToWriteBlockedListIfBlockedOnFlushPackets) {
+  writer_->SetBatchMode(true);
+  writer_->BlockOnNextFlush();
+
+  EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
+  {
+    QuicConnection::ScopedPacketFlusher flusher(&connection_,
+                                                QuicConnection::NO_ACK);
+    // flusher's destructor will call connection_.FlushPackets, which should add
+    // the connection to the write blocked list.
+  }
+}
+
 TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   int offset = 0;
@@ -3324,12 +3408,13 @@
 
   // Ack 15, nack 1-14.
 
-  QuicAckFrame nack = InitAckFrame({{15, 16}});
+  QuicAckFrame nack =
+      InitAckFrame({{QuicPacketNumber(15), QuicPacketNumber(16)}});
 
   // 14 packets have been NACK'd and lost.
   LostPacketVector lost_packets;
   for (int i = 1; i < 15; ++i) {
-    lost_packets.push_back(LostPacket(i, kMaxPacketSize));
+    lost_packets.push_back(LostPacket(QuicPacketNumber(i), kMaxPacketSize));
   }
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
@@ -3344,23 +3429,26 @@
 
 // Test sending multiple acks from the connection to the session.
 TEST_P(QuicConnectionTest, MultipleAcks) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);  // Packet 1
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, &last_packet);  // Packet 2
-  EXPECT_EQ(2u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(2u), last_packet);
   SendAckPacketToPeer();                                    // Packet 3
   SendStreamDataToPeer(5, "foo", 0, NO_FIN, &last_packet);  // Packet 4
-  EXPECT_EQ(4u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(4u), last_packet);
   SendStreamDataToPeer(1, "foo", 3, NO_FIN, &last_packet);  // Packet 5
-  EXPECT_EQ(5u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(5u), last_packet);
   SendStreamDataToPeer(3, "foo", 3, NO_FIN, &last_packet);  // Packet 6
-  EXPECT_EQ(6u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(6u), last_packet);
 
   // Client will ack packets 1, 2, [!3], 4, 5.
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicAckFrame frame1 = ConstructAckFrame(5, 3);
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   ProcessAckPacket(&frame1);
 
   // Now the client implicitly acks 3, and explicitly acks 6.
@@ -3370,11 +3458,14 @@
 }
 
 TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
+  QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2);
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr);  // Packet 1;
   // From now on, we send acks, so the send algorithm won't mark them pending.
   SendAckPacketToPeer();  // Packet 2
 
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicAckFrame frame = InitAckFrame(1);
   ProcessAckPacket(&frame);
@@ -3382,25 +3473,25 @@
   // Verify that our internal state has least-unacked as 2, because we're still
   // waiting for a potential ack for 2.
 
-  EXPECT_EQ(2u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(2u), stop_waiting()->least_unacked);
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   frame = InitAckFrame(2);
   ProcessAckPacket(&frame);
-  EXPECT_EQ(3u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(3u), stop_waiting()->least_unacked);
 
   // When we send an ack, we make sure our least-unacked makes sense.  In this
   // case since we're not waiting on an ack for 2 and all packets are acked, we
   // set it to 3.
   SendAckPacketToPeer();  // Packet 3
   // Least_unacked remains at 3 until another ack is received.
-  EXPECT_EQ(3u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(3u), stop_waiting()->least_unacked);
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
     // Check that the outgoing ack had its packet number as least_unacked.
-    EXPECT_EQ(3u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(3u), least_unacked());
   }
 
   // Ack the ack, which updates the rtt and raises the least unacked.
@@ -3409,13 +3500,13 @@
   ProcessAckPacket(&frame);
 
   SendStreamDataToPeer(1, "bar", 3, NO_FIN, nullptr);  // Packet 4
-  EXPECT_EQ(4u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(4u), stop_waiting()->least_unacked);
   SendAckPacketToPeer();  // Packet 5
   if (GetParam().no_stop_waiting) {
     // Expect no stop waiting frame is sent.
-    EXPECT_EQ(0u, least_unacked());
+    EXPECT_FALSE(least_unacked().IsInitialized());
   } else {
-    EXPECT_EQ(4u, least_unacked());
+    EXPECT_EQ(QuicPacketNumber(4u), least_unacked());
   }
 
   // Send two data packets at the end, and ensure if the last one is acked,
@@ -3424,30 +3515,31 @@
   SendStreamDataToPeer(1, "bar", 9, NO_FIN, nullptr);  // Packet 7
 
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{1, 5}, {7, 8}});
+  frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(5)},
+                        {QuicPacketNumber(7), QuicPacketNumber(8)}});
   ProcessAckPacket(&frame);
 
-  EXPECT_EQ(6u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(6u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, TLP) {
   connection_.SetMaxTailLossProbes(1);
 
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
   QuicTime retransmission_time =
       connection_.GetRetransmissionAlarm()->deadline();
   EXPECT_NE(QuicTime::Zero(), retransmission_time);
 
-  EXPECT_EQ(1u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(1u), writer_->header().packet_number);
   // Simulate the retransmission alarm firing and sending a tlp,
   // so send algorithm's OnRetransmissionTimeout is not called.
   clock_.AdvanceTime(retransmission_time - clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(2u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(2u), writer_->header().packet_number);
   // We do not raise the high water mark yet.
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, RTO) {
@@ -3456,18 +3548,18 @@
   QuicTime default_retransmission_time =
       clock_.ApproximateNow() + DefaultRetransmissionTime();
   SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 
-  EXPECT_EQ(1u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(1u), writer_->header().packet_number);
   EXPECT_EQ(default_retransmission_time,
             connection_.GetRetransmissionAlarm()->deadline());
   // Simulate the retransmission alarm firing.
   clock_.AdvanceTime(DefaultRetransmissionTime());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(2u, writer_->header().packet_number);
+  EXPECT_EQ(QuicPacketNumber(2u), writer_->header().packet_number);
   // We do not raise the high water mark yet.
-  EXPECT_EQ(1u, stop_waiting()->least_unacked);
+  EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
 }
 
 TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
@@ -3490,8 +3582,10 @@
 
   {
     InSequence s;
-    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 3, _, _));
-    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _));
+    EXPECT_CALL(*send_algorithm_,
+                OnPacketSent(_, _, QuicPacketNumber(3), _, _));
+    EXPECT_CALL(*send_algorithm_,
+                OnPacketSent(_, _, QuicPacketNumber(4), _, _));
   }
 
   // Manually mark both packets for retransmission.
@@ -3616,45 +3710,6 @@
   ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
 }
 
-TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
-  if (GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
-    return;
-  }
-
-  // SetFromConfig is always called after construction from InitializeSession.
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  QuicConfig config;
-  config.set_max_undecryptable_packets(100);
-  connection_.SetFromConfig(config);
-  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  use_tagging_decrypter();
-
-  const uint8_t tag = 0x07;
-  peer_framer_.SetEncrypter(ENCRYPTION_INITIAL,
-                            QuicMakeUnique<TaggingEncrypter>(tag));
-
-  // Process an encrypted packet which can not yet be decrypted which should
-  // result in the packet being buffered.
-  for (QuicPacketNumber i = 1; i <= 100; ++i) {
-    ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  }
-
-  // Transition to the new encryption state and process another encrypted packet
-  // which should result in the original packets being processed.
-  connection_.SetDecrypter(ENCRYPTION_INITIAL,
-                           QuicMakeUnique<StrictTaggingDecrypter>(tag));
-  connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-  connection_.SetEncrypter(ENCRYPTION_INITIAL,
-                           QuicMakeUnique<TaggingEncrypter>(tag));
-  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101);
-  ProcessDataPacketAtLevel(101, !kHasStopWaiting, ENCRYPTION_INITIAL);
-
-  // Finally, process a third packet and note that we do not reprocess the
-  // buffered packet.
-  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
-  ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_INITIAL);
-}
-
 TEST_P(QuicConnectionTest, TestRetransmitOrder) {
   connection_.SetMaxTailLossProbes(0);
 
@@ -3688,10 +3743,6 @@
 }
 
 TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) {
-  if (!GetQuicReloadableFlag(quic_decrypt_packets_on_key_change)) {
-    return;
-  }
-
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   QuicConfig config;
@@ -3706,7 +3757,7 @@
 
   // Process an encrypted packet which can not yet be decrypted which should
   // result in the packet being buffered.
-  for (QuicPacketNumber i = 1; i <= 100; ++i) {
+  for (uint64_t i = 1; i <= 100; ++i) {
     ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL);
   }
 
@@ -3848,7 +3899,7 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20));
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
   // This will be the updated deadline for the connection to idle time out.
   QuicTime new_ddl = clock_.ApproximateNow() +
                      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
@@ -3900,12 +3951,12 @@
   // execution until manually adjusted.
   QuicPacketNumber last_packet;
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(1u), last_packet);
 
   // Advance the time and send the second packet to the peer.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet);
-  EXPECT_EQ(2u, last_packet);
+  EXPECT_EQ(QuicPacketNumber(2u), last_packet);
 
   if (GetQuicReloadableFlag(
           quic_fix_time_of_first_packet_sent_after_receiving)) {
@@ -4092,7 +4143,7 @@
       .WillOnce(SaveArg<3>(&mtu_probe_size));
   connection_.SendMtuDiscoveryPacket(new_mtu);
   EXPECT_EQ(new_mtu, mtu_probe_size);
-  EXPECT_EQ(1u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(1u), creator_->packet_number());
 
   // Send more than MTU worth of data.  No acknowledgement was received so far,
   // so the MTU should be at its old value.
@@ -4103,7 +4154,7 @@
       .WillOnce(SaveArg<3>(&size_before_mtu_change))
       .WillOnce(Return());
   connection_.SendStreamDataWithString(3, data, 0, FIN);
-  EXPECT_EQ(3u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(3u), creator_->packet_number());
   EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change);
 
   // Acknowledge all packets so far.
@@ -4116,7 +4167,7 @@
   // Send the same data again.  Check that it fits into a single packet now.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   connection_.SendStreamDataWithString(3, data, 0, FIN);
-  EXPECT_EQ(4u, creator_->packet_number());
+  EXPECT_EQ(QuicPacketNumber(4u), creator_->packet_number());
 }
 
 // Tests whether MTU discovery does not happen when it is not explicitly enabled
@@ -4161,7 +4212,8 @@
   connection_.GetMtuDiscoveryAlarm()->Fire();
   EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size);
 
-  const QuicPacketCount probe_packet_number = packets_between_probes_base + 1;
+  const QuicPacketNumber probe_packet_number =
+      FirstSendingPacketNumber() + packets_between_probes_base;
   ASSERT_EQ(probe_packet_number, creator_->packet_number());
 
   // Acknowledge all packets sent so far.
@@ -4223,12 +4275,13 @@
                                                  mtu_discovery_packets.end());
       QuicPacketNumber max_packet = *max_element(mtu_discovery_packets.begin(),
                                                  mtu_discovery_packets.end());
-      ack.packets.AddRange(1, min_packet);
-      ack.packets.AddRange(max_packet + 1, creator_->packet_number() + 1);
+      ack.packets.AddRange(QuicPacketNumber(1), min_packet);
+      ack.packets.AddRange(QuicPacketNumber(max_packet + 1),
+                           creator_->packet_number() + 1);
       ack.largest_acked = creator_->packet_number();
 
     } else {
-      ack.packets.AddRange(1, creator_->packet_number() + 1);
+      ack.packets.AddRange(QuicPacketNumber(1), creator_->packet_number() + 1);
       ack.largest_acked = creator_->packet_number();
     }
 
@@ -4250,11 +4303,12 @@
   // Ensure the number of packets between probes grows exponentially by checking
   // it against the closed-form expression for the packet number.
   ASSERT_EQ(kMtuDiscoveryAttempts, mtu_discovery_packets.size());
-  for (QuicPacketNumber i = 0; i < kMtuDiscoveryAttempts; i++) {
+  for (uint64_t i = 0; i < kMtuDiscoveryAttempts; i++) {
     // 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n + 1) - 1
     const QuicPacketCount packets_between_probes =
         packets_between_probes_base * ((1 << (i + 1)) - 1);
-    EXPECT_EQ(packets_between_probes + (i + 1), mtu_discovery_packets[i]);
+    EXPECT_EQ(QuicPacketNumber(packets_between_probes + (i + 1)),
+              mtu_discovery_packets[i]);
   }
 
   EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
@@ -4290,7 +4344,8 @@
   connection_.GetMtuDiscoveryAlarm()->Fire();
   EXPECT_EQ(mtu_limit, probe_size);
 
-  const QuicPacketCount probe_sequence_number = packets_between_probes_base + 1;
+  const QuicPacketNumber probe_sequence_number =
+      FirstSendingPacketNumber() + packets_between_probes_base;
   ASSERT_EQ(probe_sequence_number, creator_->packet_number());
 
   // Acknowledge all packets sent so far.
@@ -4485,7 +4540,7 @@
   const QuicTime final_timeout = rto_time + initial_idle_timeout;
   clock_.AdvanceTime(rto_time - clock_.Now());
   ASSERT_EQ(rto_time, clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
 
   // Advance to the original timeout and fire the alarm. The connection should
@@ -4622,7 +4677,7 @@
   // Retransmit the packet via tail loss probe.
   clock_.AdvanceTime(connection_.GetRetransmissionAlarm()->deadline() -
                      clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _));
   connection_.GetRetransmissionAlarm()->Fire();
 
   // This time, we should time out and send a connection close due to the TLP.
@@ -4839,6 +4894,7 @@
   // Test that if we send a packet without delay, it is not queued.
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
@@ -4851,6 +4907,7 @@
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   writer_->SetShouldWriteFail();
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
@@ -4859,8 +4916,10 @@
 TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
   QuicFramerPeer::SetPerspective(&peer_framer_, Perspective::IS_CLIENT);
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
+  QuicPacketCreatorPeer::SetPacketNumber(creator_, 1);
   BlockOnNextWrite();
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(2u), _, _))
+      .Times(0);
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -5112,7 +5171,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5228,7 +5287,7 @@
   // default delayed ack time.
   ack_time = clock_.ApproximateNow() +
              QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5304,7 +5363,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5357,7 +5416,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5393,7 +5452,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5419,7 +5479,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5461,7 +5521,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5487,7 +5548,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5548,7 +5609,8 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5575,7 +5637,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5620,7 +5682,8 @@
 
 TEST_P(QuicConnectionTest,
        SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
-  if (GetQuicReloadableFlag(quic_enable_ack_decimation)) {
+  if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
+      !GetQuicReloadableFlag(quic_keep_ack_decimation_reordering)) {
     return;
   }
   EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber());
@@ -5647,7 +5710,7 @@
   frame1_.stream_id = 3;
 
   // Process all the initial packets in order so there aren't missing packets.
-  QuicPacketNumber kFirstDecimatedPacket = 101;
+  uint64_t kFirstDecimatedPacket = 101;
   for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
     EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
     ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL);
@@ -5844,7 +5907,7 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_EQ(1u, writer_->padding_frames().size());
   ASSERT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(2u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -5873,7 +5936,7 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_EQ(1u, writer_->padding_frames().size());
   ASSERT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(2u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
@@ -5888,7 +5951,7 @@
   // Ack the second packet, which will retransmit the first packet.
   QuicAckFrame ack = ConstructAckFrame(2, 1);
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -5927,7 +5990,7 @@
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
-  EXPECT_EQ(3u, LargestAcked(writer_->ack_frames().front()));
+  EXPECT_EQ(QuicPacketNumber(3u), LargestAcked(writer_->ack_frames().front()));
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
@@ -5950,7 +6013,8 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_FALSE(connection_.CanWriteStreamData());
   std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting);
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendPacket(ENCRYPTION_NONE, 1, std::move(packet),
                          HAS_RETRANSMITTABLE_DATA, false, false);
 }
@@ -5969,7 +6033,8 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_FALSE(connection_.CanWriteStreamData());
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
 
   EXPECT_QUIC_BUG(connection_.SendConnectivityProbingPacket(
                       writer_.get(), connection_.peer_address()),
@@ -5987,7 +6052,8 @@
   // affects the probing_writer which is not the default.
   EXPECT_CALL(visitor_, OnWriteBlocked()).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(1);
   connection_.SendConnectivityProbingPacket(&probing_writer,
                                             connection_.peer_address());
 }
@@ -6003,7 +6069,8 @@
   // writer to send connectivity probes.
   EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(1);
   connection_.SendConnectivityProbingPacket(writer_.get(),
                                             connection_.peer_address());
 }
@@ -6017,7 +6084,8 @@
   // sent.
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendConnectivityProbingPacket(&probing_writer,
                                             connection_.peer_address());
 }
@@ -6031,7 +6099,8 @@
   // sent.
   EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
 
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _))
+      .Times(0);
   connection_.SendConnectivityProbingPacket(writer_.get(),
                                             connection_.peer_address());
 }
@@ -6137,21 +6206,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                   buffer, kMaxPacketSize);
+  size_t encrypted_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   // Writer's framer's perspective is client, so that it needs to have the right
@@ -6183,21 +6251,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                   buffer, kMaxPacketSize);
+  size_t encrypted_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   BlockOnNextWrite();
@@ -6236,21 +6303,20 @@
     peer_framer_.set_version_for_tests(
         ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99));
   } else {
-    peer_framer_.set_version_for_tests(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    peer_framer_.set_version_for_tests(UnsupportedQuicVersion());
   }
 
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.version_flag = true;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
 
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
-  size_t encryped_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet,
-                                                  buffer, kMaxPacketSize);
+  size_t encryped_length = framer_.EncryptPayload(
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
 
   framer_.set_version(version());
   set_perspective(Perspective::IS_SERVER);
@@ -6297,14 +6363,14 @@
   QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
-  header.packet_number = 12;
+  header.packet_number = QuicPacketNumber(12);
   header.version_flag = false;
   QuicFrames frames;
   frames.push_back(QuicFrame(frame1_));
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(12), *packet, buffer, kMaxPacketSize);
   ASSERT_NE(0u, encrypted_length);
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -6355,11 +6421,13 @@
   connection_.GetRetransmissionAlarm()->Fire();
 
   // Retransmit due to explicit nacks.
-  QuicAckFrame nack_three = InitAckFrame({{2, 3}, {4, 5}});
+  QuicAckFrame nack_three =
+      InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)},
+                    {QuicPacketNumber(4), QuicPacketNumber(5)}});
 
   LostPacketVector lost_packets;
-  lost_packets.push_back(LostPacket(1, kMaxPacketSize));
-  lost_packets.push_back(LostPacket(3, kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(1), kMaxPacketSize));
+  lost_packets.push_back(LostPacket(QuicPacketNumber(3), kMaxPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
       .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
@@ -6395,7 +6463,7 @@
   if (peer_framer_.transport_version() > QUIC_VERSION_43) {
     header.destination_connection_id_length = PACKET_0BYTE_CONNECTION_ID;
   }
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
   header.version_flag = false;
 
   QuicConnectionCloseFrame qccf;
@@ -6408,7 +6476,7 @@
   EXPECT_TRUE(nullptr != packet);
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 1, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(1), *packet, buffer, kMaxPacketSize);
 
   EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
                                            ConnectionCloseSource::FROM_PEER));
@@ -6442,8 +6510,7 @@
 
   // Shouldn't be able to find a mutually supported version.
   ParsedQuicVersionVector unsupported_version;
-  unsupported_version.push_back(
-      ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+  unsupported_version.push_back(UnsupportedQuicVersion());
   EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
 }
 
@@ -6490,7 +6557,7 @@
 
 TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
   QuicPacketHeader header;
-  header.packet_number = 1;
+  header.packet_number = QuicPacketNumber(1);
   if (GetParam().version.transport_version > QUIC_VERSION_43) {
     header.form = IETF_QUIC_LONG_HEADER_PACKET;
   }
@@ -6594,6 +6661,9 @@
 }
 
 TEST_P(QuicConnectionTest, SendAcksImmediately) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
   CongestionBlockWrites();
   SendAckPacketToPeer();
 }
@@ -6727,7 +6797,8 @@
       EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
     }
     EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-    QuicAckFrame frame = InitAckFrame({{1u + 2u * i, 2u + 2u * i}});
+    QuicAckFrame frame = InitAckFrame(
+        {{QuicPacketNumber(1u + 2u * i), QuicPacketNumber(2u + 2u * i)}});
     ProcessAckPacket(&frame);
     EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
     // Check the deadline of the path degrading alarm.
@@ -6742,7 +6813,7 @@
       // degrading alarm.
       clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
       EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-      frame = InitAckFrame({{2, 3}});
+      frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
       ProcessAckPacket(&frame);
       EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet());
     } else {
@@ -6797,7 +6868,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   // No more retransmittable packets on the wire, so the path degrading alarm
   // should be cancelled, and the ping alarm should be set to the
@@ -6860,7 +6932,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
   // Check the deadline of the path degrading alarm.
@@ -6925,7 +6998,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
   // Check the deadline of the path degrading alarm.
@@ -6955,7 +7029,7 @@
   // degrading. And will set a timer to detect new path degrading.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_FALSE(connection_.IsPathDegrading());
   EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet());
@@ -6978,13 +7052,17 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1u, 2u}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1u), QuicPacketNumber(2u)}});
   ProcessAckPacket(&frame);
   EXPECT_FALSE(connection_.IsPathDegrading());
   EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet());
 }
 
 TEST_P(QuicConnectionTest, NoPathDegradingAfterSendingAck) {
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+  ProcessDataPacket(1);
   SendAckPacketToPeer();
   EXPECT_FALSE(connection_.sent_packet_manager().unacked_packets().empty());
   EXPECT_FALSE(connection_.sent_packet_manager().HasInFlightPackets());
@@ -7310,7 +7388,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.sent_packet_manager().HasInFlightPackets());
   // The ping alarm is set for the ping timeout, not the shorter
@@ -7327,7 +7406,7 @@
   // the wire.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7337,7 +7416,7 @@
   // the ping alarm.
   QuicTime prev_deadline = connection_.GetPingAlarm()->deadline();
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(prev_deadline, connection_.GetPingAlarm()->deadline());
@@ -7394,7 +7473,8 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7412,7 +7492,7 @@
   // the wire.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout,
@@ -7452,13 +7532,14 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
-  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  QuicAckFrame frame =
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
 
   // Ack packet 1 again. largest_acked remains at 1, so
   // OnForwardProgressConfirmed() should not be called.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-  frame = InitAckFrame({{1, 2}});
+  frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
   ProcessAckPacket(&frame);
 
   // Ack packet 2. This increases the largest_acked to 2, so
@@ -7466,7 +7547,7 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
-  frame = InitAckFrame({{2, 3}});
+  frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
   ProcessAckPacket(&frame);
 }
 
@@ -7655,7 +7736,7 @@
   std::unique_ptr<QuicPacket> packet(ConstructDataPacket(2, !kHasStopWaiting));
   char buffer[kMaxPacketSize];
   size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_NONE, 2, *packet, buffer, kMaxPacketSize);
+      ENCRYPTION_NONE, QuicPacketNumber(2), *packet, buffer, kMaxPacketSize);
   // Make sure no stream frame is processed.
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(0);
   connection_.ProcessUdpPacket(
@@ -7666,6 +7747,29 @@
   EXPECT_EQ(1u, connection_.GetStats().packets_processed);
 }
 
+TEST_P(QuicConnectionTest, AcceptPacketNumberZero) {
+  if (!GetQuicRestartFlag(quic_uint64max_uninitialized_pn) ||
+      version().transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  // Set first_sending_packet_number to be 0 to allow successfully processing
+  // acks which ack packet number 0.
+  QuicFramerPeer::SetFirstSendingPacketNumber(writer_->framer()->framer(), 0);
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+  ProcessPacket(0);
+  EXPECT_EQ(QuicPacketNumber(0), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+
+  ProcessPacket(1);
+  EXPECT_EQ(QuicPacketNumber(1), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+
+  ProcessPacket(2);
+  EXPECT_EQ(QuicPacketNumber(2), LargestAcked(*outgoing_ack()));
+  EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_constants.cc b/quic/core/quic_constants.cc
index 344a94a..8e46f88 100644
--- a/quic/core/quic_constants.cc
+++ b/quic/core/quic_constants.cc
@@ -11,4 +11,15 @@
 const char* const kEPIDGoogleFrontEnd = "GFE";
 const char* const kEPIDGoogleFrontEnd0 = "GFE0";
 
+QuicPacketNumber MaxRandomInitialPacketNumber() {
+  static const QuicPacketNumber kMaxRandomInitialPacketNumber =
+      QuicPacketNumber(0x7fffffff);
+  return kMaxRandomInitialPacketNumber;
+}
+
+QuicPacketNumber FirstSendingPacketNumber() {
+  static const QuicPacketNumber kFirstSendingPacketNumber = QuicPacketNumber(1);
+  return kFirstSendingPacketNumber;
+}
+
 }  // namespace quic
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index fa76c21..cf27bef 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -181,7 +181,7 @@
 
 // The largest gap in packets we'll accept without closing the connection.
 // This will likely have to be tuned.
-const QuicPacketNumber kMaxPacketGap = 5000;
+const QuicPacketCount kMaxPacketGap = 5000;
 
 // The maximum number of random padding bytes to add.
 const QuicByteCount kMaxNumRandomPaddingBytes = 256;
@@ -193,7 +193,7 @@
 
 // For When using Random Initial Packet Numbers, they can start
 // anyplace in the range 1...((2^31)-1) or 0x7fffffff
-const QuicPacketNumber kMaxRandomInitialPacketNumber = 0x7fffffff;
+QUIC_EXPORT_PRIVATE QuicPacketNumber MaxRandomInitialPacketNumber();
 
 // Used to represent an invalid or no control frame id.
 const QuicControlFrameId kInvalidControlFrameId = 0;
@@ -224,8 +224,10 @@
 // Maximum length allowed for the token in a NEW_TOKEN frame.
 const size_t kMaxNewTokenTokenLength = 0xffff;
 
-// Used to represent an invalid packet number.
-const QuicPacketNumber kInvalidPacketNumber = 0;
+// Packet number of first sending packet of a connection. Please note, this
+// cannot be used as first received packet because peer can choose its starting
+// packet number.
+QUIC_EXPORT_PRIVATE QuicPacketNumber FirstSendingPacketNumber();
 
 // Used by clients to tell if a public reset is sent from a Google frontend.
 QUIC_EXPORT_PRIVATE extern const char* const kEPIDGoogleFrontEnd;
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc
index ece6324..c2b5192 100644
--- a/quic/core/quic_control_frame_manager.cc
+++ b/quic/core/quic_control_frame_manager.cc
@@ -17,9 +17,7 @@
     : last_control_frame_id_(kInvalidControlFrameId),
       least_unacked_(1),
       least_unsent_(1),
-      session_(session),
-      donot_retransmit_old_window_updates_(
-          GetQuicReloadableFlag(quic_donot_retransmit_old_window_update2)) {}
+      session_(session) {}
 
 QuicControlFrameManager::~QuicControlFrameManager() {
   while (!control_frames_.empty()) {
@@ -129,13 +127,11 @@
         << "Send or retransmit a control frame with invalid control frame id";
     return;
   }
-  if (donot_retransmit_old_window_updates_ &&
-      frame.type == WINDOW_UPDATE_FRAME) {
+  if (frame.type == WINDOW_UPDATE_FRAME) {
     QuicStreamId stream_id = frame.window_update_frame->stream_id;
     if (QuicContainsKey(window_update_frames_, stream_id) &&
         id > window_update_frames_[stream_id]) {
       // Consider the older window update of the same stream as acked.
-      QUIC_RELOADABLE_FLAG_COUNT(quic_donot_retransmit_old_window_update2);
       OnControlFrameIdAcked(window_update_frames_[stream_id]);
     }
     window_update_frames_[stream_id] = id;
@@ -161,8 +157,7 @@
   if (!OnControlFrameIdAcked(id)) {
     return false;
   }
-  if (donot_retransmit_old_window_updates_ &&
-      frame.type == WINDOW_UPDATE_FRAME) {
+  if (frame.type == WINDOW_UPDATE_FRAME) {
     QuicStreamId stream_id = frame.window_update_frame->stream_id;
     if (QuicContainsKey(window_update_frames_, stream_id) &&
         window_update_frames_[stream_id] == id) {
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h
index a08d5c3..ace08c6 100644
--- a/quic/core/quic_control_frame_manager.h
+++ b/quic/core/quic_control_frame_manager.h
@@ -102,12 +102,6 @@
   // sent.
   bool WillingToWrite() const;
 
-  // TODO(wub): Remove this function once
-  // quic_donot_retransmit_old_window_update flag is deprecated.
-  bool donot_retransmit_old_window_updates() const {
-    return donot_retransmit_old_window_updates_;
-  }
-
  private:
   friend class test::QuicControlFrameManagerPeer;
 
@@ -158,9 +152,6 @@
 
   // Last sent window update frame for each stream.
   QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_;
-
-  // Latched value of quic_donot_retransmit_old_window_update2 flag.
-  const bool donot_retransmit_old_window_updates_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_control_frame_manager_test.cc b/quic/core/quic_control_frame_manager_test.cc
index a0e0b33..ccddadd 100644
--- a/quic/core/quic_control_frame_manager_test.cc
+++ b/quic/core/quic_control_frame_manager_test.cc
@@ -235,7 +235,6 @@
 }
 
 TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
-  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
   Initialize();
   // Send two more window updates of the same stream.
   manager_->WriteOrBufferWindowUpdate(kTestStreamId, 200);
@@ -271,7 +270,6 @@
 }
 
 TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
-  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
   Initialize();
   // Send two more window updates of different streams.
   manager_->WriteOrBufferWindowUpdate(kTestStreamId + 2, 200);
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index 88bfccd..81487df 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -338,11 +338,10 @@
                                           "CHLO too large");
       return;
     }
-    // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag.
-    out.set_minimum_size(
-        static_cast<size_t>(max_packet_size - kFramingOverhead));
     next_state_ = STATE_RECV_REJ;
     CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
+    session()->connection()->set_fully_pad_crypto_hadshake_packets(
+        crypto_config_->pad_inchoate_hello());
     SendHandshakeMessage(out);
     return;
   }
@@ -377,6 +376,8 @@
         *cached->proof_verify_details());
   }
   next_state_ = STATE_RECV_SHLO;
+  session()->connection()->set_fully_pad_crypto_hadshake_packets(
+      crypto_config_->pad_full_hello());
   SendHandshakeMessage(out);
   // Be prepared to decrypt with the new server write key.
   session()->connection()->SetAlternativeDecrypter(
diff --git a/quic/core/quic_crypto_client_handshaker_test.cc b/quic/core/quic_crypto_client_handshaker_test.cc
new file mode 100644
index 0000000..389be97
--- /dev/null
+++ b/quic/core/quic_crypto_client_handshaker_test.cc
@@ -0,0 +1,213 @@
+// 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/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h"
+#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
+#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace {
+
+using ::testing::Test;
+
+class TestProofHandler : public QuicCryptoClientStream::ProofHandler {
+ public:
+  ~TestProofHandler() override {}
+  void OnProofValid(
+      const QuicCryptoClientConfig::CachedState& cached) override {}
+  void OnProofVerifyDetailsAvailable(
+      const ProofVerifyDetails& verify_details) override {}
+};
+
+class InsecureProofVerifier : public ProofVerifier {
+ public:
+  InsecureProofVerifier() {}
+  ~InsecureProofVerifier() override {}
+
+  // ProofVerifier override.
+  QuicAsyncStatus VerifyProof(
+      const QuicString& hostname,
+      const uint16_t port,
+      const QuicString& server_config,
+      QuicTransportVersion transport_version,
+      QuicStringPiece chlo_hash,
+      const std::vector<QuicString>& certs,
+      const QuicString& cert_sct,
+      const QuicString& signature,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* verify_details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return QUIC_SUCCESS;
+  }
+
+  QuicAsyncStatus VerifyCertChain(
+      const QuicString& hostname,
+      const std::vector<QuicString>& certs,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return QUIC_SUCCESS;
+  }
+
+  std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+    return nullptr;
+  }
+};
+
+class DummyProofSource : public ProofSource {
+ public:
+  DummyProofSource() {}
+  ~DummyProofSource() override {}
+
+  // ProofSource override.
+  void GetProof(const QuicSocketAddress& server_address,
+                const QuicString& hostname,
+                const QuicString& server_config,
+                QuicTransportVersion transport_version,
+                QuicStringPiece chlo_hash,
+                std::unique_ptr<Callback> callback) override {
+    QuicReferenceCountedPointer<ProofSource::Chain> chain =
+        GetCertChain(server_address, hostname);
+    QuicCryptoProof proof;
+    proof.signature = "Dummy signature";
+    proof.leaf_cert_scts = "Dummy timestamp";
+    callback->Run(true, chain, proof, nullptr /* details */);
+  }
+
+  QuicReferenceCountedPointer<Chain> GetCertChain(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname) override {
+    std::vector<QuicString> certs;
+    certs.push_back("Dummy cert");
+    return QuicReferenceCountedPointer<ProofSource::Chain>(
+        new ProofSource::Chain(certs));
+  }
+
+  void ComputeTlsSignature(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname,
+      uint16_t signature_algorithm,
+      QuicStringPiece in,
+      std::unique_ptr<SignatureCallback> callback) override {
+    callback->Run(true, "Dummy signature");
+  }
+};
+
+class Handshaker : public QuicCryptoClientHandshaker {
+ public:
+  Handshaker(const QuicServerId& server_id,
+             QuicCryptoClientStream* stream,
+             QuicSession* session,
+             std::unique_ptr<ProofVerifyContext> verify_context,
+             QuicCryptoClientConfig* crypto_config,
+             QuicCryptoClientStream::ProofHandler* proof_handler)
+      : QuicCryptoClientHandshaker(server_id,
+                                   stream,
+                                   session,
+                                   std::move(verify_context),
+                                   crypto_config,
+                                   proof_handler) {}
+
+  void DoSendCHLOTest(QuicCryptoClientConfig::CachedState* cached) {
+    QuicCryptoClientHandshaker::DoSendCHLO(cached);
+  }
+};
+
+class QuicCryptoClientHandshakerTest : public Test {
+ protected:
+  QuicCryptoClientHandshakerTest()
+      : proof_handler_(),
+        helper_(),
+        alarm_factory_(),
+        server_id_("host", 123),
+        connection_(new test::MockQuicConnection(&helper_,
+                                                 &alarm_factory_,
+                                                 Perspective::IS_CLIENT)),
+        session_(connection_, false),
+        crypto_client_config_(QuicMakeUnique<InsecureProofVerifier>(),
+                              quic::TlsClientHandshaker::CreateSslCtx()),
+        client_stream_(new QuicCryptoClientStream(server_id_,
+                                                  &session_,
+                                                  nullptr,
+                                                  &crypto_client_config_,
+                                                  &proof_handler_)),
+        handshaker_(server_id_,
+                    client_stream_,
+                    &session_,
+                    nullptr,
+                    &crypto_client_config_,
+                    &proof_handler_),
+        state_() {
+    // Session takes the ownership of the client stream! (but handshaker also
+    // takes a reference to it, but doesn't take the ownership).
+    session_.SetCryptoStream(client_stream_);
+    session_.Initialize();
+  }
+
+  void InitializeServerParametersToEnableFullHello() {
+    QuicCryptoServerConfig::ConfigOptions options;
+    std::unique_ptr<QuicServerConfigProtobuf> config =
+        QuicCryptoServerConfig::GenerateConfig(helper_.GetRandomGenerator(),
+                                               helper_.GetClock(), options);
+    state_.Initialize(
+        config->config(), "sourcetoken", std::vector<QuicString>{"Dummy cert"},
+        "", "chlo_hash", "signature", helper_.GetClock()->WallNow(),
+        helper_.GetClock()->WallNow().Add(QuicTime::Delta::FromSeconds(30)));
+
+    state_.SetProofValid();
+  }
+
+  TestProofHandler proof_handler_;
+  test::MockQuicConnectionHelper helper_;
+  test::MockAlarmFactory alarm_factory_;
+  QuicServerId server_id_;
+  // Session takes the ownership of the connection.
+  test::MockQuicConnection* connection_;
+  test::MockQuicSession session_;
+  QuicCryptoClientConfig crypto_client_config_;
+  QuicCryptoClientStream* client_stream_;
+  Handshaker handshaker_;
+  QuicCryptoClientConfig::CachedState state_;
+};
+
+TEST_F(QuicCryptoClientHandshakerTest, TestSendFullPaddingInInchoateHello) {
+  handshaker_.DoSendCHLOTest(&state_);
+
+  EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest, TestDisabledPaddingInInchoateHello) {
+  crypto_client_config_.set_pad_inchoate_hello(false);
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest,
+       TestPaddingInFullHelloEvenIfInchoateDisabled) {
+  // Disable inchoate, but full hello should still be padded.
+  crypto_client_config_.set_pad_inchoate_hello(false);
+
+  InitializeServerParametersToEnableFullHello();
+
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
+}
+
+TEST_F(QuicCryptoClientHandshakerTest, TestNoPaddingInFullHelloWhenDisabled) {
+  crypto_client_config_.set_pad_full_hello(false);
+
+  InitializeServerParametersToEnableFullHello();
+
+  handshaker_.DoSendCHLOTest(&state_);
+  EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
+}
+
+}  // namespace
+}  // namespace quic
diff --git a/quic/core/quic_crypto_client_stream_test.cc b/quic/core/quic_crypto_client_stream_test.cc
index 14f34a7..d9b344a 100644
--- a/quic/core/quic_crypto_client_stream_test.cc
+++ b/quic/core/quic_crypto_client_stream_test.cc
@@ -329,54 +329,6 @@
   EXPECT_FALSE(stream()->WasChannelIDSourceCallbackRun());
 }
 
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNegotiation) {
-  server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-  crypto_config_.tb_key_params = QuicTagVector{kTB10};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(kTB10,
-            stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutServerSupport) {
-  crypto_config_.tb_key_params = QuicTagVector{kTB10, kP256};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutClientSupport) {
-  server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNotNegotiated) {
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingInPrivacyMode) {
-  server_options_.token_binding_params = QuicTagVector{kTB10};
-  crypto_config_.tb_key_params = QuicTagVector{kTB10};
-  server_id_ = QuicServerId(kServerHostname, kServerPort, true);
-  CreateConnection();
-
-  CompleteCryptoHandshake();
-  EXPECT_TRUE(stream()->encryption_established());
-  EXPECT_TRUE(stream()->handshake_confirmed());
-  EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
 TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
   // This mimics the case where client receives version negotiation packet, such
   // that, the preferred version is different from the packets' version.
@@ -440,7 +392,7 @@
     client_session_->GetMutableCryptoStream()->CryptoConnect();
     EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
-    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
+    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _))
         .Times(testing::AnyNumber());
     crypto_test_utils::AdvanceHandshake(
         client_connection_, client_session_->GetMutableCryptoStream(), 0,
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index 2b38c4b..e79a60c 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -184,6 +184,8 @@
       // retransmitted.
       session()->connection()->EnableSavingCryptoPackets();
     }
+    session()->connection()->set_fully_pad_crypto_hadshake_packets(
+        crypto_config_->pad_rej());
     SendHandshakeMessage(*reply);
 
     if (reply->tag() == kSREJ) {
@@ -233,6 +235,8 @@
       std::move(crypto_negotiated_params_->initial_crypters.decrypter));
   session()->connection()->SetDiversificationNonce(*diversification_nonce);
 
+  session()->connection()->set_fully_pad_crypto_hadshake_packets(
+      crypto_config_->pad_shlo());
   SendHandshakeMessage(*reply);
 
   session()->connection()->SetEncrypter(
@@ -463,7 +467,7 @@
     return EmptyQuicConnectionId();
   }
   return helper_->GenerateConnectionIdForReject(
-      session()->connection()->connection_id());
+      transport_version(), session()->connection()->connection_id());
 }
 
 const QuicSocketAddress QuicCryptoServerHandshaker::GetClientAddress() {
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 63de376..c4de9b0 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -141,6 +141,7 @@
     // Given the current connection_id, generates a new ConnectionId to
     // be returned with a stateless reject.
     virtual QuicConnectionId GenerateConnectionIdForReject(
+        QuicTransportVersion version,
         QuicConnectionId connection_id) const = 0;
 
     // Returns true if |message|, which was received on |self_address| is
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc
index 027e412..33635d8 100644
--- a/quic/core/quic_crypto_server_stream_test.cc
+++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -104,7 +104,7 @@
     server_session_.reset(server_session);
     EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
-    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
+    EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _))
         .Times(testing::AnyNumber());
     crypto_test_utils::FakeServerOptions options;
     options.token_binding_params = QuicTagVector{kTB10};
@@ -489,28 +489,6 @@
       QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
 }
 
-TEST_P(QuicCryptoServerStreamTest, TokenBindingNegotiated) {
-  Initialize();
-
-  client_options_.token_binding_params = QuicTagVector{kTB10, kP256};
-  CompleteCryptoHandshake();
-  EXPECT_EQ(
-      kTB10,
-      server_stream()->crypto_negotiated_params().token_binding_key_param);
-  EXPECT_TRUE(server_stream()->encryption_established());
-  EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, NoTokenBindingWithoutClientSupport) {
-  Initialize();
-
-  CompleteCryptoHandshake();
-  EXPECT_EQ(
-      0u, server_stream()->crypto_negotiated_params().token_binding_key_param);
-  EXPECT_TRUE(server_stream()->encryption_established());
-  EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
 class QuicCryptoServerStreamTestWithFailingProofSource
     : public QuicCryptoServerStreamTest {
  public:
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 440a480..8199571 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -111,19 +111,6 @@
       result);
 }
 
-bool QuicCryptoStream::ExportTokenBindingKeyingMaterial(
-    QuicString* result) const {
-  if (!encryption_established()) {
-    QUIC_BUG << "ExportTokenBindingKeyingMaterial was called before initial"
-             << "encryption was established.";
-    return false;
-  }
-  return CryptoUtils::ExportKeyingMaterial(
-      crypto_negotiated_params().initial_subkey_secret,
-      "EXPORTER-Token-Binding",
-      /* context= */ "", 32, result);
-}
-
 void QuicCryptoStream::WriteCryptoData(EncryptionLevel level,
                                        QuicStringPiece data) {
   // TODO(nharper): This approach to writing data, by setting the encryption
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index a2cf9fe..0593f44 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -56,16 +56,6 @@
                             size_t result_len,
                             QuicString* result) const;
 
-  // Performs key extraction for Token Binding. Unlike ExportKeyingMaterial,
-  // this function can be called before forward-secure encryption is
-  // established. Returns false if initial encryption has not been established,
-  // and true on success.
-  //
-  // Since this depends only on the initial keys, a signature over it can be
-  // repurposed by an attacker who obtains the client's or server's DH private
-  // value.
-  bool ExportTokenBindingKeyingMaterial(QuicString* result) const;
-
   // Writes |data| to the QuicStream at level |level|.
   virtual void WriteCryptoData(EncryptionLevel level, QuicStringPiece data);
 
diff --git a/quic/core/quic_default_packet_writer.cc b/quic/core/quic_default_packet_writer.cc
index 6e8e833..2c162e0 100644
--- a/quic/core/quic_default_packet_writer.cc
+++ b/quic/core/quic_default_packet_writer.cc
@@ -24,7 +24,7 @@
       << "QuicDefaultPacketWriter does not accept any options.";
   WriteResult result = QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
                                                     self_address, peer_address);
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     write_blocked_ = true;
   }
   return result;
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index f476a47..0cb03aa 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -92,6 +92,13 @@
     }
     return WRITE_FAILED;
   }
+  bool WriteCryptoData(EncryptionLevel level,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override {
+    QUIC_BUG << "PacketCollector::WriteCryptoData is unimplemented.";
+    return false;
+  }
 
   std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
     return &packets_;
@@ -235,9 +242,9 @@
     if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_,
                                       self_address_, &error_details_)) {
       can_accept_ = true;
-      rejector_->OnChlo(version, connection_id,
-                        helper_->GenerateConnectionIdForReject(connection_id),
-                        chlo);
+      rejector_->OnChlo(
+          version, connection_id,
+          helper_->GenerateConnectionIdForReject(version, connection_id), chlo);
     }
   }
 
@@ -506,27 +513,29 @@
   }
 
   // initial packet number of 0 is always invalid.
-  if (header.packet_number == kInvalidPacketNumber) {
+  if (!header.packet_number.IsInitialized()) {
     return kFateTimeWait;
   }
   if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
     QUIC_RESTART_FLAG_COUNT_N(quic_enable_accept_random_ipn, 1, 2);
     // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check
     // maximum accordingly.
-    if (header.packet_number > kMaxRandomInitialPacketNumber) {
+    if (header.packet_number > MaxRandomInitialPacketNumber()) {
       return kFateTimeWait;
     }
   } else {
     // Count those that would have been accepted if FLAGS..random_ipn
     // were true -- to detect/diagnose potential issues prior to
     // enabling the flag.
-    if ((header.packet_number > kMaxReasonableInitialPacketNumber) &&
-        (header.packet_number <= kMaxRandomInitialPacketNumber)) {
+    if ((header.packet_number >
+         QuicPacketNumber(kMaxReasonableInitialPacketNumber)) &&
+        (header.packet_number <= MaxRandomInitialPacketNumber())) {
       QUIC_CODE_COUNT_N(had_possibly_random_ipn, 1, 2);
     }
     // Check that the sequence number is within the range that the client is
     // expected to send before receiving a response from the server.
-    if (header.packet_number > kMaxReasonableInitialPacketNumber) {
+    if (header.packet_number >
+        QuicPacketNumber(kMaxReasonableInitialPacketNumber)) {
       return kFateTimeWait;
     }
   }
@@ -552,9 +561,7 @@
     // expediency. Stop doing this when removing flag
     // quic_always_reset_ietf_connections.
     if (!GetQuicReloadableFlag(quic_always_reset_ietf_connections) &&
-        (!GetQuicReloadableFlag(
-             quic_send_reset_for_post_handshake_connections_without_termination_packets) ||  // NOLINT
-         (source == ConnectionCloseSource::FROM_PEER))) {
+        source == ConnectionCloseSource::FROM_PEER) {
       action = QuicTimeWaitListManager::DO_NOTHING;
     } else if (!connection->IsHandshakeConfirmed()) {
       QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed);
@@ -727,6 +734,8 @@
 
 void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {}
 
+void QuicDispatcher::OnStopSendingReceived(const QuicStopSendingFrame& frame) {}
+
 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
     QuicConnectionId connection_id) {
   QUIC_DLOG(INFO) << "Connection " << connection_id
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 3597a97..d6eb35b 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -91,6 +91,11 @@
   // Collects reset error code received on streams.
   void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
 
+  // QuicSession::Visitor interface implementation (via inheritance of
+  // QuicTimeWaitListManager::Visitor):
+  // Collects reset error code received on streams.
+  void OnStopSendingReceived(const QuicStopSendingFrame& frame) override;
+
   // QuicTimeWaitListManager::Visitor interface implementation
   // Called whenever the time wait list manager adds a new connection to the
   // time-wait list.
@@ -110,7 +115,7 @@
   // send a handshake and then up to 50 or so data packets, and then it may
   // resend the handshake packet up to 10 times.  (Retransmitted packets are
   // sent with unique packet numbers.)
-  static const QuicPacketNumber kMaxReasonableInitialPacketNumber = 100;
+  static const uint64_t kMaxReasonableInitialPacketNumber = 100;
   static_assert(kMaxReasonableInitialPacketNumber >=
                     kInitialCongestionWindow + 10,
                 "kMaxReasonableInitialPacketNumber is unreasonably small "
@@ -348,7 +353,7 @@
 
   // Please do not use this method.
   // TODO(fayang): Remove this method when deprecating
-  // quic_proxy_use_real_packet_format_when_reject flag.
+  // quic_fix_last_packet_is_ietf_quic flag.
   PacketHeaderFormat GetLastPacketFormat() const;
 
  private:
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index afc4687..0381cf5 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -268,7 +268,7 @@
                      const QuicString& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length,
-                     QuicPacketNumber packet_number) {
+                     uint64_t packet_number) {
     ProcessPacket(peer_address, connection_id, has_version_flag,
                   CurrentSupportedVersions().front(), data,
                   connection_id_length, packet_number_length, packet_number);
@@ -282,7 +282,7 @@
                      const QuicString& data,
                      QuicConnectionIdLength connection_id_length,
                      QuicPacketNumberLength packet_number_length,
-                     QuicPacketNumber packet_number) {
+                     uint64_t packet_number) {
     ParsedQuicVersionVector versions(SupportedVersions(version));
     std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
         connection_id, EmptyQuicConnectionId(), has_version_flag, false,
@@ -676,18 +676,19 @@
   SetQuicRestartFlag(quic_enable_accept_random_ipn, true);
   ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
-                kMaxRandomInitialPacketNumber +
+                MaxRandomInitialPacketNumber().ToUint64() +
                     QuicDispatcher::kMaxReasonableInitialPacketNumber + 1);
 }
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
@@ -741,6 +742,39 @@
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
 
+  // Turn off version 47.
+  SetQuicReloadableFlag(quic_enable_version_47, false);
+  connection_id = TestConnectionId(++conn_id);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq"), _))
+      .Times(0);
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
+  // Turn on version 47.
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  connection_id = TestConnectionId(++conn_id);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq"), _))
+      .WillOnce(testing::Return(CreateSession(
+          dispatcher_.get(), config_, connection_id, client_address,
+          &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+  EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+              ProcessUdpPacket(_, _, _))
+      .WillOnce(WithArg<2>(
+          Invoke([this, connection_id](const QuicEncryptedPacket& packet) {
+            ValidatePacket(connection_id, packet);
+          })));
+  EXPECT_CALL(*dispatcher_,
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
   // Turn off version 46.
   SetQuicReloadableFlag(quic_enable_version_46, false);
   connection_id = TestConnectionId(++conn_id);
@@ -1956,7 +1990,7 @@
 
   // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
   // last one should be dropped.
-  for (QuicPacketNumber packet_number = 2;
+  for (uint64_t packet_number = 2;
        packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
     ProcessPacket(client_addr_, last_connection_id, true, "data packet");
   }
diff --git a/quic/core/quic_epoll_alarm_factory.cc b/quic/core/quic_epoll_alarm_factory.cc
index 550ee13..2ec2f6f 100644
--- a/quic/core/quic_epoll_alarm_factory.cc
+++ b/quic/core/quic_epoll_alarm_factory.cc
@@ -14,7 +14,7 @@
 
 class QuicEpollAlarm : public QuicAlarm {
  public:
-  QuicEpollAlarm(gfe2::EpollServer* epoll_server,
+  QuicEpollAlarm(QuicEpollServer* epoll_server,
                  QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
       : QuicAlarm(std::move(delegate)),
         epoll_server_(epoll_server),
@@ -44,13 +44,13 @@
   }
 
  private:
-  class EpollAlarmImpl : public gfe2::EpollAlarm {
+  class EpollAlarmImpl : public QuicEpollAlarmBase {
    public:
     explicit EpollAlarmImpl(QuicEpollAlarm* alarm) : alarm_(alarm) {}
 
     // Use the same integer type as the base class.
     int64 /* allow-non-std-int */ OnAlarm() override {
-      EpollAlarm::OnAlarm();
+      QuicEpollAlarmBase::OnAlarm();
       alarm_->Fire();
       // Fire will take care of registering the alarm, if needed.
       return 0;
@@ -60,13 +60,13 @@
     QuicEpollAlarm* alarm_;
   };
 
-  gfe2::EpollServer* epoll_server_;
+  QuicEpollServer* epoll_server_;
   EpollAlarmImpl epoll_alarm_impl_;
 };
 
 }  // namespace
 
-QuicEpollAlarmFactory::QuicEpollAlarmFactory(gfe2::EpollServer* epoll_server)
+QuicEpollAlarmFactory::QuicEpollAlarmFactory(QuicEpollServer* epoll_server)
     : epoll_server_(epoll_server) {}
 
 QuicEpollAlarmFactory::~QuicEpollAlarmFactory() {}
diff --git a/quic/core/quic_epoll_alarm_factory.h b/quic/core/quic_epoll_alarm_factory.h
index d1ec7ca..fc9b45c 100644
--- a/quic/core/quic_epoll_alarm_factory.h
+++ b/quic/core/quic_epoll_alarm_factory.h
@@ -5,17 +5,17 @@
 #ifndef QUICHE_QUIC_CORE_QUIC_EPOLL_ALARM_FACTORY_H_
 #define QUICHE_QUIC_CORE_QUIC_EPOLL_ALARM_FACTORY_H_
 
-#include "gfe/gfe2/base/epoll_server.h"
 #include "net/third_party/quiche/src/quic/core/quic_alarm.h"
 #include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
 #include "net/third_party/quiche/src/quic/core/quic_one_block_arena.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 
 namespace quic {
 
 // Creates alarms that use the supplied EpollServer for timing and firing.
 class QuicEpollAlarmFactory : public QuicAlarmFactory {
  public:
-  explicit QuicEpollAlarmFactory(gfe2::EpollServer* eps);
+  explicit QuicEpollAlarmFactory(QuicEpollServer* eps);
   QuicEpollAlarmFactory(const QuicEpollAlarmFactory&) = delete;
   QuicEpollAlarmFactory& operator=(const QuicEpollAlarmFactory&) = delete;
   ~QuicEpollAlarmFactory() override;
@@ -27,7 +27,7 @@
       QuicConnectionArena* arena) override;
 
  private:
-  gfe2::EpollServer* epoll_server_;  // Not owned.
+  QuicEpollServer* epoll_server_;  // Not owned.
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_epoll_connection_helper.cc b/quic/core/quic_epoll_connection_helper.cc
index 3070c99..49002f6 100644
--- a/quic/core/quic_epoll_connection_helper.cc
+++ b/quic/core/quic_epoll_connection_helper.cc
@@ -16,7 +16,7 @@
 namespace quic {
 
 QuicEpollConnectionHelper::QuicEpollConnectionHelper(
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     QuicAllocator type)
     : clock_(epoll_server),
       random_generator_(QuicRandom::GetInstance()),
diff --git a/quic/core/quic_epoll_connection_helper.h b/quic/core/quic_epoll_connection_helper.h
index 858954a..62e030c 100644
--- a/quic/core/quic_epoll_connection_helper.h
+++ b/quic/core/quic_epoll_connection_helper.h
@@ -18,6 +18,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 #include "net/quic/platform/impl/quic_epoll_clock.h"
 
@@ -43,7 +44,7 @@
 
 class QuicEpollConnectionHelper : public QuicConnectionHelperInterface {
  public:
-  QuicEpollConnectionHelper(gfe2::EpollServer* eps, QuicAllocator allocator);
+  QuicEpollConnectionHelper(QuicEpollServer* eps, QuicAllocator allocator);
   QuicEpollConnectionHelper(const QuicEpollConnectionHelper&) = delete;
   QuicEpollConnectionHelper& operator=(const QuicEpollConnectionHelper&) =
       delete;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index e659b38..1b93074 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -130,7 +130,7 @@
 const uint8_t kSourceConnectionIdLengthMask = 0x0F;
 
 // Returns the absolute value of the difference between |a| and |b|.
-QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) {
+uint64_t Delta(uint64_t a, uint64_t b) {
   // Since these are unsigned numbers, we can't just return abs(a - b)
   if (a < b) {
     return b - a;
@@ -138,12 +138,18 @@
   return a - b;
 }
 
-QuicPacketNumber ClosestTo(QuicPacketNumber target,
-                           QuicPacketNumber a,
-                           QuicPacketNumber b) {
+uint64_t ClosestTo(uint64_t target, uint64_t a, uint64_t b) {
   return (Delta(target, a) < Delta(target, b)) ? a : b;
 }
 
+uint64_t PacketNumberIntervalLength(
+    const QuicInterval<QuicPacketNumber>& interval) {
+  if (interval.Empty()) {
+    return 0u;
+  }
+  return interval.max() - interval.min();
+}
+
 QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
   switch (flags & PACKET_FLAGS_8BYTE_PACKET) {
     case PACKET_FLAGS_8BYTE_PACKET:
@@ -180,7 +186,7 @@
 uint8_t PacketNumberLengthToOnWireValue(
     QuicTransportVersion version,
     QuicPacketNumberLength packet_number_length) {
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     return packet_number_length - 1;
   }
   switch (packet_number_length) {
@@ -203,7 +209,7 @@
     QuicPacketNumberLength* packet_number_length) {
   DCHECK(!(type & FLAGS_LONG_HEADER));
   const bool two_bits_packet_number_length =
-      infer_packet_header_type_from_version ? version == QUIC_VERSION_99
+      infer_packet_header_type_from_version ? version > QUIC_VERSION_46
                                             : (type & FLAGS_FIXED_BIT);
   if (two_bits_packet_number_length) {
     *packet_number_length =
@@ -231,13 +237,13 @@
                                     QuicLongHeaderType type) {
   switch (type) {
     case INITIAL:
-      return version == QUIC_VERSION_99 ? 0 : 0x7F;
+      return version > QUIC_VERSION_46 ? 0 : 0x7F;
     case ZERO_RTT_PROTECTED:
-      return version == QUIC_VERSION_99 ? 1 << 4 : 0x7C;
+      return version > QUIC_VERSION_46 ? 1 << 4 : 0x7C;
     case HANDSHAKE:
-      return version == QUIC_VERSION_99 ? 2 << 4 : 0x7D;
+      return version > QUIC_VERSION_46 ? 2 << 4 : 0x7D;
     case RETRY:
-      return version == QUIC_VERSION_99 ? 3 << 4 : 0x7E;
+      return version > QUIC_VERSION_46 ? 3 << 4 : 0x7E;
     case VERSION_NEGOTIATION:
       return 0xF0;  // Value does not matter
     default:
@@ -250,7 +256,7 @@
                        uint8_t type,
                        QuicLongHeaderType* long_header_type) {
   DCHECK((type & FLAGS_LONG_HEADER) && version != QUIC_VERSION_UNSUPPORTED);
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     switch ((type & 0x30) >> 4) {
       case 0:
         *long_header_type = INITIAL;
@@ -297,7 +303,7 @@
 QuicPacketNumberLength GetLongHeaderPacketNumberLength(
     QuicTransportVersion version,
     uint8_t type) {
-  if (version == QUIC_VERSION_99) {
+  if (version > QUIC_VERSION_46) {
     return static_cast<QuicPacketNumberLength>((type & 0x03) + 1);
   }
   return PACKET_4BYTE_PACKET_NUMBER;
@@ -324,6 +330,19 @@
   return static_cast<uint8_t>(length - kConnectionIdLengthAdjustment);
 }
 
+bool IsValidPacketNumberLength(QuicPacketNumberLength packet_number_length) {
+  size_t length = packet_number_length;
+  return length == 1 || length == 2 || length == 4 || length == 6 ||
+         length == 8;
+}
+
+bool IsValidFullPacketNumber(uint64_t full_packet_number,
+                             QuicTransportVersion version) {
+  return full_packet_number > 0 ||
+         (GetQuicRestartFlag(quic_uint64max_uninitialized_pn) &&
+          version == QUIC_VERSION_99);
+}
+
 }  // namespace
 
 QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
@@ -331,7 +350,6 @@
                        Perspective perspective)
     : visitor_(nullptr),
       error_(QUIC_NO_ERROR),
-      largest_packet_number_(0),
       last_serialized_connection_id_(EmptyQuicConnectionId()),
       last_version_label_(0),
       last_header_form_(GOOGLE_QUIC_PACKET),
@@ -345,9 +363,8 @@
       process_timestamps_(false),
       creation_time_(creation_time),
       last_timestamp_(QuicTime::Delta::Zero()),
+      first_sending_packet_number_(FirstSendingPacketNumber()),
       data_producer_(nullptr),
-      process_stateless_reset_at_client_only_(
-          GetQuicReloadableFlag(quic_process_stateless_reset_at_client_only)),
       infer_packet_header_type_from_version_(perspective ==
                                              Perspective::IS_CLIENT) {
   DCHECK(!supported_versions.empty());
@@ -377,6 +394,13 @@
 }
 
 // static
+size_t QuicFramer::GetMinCryptoFrameSize(QuicStreamOffset offset,
+                                         QuicPacketLength data_length) {
+  return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(offset) +
+         QuicDataWriter::GetVarInt62Len(data_length);
+}
+
+// static
 size_t QuicFramer::GetMessageFrameSize(QuicTransportVersion version,
                                        bool last_frame_in_packet,
                                        QuicByteCount length) {
@@ -500,6 +524,9 @@
   if (version != QUIC_VERSION_99) {
     return kQuicFrameTypeSize + kQuicMaxStreamIdSize;
   }
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   if (frame.stream_id == 0) {
     // return size of IETF QUIC Blocked frame
     return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.offset);
@@ -869,7 +896,6 @@
         set_detailed_error(
             "Attempt to append CRYPTO frame and not in version 99.");
         return RaiseError(QUIC_INTERNAL_ERROR);
-
       default:
         RaiseError(QUIC_INVALID_FRAME_DATA);
         QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
@@ -1050,10 +1076,30 @@
   return writer.length();
 }
 
+size_t QuicFramer::BuildIetfConnectivityProbingPacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length) {
+  QuicFrames frames;
+
+  // Write a PING frame, which has no data payload.
+  QuicPingFrame ping_frame;
+  frames.push_back(QuicFrame(ping_frame));
+
+  // Add padding to the rest of the packet.
+  QuicPaddingFrame padding_frame;
+  frames.push_back(QuicFrame(padding_frame));
+
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
+}
+
 size_t QuicFramer::BuildConnectivityProbingPacket(
     const QuicPacketHeader& header,
     char* buffer,
     size_t packet_length) {
+  if (version_.transport_version == QUIC_VERSION_99) {
+    return BuildIetfConnectivityProbingPacket(header, buffer, packet_length);
+  }
   QuicDataWriter writer(packet_length, buffer, endianness());
 
   if (!AppendPacketHeader(header, &writer)) {
@@ -1088,47 +1134,25 @@
     size_t packet_length,
     QuicPathFrameBuffer* payload,
     QuicRandom* randomizer) {
-  QuicDataWriter writer(packet_length, buffer, endianness());
-  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
-      << "Attempt to build a PATH_CHALLENGE Connectivity Probing packet and "
-         "not doing IETF QUIC";
-
-  if (!AppendPacketHeader(header, &writer)) {
-    QUIC_BUG << "AppendPacketHeader failed";
+  if (version_.transport_version != QUIC_VERSION_99) {
+    QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing "
+                "packet and not doing IETF QUIC";
     return 0;
   }
+  QuicFrames frames;
 
   // Write a PATH_CHALLENGE frame, which has a random 8-byte payload
   randomizer->RandBytes(payload->data(), payload->size());
 
   QuicPathChallengeFrame path_challenge_frame(0, *payload);
-  if (!AppendTypeByte(QuicFrame(&path_challenge_frame),
-                      /* last_frame_in_packet = */ false, &writer)) {
-    QUIC_BUG
-        << "AppendTypeByte failed for PATH_CHALLENGE frame in probing packet";
-    return 0;
-  }
-
-  if (!AppendPathChallengeFrame(path_challenge_frame, &writer)) {
-    QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
-                "probing packet";
-    return 0;
-  }
+  frames.push_back(QuicFrame(&path_challenge_frame));
 
   // Add padding to the rest of the packet in order to assess Path MTU
   // characteristics.
   QuicPaddingFrame padding_frame;
-  if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
-    QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
-    return 0;
-  }
-  if (!AppendPaddingFrame(padding_frame, &writer)) {
-    QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
-             << " failed";
-    return 0;
-  }
+  frames.push_back(QuicFrame(padding_frame));
 
-  return writer.length();
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
 }
 
 size_t QuicFramer::BuildPathResponsePacket(
@@ -1142,53 +1166,33 @@
         << "Attempt to generate connectivity response with no request payloads";
     return 0;
   }
-
-  QuicDataWriter writer(packet_length, buffer, endianness());
-
-  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
-      << "Attempt to build a PATH_RESPONSE Connectivity Probing packet and "
-         "not doing IETF QUIC";
-
-  if (!AppendPacketHeader(header, &writer)) {
-    QUIC_BUG << "AppendPacketHeader failed";
+  if (version_.transport_version != QUIC_VERSION_99) {
+    QUIC_BUG << "Attempt to build a PATH_RESPONSE Connectivity Probing "
+                "packet and not doing IETF QUIC";
     return 0;
   }
 
-  // Write a set of PATH_RESPONSE frames to a single packet, each with the
-  // 8-byte payload of the corresponding PATH_REQUEST frame from a single
-  // received packet.
+  std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames;
   for (const QuicPathFrameBuffer& payload : payloads) {
     // Note that the control frame ID can be 0 since this is not retransmitted.
-    QuicPathResponseFrame path_response_frame(0, payload);
+    path_response_frames.push_back(
+        QuicMakeUnique<QuicPathResponseFrame>(0, payload));
+  }
 
-    if (!AppendTypeByte(QuicFrame(&path_response_frame), false, &writer)) {
-      QUIC_BUG
-          << "AppendTypeByte failed for PATH_RESPONSE frame in probing packet";
-      return 0;
-    }
-
-    if (!AppendPathResponseFrame(path_response_frame, &writer)) {
-      QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
-                  "probing packet";
-      return 0;
-    }
+  QuicFrames frames;
+  for (const std::unique_ptr<QuicPathResponseFrame>& path_response_frame :
+       path_response_frames) {
+    frames.push_back(QuicFrame(path_response_frame.get()));
   }
 
   if (is_padded) {
     // Add padding to the rest of the packet in order to assess Path MTU
     // characteristics.
     QuicPaddingFrame padding_frame;
-    if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
-      QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
-      return 0;
-    }
-    if (!AppendPaddingFrame(padding_frame, &writer)) {
-      QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
-               << " failed";
-      return 0;
-    }
+    frames.push_back(QuicFrame(padding_frame));
   }
-  return writer.length();
+
+  return BuildIetfDataPacket(header, frames, buffer, packet_length);
 }
 
 // static
@@ -1274,7 +1278,7 @@
   } else {
     // Append an random packet number.
     QuicPacketNumber random_packet_number =
-        QuicRandom::GetInstance()->RandUint64() % 255 + 1;
+        QuicPacketNumber(QuicRandom::GetInstance()->RandUint64() % 255 + 1);
     if (!AppendPacketNumber(PACKET_1BYTE_PACKET_NUMBER, random_packet_number,
                             &writer)) {
       return nullptr;
@@ -1470,35 +1474,17 @@
                                        size_t buffer_length) {
   DCHECK_NE(GOOGLE_QUIC_PACKET, header->form);
   DCHECK(!header->has_possible_stateless_reset_token);
-  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET) {
-    if (!process_stateless_reset_at_client_only_) {
-      // Peak possible stateless reset token. Will only be used on decryption
-      // failure.
-      QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
-      if (remaining.length() >=
-          sizeof(header->possible_stateless_reset_token)) {
-        remaining.copy(
-            reinterpret_cast<char*>(&header->possible_stateless_reset_token),
-            sizeof(header->possible_stateless_reset_token),
-            remaining.length() -
-                sizeof(header->possible_stateless_reset_token));
-      }
-    } else {
-      QUIC_RELOADABLE_FLAG_COUNT(quic_process_stateless_reset_at_client_only);
-      if (perspective_ == Perspective::IS_CLIENT) {
-        // Peek possible stateless reset token. Will only be used on decryption
-        // failure.
-        QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
-        if (remaining.length() >=
-            sizeof(header->possible_stateless_reset_token)) {
-          header->has_possible_stateless_reset_token = true;
-          memcpy(
-              &header->possible_stateless_reset_token,
-              &remaining.data()[remaining.length() -
-                                sizeof(header->possible_stateless_reset_token)],
-              sizeof(header->possible_stateless_reset_token));
-        }
-      }
+  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET &&
+      perspective_ == Perspective::IS_CLIENT) {
+    // Peek possible stateless reset token. Will only be used on decryption
+    // failure.
+    QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
+    if (remaining.length() >= sizeof(header->possible_stateless_reset_token)) {
+      header->has_possible_stateless_reset_token = true;
+      memcpy(&header->possible_stateless_reset_token,
+             &remaining.data()[remaining.length() -
+                               sizeof(header->possible_stateless_reset_token)],
+             sizeof(header->possible_stateless_reset_token));
     }
   }
 
@@ -1506,15 +1492,15 @@
       header->long_packet_type != VERSION_NEGOTIATION) {
     // Process packet number.
     QuicPacketNumber base_packet_number = largest_packet_number_;
-
+    uint64_t full_packet_number;
     if (!ProcessAndCalculatePacketNumber(
             encrypted_reader, header->packet_number_length, base_packet_number,
-            &header->packet_number)) {
+            &full_packet_number)) {
       set_detailed_error("Unable to read packet number.");
       return RaiseError(QUIC_INVALID_PACKET_HEADER);
     }
 
-    if (header->packet_number == kInvalidPacketNumber) {
+    if (!IsValidFullPacketNumber(full_packet_number, transport_version())) {
       if (IsIetfStatelessResetPacket(*header)) {
         // This is a stateless reset packet.
         QuicIetfStatelessResetPacket packet(
@@ -1525,6 +1511,7 @@
       set_detailed_error("packet numbers cannot be 0.");
       return RaiseError(QUIC_INVALID_PACKET_HEADER);
     }
+    header->packet_number = QuicPacketNumber(full_packet_number);
   }
 
   // A nonce should only present in SHLO from the server to the client when
@@ -1567,8 +1554,12 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_ =
-      std::max(header->packet_number, largest_packet_number_);
+  if (largest_packet_number_.IsInitialized()) {
+    largest_packet_number_ =
+        std::max(header->packet_number, largest_packet_number_);
+  } else {
+    largest_packet_number_ = header->packet_number;
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     // The visitor suppresses further processing of the packet.
@@ -1629,8 +1620,12 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_ =
-      std::max(header->packet_number, largest_packet_number_);
+  if (largest_packet_number_.IsInitialized()) {
+    largest_packet_number_ =
+        std::max(header->packet_number, largest_packet_number_);
+  } else {
+    largest_packet_number_ = header->packet_number;
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     // The visitor suppresses further processing of the packet.
@@ -1699,10 +1694,11 @@
 
 bool QuicFramer::IsIetfStatelessResetPacket(
     const QuicPacketHeader& header) const {
-  return perspective_ == Perspective::IS_CLIENT &&
-         header.form == IETF_QUIC_SHORT_HEADER_PACKET &&
-         (!process_stateless_reset_at_client_only_ ||
-          header.has_possible_stateless_reset_token) &&
+  QUIC_BUG_IF(header.has_possible_stateless_reset_token &&
+              perspective_ != Perspective::IS_CLIENT)
+      << "has_possible_stateless_reset_token can only be true at client side.";
+  return header.form == IETF_QUIC_SHORT_HEADER_PACKET &&
+         header.has_possible_stateless_reset_token &&
          visitor_->IsValidStatelessResetToken(
              header.possible_stateless_reset_token);
 }
@@ -1737,12 +1733,13 @@
       }
       break;
     case PACKET_8BYTE_CONNECTION_ID:
-      QUIC_BUG_IF(header.destination_connection_id.length() !=
-                      kQuicDefaultConnectionIdLength &&
-                  transport_version() < QUIC_VERSION_99)
-          << "Cannot use connection ID of length "
-          << header.destination_connection_id.length() << " with version "
+      QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+          header.destination_connection_id, transport_version()))
+          << "AppendPacketHeader: attempted to use connection ID "
+          << header.destination_connection_id
+          << " which is invalid with version "
           << QuicVersionToString(transport_version());
+
       public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
       if (perspective_ == Perspective::IS_CLIENT) {
         public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
@@ -1784,7 +1781,7 @@
 bool QuicFramer::AppendIetfHeaderTypeByte(const QuicPacketHeader& header,
                                           QuicDataWriter* writer) {
   uint8_t type = 0;
-  if (transport_version() == QUIC_VERSION_99) {
+  if (transport_version() > QUIC_VERSION_46) {
     if (header.version_flag) {
       type = static_cast<uint8_t>(
           FLAGS_LONG_HEADER | FLAGS_FIXED_BIT |
@@ -1819,11 +1816,10 @@
 bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header,
                                         QuicDataWriter* writer) {
   QUIC_DVLOG(1) << ENDPOINT << "Appending IETF header: " << header;
-  QUIC_BUG_IF(header.destination_connection_id.length() !=
-                  kQuicDefaultConnectionIdLength &&
-              transport_version() < QUIC_VERSION_99)
-      << "Cannot use connection ID of length "
-      << header.destination_connection_id.length() << " with version "
+  QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion(
+      header.destination_connection_id, transport_version()))
+      << "AppendIetfPacketHeader: attempted to use connection ID "
+      << header.destination_connection_id << " which is invalid with version "
       << QuicVersionToString(transport_version());
   if (!AppendIetfHeaderTypeByte(header, writer)) {
     return false;
@@ -1892,10 +1888,10 @@
   return QuicTime::Delta::FromMicroseconds(time);
 }
 
-QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire(
+uint64_t QuicFramer::CalculatePacketNumberFromWire(
     QuicPacketNumberLength packet_number_length,
     QuicPacketNumber base_packet_number,
-    QuicPacketNumber packet_number) const {
+    uint64_t packet_number) const {
   // The new packet number might have wrapped to the next epoch, or
   // it might have reverse wrapped to the previous epoch, or it might
   // remain in the same epoch.  Select the packet number closest to the
@@ -1904,12 +1900,14 @@
   // epoch_delta is the delta between epochs the packet number was serialized
   // with, so the correct value is likely the same epoch as the last sequence
   // number or an adjacent epoch.
-  const QuicPacketNumber epoch_delta = UINT64_C(1)
-                                       << (8 * packet_number_length);
-  QuicPacketNumber next_packet_number = base_packet_number + 1;
-  QuicPacketNumber epoch = base_packet_number & ~(epoch_delta - 1);
-  QuicPacketNumber prev_epoch = epoch - epoch_delta;
-  QuicPacketNumber next_epoch = epoch + epoch_delta;
+  if (!base_packet_number.IsInitialized()) {
+    return packet_number;
+  }
+  const uint64_t epoch_delta = UINT64_C(1) << (8 * packet_number_length);
+  uint64_t next_packet_number = base_packet_number.ToUint64() + 1;
+  uint64_t epoch = base_packet_number.ToUint64() & ~(epoch_delta - 1);
+  uint64_t prev_epoch = epoch - epoch_delta;
+  uint64_t next_epoch = epoch + epoch_delta;
 
   return ClosestTo(next_packet_number, epoch + packet_number,
                    ClosestTo(next_packet_number, prev_epoch + packet_number,
@@ -2009,11 +2007,15 @@
 QuicPacketNumberLength QuicFramer::GetMinPacketNumberLength(
     QuicTransportVersion version,
     QuicPacketNumber packet_number) {
-  if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) {
+  DCHECK(packet_number.IsInitialized());
+  if (packet_number < QuicPacketNumber(1 << (PACKET_1BYTE_PACKET_NUMBER * 8))) {
     return PACKET_1BYTE_PACKET_NUMBER;
-  } else if (packet_number < 1 << (PACKET_2BYTE_PACKET_NUMBER * 8)) {
+  } else if (packet_number <
+             QuicPacketNumber(1 << (PACKET_2BYTE_PACKET_NUMBER * 8))) {
     return PACKET_2BYTE_PACKET_NUMBER;
-  } else if (packet_number < UINT64_C(1) << (PACKET_4BYTE_PACKET_NUMBER * 8)) {
+  } else if (packet_number <
+             QuicPacketNumber(UINT64_C(1)
+                              << (PACKET_4BYTE_PACKET_NUMBER * 8))) {
     return PACKET_4BYTE_PACKET_NUMBER;
   } else {
     return PACKET_6BYTE_PACKET_NUMBER;
@@ -2051,7 +2053,7 @@
   new_ack_info.first_block_length = frame.packets.LastIntervalLength();
   auto itr = frame.packets.rbegin();
   QuicPacketNumber previous_start = itr->min();
-  new_ack_info.max_block_length = itr->Length();
+  new_ack_info.max_block_length = PacketNumberIntervalLength(*itr);
   ++itr;
 
   // Don't do any more work after getting information for 256 ACK blocks; any
@@ -2060,12 +2062,12 @@
          new_ack_info.num_ack_blocks < std::numeric_limits<uint8_t>::max();
        previous_start = itr->min(), ++itr) {
     const auto& interval = *itr;
-    const QuicPacketNumber total_gap = previous_start - interval.max();
+    const QuicPacketCount total_gap = previous_start - interval.max();
     new_ack_info.num_ack_blocks +=
         (total_gap + std::numeric_limits<uint8_t>::max() - 1) /
         std::numeric_limits<uint8_t>::max();
-    new_ack_info.max_block_length =
-        std::max(new_ack_info.max_block_length, interval.Length());
+    new_ack_info.max_block_length = std::max(
+        new_ack_info.max_block_length, PacketNumberIntervalLength(interval));
   }
   return new_ack_info;
 }
@@ -2073,18 +2075,19 @@
 bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
                                               QuicPacketHeader* header) {
   QuicPacketNumber base_packet_number = largest_packet_number_;
-
+  uint64_t full_packet_number;
   if (!ProcessAndCalculatePacketNumber(
           encrypted_reader, header->packet_number_length, base_packet_number,
-          &header->packet_number)) {
+          &full_packet_number)) {
     set_detailed_error("Unable to read packet number.");
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
 
-  if (header->packet_number == kInvalidPacketNumber) {
+  if (!IsValidFullPacketNumber(full_packet_number, transport_version())) {
     set_detailed_error("packet numbers cannot be 0.");
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
+  header->packet_number = QuicPacketNumber(full_packet_number);
 
   if (!visitor_->OnUnauthenticatedHeader(*header)) {
     set_detailed_error(
@@ -2130,7 +2133,7 @@
     } else {
       header->version = ParseQuicVersionLabel(version_label);
       if (header->version.transport_version != QUIC_VERSION_UNSUPPORTED) {
-        if (header->version.transport_version == QUIC_VERSION_99 &&
+        if (header->version.transport_version > QUIC_VERSION_46 &&
             !(type & FLAGS_FIXED_BIT)) {
           set_detailed_error("Fixed bit is 0 in long header.");
           return false;
@@ -2167,7 +2170,7 @@
     header->destination_connection_id = last_serialized_connection_id_;
   }
   if (infer_packet_header_type_from_version_ &&
-      transport_version() == QUIC_VERSION_99 && !(type & FLAGS_FIXED_BIT)) {
+      transport_version() > QUIC_VERSION_46 && !(type & FLAGS_FIXED_BIT)) {
     set_detailed_error("Fixed bit is 0 in short header.");
     return false;
   }
@@ -2240,8 +2243,8 @@
     QuicDataReader* reader,
     QuicPacketNumberLength packet_number_length,
     QuicPacketNumber base_packet_number,
-    QuicPacketNumber* packet_number) {
-  QuicPacketNumber wire_packet_number;
+    uint64_t* packet_number) {
+  uint64_t wire_packet_number;
   if (!reader->ReadBytesToUInt64(packet_number_length, &wire_packet_number)) {
     return false;
   }
@@ -2459,7 +2462,8 @@
     encoded_bytes -= reader->BytesRemaining();
 
     // Check that the frame type is minimally encoded.
-    if (encoded_bytes != QuicDataWriter::GetVarInt62Len(frame_type)) {
+    if (encoded_bytes !=
+        static_cast<size_t>(QuicDataWriter::GetVarInt62Len(frame_type))) {
       // The frame type was not minimally encoded.
       set_detailed_error("Frame type not minimally encoded.");
       return RaiseError(IETF_QUIC_PROTOCOL_VIOLATION);
@@ -2917,12 +2921,21 @@
       ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits,
                   kLargestAckedOffset));
 
-  QuicPacketNumber largest_acked;
+  uint64_t largest_acked;
   if (!reader->ReadBytesToUInt64(largest_acked_length, &largest_acked)) {
     set_detailed_error("Unable to read largest acked.");
     return false;
   }
 
+  if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      largest_acked < first_sending_packet_number_.ToUint64()) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 1, 3);
+    // Connection always sends packet starting from kFirstSendingPacketNumber >
+    // 0, peer has observed an unsent packet.
+    set_detailed_error("Largest acked is 0.");
+    return false;
+  }
+
   uint64_t ack_delay_time_us;
   if (!reader->ReadUFloat16(&ack_delay_time_us)) {
     set_detailed_error("Unable to read ack delay time.");
@@ -2930,7 +2943,7 @@
   }
 
   if (!visitor_->OnAckFrameStart(
-          largest_acked,
+          QuicPacketNumber(largest_acked),
           ack_delay_time_us == kUFloat16MaxValue
               ? QuicTime::Delta::Infinite()
               : QuicTime::Delta::FromMicroseconds(ack_delay_time_us))) {
@@ -2954,6 +2967,8 @@
 
   if (first_block_length == 0) {
     // For non-empty ACKs, the first block length must be non-zero.
+    // TODO(fayang): remove this if and return false directly when deprecating
+    // gfe2_reloadable_flag_quic_disallow_peer_ack_0.
     if (largest_acked != 0 || num_ack_blocks != 0) {
       set_detailed_error(
           QuicStrCat("First block length is zero but ACK is "
@@ -2963,9 +2978,16 @@
               .c_str());
       return false;
     }
+    DCHECK(!GetQuicReloadableFlag(quic_disallow_peer_ack_0));
   }
-
-  if (first_block_length > largest_acked + 1) {
+  bool first_ack_block_underflow = first_block_length > largest_acked + 1;
+  if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      first_block_length + first_sending_packet_number_.ToUint64() >
+          largest_acked + 1) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 2, 3);
+    first_ack_block_underflow = true;
+  }
+  if (first_ack_block_underflow) {
     set_detailed_error(QuicStrCat("Underflow with first ack block length ",
                                   first_block_length, " largest acked is ",
                                   largest_acked, ".")
@@ -2973,8 +2995,9 @@
     return false;
   }
 
-  QuicPacketNumber first_received = largest_acked + 1 - first_block_length;
-  if (!visitor_->OnAckRange(first_received, largest_acked + 1)) {
+  uint64_t first_received = largest_acked + 1 - first_block_length;
+  if (!visitor_->OnAckRange(QuicPacketNumber(first_received),
+                            QuicPacketNumber(largest_acked + 1))) {
     // The visitor suppresses further processing of the packet. Although
     // this is not a parsing error, returns false as this is in middle
     // of processing an ack frame,
@@ -2994,7 +3017,14 @@
         set_detailed_error("Unable to ack block length.");
         return false;
       }
-      if (first_received < gap + current_block_length) {
+      bool ack_block_underflow = first_received < gap + current_block_length;
+      if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+          first_received < gap + current_block_length +
+                               first_sending_packet_number_.ToUint64()) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 3, 3);
+        ack_block_underflow = true;
+      }
+      if (ack_block_underflow) {
         set_detailed_error(
             QuicStrCat("Underflow with ack block length ", current_block_length,
                        ", end of block is ", first_received - gap, ".")
@@ -3004,8 +3034,9 @@
 
       first_received -= (gap + current_block_length);
       if (current_block_length > 0) {
-        if (!visitor_->OnAckRange(first_received,
-                                  first_received + current_block_length)) {
+        if (!visitor_->OnAckRange(
+                QuicPacketNumber(first_received),
+                QuicPacketNumber(first_received) + current_block_length)) {
           // The visitor suppresses further processing of the packet. Although
           // this is not a parsing error, returns false as this is in middle
           // of processing an ack frame,
@@ -3022,13 +3053,13 @@
     return false;
   }
 
-  if (!ProcessTimestampsInAckFrame(num_received_packets, largest_acked,
-                                   reader)) {
+  if (!ProcessTimestampsInAckFrame(num_received_packets,
+                                   QuicPacketNumber(largest_acked), reader)) {
     return false;
   }
 
   // Done processing the ACK frame.
-  return visitor_->OnAckFrameEnd(first_received);
+  return visitor_->OnAckFrameEnd(QuicPacketNumber(first_received));
 }
 
 bool QuicFramer::ProcessTimestampsInAckFrame(uint8_t num_received_packets,
@@ -3084,11 +3115,17 @@
 bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader,
                                      uint64_t frame_type,
                                      QuicAckFrame* ack_frame) {
-  QuicPacketNumber largest_acked;
+  uint64_t largest_acked;
   if (!reader->ReadVarInt62(&largest_acked)) {
     set_detailed_error("Unable to read largest acked.");
     return false;
   }
+  if (largest_acked < first_sending_packet_number_.ToUint64()) {
+    // Connection always sends packet starting from kFirstSendingPacketNumber >
+    // 0, peer has observed an unsent packet.
+    set_detailed_error("Largest acked is 0.");
+    return false;
+  }
   ack_frame->largest_acked = static_cast<QuicPacketNumber>(largest_acked);
   uint64_t ack_delay_time_in_us;
   if (!reader->ReadVarInt62(&ack_delay_time_in_us)) {
@@ -3125,7 +3162,8 @@
     ack_frame->ect_1_count = 0;
     ack_frame->ecn_ce_count = 0;
   }
-  if (!visitor_->OnAckFrameStart(largest_acked, ack_frame->ack_delay_time)) {
+  if (!visitor_->OnAckFrameStart(QuicPacketNumber(largest_acked),
+                                 ack_frame->ack_delay_time)) {
     // The visitor suppresses further processing of the packet. Although this is
     // not a parsing error, returns false as this is in middle of processing an
     // ACK frame.
@@ -3150,14 +3188,15 @@
   }
   // Calculate the packets being acked in the first block.
   //  +1 because AddRange implementation requires [low,high)
-  QuicPacketNumber block_high = largest_acked + 1;
-  QuicPacketNumber block_low = largest_acked - ack_block_value;
+  uint64_t block_high = largest_acked + 1;
+  uint64_t block_low = largest_acked - ack_block_value;
 
   // ack_block_value is the number of packets preceding the
   // largest_acked packet which are in the block being acked. Thus,
   // its maximum value is largest_acked-1. Test this, reporting an
   // error if the value is wrong.
-  if (ack_block_value > largest_acked) {
+  if (ack_block_value + first_sending_packet_number_.ToUint64() >
+      largest_acked) {
     set_detailed_error(QuicStrCat("Underflow with first ack block length ",
                                   ack_block_value + 1, " largest acked is ",
                                   largest_acked, ".")
@@ -3165,7 +3204,8 @@
     return false;
   }
 
-  if (!visitor_->OnAckRange(block_low, block_high)) {
+  if (!visitor_->OnAckRange(QuicPacketNumber(block_low),
+                            QuicPacketNumber(block_high))) {
     // The visitor suppresses further processing of the packet. Although
     // this is not a parsing error, returns false as this is in middle
     // of processing an ACK frame.
@@ -3208,7 +3248,8 @@
       set_detailed_error("Unable to read ack block value.");
       return false;
     }
-    if (ack_block_value > (block_high - 1)) {
+    if (ack_block_value + first_sending_packet_number_.ToUint64() >
+        (block_high - 1)) {
       set_detailed_error(
           QuicStrCat("Underflow with ack block length ", ack_block_value + 1,
                      " latest ack block end is ", block_high - 1, ".")
@@ -3218,7 +3259,8 @@
     // Calculate the low end of the new nth ack block. The +1 is
     // because the encoded value is the blocksize-1.
     block_low = block_high - 1 - ack_block_value;
-    if (!visitor_->OnAckRange(block_low, block_high)) {
+    if (!visitor_->OnAckRange(QuicPacketNumber(block_low),
+                              QuicPacketNumber(block_high))) {
       // The visitor suppresses further processing of the packet. Although
       // this is not a parsing error, returns false as this is in middle
       // of processing an ACK frame.
@@ -3230,19 +3272,22 @@
     ack_block_count--;
   }
 
-  return visitor_->OnAckFrameEnd(block_low);
+  return visitor_->OnAckFrameEnd(QuicPacketNumber(block_low));
 }
 
 bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader,
                                          const QuicPacketHeader& header,
                                          QuicStopWaitingFrame* stop_waiting) {
-  QuicPacketNumber least_unacked_delta;
+  uint64_t least_unacked_delta;
   if (!reader->ReadBytesToUInt64(header.packet_number_length,
                                  &least_unacked_delta)) {
     set_detailed_error("Unable to read least unacked delta.");
     return false;
   }
-  if (header.packet_number < least_unacked_delta) {
+  if (header.packet_number.ToUint64() < least_unacked_delta ||
+      (GetQuicReloadableFlag(
+           quic_close_connection_with_zero_least_unacked_stop_waiting) &&
+       header.packet_number.ToUint64() == least_unacked_delta)) {
     set_detailed_error("Invalid unacked delta.");
     return false;
   }
@@ -3461,9 +3506,10 @@
                                   size_t total_len,
                                   size_t buffer_len,
                                   char* buffer) {
+  DCHECK(packet_number.IsInitialized());
   size_t output_length = 0;
   if (!encrypter_[level]->EncryptPacket(
-          version_.transport_version, packet_number,
+          version_.transport_version, packet_number.ToUint64(),
           QuicStringPiece(buffer, ad_len),  // Associated data
           QuicStringPiece(buffer + ad_len, total_len - ad_len),  // Plaintext
           buffer + ad_len,  // Destination buffer
@@ -3480,6 +3526,7 @@
                                   const QuicPacket& packet,
                                   char* buffer,
                                   size_t buffer_len) {
+  DCHECK(packet_number.IsInitialized());
   DCHECK(encrypter_[level] != nullptr);
 
   QuicStringPiece associated_data =
@@ -3491,7 +3538,7 @@
   // Encrypt the plaintext into the buffer.
   size_t output_length = 0;
   if (!encrypter_[level]->EncryptPacket(
-          version_.transport_version, packet_number, associated_data,
+          version_.transport_version, packet_number.ToUint64(), associated_data,
           packet.Plaintext(version_.transport_version), buffer + ad_len,
           &output_length, buffer_len - ad_len)) {
     RaiseError(QUIC_ENCRYPTION_FAILURE);
@@ -3533,8 +3580,9 @@
       header.nonce != nullptr, header.packet_number_length);
 
   bool success = decrypter_->DecryptPacket(
-      version_.transport_version, header.packet_number, associated_data,
-      encrypted, decrypted_buffer, decrypted_length, buffer_length);
+      version_.transport_version, header.packet_number.ToUint64(),
+      associated_data, encrypted, decrypted_buffer, decrypted_length,
+      buffer_length);
   if (success) {
     visitor_->OnDecryptedPacket(decrypter_level_);
   } else if (alternative_decrypter_ != nullptr) {
@@ -3556,8 +3604,9 @@
 
     if (try_alternative_decryption) {
       success = alternative_decrypter_->DecryptPacket(
-          version_.transport_version, header.packet_number, associated_data,
-          encrypted, decrypted_buffer, decrypted_length, buffer_length);
+          version_.transport_version, header.packet_number.ToUint64(),
+          associated_data, encrypted, decrypted_buffer, decrypted_length,
+          buffer_length);
     }
     if (success) {
       visitor_->OnDecryptedPacket(alternative_decrypter_level_);
@@ -3590,7 +3639,7 @@
   // Type byte, largest_acked, and delay_time are straight-forward.
   size_t ack_frame_size = kQuicFrameTypeSize;
   QuicPacketNumber largest_acked = LargestAcked(frame);
-  ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked);
+  ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked.ToUint64());
   uint64_t ack_delay_time_us;
   ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
   ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
@@ -3650,18 +3699,18 @@
   size_t ack_block_count_size = QuicDataWriter::GetVarInt62Len(ack_block_count);
   ack_frame_size += ack_block_count_size;
 
-  QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest;
+  uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
   size_t first_ack_block_size = QuicDataWriter::GetVarInt62Len(first_ack_block);
   ack_frame_size += first_ack_block_size;
 
   // Account for the remaining Intervals, if any.
   while (ack_block_count != 0) {
-    QuicPacketNumber gap_size = ack_block_smallest - itr->max();
+    uint64_t gap_size = ack_block_smallest - itr->max();
     // Decrement per the protocol specification
     size_t size_of_gap_size = QuicDataWriter::GetVarInt62Len(gap_size - 1);
     ack_frame_size += size_of_gap_size;
 
-    QuicPacketNumber block_size = itr->max() - itr->min();
+    uint64_t block_size = itr->max() - itr->min();
     // Decrement per the protocol specification
     size_t size_of_block_size = QuicDataWriter::GetVarInt62Len(block_size - 1);
     ack_frame_size += size_of_block_size;
@@ -3677,6 +3726,7 @@
 size_t QuicFramer::GetAckFrameSize(
     const QuicAckFrame& ack,
     QuicPacketNumberLength packet_number_length) {
+  DCHECK(!ack.packets.Empty());
   size_t ack_size = 0;
 
   if (version_.transport_version == QUIC_VERSION_99) {
@@ -3686,7 +3736,7 @@
   QuicPacketNumberLength largest_acked_length =
       GetMinPacketNumberLength(version_.transport_version, LargestAcked(ack));
   QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength(
-      version_.transport_version, ack_info.max_block_length);
+      version_.transport_version, QuicPacketNumber(ack_info.max_block_length));
 
   ack_size =
       GetMinAckFrameSize(version_.transport_version, largest_acked_length);
@@ -3727,7 +3777,10 @@
                  frame.stream_frame.offset, last_frame_in_packet,
                  frame.stream_frame.data_length) +
              frame.stream_frame.data_length;
-    // TODO(nharper): Add a case for CRYPTO_FRAME here?
+    case CRYPTO_FRAME:
+      return GetMinCryptoFrameSize(frame.crypto_frame->offset,
+                                   frame.crypto_frame->data_length) +
+             frame.crypto_frame->data_length;
     case ACK_FRAME: {
       return GetAckFrameSize(*frame.ack_frame, packet_number_length);
     }
@@ -3913,12 +3966,13 @@
 bool QuicFramer::AppendPacketNumber(QuicPacketNumberLength packet_number_length,
                                     QuicPacketNumber packet_number,
                                     QuicDataWriter* writer) {
-  size_t length = packet_number_length;
-  if (length != 1 && length != 2 && length != 4 && length != 6 && length != 8) {
-    QUIC_BUG << "Invalid packet_number_length: " << length;
+  DCHECK(packet_number.IsInitialized());
+  if (!IsValidPacketNumberLength(packet_number_length)) {
+    QUIC_BUG << "Invalid packet_number_length: " << packet_number_length;
     return false;
   }
-  return writer->WriteBytesToUInt64(packet_number_length, packet_number);
+  return writer->WriteBytesToUInt64(packet_number_length,
+                                    packet_number.ToUint64());
 }
 
 // static
@@ -3947,10 +4001,18 @@
 // static
 bool QuicFramer::AppendAckBlock(uint8_t gap,
                                 QuicPacketNumberLength length_length,
-                                QuicPacketNumber length,
+                                uint64_t length,
                                 QuicDataWriter* writer) {
+  if (length == 0) {
+    if (!IsValidPacketNumberLength(length_length)) {
+      QUIC_BUG << "Invalid packet_number_length: " << length_length;
+      return false;
+    }
+    return writer->WriteUInt8(gap) &&
+           writer->WriteBytesToUInt64(length_length, length);
+  }
   return writer->WriteUInt8(gap) &&
-         AppendPacketNumber(length_length, length, writer);
+         AppendPacketNumber(length_length, QuicPacketNumber(length), writer);
 }
 
 bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
@@ -4120,8 +4182,20 @@
     set_detailed_error("Writing data length failed.");
     return false;
   }
-  // TODO(nharper): Append stream frame contents.
-  return false;
+  if (data_producer_ == nullptr) {
+    if (frame.data_buffer == nullptr ||
+        !writer->WriteBytes(frame.data_buffer, frame.data_length)) {
+      set_detailed_error("Writing frame data failed.");
+      return false;
+    }
+  } else {
+    DCHECK_EQ(nullptr, frame.data_buffer);
+    if (!data_producer_->WriteCryptoData(frame.level, frame.offset,
+                                         frame.data_length, writer)) {
+      return false;
+    }
+  }
+  return true;
 }
 
 void QuicFramer::set_version(const ParsedQuicVersion version) {
@@ -4139,8 +4213,9 @@
   QuicPacketNumber largest_acked = LargestAcked(frame);
   QuicPacketNumberLength largest_acked_length =
       GetMinPacketNumberLength(version_.transport_version, largest_acked);
-  QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength(
-      version_.transport_version, new_ack_info.max_block_length);
+  QuicPacketNumberLength ack_block_length =
+      GetMinPacketNumberLength(version_.transport_version,
+                               QuicPacketNumber(new_ack_info.max_block_length));
   // Calculate available bytes for timestamps and ack blocks.
   int32_t available_timestamp_and_ack_block_bytes =
       writer->capacity() - writer->length() - ack_block_length -
@@ -4199,7 +4274,8 @@
   }
 
   // First ack block length.
-  if (!AppendPacketNumber(ack_block_length, new_ack_info.first_block_length,
+  if (!AppendPacketNumber(ack_block_length,
+                          QuicPacketNumber(new_ack_info.first_block_length),
                           writer)) {
     return false;
   }
@@ -4223,7 +4299,7 @@
          itr != frame.packets.rend() && num_ack_blocks_written < num_ack_blocks;
          previous_start = itr->min(), ++itr) {
       const auto& interval = *itr;
-      const QuicPacketNumber total_gap = previous_start - interval.max();
+      const uint64_t total_gap = previous_start - interval.max();
       const size_t num_encoded_gaps =
           (total_gap + std::numeric_limits<uint8_t>::max() - 1) /
           std::numeric_limits<uint8_t>::max();
@@ -4251,8 +4327,8 @@
           total_gap -
           (num_encoded_gaps - 1) * std::numeric_limits<uint8_t>::max();
       // Append the final ACK block with a non-empty size.
-      if (!AppendAckBlock(last_gap, ack_block_length, interval.Length(),
-                          writer)) {
+      if (!AppendAckBlock(last_gap, ack_block_length,
+                          PacketNumberIntervalLength(interval), writer)) {
         return false;
       }
       ++num_ack_blocks_written;
@@ -4297,8 +4373,7 @@
 
   auto it = frame.received_packet_times.begin();
   QuicPacketNumber packet_number = it->first;
-  QuicPacketNumber delta_from_largest_observed =
-      LargestAcked(frame) - packet_number;
+  uint64_t delta_from_largest_observed = LargestAcked(frame) - packet_number;
 
   DCHECK_GE(std::numeric_limits<uint8_t>::max(), delta_from_largest_observed);
   if (delta_from_largest_observed > std::numeric_limits<uint8_t>::max()) {
@@ -4345,10 +4420,11 @@
                                         const QuicStopWaitingFrame& frame,
                                         QuicDataWriter* writer) {
   DCHECK_GE(QUIC_VERSION_43, version_.transport_version);
-  DCHECK_GE(header.packet_number, frame.least_unacked);
-  const QuicPacketNumber least_unacked_delta =
+  DCHECK(frame.least_unacked.IsInitialized() &&
+         header.packet_number >= frame.least_unacked);
+  const uint64_t least_unacked_delta =
       header.packet_number - frame.least_unacked;
-  const QuicPacketNumber length_shift = header.packet_number_length * 8;
+  const uint64_t length_shift = header.packet_number_length * 8;
 
   if (least_unacked_delta >> length_shift > 0) {
     QUIC_BUG << "packet_number_length " << header.packet_number_length
@@ -4358,8 +4434,12 @@
              << " version:" << version_.transport_version;
     return false;
   }
-  if (!AppendPacketNumber(header.packet_number_length, least_unacked_delta,
-                          writer)) {
+  if (least_unacked_delta == 0) {
+    return writer->WriteBytesToUInt64(header.packet_number_length,
+                                      least_unacked_delta);
+  }
+  if (!AppendPacketNumber(header.packet_number_length,
+                          QuicPacketNumber(least_unacked_delta), writer)) {
     QUIC_BUG << " seq failed: " << header.packet_number_length;
     return false;
   }
@@ -4382,7 +4462,7 @@
     return 0;
   }
   available_space -= encoded_size;
-  uint64_t previous_ack_end = itr->min();
+  QuicPacketNumber previous_ack_end = itr->min();
   ack_block_count--;
 
   while (ack_block_count) {
@@ -4426,7 +4506,7 @@
   }
 
   QuicPacketNumber largest_acked = LargestAcked(frame);
-  if (!writer->WriteVarInt62(largest_acked)) {
+  if (!writer->WriteVarInt62(largest_acked.ToUint64())) {
     set_detailed_error("No room for largest-acked in ack frame");
     return false;
   }
@@ -4480,9 +4560,9 @@
   // Case 2 or 3
   auto itr = frame.packets.rbegin();
 
-  QuicPacketNumber ack_block_largest = largest_acked;
+  QuicPacketNumber ack_block_largest(largest_acked);
   QuicPacketNumber ack_block_smallest;
-  if ((itr->max() - 1) == largest_acked) {
+  if ((itr->max() - 1) == QuicPacketNumber(largest_acked)) {
     // If largest_acked + 1 is equal to the Max() of the first Interval
     // in the QuicAckFrame then the first Interval is the first ack block of the
     // frame; remaining Intervals are additional ack blocks.  The QuicAckFrame's
@@ -4513,7 +4593,7 @@
     return false;
   }
 
-  QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest;
+  uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
   if (!writer->WriteVarInt62(first_ack_block)) {
     set_detailed_error("No room for first ack block in ack frame");
     return false;
@@ -4521,13 +4601,13 @@
 
   // For the remaining QuicAckFrame Intervals, if any
   while (ack_block_count != 0) {
-    QuicPacketNumber gap_size = ack_block_smallest - itr->max();
+    uint64_t gap_size = ack_block_smallest - itr->max();
     if (!writer->WriteVarInt62(gap_size - 1)) {
       set_detailed_error("No room for gap block in ack frame");
       return false;
     }
 
-    QuicPacketNumber block_size = itr->max() - itr->min();
+    uint64_t block_size = itr->max() - itr->min();
     if (!writer->WriteVarInt62(block_size - 1)) {
       set_detailed_error("No room for nth ack block in ack frame");
       return false;
@@ -4608,6 +4688,9 @@
 bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame,
                                     QuicDataWriter* writer) {
   if (version_.transport_version == QUIC_VERSION_99) {
+    // TODO(fkastenholz): This should be converted to use
+    // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+    // and not rely on 0.
     if (frame.stream_id == 0) {
       return AppendIetfBlockedFrame(frame, writer);
     }
@@ -4985,6 +5068,9 @@
 bool QuicFramer::ProcessIetfBlockedFrame(QuicDataReader* reader,
                                          QuicBlockedFrame* frame) {
   // Indicates that it is a BLOCKED frame (as opposed to STREAM_BLOCKED).
+  // TODO(fkastenholz): This should be converted to use
+  // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value
+  // and not rely on 0.
   frame->stream_id = 0;
   if (!reader->ReadVarInt62(&frame->offset)) {
     set_detailed_error("Can not read blocked offset.");
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 828daa0..46280c5 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -270,6 +270,10 @@
                                       QuicStreamOffset offset,
                                       bool last_frame_in_packet,
                                       QuicPacketLength data_length);
+  // Returns the overhead of framing a CRYPTO frame with the specific offset and
+  // data length provided, but not counting the size of the data payload.
+  static size_t GetMinCryptoFrameSize(QuicStreamOffset offset,
+                                      QuicPacketLength data_length);
   static size_t GetMessageFrameSize(QuicTransportVersion version,
                                     bool last_frame_in_packet,
                                     QuicByteCount length);
@@ -374,6 +378,12 @@
                                         char* buffer,
                                         size_t packet_length);
 
+  // Serializes an IETF probing packet, which is a padded PING packet.
+  // Returns the length of the packet. Returns 0 if it fails to serialize.
+  size_t BuildIetfConnectivityProbingPacket(const QuicPacketHeader& header,
+                                            char* buffer,
+                                            size_t packet_length);
+
   // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
   // fills the packet with padding.
   size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header,
@@ -506,7 +516,7 @@
   // Returns header wire format of last received packet.
   // Please do not use this method.
   // TODO(fayang): Remove last_header_form_ when deprecating
-  // quic_proxy_use_real_packet_format_when_reject flag.
+  // quic_fix_last_packet_is_ietf_quic flag.
   PacketHeaderFormat GetLastPacketFormat() const;
 
   void set_validate_flags(bool value) { validate_flags_ = value; }
@@ -534,6 +544,10 @@
 
   QuicTime creation_time() const { return creation_time_; }
 
+  QuicPacketNumber first_sending_packet_number() const {
+    return first_sending_packet_number_;
+  }
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -545,9 +559,9 @@
     ~AckFrameInfo();
 
     // The maximum ack block length.
-    QuicPacketNumber max_block_length;
+    QuicPacketCount max_block_length;
     // Length of first ack block.
-    QuicPacketNumber first_block_length;
+    QuicPacketCount first_block_length;
     // Number of ACK blocks needed for the ACK frame.
     size_t num_ack_blocks;
   };
@@ -597,7 +611,7 @@
       QuicDataReader* reader,
       QuicPacketNumberLength packet_number_length,
       QuicPacketNumber base_packet_number,
-      QuicPacketNumber* packet_number);
+      uint64_t* packet_number);
   bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header);
   bool ProcessIetfFrameData(QuicDataReader* reader,
                             const QuicPacketHeader& header);
@@ -635,10 +649,10 @@
 
   // Returns the full packet number from the truncated
   // wire format version and the last seen packet number.
-  QuicPacketNumber CalculatePacketNumberFromWire(
+  uint64_t CalculatePacketNumberFromWire(
       QuicPacketNumberLength packet_number_length,
       QuicPacketNumber base_packet_number,
-      QuicPacketNumber packet_number) const;
+      uint64_t packet_number) const;
 
   // Returns the QuicTime::Delta corresponding to the time from when the framer
   // was created.
@@ -675,7 +689,7 @@
   // successfully appended.
   static bool AppendAckBlock(uint8_t gap,
                              QuicPacketNumberLength length_length,
-                             QuicPacketNumber length,
+                             uint64_t length,
                              QuicDataWriter* writer);
 
   static uint8_t GetPacketNumberFlags(
@@ -869,13 +883,15 @@
   // The last timestamp received if process_timestamps_ is true.
   QuicTime::Delta last_timestamp_;
 
+  // If this is a framer of a connection, this is the packet number of first
+  // sending packet. If this is a framer of a framer of dispatcher, this is the
+  // packet number of sent packets (for those which have packet number).
+  const QuicPacketNumber first_sending_packet_number_;
+
   // If not null, framer asks data_producer_ to write stream frame data. Not
   // owned. TODO(fayang): Consider add data producer to framer's constructor.
   QuicStreamFrameDataProducer* data_producer_;
 
-  // Latched value of quic_process_stateless_reset_at_client_only flag.
-  const bool process_stateless_reset_at_client_only_;
-
   // If true, framer infers packet header type (IETF/GQUIC) from version_.
   // Otherwise, framer infers packet header type from first byte of a received
   // packet.
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index a75bceb..888c87e 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -36,8 +36,8 @@
 namespace test {
 namespace {
 
-const QuicPacketNumber kEpoch = UINT64_C(1) << 32;
-const QuicPacketNumber kMask = kEpoch - 1;
+const uint64_t kEpoch = UINT64_C(1) << 32;
+const uint64_t kMask = kEpoch - 1;
 
 const QuicUint128 kTestStatelessResetToken = 1010101;  // 0x0F69B5
 
@@ -51,10 +51,11 @@
   return TestConnectionId(UINT64_C(0xFEDCBA9876543211));
 }
 
-const QuicPacketNumber kPacketNumber = UINT64_C(0x12345678);
-const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234);
-const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233);
-const QuicPacketNumber kLeastUnacked = UINT64_C(0x012345670);
+const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678));
+const QuicPacketNumber kSmallLargestObserved =
+    QuicPacketNumber(UINT16_C(0x1234));
+const QuicPacketNumber kSmallMissingPacket = QuicPacketNumber(UINT16_C(0x1233));
+const QuicPacketNumber kLeastUnacked = QuicPacketNumber(UINT64_C(0x012345670));
 const QuicStreamId kStreamId = UINT64_C(0x01020304);
 // Note that the high 4 bits of the stream offset must be less than 0x40
 // in order to ensure that the value can be encoded using VarInt62 encoding.
@@ -65,7 +66,7 @@
 // This is the largest packet number that can be represented in IETF QUIC
 // varint62 format.
 const QuicPacketNumber kLargestIetfLargestObserved =
-    UINT64_C(0x3fffffffffffffff);
+    QuicPacketNumber(UINT64_C(0x3fffffffffffffff));
 // Encodings for the two bits in a VarInt62 that
 // describe the length of the VarInt61. For binary packet
 // formats in this file, the convention is to code the
@@ -83,14 +84,14 @@
   bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; }
   bool SetIV(QuicStringPiece iv) override { return true; }
   bool EncryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece plaintext,
                      char* output,
                      size_t* output_length,
                      size_t max_output_length) override {
     version_ = version;
-    packet_number_ = packet_number;
+    packet_number_ = QuicPacketNumber(packet_number);
     associated_data_ = QuicString(associated_data);
     plaintext_ = QuicString(plaintext);
     memcpy(output, plaintext.data(), plaintext.length());
@@ -129,14 +130,14 @@
     return true;
   }
   bool DecryptPacket(QuicTransportVersion version,
-                     QuicPacketNumber packet_number,
+                     uint64_t packet_number,
                      QuicStringPiece associated_data,
                      QuicStringPiece ciphertext,
                      char* output,
                      size_t* output_length,
                      size_t max_output_length) override {
     version_ = version;
-    packet_number_ = packet_number;
+    packet_number_ = QuicPacketNumber(packet_number);
     associated_data_ = QuicString(associated_data);
     ciphertext_ = QuicString(ciphertext);
     memcpy(output, ciphertext.data(), ciphertext.length());
@@ -223,7 +224,13 @@
   }
 
   bool OnCryptoFrame(const QuicCryptoFrame& frame) override {
-    // TODO(nharper): Implement.
+    ++frame_count_;
+    // Save a copy of the data so it is valid after the packet is processed.
+    QuicString* string_data =
+        new QuicString(frame.data_buffer, frame.data_length);
+    crypto_data_.push_back(QuicWrapUnique(string_data));
+    crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
+        ENCRYPTION_NONE, frame.offset, *string_data));
     return true;
   }
 
@@ -373,6 +380,7 @@
   std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_;
   std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
   std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_;
+  std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_;
   std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_;
   std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_;
   std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_;
@@ -393,6 +401,7 @@
   QuicRetireConnectionIdFrame retire_connection_id_;
   QuicNewTokenFrame new_token_;
   std::vector<std::unique_ptr<QuicString>> stream_data_;
+  std::vector<std::unique_ptr<QuicString>> crypto_data_;
 };
 
 // Simple struct for defining a packet's content, and associated
@@ -428,6 +437,7 @@
                          std::unique_ptr<QuicEncrypter>(encrypter_));
 
     framer_.set_visitor(&visitor_);
+    framer_.InferPacketHeaderTypeFromVersion();
   }
 
   // Helper function to get unsigned char representation of the handshake
@@ -577,9 +587,9 @@
     EXPECT_EQ(str, QuicString(frame->data_buffer, frame->data_length));
   }
 
-  void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number,
+  void CheckCalculatePacketNumber(uint64_t expected_packet_number,
                                   QuicPacketNumber last_packet_number) {
-    QuicPacketNumber wire_packet_number = expected_packet_number & kMask;
+    uint64_t wire_packet_number = expected_packet_number & kMask;
     EXPECT_EQ(expected_packet_number,
               QuicFramerPeer::CalculatePacketNumberFromWire(
                   &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number,
@@ -623,12 +633,17 @@
 
 TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) {
   // A few quick manual sanity checks.
-  CheckCalculatePacketNumber(UINT64_C(1), UINT64_C(0));
-  CheckCalculatePacketNumber(kEpoch + 1, kMask);
-  CheckCalculatePacketNumber(kEpoch, kMask);
+  CheckCalculatePacketNumber(UINT64_C(1), QuicPacketNumber());
+  CheckCalculatePacketNumber(kEpoch + 1, QuicPacketNumber(kMask));
+  CheckCalculatePacketNumber(kEpoch, QuicPacketNumber(kMask));
+  for (uint64_t j = 0; j < 10; j++) {
+    CheckCalculatePacketNumber(j, QuicPacketNumber());
+    CheckCalculatePacketNumber(kEpoch - 1 - j, QuicPacketNumber());
+  }
 
   // Cases where the last number was close to the start of the range.
-  for (uint64_t last = 0; last < 10; last++) {
+  for (QuicPacketNumber last = QuicPacketNumber(1); last < QuicPacketNumber(10);
+       last++) {
     // Small numbers should not wrap (even if they're out of order).
     for (uint64_t j = 0; j < 10; j++) {
       CheckCalculatePacketNumber(j, last);
@@ -644,7 +659,7 @@
 TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) {
   // Cases where the last number was close to the end of the range
   for (uint64_t i = 0; i < 10; i++) {
-    QuicPacketNumber last = kEpoch - i;
+    QuicPacketNumber last = QuicPacketNumber(kEpoch - i);
 
     // Small numbers should wrap.
     for (uint64_t j = 0; j < 10; j++) {
@@ -665,7 +680,7 @@
   const uint64_t cur_epoch = 2 * kEpoch;
   // Cases where the last number was close to the start of the range
   for (uint64_t i = 0; i < 10; i++) {
-    uint64_t last = cur_epoch + i;
+    QuicPacketNumber last = QuicPacketNumber(cur_epoch + i);
     // Small number should not wrap (even if they're out of order).
     for (uint64_t j = 0; j < 10; j++) {
       CheckCalculatePacketNumber(cur_epoch + j, last);
@@ -684,7 +699,7 @@
   const uint64_t next_epoch = 3 * kEpoch;
   // Cases where the last number was close to the end of the range
   for (uint64_t i = 0; i < 10; i++) {
-    QuicPacketNumber last = next_epoch - 1 - i;
+    QuicPacketNumber last = QuicPacketNumber(next_epoch - 1 - i);
 
     // Small numbers should wrap.
     for (uint64_t j = 0; j < 10; j++) {
@@ -707,7 +722,7 @@
   for (uint64_t i = 0; i < 10; i++) {
     // Subtract 1, because the expected next packet number is 1 more than the
     // last packet number.
-    QuicPacketNumber last = max_number - i - 1;
+    QuicPacketNumber last = QuicPacketNumber(max_number - i - 1);
 
     // Small numbers should not wrap, because they have nowhere to go.
     for (uint64_t j = 0; j < 10; j++) {
@@ -749,10 +764,21 @@
     // packet number
     0x78, 0x56, 0x34, 0x12,
   };
+  unsigned char packet47[kMaxPacketSize + 1] = {
+    // type (short header 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78, 0x56, 0x34, 0x12,
+  };
   // clang-format on
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() > QUIC_VERSION_43) {
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
   }
@@ -826,9 +852,9 @@
 
 TEST_P(QuicFramerTest, LongPacketHeader) {
   // clang-format off
-  PacketFragments packet = {
+  PacketFragments packet44 = {
     // type (long header with packet type INITIAL)
-    {"Unable to read public flags.",
+    {"Unable to read type.",
      {0xFF}},
     // version tag
     {"Unable to read protocol version.",
@@ -843,14 +869,33 @@
     {"Unable to read packet number.",
      {0x12, 0x34, 0x56, 0x78}},
   };
+  PacketFragments packet47 = {
+    // type (long header with packet type INITIAL)
+    {"Unable to read type.",
+     {0xC3}},
+    // version tag
+    {"Unable to read protocol version.",
+     {QUIC_VERSION_BYTES}},
+    // connection_id length
+    {"Unable to read ConnectionId length.",
+     {0x50}},
+    // connection_id
+    {"Unable to read Destination ConnectionId.",
+     {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+    // packet number
+    {"Unable to read packet number.",
+     {0x12, 0x34, 0x56, 0x78}},
+  };
   // clang-format on
 
   if (framer_.transport_version() <= QUIC_VERSION_43) {
     return;
   }
 
+  PacketFragments& fragments =
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44;
   std::unique_ptr<QuicEncryptedPacket> encrypted(
-      AssemblePacketFromFragments(packet));
+      AssemblePacketFromFragments(fragments));
 
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
   EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
@@ -861,7 +906,9 @@
   EXPECT_TRUE(visitor_.header_->version_flag);
   EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
 
-  CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
+  CheckFramingBoundaries(
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44,
+      QUIC_INVALID_PACKET_HEADER);
 }
 
 TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
@@ -900,7 +947,7 @@
          {0x12, 0x34, 0x56, 0x78}},
    };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
         // type (short header, 4 byte packet number)
         {"Unable to read type.",
          {0x43}},
@@ -912,8 +959,8 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() == QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
           : (framer_.transport_version() > QUIC_VERSION_43
                  ? packet44
                  : (framer_.transport_version() == QUIC_VERSION_35 ? packet
@@ -966,7 +1013,7 @@
 
   PacketFragments packet44 = {
       // type (long header with packet type ZERO_RTT_PROTECTED)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0xFC}},
       // version tag
       {"Unable to read protocol version.",
@@ -982,10 +1029,10 @@
        {0x12, 0x34, 0x56, 0x78}},
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
       // packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0xD3}},
       // version tag
       {"Unable to read protocol version.",
@@ -1003,8 +1050,8 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() == QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
           : (framer_.transport_version() > QUIC_VERSION_43
                  ? packet44
                  : (framer_.transport_version() == QUIC_VERSION_35 ? packet
@@ -1054,7 +1101,7 @@
 
   PacketFragments packet44 = {
       // type (short header, 4 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x32}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1063,13 +1110,27 @@
       {"Unable to read packet number.",
        {0x12, 0x34, 0x56, 0x78}},
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"Unable to read type.",
+       {0x43}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x12, 0x34, 0x56, 0x78}},
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() == QUIC_VERSION_35 ? packet
-                                                            : packet39);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() == QUIC_VERSION_35 ? packet
+                                                                   : packet39));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1114,7 +1175,7 @@
 
   PacketFragments packet44 = {
       // type (short header, 2 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x31}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1123,13 +1184,27 @@
       {"Unable to read packet number.",
        {0x56, 0x78}},
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 2 byte packet number)
+      {"Unable to read type.",
+       {0x41}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x56, 0x78}},
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() == QUIC_VERSION_35 ? packet
-                                                            : packet39);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() == QUIC_VERSION_35 ? packet
+                                                                   : packet39));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1163,7 +1238,7 @@
 
   PacketFragments packet44 = {
       // type (8 byte connection_id and 1 byte packet number)
-      {"Unable to read public flags.",
+      {"Unable to read type.",
        {0x30}},
       // connection_id
       {"Unable to read Destination ConnectionId.",
@@ -1173,10 +1248,24 @@
        {0x78}},
   };
 
+  PacketFragments packet47 = {
+      // type (8 byte connection_id and 1 byte packet number)
+      {"Unable to read type.",
+       {0x40}},
+      // connection_id
+      {"Unable to read Destination ConnectionId.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"Unable to read packet number.",
+       {0x78}},
+  };
+
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet;
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet);
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -1318,7 +1407,7 @@
     0x00, 0x00, 0x00, 0x00
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
     // number.
     0xD0,
@@ -1344,9 +1433,9 @@
 
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_size = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -1571,9 +1660,9 @@
     0x00, 0x00,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
-    0x32,
+    0x43,
     // connection_id
     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
     // packet number
@@ -1581,8 +1670,35 @@
 
     // paddings
     0x00, 0x00,
-    // frame type - Stream with FIN, LEN, and OFFSET bits set.
-    0x10 | 0x01 | 0x02 | 0x04,
+    // frame type (stream frame with fin)
+    0xFF,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data length
+    0x00, 0x0c,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+    // paddings
+    0x00, 0x00,
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // paddings
+    0x00, 0x00,
+    // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
+    0x08 | 0x01 | 0x02 | 0x04,
 
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
@@ -1608,6 +1724,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -1726,6 +1845,36 @@
          'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stream frame with fin)
+      {"",
+       {0xFF}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x01, 0x02, 0x03, 0x04}},
+      // offset
+      {"Unable to read offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      {"Unable to read frame data.",
+       {
+         // data length
+         0x00, 0x0c,
+         // data
+         'h',  'e',  'l',  'l',
+         'o',  ' ',  'w',  'o',
+         'r',  'l',  'd',  '!'}},
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -1736,9 +1885,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type - Stream with FIN, LEN, and OFFSET bits set.
+      // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
       {"",
-       { 0x10 | 0x01 | 0x02 | 0x04 }},
+       { 0x08 | 0x01 | 0x02 | 0x04 }},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -1760,10 +1909,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -1802,9 +1954,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type - Stream with FIN, LEN, and OFFSET bits set.
+      // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set.
       {"",
-       { 0x10 | 0x01 | 0x02 | 0x04 }},
+       { 0x08 | 0x01 | 0x02 | 0x04 }},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -2123,6 +2275,36 @@
           'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+       // frame type (stream frame with fin)
+       {"",
+        {0xFD}},
+       // stream id
+       {"Unable to read stream_id.",
+        {0x03, 0x04}},
+       // offset
+       {"Unable to read offset.",
+        {0x3A, 0x98, 0xFE, 0xDC,
+         0x32, 0x10, 0x76, 0x54}},
+       {"Unable to read frame data.",
+        {
+          // data length
+          0x00, 0x0c,
+          // data
+          'h',  'e',  'l',  'l',
+          'o',  ' ',  'w',  'o',
+          'r',  'l',  'd',  '!'}},
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -2133,9 +2315,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (stream frame with LEN, FIN, and OFFSET bits set)
+      // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set)
       {"",
-       {0x10 | 0x01 | 0x02 | 0x04}},
+       {0x08 | 0x01 | 0x02 | 0x04}},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62TwoBytes + 0x03, 0x04}},
@@ -2157,10 +2339,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2274,6 +2459,36 @@
          'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stream frame with fin)
+      {"",
+       {0xFC}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x04}},
+      // offset
+      {"Unable to read offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      {"Unable to read frame data.",
+       {
+         // data length
+         0x00, 0x0c,
+         // data
+         'h',  'e',  'l',  'l',
+         'o',  ' ',  'w',  'o',
+         'r',  'l',  'd',  '!'}},
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -2284,9 +2499,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (stream frame with LEN, FIN, and OFFSET bits set)
+      // frame type (IETF_STREAM frame with LEN, FIN, and OFFSET bits set)
       {"",
-       {0x10 | 0x01 | 0x02 | 0x04}},
+       {0x08 | 0x01 | 0x02 | 0x04}},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62OneByte + 0x04}},
@@ -2308,10 +2523,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2437,6 +2655,43 @@
          'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet47 = {
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      {"",
+       {0xD3}},
+      // version tag
+      {"",
+       {QUIC_VERSION_BYTES}},
+      // connection_id length
+      {"",
+       {0x50}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stream frame with fin)
+      {"",
+       {0xFE}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x02, 0x03, 0x04}},
+      // offset
+      {"Unable to read offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      {"Unable to read frame data.",
+       {
+         // data length
+         0x00, 0x0c,
+         // data
+         'h',  'e',  'l',  'l',
+         'o',  ' ',  'w',  'o',
+         'r',  'l',  'd',  '!'}},
+  };
+
   PacketFragments packet99 = {
       // public flags (long header with packet type ZERO_RTT_PROTECTED and
       // 4-byte packet number)
@@ -2454,9 +2709,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (stream frame with FIN, LEN, and OFFSET bits set)
+      // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
       {"",
-       {0x10 | 0x01 | 0x02 | 0x04}},
+       {0x08 | 0x01 | 0x02 | 0x04}},
       // stream id
       {"Unable to read stream_id.",
        {kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04}},
@@ -2478,10 +2733,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2575,10 +2833,35 @@
       'o',  ' ',  'w',  'o',
       'r',  'l',  'd',  '!',
   };
+
+  unsigned char packet47[] = {
+      // type (short header, 4 byte packet number)
+      0x43,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+
+      // frame type (STREAM Frame with FIN, LEN, and OFFSET bits set)
+      0x10 | 0x01 | 0x02 | 0x04,
+      // stream id
+      kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
+      // offset
+      kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+      0x32, 0x10, 0x76, 0x54,
+      // data length
+      kVarInt62OneByte + 0x0c,
+      // data
+      'h',  'e',  'l',  'l',
+      'o',  ' ',  'w',  'o',
+      'r',  'l',  'd',  '!',
+  };
   // clang-format on
 
   unsigned char* p = packet;
-  if (framer_.transport_version() > QUIC_VERSION_43) {
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
     p = packet39;
@@ -2619,19 +2902,33 @@
     // packet number
     0x01,
   };
+
+  unsigned char packet47[] = {
+    // type (short header, 1 byte packet number)
+    0x40,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x01,
+  };
   // clang-format on
 
   QuicEncryptedPacket encrypted(
-      framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44)
-                                                    : AsChars(packet),
-      framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
-                                                    : QUIC_ARRAYSIZE(packet),
+      framer_.transport_version() > QUIC_VERSION_46
+          ? AsChars(packet47)
+          : (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44)
+                                                           : AsChars(packet)),
+      framer_.transport_version() > QUIC_VERSION_46
+          ? QUIC_ARRAYSIZE(packet47)
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? QUIC_ARRAYSIZE(packet44)
+                 : QUIC_ARRAYSIZE(packet)),
       false);
   EXPECT_TRUE(framer_.ProcessPacket(encrypted));
 
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
-  EXPECT_EQ(0u, visitor_.header_->packet_number);
+  EXPECT_FALSE(visitor_.header_->packet_number.IsInitialized());
 }
 
 TEST_P(QuicFramerTest, AckFrameOneAckBlock) {
@@ -2720,22 +3017,50 @@
        {0x00}}
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (short packet, 4 byte packet number)
       {"",
-       {0x32}},
+       {0x43}},
       // connection_id
       {"",
        {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+      // frame type (ack frame)
+      // (one ack block, 2 byte largest observed, 2 byte block length)
+      {"",
+       {0x45}},
+      // largest acked
+      {"Unable to read largest acked.",
+       {0x12, 0x34}},
+      // Zero delta time.
+      {"Unable to read ack delay time.",
+       {0x00, 0x00}},
+      // first ack block length.
+      {"Unable to read first ack block length.",
+       {0x12, 0x34}},
+      // num timestamps.
+      {"Unable to read num received packets.",
+       {0x00}}
+  };
+
+  PacketFragments packet99 = {
+      // type (short packet, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+       // frame type (IETF_ACK)
        // (one ack block, 2 byte largest observed, 2 byte block length)
        // IETF-Quic ignores the bit-fields in the ack type, all of
        // that information is encoded elsewhere in the frame.
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62TwoBytes  + 0x12, 0x34}},
@@ -2759,10 +3084,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2871,6 +3199,34 @@
        {0x00}}
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (ack frame)
+      // (one ack block, 2 byte largest observed, 2 byte block length)
+      {"",
+       {0x45}},
+      // largest acked
+      {"Unable to read largest acked.",
+       {0x12, 0x34}},
+      // Zero delta time.
+      {"Unable to read ack delay time.",
+       {0x00, 0x00}},
+      // first ack block length.
+      {"Unable to read first ack block length.",
+       {0x88, 0x88}},
+      // num timestamps.
+      {"Underflow with first ack block length 34952 largest acked is 4660.",
+       {0x00}}
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -2881,9 +3237,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62TwoBytes  + 0x12, 0x34}},
@@ -2902,10 +3258,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
@@ -2931,9 +3290,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62OneByte  + 63}},
@@ -2988,9 +3347,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62OneByte  + 63}},
@@ -3043,9 +3402,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62OneByte  + 10}},
@@ -3092,9 +3451,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62OneByte  + 10}},
@@ -3123,7 +3482,7 @@
   CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA);
 }
 
-// An ack block that acks the entire range, 0...0x3fffffffffffffff
+// An ack block that acks the entire range, 1...0x3fffffffffffffff
 TEST_P(QuicFramerTest, AckBlockAcksEverything) {
   if (framer_.transport_version() != QUIC_VERSION_99) {
     // for now, only v99
@@ -3140,9 +3499,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62EightBytes  + 0x3f, 0xff, 0xff, 0xff,
@@ -3156,7 +3515,7 @@
        // first ack block length.
        {"Unable to read first ack block length.",
         {kVarInt62EightBytes  + 0x3f, 0xff, 0xff, 0xff,
-         0xff, 0xff, 0xff, 0xff}},
+         0xff, 0xff, 0xff, 0xfe}},
   };
   // clang-format on
 
@@ -3167,8 +3526,8 @@
   const QuicAckFrame& frame = *visitor_.ack_frames_[0];
   EXPECT_EQ(1u, frame.packets.NumIntervals());
   EXPECT_EQ(kLargestIetfLargestObserved, LargestAcked(frame));
-  // +1 because it's 0..Largest, inclusive.
-  EXPECT_EQ(kLargestIetfLargestObserved + 1, frame.packets.NumPacketsSlow());
+  EXPECT_EQ(kLargestIetfLargestObserved.ToUint64(),
+            frame.packets.NumPacketsSlow());
 }
 
 // This test looks for a malformed ack where
@@ -3312,12 +3671,55 @@
         { 0x00 }},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       { 0x43 }},
+      // connection_id
+      {"",
+       { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+      // packet number
+      {"",
+       { 0x12, 0x34, 0x56, 0x78 }},
+
+      // frame type (ack frame)
+      // (more than one ack block, 2 byte largest observed, 2 byte block length)
+      {"",
+       { 0x65 }},
+      // largest acked
+      {"Unable to read largest acked.",
+       { 0x12, 0x34 }},
+      // Zero delta time.
+      {"Unable to read ack delay time.",
+       { 0x00, 0x00 }},
+      // num ack blocks ranges.
+      {"Unable to read num of ack blocks.",
+       { 0x01 }},
+      // first ack block length.
+      {"Unable to read first ack block length.",
+       { 0x00, 0x00 }},
+      // gap to next block.
+      { "First block length is zero but ACK is not empty. "
+        "largest acked is 4660, num ack blocks is 1.",
+        { 0x01 }},
+      // ack block length.
+      { "First block length is zero but ACK is not empty. "
+        "largest acked is 4660, num ack blocks is 1.",
+        { 0x0e, 0xaf }},
+      // Number of timestamps.
+      { "First block length is zero but ACK is not empty. "
+        "largest acked is 4660, num ack blocks is 1.",
+        { 0x00 }},
+  };
+
   // clang-format on
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                            : packet);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
+                                                                   : packet));
 
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
@@ -3422,6 +3824,34 @@
        {0x00}}
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x56, 0x78, 0x9A, 0xBC}},
+      // frame type (ack frame)
+      // (one ack block, 4 byte largest observed, 2 byte block length)
+      {"",
+       {0x49}},
+      // largest acked
+      {"Unable to read largest acked.",
+       {0x12, 0x34, 0x56, 0x78}},
+      // Zero delta time.
+      {"Unable to read ack delay time.",
+       {0x00, 0x00}},
+      // first ack block length.
+      {"Unable to read first ack block length.",
+       {0x12, 0x34}},
+      // num timestamps.
+      {"Unable to read num received packets.",
+       {0x00}}
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -3432,9 +3862,9 @@
       // packet number
       {"",
        {0x56, 0x78, 0x9A, 0xBC}},
-       // frame type (ack frame)
+       // frame type (IETF_ACK frame)
        {"",
-        {0x1a}},
+        {0x02}},
        // largest acked
        {"Unable to read largest acked.",
         {kVarInt62FourBytes  + 0x12, 0x34, 0x56, 0x78}},
@@ -3453,10 +3883,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3684,10 +4117,10 @@
         { 0x32, 0x10 }},
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (short header, 4 byte packet number)
       {"",
-       { 0x32 }},
+       { 0x43 }},
       // connection_id
       {"",
        { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
@@ -3696,8 +4129,76 @@
        { 0x12, 0x34, 0x56, 0x78 }},
 
       // frame type (ack frame)
+      // (more than one ack block, 2 byte largest observed, 2 byte block length)
       {"",
-       { 0x1a }},
+       { 0x65 }},
+      // largest acked
+      {"Unable to read largest acked.",
+       { 0x12, 0x34 }},
+      // Zero delta time.
+      {"Unable to read ack delay time.",
+       { 0x00, 0x00 }},
+      // num ack blocks ranges.
+      {"Unable to read num of ack blocks.",
+       { 0x04 }},
+      // first ack block length.
+      {"Unable to read first ack block length.",
+       { 0x00, 0x01 }},
+      // gap to next block.
+      { "Unable to read gap to next ack block.",
+        { 0x01 }},
+      // ack block length.
+      { "Unable to ack block length.",
+        { 0x0e, 0xaf }},
+      // gap to next block.
+      { "Unable to read gap to next ack block.",
+        { 0xff }},
+      // ack block length.
+      { "Unable to ack block length.",
+        { 0x00, 0x00 }},
+      // gap to next block.
+      { "Unable to read gap to next ack block.",
+        { 0x91 }},
+      // ack block length.
+      { "Unable to ack block length.",
+        { 0x01, 0xea }},
+      // gap to next block.
+      { "Unable to read gap to next ack block.",
+        { 0x05 }},
+      // ack block length.
+      { "Unable to ack block length.",
+        { 0x00, 0x04 }},
+      // Number of timestamps.
+      { "Unable to read num received packets.",
+        { 0x02 }},
+      // Delta from largest observed.
+      { "Unable to read sequence delta in received packets.",
+        { 0x01 }},
+      // Delta time.
+      { "Unable to read time delta in received packets.",
+        { 0x76, 0x54, 0x32, 0x10 }},
+      // Delta from largest observed.
+      { "Unable to read sequence delta in received packets.",
+        { 0x02 }},
+      // Delta time.
+      { "Unable to read incremental time delta in received packets.",
+        { 0x32, 0x10 }},
+  };
+
+  PacketFragments packet99 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       { 0x43 }},
+      // connection_id
+      {"",
+       { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }},
+      // packet number
+      {"",
+       { 0x12, 0x34, 0x56, 0x78 }},
+
+      // frame type (IETF_ACK frame)
+      {"",
+       { 0x02 }},
        // largest acked
        {"Unable to read largest acked.",
         { kVarInt62TwoBytes + 0x12, 0x34 }},   // = 4660
@@ -3744,10 +4245,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
 
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
@@ -3833,13 +4337,33 @@
       {"Unable to read least unacked delta.",
         {0x00, 0x00, 0x00, 0x08}}
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stop waiting frame)
+      {"",
+       {0x06}},
+      // least packet number awaiting an ack, delta from packet number.
+      {"Unable to read least unacked delta.",
+        {0x00, 0x00, 0x00, 0x08}}
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                            : packet);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
+                                                                   : packet));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -3903,14 +4427,29 @@
     // least packet number awaiting an ack, delta from packet number.
     0x57, 0x78, 0x9A, 0xA8,
   };
+
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+    // frame type (stop waiting frame)
+    0x06,
+    // least packet number awaiting an ack, delta from packet number.
+    0x57, 0x78, 0x9A, 0xA8,
+  };
   // clang-format on
 
   QuicEncryptedPacket encrypted(
-      AsChars(framer_.transport_version() > QUIC_VERSION_43
-                  ? packet44
-                  : (framer_.transport_version() == QUIC_VERSION_35
-                         ? packet
-                         : packet39)),
+      AsChars(framer_.transport_version() > QUIC_VERSION_46
+                  ? packet47
+                  : (framer_.transport_version() > QUIC_VERSION_43
+                         ? packet44
+                         : (framer_.transport_version() == QUIC_VERSION_35
+                                ? packet
+                                : packet39))),
       framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
                                                     : QUIC_ARRAYSIZE(packet),
       false);
@@ -3996,7 +4535,7 @@
        {0x00, 0x00, 0x00, 0x01}}
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (short header, 4 byte packet number)
       {"",
        {0x43}},
@@ -4010,6 +4549,31 @@
       {"",
        {0x01}},
       // stream id
+      {"Unable to read stream_id.",
+       {0x01, 0x02, 0x03, 0x04}},
+      // sent byte offset
+      {"Unable to read rst stream sent byte offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      // error code
+      {"Unable to read rst stream error code.",
+       {0x00, 0x00, 0x00, 0x01}}
+  };
+
+  PacketFragments packet99 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (IETF_RST_STREAM frame)
+      {"",
+       {0x04}},
+      // stream id
       {"Unable to read rst stream stream id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
       // application error code
@@ -4024,10 +4588,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4130,7 +4697,7 @@
       }
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet47 = {
       // type (short header, 4 byte packet number)
       {"",
        {0x43}},
@@ -4145,6 +4712,34 @@
        {0x02}},
       // error code
       {"Unable to read connection close error code.",
+       {0x00, 0x00, 0x00, 0x11}},
+      {"Unable to read connection close error details.",
+       {
+         // error details length
+         0x0, 0x0d,
+         // error details
+         'b',  'e',  'c',  'a',
+         'u',  's',  'e',  ' ',
+         'I',  ' ',  'c',  'a',
+         'n'}
+      }
+  };
+
+  PacketFragments packet99 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (IETF_CONNECTION_CLOSE frame)
+      {"",
+       {0x1c}},
+      // error code
+      {"Unable to read connection close error code.",
        {0x00, 0x11}},
       {"Unable to read connection close frame type.",
        {kVarInt62TwoBytes + 0x12, 0x34 }},
@@ -4164,10 +4759,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4208,9 +4806,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (application close frame)
+      // frame type (IETF_APPLICATION_CLOSE frame)
       {"",
-       {0x03}},
+       {0x1d}},
       // error code
       {"Unable to read application close error code.",
        {0x00, 0x11}},
@@ -4347,13 +4945,47 @@
          'n'}
       }
   };
+
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (go away frame)
+      {"",
+       {0x03}},
+      // error code
+      {"Unable to read go away error code.",
+       {0x00, 0x00, 0x00, 0x09}},
+      // stream id
+      {"Unable to read last good stream id.",
+       {0x01, 0x02, 0x03, 0x04}},
+      // stream id
+      {"Unable to read goaway reason.",
+       {
+         // error details length
+         0x0, 0x0d,
+         // error details
+         'b',  'e',  'c',  'a',
+         'u',  's',  'e',  ' ',
+         'I',  ' ',  'c',  'a',
+         'n'}
+      }
+  };
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                            : packet);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
+                                                                   : packet));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4425,6 +5057,28 @@
   PacketFragments packet44 = {
       // type (short header, 4 byte packet number)
       {"",
+       {0x32}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (window update frame)
+      {"",
+       {0x04}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x01, 0x02, 0x03, 0x04}},
+      // byte offset
+      {"Unable to read window byte_offset.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+  };
+
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
        {0x43}},
       // connection_id
       {"",
@@ -4447,10 +5101,12 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() > QUIC_VERSION_43
-          ? packet44
-          : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                            : packet);
+      framer_.transport_version() > QUIC_VERSION_46
+          ? packet47
+          : (framer_.transport_version() > QUIC_VERSION_43
+                 ? packet44
+                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
+                                                                   : packet));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4483,9 +5139,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (IETF max data frame)
+      // frame type (IETF_MAX_DATA frame)
       {"",
-       {0x04}},
+       {0x10}},
       // byte offset
       {"Can not read MAX_DATA byte-offset",
        {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
@@ -4525,9 +5181,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (ietf max stream data frame)
+      // frame type (IETF_MAX_STREAM_DATA frame)
       {"",
-       {0x05}},
+       {0x11}},
       // stream id
       {"Can not read MAX_STREAM_DATA stream id",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -4610,6 +5266,24 @@
        {0x01, 0x02, 0x03, 0x04}},
   };
 
+  PacketFragments packet47 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (blocked frame)
+      {"",
+       {0x05}},
+      // stream id
+      {"Unable to read stream_id.",
+       {0x01, 0x02, 0x03, 0x04}},
+  };
+
   PacketFragments packet99 = {
       // type (short header, 4 byte packet number)
       {"",
@@ -4620,9 +5294,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (IETF stream blocked frame)
+      // frame type (IETF_STREAM_BLOCKED frame)
       {"",
-       {0x09}},
+       {0x15}},
       // stream id
       {"Can not read stream blocked stream id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -4635,10 +5309,13 @@
   PacketFragments& fragments =
       framer_.transport_version() == QUIC_VERSION_99
           ? packet99
-          : (framer_.transport_version() > QUIC_VERSION_43
-                 ? packet44
-                 : (framer_.transport_version() != QUIC_VERSION_35 ? packet39
-                                                                   : packet));
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? packet47
+                 : (framer_.transport_version() > QUIC_VERSION_43
+                        ? packet44
+                        : (framer_.transport_version() != QUIC_VERSION_35
+                               ? packet39
+                               : packet)));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -4700,16 +5377,49 @@
      // frame type
      0x07,
     };
+
+  unsigned char packet47[] = {
+     // type (short header, 4 byte packet number)
+     0x43,
+     // connection_id
+     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+     // packet number
+     0x12, 0x34, 0x56, 0x78,
+
+     // frame type
+     0x07,
+    };
+
+  unsigned char packet99[] = {
+     // type (short header, 4 byte packet number)
+     0x43,
+     // connection_id
+     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+     // packet number
+     0x12, 0x34, 0x56, 0x78,
+
+     // frame type (IETF_PING frame)
+     0x01,
+    };
   // clang-format on
 
   QuicEncryptedPacket encrypted(
-      AsChars(framer_.transport_version() > QUIC_VERSION_43
-                  ? packet44
-                  : (framer_.transport_version() == QUIC_VERSION_35
-                         ? packet
-                         : packet39)),
-      framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44)
-                                                    : QUIC_ARRAYSIZE(packet),
+      AsChars(framer_.transport_version() == QUIC_VERSION_99
+                  ? packet99
+                  : (framer_.transport_version() > QUIC_VERSION_46
+                         ? packet47
+                         : framer_.transport_version() > QUIC_VERSION_43
+                               ? packet44
+                               : (framer_.transport_version() == QUIC_VERSION_35
+                                      ? packet
+                                      : packet39))),
+      framer_.transport_version() == QUIC_VERSION_99
+          ? QUIC_ARRAYSIZE(packet99)
+          : (framer_.transport_version() > QUIC_VERSION_46
+                 ? QUIC_ARRAYSIZE(packet47)
+                 : framer_.transport_version() > QUIC_VERSION_43
+                       ? QUIC_ARRAYSIZE(packet44)
+                       : QUIC_ARRAYSIZE(packet)),
       false);
   EXPECT_TRUE(framer_.ProcessPacket(encrypted));
 
@@ -4755,10 +5465,37 @@
         {{},
          {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
    };
+
+  PacketFragments packet47 = {
+       // type (short header, 4 byte packet number)
+       {"",
+        {0x43}},
+       // connection_id
+       {"",
+        {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+       // packet number
+       {"",
+        {0x12, 0x34, 0x56, 0x78}},
+       // message frame type.
+       {"",
+        { 0x21 }},
+       // message length
+       {"Unable to read message length",
+        {0x07}},
+       // message data
+       {"Unable to read message data",
+        {'m', 'e', 's', 's', 'a', 'g', 'e'}},
+        // message frame no length.
+        {"",
+         { 0x20 }},
+        // message data
+        {{},
+         {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}},
+   };
   // clang-format on
 
-  std::unique_ptr<QuicEncryptedPacket> encrypted(
-      AssemblePacketFromFragments(packet45));
+  std::unique_ptr<QuicEncryptedPacket> encrypted(AssemblePacketFromFragments(
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
 
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -4771,7 +5508,9 @@
   EXPECT_EQ(7u, visitor_.message_frames_[0]->message_data.length());
   EXPECT_EQ(8u, visitor_.message_frames_[1]->message_data.length());
 
-  CheckFramingBoundaries(packet45, QUIC_INVALID_MESSAGE_DATA);
+  CheckFramingBoundaries(
+      framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45,
+      QUIC_INVALID_MESSAGE_DATA);
 }
 
 TEST_P(QuicFramerTest, PublicResetPacketV33) {
@@ -5186,6 +5925,19 @@
     0x00, 0x00, 0x00, 0x00
   };
 
+  unsigned char packet47[kMaxPacketSize] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
   unsigned char packet99[kMaxPacketSize] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -5203,6 +5955,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -5321,6 +6075,33 @@
     0x00, 0x00,
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // paddings
+    0x00, 0x00,
+    // frame type (stream frame with fin)
+    0xFF,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data length
+    0x00, 0x0c,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+    // paddings
+    0x00, 0x00,
+  };
+
   unsigned char packet99[] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -5331,8 +6112,8 @@
 
     // paddings
     0x00, 0x00,
-    // frame type (stream frame with FIN, LEN, and OFFSET bits set)
-    0x10 | 0x01 | 0x02 | 0x04,
+    // frame type (IETF_STREAM with FIN, LEN, and OFFSET bits set)
+    0x08 | 0x01 | 0x02 | 0x04,
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // offset
@@ -5357,6 +6138,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -5419,6 +6203,19 @@
     0x00, 0x00, 0x00, 0x00
   };
 
+  unsigned char packet47[kMaxPacketSize] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
   unsigned char packet99[kMaxPacketSize] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -5436,6 +6233,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -5507,6 +6306,19 @@
     0x00, 0x00, 0x00, 0x00
   };
 
+  unsigned char packet47[kMaxPacketSize] = {
+    // type (short header, 2 byte packet number)
+    0x41,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x56, 0x78,
+
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
   unsigned char packet99[kMaxPacketSize] = {
     // type (short header, 2 byte packet number)
     0x41,
@@ -5524,6 +6336,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -5582,6 +6396,19 @@
     0x00, 0x00, 0x00, 0x00
   };
 
+  unsigned char packet47[kMaxPacketSize] = {
+    // type (short header, 1 byte packet number)
+    0x40,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78,
+
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+
   unsigned char packet99[kMaxPacketSize] = {
     // type (short header, 1 byte packet number)
     0x40,
@@ -5599,6 +6426,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   }
@@ -5694,6 +6523,27 @@
     'r',  'l',  'd',  '!',
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (stream frame with fin and no length)
+    0xDF,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+  };
+
   unsigned char packet99[] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -5702,8 +6552,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (stream frame with FIN and OFFSET, no length)
-    0x10 | 0x01 | 0x04,
+    // frame type (IETF_STREAM frame with FIN and OFFSET, no length)
+    0x08 | 0x01 | 0x04,
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // offset
@@ -5724,6 +6574,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -5811,6 +6664,28 @@
       'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!',
   };
 
+  unsigned char packet47[] = {
+      // type (long header with packet type ZERO_RTT_PROTECTED)
+      0xD3,
+      // version tag
+      QUIC_VERSION_BYTES,
+      // connection_id length
+      0x50,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+
+      // frame type (stream frame with fin and no length)
+      0xDF,
+      // stream id
+      0x01, 0x02, 0x03, 0x04,
+      // offset
+      0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54,
+      // data
+      'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!',
+  };
+
   unsigned char packet99[] = {
       // type (long header with packet type ZERO_RTT_PROTECTED)
       0xD3,
@@ -5823,8 +6698,8 @@
       // packet number
       0x12, 0x34, 0x56, 0x78,
 
-      // frame type (stream frame with fin and offset, no length)
-      0x10 | 0x01 | 0x04,
+      // frame type (IETF_STREAM frame with fin and offset, no length)
+      0x08 | 0x01 | 0x04,
       // stream id
       kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
       // offset
@@ -5843,6 +6718,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -5853,6 +6731,112 @@
                                       data->length(), AsChars(p), p_size);
 }
 
+TEST_P(QuicFramerTest, BuildCryptoFramePacket) {
+  if (framer_.transport_version() < QUIC_VERSION_99) {
+    // CRYPTO frames aren't supported prior to v46.
+    return;
+  }
+  QuicPacketHeader header;
+  header.destination_connection_id = FramerTestConnectionId();
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+
+  SimpleDataProducer data_producer;
+  framer_.set_data_producer(&data_producer);
+
+  QuicStringPiece crypto_frame_contents("hello world!");
+  QuicCryptoFrame crypto_frame(ENCRYPTION_NONE, kStreamOffset,
+                               crypto_frame_contents.length());
+  data_producer.SaveCryptoData(ENCRYPTION_NONE, kStreamOffset,
+                               crypto_frame_contents);
+
+  QuicFrames frames = {QuicFrame(&crypto_frame)};
+
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_CRYPTO frame)
+    0x06,
+    // offset
+    kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // length
+    kVarInt62OneByte + 12,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+  };
+  // clang-format on
+
+  size_t packet_size = QUIC_ARRAYSIZE(packet);
+
+  std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+  ASSERT_TRUE(data != nullptr);
+  test::CompareCharArraysWithHexError("constructed packet", data->data(),
+                                      data->length(), AsChars(packet),
+                                      packet_size);
+}
+
+TEST_P(QuicFramerTest, CryptoFrame) {
+  if (framer_.transport_version() < QUIC_VERSION_99) {
+    // CRYPTO frames aren't supported prior to v46.
+    return;
+  }
+
+  // clang-format off
+  PacketFragments packet = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (IETF_CRYPTO frame)
+      {"",
+       {0x06}},
+      // offset
+      {"",
+       {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      // data length
+      {"Invalid data length.",
+       {kVarInt62OneByte + 12}},
+      // data
+      {"Unable to read frame data.",
+       {'h',  'e',  'l',  'l',
+        'o',  ' ',  'w',  'o',
+        'r',  'l',  'd',  '!'}},
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet));
+  EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  ASSERT_TRUE(visitor_.header_.get());
+  EXPECT_TRUE(CheckDecryption(
+      *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce,
+      PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
+  ASSERT_EQ(1u, visitor_.crypto_frames_.size());
+  QuicCryptoFrame* frame = visitor_.crypto_frames_[0].get();
+  EXPECT_EQ(kStreamOffset, frame->offset);
+  EXPECT_EQ("hello world!", QuicString(frame->data_buffer, frame->data_length));
+
+  CheckFramingBoundaries(packet, QUIC_INVALID_FRAME_DATA);
+}
+
 TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
   // clang-format off
   unsigned char packet[] = {
@@ -5969,7 +6953,7 @@
       0x00,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
       // type (short header, 4 byte packet number)
       0x43,
       // connection_id
@@ -5978,7 +6962,28 @@
       0x12, 0x34, 0x56, 0x78,
 
       // frame type (ack frame)
-      0x1a,
+      // (no ack blocks, 2 byte largest observed, 2 byte block length)
+      0x45,
+      // largest acked
+      0x12, 0x34,
+      // Zero delta time.
+      0x00, 0x00,
+      // first ack block length.
+      0x12, 0x34,
+      // num timestamps.
+      0x00,
+  };
+
+  unsigned char packet99[] = {
+      // type (short header, 4 byte packet number)
+      0x43,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+
+      // frame type (IETF_ACK frame)
+      0x02,
       // largest acked
       kVarInt62TwoBytes + 0x12, 0x34,
       // Zero delta time.
@@ -5994,6 +6999,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -6083,6 +7091,27 @@
       0x00,
   };
 
+  unsigned char packet47[] = {
+      // type (short header, 4 byte packet number)
+      0x43,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+
+      // frame type (ack frame)
+      // (no ack blocks, 4 byte largest observed, 4 byte block length)
+      0x4A,
+      // largest acked
+      0x12, 0x34, 0x56, 0x78,
+      // Zero delta time.
+      0x00, 0x00,
+      // first ack block length.
+      0x12, 0x34, 0x56, 0x78,
+      // num timestamps.
+      0x00,
+  };
+
 
   unsigned char packet99[] = {
       // type (short header, 4 byte packet number)
@@ -6092,8 +7121,8 @@
       // packet number
       0x12, 0x34, 0x56, 0x78,
 
-      // frame type (ack frame)
-      0x1a,
+      // frame type (IETF_ACK frame)
+      0x02,
       // largest acked
       kVarInt62FourBytes + 0x12, 0x34, 0x56, 0x78,
       // Zero delta time.
@@ -6109,6 +7138,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -6131,9 +7163,9 @@
 
   // Use kSmallLargestObserved to make this test finished in a short time.
   QuicAckFrame ack_frame =
-      InitAckFrame({{1, 5},
-                    {10, 500},
-                    {900, kSmallMissingPacket},
+      InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(5)},
+                    {QuicPacketNumber(10), QuicPacketNumber(500)},
+                    {QuicPacketNumber(900), kSmallMissingPacket},
                     {kSmallMissingPacket + 1, kSmallLargestObserved + 1}});
   ack_frame.ack_delay_time = QuicTime::Delta::Zero();
 
@@ -6257,7 +7289,7 @@
       0x00,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
       // type (short header, 4 byte packet number)
       0x43,
       // connection_id
@@ -6266,7 +7298,46 @@
       0x12, 0x34, 0x56, 0x78,
 
       // frame type (ack frame)
-      0x1a,
+      // (has ack blocks, 2 byte largest observed, 2 byte block length)
+      0x65,
+      // largest acked
+      0x12, 0x34,
+      // Zero delta time.
+      0x00, 0x00,
+      // num ack blocks ranges.
+      0x04,
+      // first ack block length.
+      0x00, 0x01,
+      // gap to next block.
+      0x01,
+      // ack block length.
+      0x0e, 0xaf,
+      // gap to next block.
+      0xff,
+      // ack block length.
+      0x00, 0x00,
+      // gap to next block.
+      0x91,
+      // ack block length.
+      0x01, 0xea,
+      // gap to next block.
+      0x05,
+      // ack block length.
+      0x00, 0x04,
+      // num timestamps.
+      0x00,
+  };
+
+  unsigned char packet99[] = {
+      // type (short header, 4 byte packet number)
+      0x43,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+
+      // frame type (IETF_ACK frame)
+      0x02,
       // largest acked
       kVarInt62TwoBytes + 0x12, 0x34,
       // Zero delta time.
@@ -6297,6 +7368,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -6324,9 +7398,9 @@
   ack_frame.ack_delay_time = QuicTime::Delta::Zero();
   // 300 ack blocks.
   for (size_t i = 2; i < 2 * 300; i += 2) {
-    ack_frame.packets.Add(i);
+    ack_frame.packets.Add(QuicPacketNumber(i));
   }
-  ack_frame.packets.AddRange(600, kSmallLargestObserved + 1);
+  ack_frame.packets.AddRange(QuicPacketNumber(600), kSmallLargestObserved + 1);
 
   QuicFrames frames = {QuicFrame(&ack_frame)};
 
@@ -6610,7 +7684,7 @@
       0x00,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
       // type (short header, 4 byte packet number)
       0x43,
       // connection_id
@@ -6618,7 +7692,100 @@
       // packet number
       0x12, 0x34, 0x56, 0x78,
       // frame type (ack frame)
-      0x1a,
+      // (has ack blocks, 2 byte largest observed, 2 byte block length)
+      0x65,
+      // largest acked
+      0x12, 0x34,
+      // Zero delta time.
+      0x00, 0x00,
+      // num ack blocks ranges.
+      0xff,
+      // first ack block length.
+      0x0f, 0xdd,
+      // 255 = 4 * 63 + 3
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01,
+      // num timestamps.
+      0x00,
+  };
+
+  unsigned char packet99[] = {
+      // type (short header, 4 byte packet number)
+      0x43,
+      // connection_id
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
+      // frame type (IETF_ACK frame)
+      0x02,
       // largest acked
       kVarInt62TwoBytes + 0x12, 0x34,
       // Zero delta time.
@@ -6700,6 +7867,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -6848,7 +8018,7 @@
     0x05, 0x06, 0x07, 0x08,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short packet, 4 byte packet number)
     0x43,
     // connection_id
@@ -6859,6 +8029,25 @@
     // frame type (rst stream frame)
     0x01,
     // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // sent byte offset
+    0x08, 0x07, 0x06, 0x05,
+    0x04, 0x03, 0x02, 0x01,
+    // error code
+    0x05, 0x06, 0x07, 0x08,
+  };
+
+  unsigned char packet99[] = {
+    // type (short packet, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_RST_STREAM frame)
+    0x04,
+    // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // error code (not VarInt32 encoded)
     0x00, 0x01,
@@ -6877,6 +8066,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -6972,7 +8164,7 @@
     'n',
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -6983,6 +8175,27 @@
     // frame type (connection close frame)
     0x02,
     // error code
+    0x05, 0x06, 0x07, 0x08,
+    // error details length
+    0x00, 0x0d,
+    // error details
+    'b',  'e',  'c',  'a',
+    'u',  's',  'e',  ' ',
+    'I',  ' ',  'c',  'a',
+    'n',
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_CONNECTION_CLOSE frame)
+    0x1c,
+    // error code
     0x00, 0x11,
     // Frame type within the CONNECTION_CLOSE frame
     kVarInt62OneByte + 0x05,
@@ -7001,6 +8214,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -7180,7 +8396,7 @@
     'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -7191,6 +8407,55 @@
     // frame type (connection close frame)
     0x02,
     // error code
+    0x05, 0x06, 0x07, 0x08,
+    // error details length
+    0x01, 0x00,
+    // error details (truncated to 256 bytes)
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_CONNECTION_CLOSE frame)
+    0x1c,
+    // error code
     0x00, 0x0a,
     // Frame type within the CONNECTION_CLOSE frame
     kVarInt62OneByte + 0x00,
@@ -7237,6 +8502,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -7278,8 +8546,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (application close frame)
-    0x03,
+    // frame type (IETF_APPLICATION_CLOSE frame)
+    0x1d,
     // error code
     0x00, 0x11,
     // error details length
@@ -7326,8 +8594,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type
-    0x03,
+    // frame type (IETF_APPLICATION_CLOSE frame)
+    0x1d,
     // error code
     0x00, 0x11,
     // error details length
@@ -7464,11 +8732,37 @@
     'n',
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (go away frame)
+    0x03,
+    // error code
+    0x05, 0x06, 0x07, 0x08,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // error details length
+    0x00, 0x0d,
+    // error details
+    'b',  'e',  'c',  'a',
+    'u',  's',  'e',  ' ',
+    'I',  ' ',  'c',  'a',
+    'n',
+  };
+
   // clang-format on
 
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() > QUIC_VERSION_43) {
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -7653,11 +8947,65 @@
     'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
     'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
   };
+
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (go away frame)
+    0x03,
+    // error code
+    0x05, 0x06, 0x07, 0x08,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // error details length
+    0x01, 0x00,
+    // error details (truncated to 256 bytes)
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+    'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',
+  };
   // clang-format on
 
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() > QUIC_VERSION_43) {
+  if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -7736,6 +9084,23 @@
     0x55, 0x66, 0x77, 0x88,
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (window update frame)
+    0x04,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // byte offset
+    0x11, 0x22, 0x33, 0x44,
+    0x55, 0x66, 0x77, 0x88,
+  };
+
   unsigned char packet99[] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -7744,8 +9109,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (max stream data frame)
-    0x05,
+    // frame type (IETF_MAX_STREAM_DATA frame)
+    0x11,
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // byte offset
@@ -7762,6 +9127,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -7799,8 +9167,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (max stream data frame)
-    0x05,
+    // frame type (IETF_MAX_STREAM_DATA frame)
+    0x11,
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // byte offset
@@ -7843,8 +9211,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (max data frame)
-    0x04,
+    // frame type (IETF_MAX_DATA frame)
+    0x10,
     // byte offset
     kVarInt62EightBytes + 0x11, 0x22, 0x33, 0x44,
     0x55, 0x66, 0x77, 0x88,
@@ -7867,7 +9235,16 @@
   header.packet_number = kPacketNumber;
 
   QuicBlockedFrame blocked_frame;
-  blocked_frame.stream_id = kStreamId;
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    // For V99, the stream ID must be 0 for the frame
+    // to be a BLOCKED frame. if non-0, it will be a
+    // STREAM_BLOCKED frame.
+    // TODO(fkastenholz): This should be converted to use
+    // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value.
+    blocked_frame.stream_id = 0;
+  } else {
+    blocked_frame.stream_id = kStreamId;
+  }
   blocked_frame.offset = kStreamOffset;
 
   QuicFrames frames = {QuicFrame(&blocked_frame)};
@@ -7915,6 +9292,20 @@
     0x01, 0x02, 0x03, 0x04,
   };
 
+  unsigned char packet47[] = {
+    // type (short packet, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (blocked frame)
+    0x05,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+  };
+
   unsigned char packet99[] = {
     // type (short packet, 4 byte packet number)
     0x43,
@@ -7923,10 +9314,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type
-    0x09,
-    // stream id
-    kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
+    // frame type (IETF_BLOCKED frame) wahoo
+    0x14,
     // Offset
     kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54
   };
@@ -7940,6 +9329,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -7997,7 +9389,7 @@
     0x07,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -8008,11 +9400,25 @@
     // frame type
     0x07,
   };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_PING frame)
+    0x01,
+  };
   // clang-format on
 
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -8063,7 +9469,7 @@
     'm', 'e', 's', 's', 'a', 'g', 'e', '2'
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -8082,11 +9488,33 @@
     // Message Data
     'm', 'e', 's', 's', 'a', 'g', 'e', '2'
   };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_MESSAGE frame)
+    0x21,
+    // Length
+    0x07,
+    // Message Data
+    'm', 'e', 's', 's', 'a', 'g', 'e',
+    // frame type (message frame no length)
+    0x20,
+    // Message Data
+    'm', 'e', 's', 's', 'a', 'g', 'e', '2'
+  };
   // clang-format on
 
   unsigned char* p = packet45;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   }
 
   std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8152,7 +9580,7 @@
     0x00, 0x00, 0x00, 0x00
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -8166,6 +9594,21 @@
     0x00,
     0x00, 0x00, 0x00, 0x00
   };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_PING frame)
+    0x01,
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
   // clang-format on
 
   unsigned char* p = packet;
@@ -8173,6 +9616,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     packet_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    packet_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     packet_size = QUIC_ARRAYSIZE(packet44);
@@ -8196,6 +9642,49 @@
                                       data.length(), AsChars(p), packet_size);
 }
 
+// Test that the IETF connectivity probing packet is serialized correctly as a
+// padded PING packet, v99 only.
+TEST_P(QuicFramerTest, BuildIetfConnectivityProbingPacket) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPacketHeader header;
+  header.destination_connection_id = FramerTestConnectionId();
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+
+  unsigned char packet99[] = {// type (short header, 4 byte packet number)
+                              0x43,
+                              // connection_id
+                              0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+                              // packet number
+                              0x12, 0x34, 0x56, 0x78,
+
+                              // frame type (IETF_PING frame)
+                              0x01,
+                              // frame type (padding frame)
+                              0x00, 0x00, 0x00, 0x00, 0x00};
+  // clang-format on
+
+  unsigned char* p = packet99;
+  size_t packet_size = QUIC_ARRAYSIZE(packet99);
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+
+  size_t length = framer_.BuildIetfConnectivityProbingPacket(
+      header, buffer.get(), packet_size);
+
+  EXPECT_NE(0u, length);
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(p), packet_size);
+}
+
 // Test that the path challenge connectivity probing packet is serialized
 // correctly as a padded PATH CHALLENGE packet.
 TEST_P(QuicFramerTest, BuildPaddedPathChallengePacket) {
@@ -8219,8 +9708,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // Path Challenge Frame type
-    0x0e,
+    // Path Challenge Frame type (IETF_PATH_CHALLENGE)
+    0x1a,
     // 8 "random" bytes, MockRandom makes lots of r's
     'r', 'r', 'r', 'r', 'r', 'r', 'r', 'r',
     // frame type (padding frame)
@@ -8277,8 +9766,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // Path Challenge Frame type
-    0x0f,
+    // Path Response Frame type (IETF_PATH_RESPONSE)
+    0x1b,
     // 8 "random" bytes
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   };
@@ -8323,8 +9812,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // Path Challenge Frame type
-    0x0f,
+    // Path Response Frame type (IETF_PATH_RESPONSE)
+    0x1b,
     // 8 "random" bytes
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     // Padding type and pad
@@ -8375,10 +9864,10 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // 3 path challenge frames (type byte and payload)
-    0x0f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    0x0f, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-    0x0f, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    // 3 path response frames (IETF_PATH_RESPONSE type byte and payload)
+    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
   };
   // clang-format on
 
@@ -8428,10 +9917,10 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // 3 path challenge frames (type byte and payload)
-    0x0f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-    0x0f, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-    0x0f, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    // 3 path response frames (IETF_PATH_RESPONSE byte and payload)
+    0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x1b, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x1b, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
     // Padding
     0x00, 0x00, 0x00, 0x00, 0x00
   };
@@ -8503,7 +9992,7 @@
     0x07,
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -8514,6 +10003,18 @@
     // frame type
     0x07,
   };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_PING frame)
+    0x01,
+  };
   // clang-format on
 
   std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
@@ -8522,6 +10023,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -8784,6 +10287,21 @@
     'm',  'n',  'o',  'p',
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // redundancy
+    'a',  'b',  'c',  'd',
+    'e',  'f',  'g',  'h',
+    'i',  'j',  'k',  'l',
+    'm',  'n',  'o',  'p',
+  };
+
   unsigned char packet99[] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -8803,6 +10321,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -8877,6 +10397,25 @@
     'm',  'n',  'o',  'p',
   };
 
+  unsigned char packet47[] = {
+    // type (long header with packet type ZERO_RTT_PROTECTED)
+    0xD3,
+    // version tag
+    'Q', '.', '1', '0',
+    // connection_id length
+    0x50,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // redundancy
+    'a',  'b',  'c',  'd',
+    'e',  'f',  'g',  'h',
+    'i',  'j',  'k',  'l',
+    'm',  'n',  'o',  'p',
+  };
+
   unsigned char packet99[] = {
     // type (long header with packet type ZERO_RTT_PROTECTED)
     0xD3,
@@ -8900,6 +10439,8 @@
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -8954,10 +10495,10 @@
       QuicEncryptedPacket(buffer, encrypted_length, false)));
   ASSERT_EQ(1u, visitor_.ack_frames_.size());
   QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
-  EXPECT_EQ(600u, LargestAcked(processed_ack_frame));
+  EXPECT_EQ(QuicPacketNumber(600u), LargestAcked(processed_ack_frame));
   ASSERT_EQ(256u, processed_ack_frame.packets.NumPacketsSlow());
-  EXPECT_EQ(90u, processed_ack_frame.packets.Min());
-  EXPECT_EQ(600u, processed_ack_frame.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(90u), processed_ack_frame.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(600u), processed_ack_frame.packets.Max());
 }
 
 TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
@@ -8994,10 +10535,10 @@
       QuicEncryptedPacket(buffer, encrypted_length, false)));
   ASSERT_EQ(1u, visitor_.ack_frames_.size());
   QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
-  EXPECT_EQ(600u, LargestAcked(processed_ack_frame));
+  EXPECT_EQ(QuicPacketNumber(600u), LargestAcked(processed_ack_frame));
   ASSERT_EQ(240u, processed_ack_frame.packets.NumPacketsSlow());
-  EXPECT_EQ(122u, processed_ack_frame.packets.Min());
-  EXPECT_EQ(600u, processed_ack_frame.packets.Max());
+  EXPECT_EQ(QuicPacketNumber(122u), processed_ack_frame.packets.Min());
+  EXPECT_EQ(QuicPacketNumber(600u), processed_ack_frame.packets.Max());
 }
 
 TEST_P(QuicFramerTest, CleanTruncation) {
@@ -9158,6 +10699,43 @@
     0x9A, 0xBE,
   };
 
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (stream frame with fin)
+    0xFF,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data length
+    0x00, 0x0c,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+
+    // frame type (ack frame)
+    0x40,
+    // least packet number awaiting an ack
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xA0,
+    // largest observed packet number
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xBF,
+    // num missing packets
+    0x01,
+    // missing packet
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xBE,
+  };
+
   unsigned char packet99[] = {
     // type (short header, 4 byte packet number)
     0x43,
@@ -9166,8 +10744,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (stream frame with fin, length, and offset bits set)
-    0x10 | 0x01 | 0x02 | 0x04,
+    // frame type (IETF_STREAM frame with fin, length, and offset bits set)
+    0x08 | 0x01 | 0x02 | 0x04,
     // stream id
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // offset
@@ -9212,6 +10790,9 @@
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
     p_size = QUIC_ARRAYSIZE(packet44);
@@ -9411,7 +10992,7 @@
     'r',  'l',  'd',  '!',
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet47[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // packet number
@@ -9431,11 +11012,34 @@
     'o',  ' ',  'w',  'o',
     'r',  'l',  'd',  '!',
   };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_STREAM frame with fin, length, and offset bits set)
+    0x08 | 0x01 | 0x02 | 0x04,
+    // stream id
+    0x01, 0x02, 0x03, 0x04,
+    // offset
+    0x3A, 0x98, 0xFE, 0xDC,
+    0x32, 0x10, 0x76, 0x54,
+    // data length
+    0x00, 0x0c,
+    // data
+    'h',  'e',  'l',  'l',
+    'o',  ' ',  'w',  'o',
+    'r',  'l',  'd',  '!',
+  };
   // clang-format on
 
   unsigned char* p = packet;
   if (framer_.transport_version() == QUIC_VERSION_99) {
     p = packet99;
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet44;
   } else if (framer_.transport_version() != QUIC_VERSION_35) {
@@ -9457,7 +11061,7 @@
   iovec.iov_len = data.length();
   producer.SaveStreamData(
       QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iovec, 1, 0,
-      0, data.length());
+      data.length());
   for (size_t offset = 0; offset < 5; ++offset) {
     if (offset == 0 || offset == 4) {
       EXPECT_TRUE(framer_.StartsWithChlo(
@@ -9486,9 +11090,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (blocked)
+      // frame type (IETF_BLOCKED)
       {"",
-       {0x08}},
+       {0x14}},
       // blocked offset
       {"Can not read blocked offset.",
        {kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}},
@@ -9536,8 +11140,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (blocked)
-    0x08,
+    // frame type (IETF_BLOCKED)
+    0x14,
     // Offset
     kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54
   };
@@ -9568,9 +11172,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (blocked)
+      // frame type (IETF_STREAM_BLOCKED)
       {"",
-       {0x09}},
+       {0x15}},
       // blocked offset
       {"Can not read stream blocked stream id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -9621,8 +11225,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (blocked)
-    0x09,
+    // frame type (IETF_STREAM_BLOCKED)
+    0x15,
     // Stream ID
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // Offset
@@ -9655,9 +11259,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (max stream id)
+      // frame type (IETF_MAX_STREAM_ID)
       {"",
-       {0x06}},
+       {0x12}},
       // max. stream id
       {"Can not read MAX_STREAM_ID stream id.",
        {kVarInt62OneByte + 0x01}},
@@ -9704,8 +11308,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (max stream id frame)
-    0x06,
+    // frame type (IETF_MAX_STREAM_ID frame)
+    0x12,
     // Max stream id
     kVarInt62OneByte + 0x01
   };
@@ -9736,9 +11340,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (stream id blocked)
+      // frame type (IETF_STREAM_ID_BLOCKED frame)
       {"",
-       {0x0a}},
+       {0x16}},
       // stream id
       {"Can not read STREAM_ID_BLOCKED stream id.",
        {kVarInt62OneByte + 0x01}},
@@ -9785,8 +11389,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (stream id blocked frame)
-    0x0a,
+    // frame type (IETF_STREAM_ID_BLOCKED frame)
+    0x16,
     // Max stream id
     kVarInt62OneByte + 0x01
   };
@@ -9816,9 +11420,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (new connection id frame)
+      // frame type (IETF_NEW_CONNECTION_ID frame)
       {"",
-       {0x0b}},
+       {0x18}},
       // error code
       {"Unable to read new connection ID frame sequence number.",
        {kVarInt62OneByte + 0x11}},
@@ -9884,8 +11488,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (new connection id frame)
-    0x0b,
+    // frame type (IETF_NEW_CONNECTION_ID frame)
+    0x18,
     // sequence number
     kVarInt62OneByte + 0x11,
     // new connection id length
@@ -9922,9 +11526,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (new token frame)
+      // frame type (IETF_NEW_TOKEN frame)
       {"",
-       {0x19}},
+       {0x07}},
       // Length
       {"Unable to read new token length.",
        {kVarInt62OneByte + 0x08}},
@@ -9982,8 +11586,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (new token frame)
-    0x19,
+    // frame type (IETF_NEW_TOKEN frame)
+    0x07,
     // Length and token
     kVarInt62OneByte + 0x08,
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
@@ -10015,9 +11619,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (stop sending)
+      // frame type (IETF_STOP_SENDING frame)
       {"",
-       {0x0c}},
+       {0x05}},
       // stream id
       {"Unable to read stop sending stream id.",
        {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
@@ -10068,8 +11672,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (stop sending)
-    0x0c,
+    // frame type (IETF_STOP_SENDING frame)
+    0x05,
     // Stream ID
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // Application error code
@@ -10102,9 +11706,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (path challenge)
+      // frame type (IETF_PATH_CHALLENGE)
       {"",
-       {0x0e}},
+       {0x1a}},
       // data
       {"Can not read path challenge data.",
        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}},
@@ -10152,8 +11756,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (path challenge)
-    0x0e,
+    // frame type (IETF_PATH_CHALLENGE)
+    0x1a,
     // Data
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
   };
@@ -10184,9 +11788,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x9A, 0xBC}},
-      // frame type (path response)
+      // frame type (IETF_PATH_RESPONSE)
       {"",
-       {0x0f}},
+       {0x1b}},
       // data
       {"Can not read path response data.",
        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}},
@@ -10234,8 +11838,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (path response)
-    0x0f,
+    // frame type (IETF_PATH_RESPONSE)
+    0x1b,
     // Data
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
   };
@@ -10978,9 +12582,9 @@
       // packet number
       {"",
        {0x12, 0x34, 0x56, 0x78}},
-      // frame type (retire connection id frame)
+      // frame type (IETF_RETIRE_CONNECTION_ID frame)
       {"",
-       {0x0d}},
+       {0x19}},
       // Sequence number
       {"Unable to read retire connection ID frame sequence number.",
        {kVarInt62TwoBytes + 0x11, 0x22}}
@@ -11031,8 +12635,8 @@
     // packet number
     0x12, 0x34, 0x56, 0x78,
 
-    // frame type (retire connection id frame)
-    0x0d,
+    // frame type (IETF_RETIRE_CONNECTION_ID frame)
+    0x19,
     // sequence number
     kVarInt62TwoBytes + 0x11, 0x22
   };
@@ -11046,6 +12650,444 @@
                                       QUIC_ARRAYSIZE(packet99));
 }
 
+TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) {
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78, 0x56, 0x34, 0x12,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x00,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x00,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet39[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x00,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x00,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet44[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x00,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x00,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x00,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x00,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_ACK frame)
+    0x02,
+    // Largest acked
+    kVarInt62OneByte + 0x00,
+    // Zero delta time.
+    kVarInt62OneByte + 0x00,
+    // Ack block count 0
+    kVarInt62OneByte + 0x00,
+    // First ack block length
+    kVarInt62OneByte + 0x00,
+  };
+  // clang-format on
+
+  unsigned char* p = packet;
+  size_t p_size = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
+    p = packet44;
+    p_size = QUIC_ARRAYSIZE(packet44);
+  } else if (framer_.transport_version() != QUIC_VERSION_35) {
+    p = packet39;
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
+  if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      framer_.transport_version() != QUIC_VERSION_99) {
+    EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+    return;
+  }
+  EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+  EXPECT_EQ(framer_.detailed_error(), "Largest acked is 0.");
+}
+
+TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) {
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78, 0x56, 0x34, 0x12,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x02, 0x00,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x03, 0x00,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet39[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x02,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x03,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet44[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x02,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x03,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x45,
+    // largest observed
+    0x00, 0x02,
+    // Zero delta time.
+    0x00, 0x00,
+    // first ack block length.
+    0x00, 0x03,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_ACK frame)
+    0x02,
+    // Largest acked
+    kVarInt62OneByte + 0x02,
+    // Zero delta time.
+    kVarInt62OneByte + 0x00,
+    // Ack block count 0
+    kVarInt62OneByte + 0x00,
+    // First ack block length
+    kVarInt62OneByte + 0x02,
+  };
+  // clang-format on
+
+  unsigned char* p = packet;
+  size_t p_size = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
+    p = packet44;
+    p_size = QUIC_ARRAYSIZE(packet44);
+  } else if (framer_.transport_version() != QUIC_VERSION_35) {
+    p = packet39;
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
+  if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      framer_.transport_version() != QUIC_VERSION_99) {
+    EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+    return;
+  }
+  EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+  EXPECT_EQ(framer_.detailed_error(),
+            "Underflow with first ack block length 3 largest acked is 2.");
+}
+
+TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) {
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x78, 0x56, 0x34, 0x12,
+
+    // frame type (ack frame)
+    0x60,
+    // largest observed
+    0x0A,
+    // Zero delta time.
+    0x00, 0x00,
+    // Num of ack blocks
+    0x02,
+    // first ack block length.
+    0x02,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x01,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x06,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet39[] = {
+    // public flags (8 byte connection_id)
+    0x2C,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x60,
+    // largest observed
+    0x0A,
+    // Zero delta time.
+    0x00, 0x00,
+    // Num of ack blocks
+    0x02,
+    // first ack block length.
+    0x02,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x01,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x06,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet44[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x60,
+    // largest observed
+    0x0A,
+    // Zero delta time.
+    0x00, 0x00,
+    // Num of ack blocks
+    0x02,
+    // first ack block length.
+    0x02,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x01,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x06,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet47[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (ack frame)
+    0x60,
+    // largest observed
+    0x0A,
+    // Zero delta time.
+    0x00, 0x00,
+    // Num of ack blocks
+    0x02,
+    // first ack block length.
+    0x02,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x01,
+    // gap to next block
+    0x01,
+    // ack block length
+    0x06,
+    // num timestamps.
+    0x00
+  };
+
+  unsigned char packet99[] = {
+    // type (short header, 4 byte packet number)
+    0x43,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // frame type (IETF_ACK frame)
+    0x02,
+    // Largest acked
+    kVarInt62OneByte + 0x0A,
+    // Zero delta time.
+    kVarInt62OneByte + 0x00,
+    // Ack block count 2
+    kVarInt62OneByte + 0x02,
+    // First ack block length
+    kVarInt62OneByte + 0x01,
+    // gap to next block length
+    kVarInt62OneByte + 0x00,
+    // ack block length
+    kVarInt62OneByte + 0x00,
+    // gap to next block length
+    kVarInt62OneByte + 0x00,
+    // ack block length
+    kVarInt62OneByte + 0x05,
+  };
+  // clang-format on
+
+  unsigned char* p = packet;
+  size_t p_size = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() > QUIC_VERSION_46) {
+    p = packet47;
+    p_size = QUIC_ARRAYSIZE(packet47);
+  } else if (framer_.transport_version() > QUIC_VERSION_43) {
+    p = packet44;
+    p_size = QUIC_ARRAYSIZE(packet44);
+  } else if (framer_.transport_version() != QUIC_VERSION_35) {
+    p = packet39;
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_size, false);
+  if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) &&
+      framer_.transport_version() != QUIC_VERSION_99) {
+    EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+    return;
+  }
+  EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    EXPECT_EQ(framer_.detailed_error(),
+              "Underflow with ack block length 6 latest ack block end is 5.");
+  } else {
+    EXPECT_EQ(framer_.detailed_error(),
+              "Underflow with ack block length 6, end of block is 6.");
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc
index 2e10b61..d35800a 100644
--- a/quic/core/quic_ietf_framer_test.cc
+++ b/quic/core/quic_ietf_framer_test.cc
@@ -623,6 +623,39 @@
   }
 }
 
+TEST_F(QuicIetfFramerTest, CryptoFrame) {
+  SimpleDataProducer data_producer;
+  framer_.set_data_producer(&data_producer);
+  char packet_buffer[kNormalPacketBufferSize];
+
+  QuicStringPiece frame_data("This is a CRYPTO frame.");
+
+  QuicStreamOffset offsets[] = {kOffset8, kOffset4, kOffset2, kOffset1,
+                                kOffset0};
+  for (QuicStreamOffset offset : offsets) {
+    QuicCryptoFrame frame(ENCRYPTION_NONE, offset, frame_data.length());
+    data_producer.SaveCryptoData(ENCRYPTION_NONE, offset, frame_data);
+
+    QuicDataWriter writer(QUIC_ARRAYSIZE(packet_buffer), packet_buffer,
+                          NETWORK_BYTE_ORDER);
+
+    // Write the frame.
+    EXPECT_TRUE(QuicFramerPeer::AppendCryptoFrame(&framer_, frame, &writer));
+    EXPECT_NE(0u, writer.length());
+    // Read it back.
+    QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
+    QuicCryptoFrame read_frame;
+    EXPECT_TRUE(
+        QuicFramerPeer::ProcessCryptoFrame(&framer_, &reader, &read_frame));
+
+    // Check that the frames match:
+    QuicStringPiece read_data(read_frame.data_buffer, read_frame.data_length);
+    EXPECT_EQ(read_frame.data_length, frame.data_length);
+    EXPECT_EQ(read_frame.offset, frame.offset);
+    EXPECT_EQ(read_data, frame_data);
+  }
+}
+
 TEST_F(QuicIetfFramerTest, ConnectionCloseEmptyString) {
   char packet_buffer[kNormalPacketBufferSize];
 
@@ -695,35 +728,187 @@
 // Testing for the IETF ACK framer.
 // clang-format off
 struct ack_frame ack_frame_variants[] = {
-  { 90000, false, 0, 0, 0, {{1000, 2001}}, IETF_ACK },
-  { 0, false, 0, 0, 0, {{1000, 2001}}, IETF_ACK },
-  { 1, false, 0, 0, 0, {{1, 2}, {5, 6}}, IETF_ACK },
-  { 63, false, 0, 0, 0, {{1, 2}, {5, 6}}, IETF_ACK },
-  { 64, false, 0, 0, 0, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}},
-    IETF_ACK},
-  { 10000, false, 0, 0, 0, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}},
-    IETF_ACK},
-  { 100000000, false, 0, 0, 0,
-    {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}},
-    IETF_ACK},
-  { 0, false, 0, 0, 0, {{1, 65}}, IETF_ACK },
-  { 9223372036854775807, false, 0, 0, 0, {{1, 11}, {74, 138}}, IETF_ACK },
-  // This ack is for packets 60 & 125. There are 64 packets in the gap.
-  // The encoded value is gap_size - 1, or 63. Crosses a VarInt62 encoding
-  // boundary...
-  { 1, false, 0, 0, 0, {{60, 61}, {125, 126}}, IETF_ACK },
-  { 2, false, 0, 0, 0, {{ 1, 65}, {129, 130}}, IETF_ACK },
-  { 3, false, 0, 0, 0, {{ 1, 65}, {129, 195}}, IETF_ACK },
-  { 4, false, 0, 0, 0, {{ 1, 65}, {129, 194}}, IETF_ACK },
-  { 5, false, 0, 0, 0, {{ 1, 65}, {129, 193}}, IETF_ACK },
-  { 6, false, 0, 0, 0, {{ 1, 65}, {129, 192}}, IETF_ACK },
-  // declare some ack_ecn frames to try.
-  { 6, false, 100, 200, 300, {{ 1, 65}, {129, 192}}, IETF_ACK },
-  { 6, true, 100, 200, 300, {{ 1, 65}, {129, 192}}, IETF_ACK_ECN },
-  { 6, true, 100, 0, 0, {{ 1, 65}, {129, 192}}, IETF_ACK_ECN },
-  { 6, true, 0, 200, 0, {{ 1, 65}, {129, 192}}, IETF_ACK_ECN },
-  { 6, true, 0, 0, 300, {{ 1, 65}, {129, 192}}, IETF_ACK_ECN },
-  { 6, true, 0, 0, 0, {{ 1, 65}, {129, 192}}, IETF_ACK },
+    {90000,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1000), QuicPacketNumber(2001)}},
+     IETF_ACK},
+    {0,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1000), QuicPacketNumber(2001)}},
+     IETF_ACK},
+    {1,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(2)},
+      {QuicPacketNumber(5), QuicPacketNumber(6)}},
+     IETF_ACK},
+    {63,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(2)},
+      {QuicPacketNumber(5), QuicPacketNumber(6)}},
+     IETF_ACK},
+    {64,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(2)},
+      {QuicPacketNumber(3), QuicPacketNumber(4)},
+      {QuicPacketNumber(5), QuicPacketNumber(6)},
+      {QuicPacketNumber(7), QuicPacketNumber(8)},
+      {QuicPacketNumber(9), QuicPacketNumber(10)},
+      {QuicPacketNumber(11), QuicPacketNumber(12)}},
+     IETF_ACK},
+    {10000,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(2)},
+      {QuicPacketNumber(3), QuicPacketNumber(4)},
+      {QuicPacketNumber(5), QuicPacketNumber(6)},
+      {QuicPacketNumber(7), QuicPacketNumber(8)},
+      {QuicPacketNumber(9), QuicPacketNumber(10)},
+      {QuicPacketNumber(11), QuicPacketNumber(12)}},
+     IETF_ACK},
+    {100000000,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(2)},
+      {QuicPacketNumber(3), QuicPacketNumber(4)},
+      {QuicPacketNumber(5), QuicPacketNumber(6)},
+      {QuicPacketNumber(7), QuicPacketNumber(8)},
+      {QuicPacketNumber(9), QuicPacketNumber(10)},
+      {QuicPacketNumber(11), QuicPacketNumber(12)}},
+     IETF_ACK},
+    {0,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)}},
+     IETF_ACK},
+    {9223372036854775807,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(11)},
+      {QuicPacketNumber(74), QuicPacketNumber(138)}},
+     IETF_ACK},
+    // This ack is for packets 60 & 125. There are 64 packets in the gap.
+    // The encoded value is gap_size - 1, or 63. Crosses a VarInt62 encoding
+    // boundary...
+    {1,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(60), QuicPacketNumber(61)},
+      {QuicPacketNumber(125), QuicPacketNumber(126)}},
+     IETF_ACK},
+    {2,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(130)}},
+     IETF_ACK},
+    {3,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(195)}},
+     IETF_ACK},
+    {4,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(194)}},
+     IETF_ACK},
+    {5,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(193)}},
+     IETF_ACK},
+    {6,
+     false,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK},
+    // declare some ack_ecn frames to try.
+    {6,
+     false,
+     100,
+     200,
+     300,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK},
+    {6,
+     true,
+     100,
+     200,
+     300,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK_ECN},
+    {6,
+     true,
+     100,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK_ECN},
+    {6,
+     true,
+     0,
+     200,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK_ECN},
+    {6,
+     true,
+     0,
+     0,
+     300,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK_ECN},
+    {6,
+     true,
+     0,
+     0,
+     0,
+     {{QuicPacketNumber(1), QuicPacketNumber(65)},
+      {QuicPacketNumber(129), QuicPacketNumber(192)}},
+     IETF_ACK},
 };
 // clang-format on
 
@@ -749,7 +934,7 @@
                         NETWORK_BYTE_ORDER);
 
   QuicAckFrame transmit_frame;
-  transmit_frame.largest_acked = 1;
+  transmit_frame.largest_acked = QuicPacketNumber(1);
   transmit_frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(0);
 
   size_t expected_size =
@@ -759,7 +944,7 @@
       &framer_, transmit_frame, &writer));
 
   uint8_t packet[] = {
-      0x1a,  // type
+      0x02,  // type, IETF_ACK
       0x01,  // largest_acked,
       0x00,  // delay
       0x00,  // count of additional ack blocks
diff --git a/quic/core/quic_lru_cache.h b/quic/core/quic_lru_cache.h
index 12e140b..b8c78c6 100644
--- a/quic/core/quic_lru_cache.h
+++ b/quic/core/quic_lru_cache.h
@@ -10,7 +10,6 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_lru_cache.h"
 
 namespace quic {
 
@@ -18,13 +17,12 @@
 // This cache CANNOT be shared by multiple threads (even with locks) because
 // Value* returned by Lookup() can be invalid if the entry is evicted by other
 // threads.
-// TODO(vasilvv): rename this class when quic_new_lru_cache flag is deprecated.
 template <class K, class V>
-class QuicLRUCacheNew {
+class QuicLRUCache {
  public:
-  explicit QuicLRUCacheNew(size_t capacity) : capacity_(capacity) {}
-  QuicLRUCacheNew(const QuicLRUCacheNew&) = delete;
-  QuicLRUCacheNew& operator=(const QuicLRUCacheNew&) = delete;
+  explicit QuicLRUCache(size_t capacity) : capacity_(capacity) {}
+  QuicLRUCache(const QuicLRUCache&) = delete;
+  QuicLRUCache& operator=(const QuicLRUCache&) = delete;
 
   // Inserts one unit of |key|, |value| pair to the cache. Cache takes ownership
   // of inserted |value|.
@@ -45,7 +43,6 @@
   // value is guaranteed to be valid until Insert or Clear.
   // Else return nullptr.
   V* Lookup(const K& key) {
-    QUIC_RELOADABLE_FLAG_COUNT(quic_new_lru_cache);
     auto it = cache_.find(key);
     if (it == cache_.end()) {
       return nullptr;
@@ -72,63 +69,6 @@
   const size_t capacity_;
 };
 
-// TODO(vasilvv): remove this class when quic_new_lru_cache flag is deprecated.
-template <class K, class V>
-class QuicLRUCache {
- public:
-  explicit QuicLRUCache(size_t capacity)
-      : QuicLRUCache(capacity, GetQuicReloadableFlag(quic_new_lru_cache)) {}
-  QuicLRUCache(size_t capacity, bool use_new)
-      : new_(capacity), old_(capacity), use_new_(use_new) {}
-  QuicLRUCache(const QuicLRUCache&) = delete;
-  QuicLRUCache& operator=(const QuicLRUCache&) = delete;
-
-  void Insert(const K& key, std::unique_ptr<V> value) {
-    if (use_new_) {
-      new_.Insert(key, std::move(value));
-    } else {
-      old_.Insert(key, std::move(value));
-    }
-  }
-
-  V* Lookup(const K& key) {
-    if (use_new_) {
-      return new_.Lookup(key);
-    } else {
-      return old_.Lookup(key);
-    }
-  }
-
-  void Clear() {
-    if (use_new_) {
-      new_.Clear();
-    } else {
-      old_.Clear();
-    }
-  }
-
-  size_t MaxSize() const {
-    if (use_new_) {
-      return new_.MaxSize();
-    } else {
-      return old_.MaxSize();
-    }
-  }
-
-  size_t Size() const {
-    if (use_new_) {
-      return new_.Size();
-    } else {
-      return old_.Size();
-    }
-  }
-
- private:
-  QuicLRUCacheNew<K, V> new_;
-  QuicLRUCacheOld<K, V> old_;
-  bool use_new_;
-};
-
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_QUIC_LRU_CACHE_H_
diff --git a/quic/core/quic_lru_cache_test.cc b/quic/core/quic_lru_cache_test.cc
index c335d5b..92f788b 100644
--- a/quic/core/quic_lru_cache_test.cc
+++ b/quic/core/quic_lru_cache_test.cc
@@ -16,12 +16,8 @@
   uint32_t value;
 };
 
-class QuicLRUCacheTest : public QuicTestWithParam<bool> {};
-
-INSTANTIATE_TEST_CASE_P(QuicLRUCacheTests, QuicLRUCacheTest, testing::Bool());
-
-TEST_P(QuicLRUCacheTest, InsertAndLookup) {
-  QuicLRUCache<int, CachedItem> cache(5, GetParam());
+TEST(QuicLRUCacheTest, InsertAndLookup) {
+  QuicLRUCache<int, CachedItem> cache(5);
   EXPECT_EQ(nullptr, cache.Lookup(1));
   EXPECT_EQ(0u, cache.Size());
   EXPECT_EQ(5u, cache.MaxSize());
@@ -48,8 +44,8 @@
   EXPECT_EQ(0u, cache.Size());
 }
 
-TEST_P(QuicLRUCacheTest, Eviction) {
-  QuicLRUCache<int, CachedItem> cache(3, GetParam());
+TEST(QuicLRUCacheTest, Eviction) {
+  QuicLRUCache<int, CachedItem> cache(3);
 
   for (size_t i = 1; i <= 4; ++i) {
     std::unique_ptr<CachedItem> item(new CachedItem(10 + i));
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 7f48c74..cc4f50e 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -49,7 +49,12 @@
       connection_id_length_(PACKET_8BYTE_CONNECTION_ID),
       packet_size_(0),
       connection_id_(connection_id),
-      packet_(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, false),
+      packet_(QuicPacketNumber(),
+              PACKET_1BYTE_PACKET_NUMBER,
+              nullptr,
+              0,
+              false,
+              false),
       long_header_type_(HANDSHAKE),
       pending_padding_bytes_(0),
       needs_full_padding_(false),
@@ -120,11 +125,11 @@
   }
 
   DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1);
-  const QuicPacketNumber current_delta =
+  const uint64_t current_delta =
       packet_.packet_number + 1 - least_packet_awaited_by_peer;
   const uint64_t delta = std::max(current_delta, max_packets_in_flight);
   packet_.packet_number_length = QuicFramer::GetMinPacketNumberLength(
-      framer_->transport_version(), delta * 4);
+      framer_->transport_version(), QuicPacketNumber(delta * 4));
 }
 
 bool QuicPacketCreator::ConsumeData(QuicStreamId id,
@@ -334,14 +339,14 @@
   packet_.has_stop_waiting = false;
   packet_.has_crypto_handshake = NOT_HANDSHAKE;
   packet_.num_padding_bytes = 0;
-  packet_.original_packet_number = kInvalidPacketNumber;
+  packet_.original_packet_number.Clear();
   if (!can_set_transmission_type_ || ShouldSetTransmissionTypeForNextFrame()) {
     packet_.transmission_type = NOT_RETRANSMISSION;
   }
   packet_.encrypted_buffer = nullptr;
   packet_.encrypted_length = 0;
   DCHECK(packet_.retransmittable_frames.empty());
-  packet_.largest_acked = kInvalidPacketNumber;
+  packet_.largest_acked.Clear();
   needs_full_padding_ = false;
 }
 
@@ -655,8 +660,8 @@
 
 // TODO(b/74062209): Make this a public method of framer?
 SerializedPacket QuicPacketCreator::NoPacket() {
-  return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false,
-                          false);
+  return SerializedPacket(QuicPacketNumber(), PACKET_1BYTE_PACKET_NUMBER,
+                          nullptr, 0, false, false);
 }
 
 QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength()
@@ -699,7 +704,12 @@
   } else {
     header->nonce = nullptr;
   }
-  header->packet_number = ++packet_.packet_number;
+  if (!packet_.packet_number.IsInitialized()) {
+    packet_.packet_number = framer_->first_sending_packet_number();
+  } else {
+    ++packet_.packet_number;
+  }
+  header->packet_number = packet_.packet_number;
   header->packet_number_length = GetPacketNumberLength();
   if (!HasIetfLongHeader()) {
     return;
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 0ea9b13..5dd4abb 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -91,8 +91,7 @@
     // Save data before data is consumed.
     QuicByteCount data_length = total_length - iov_offset;
     if (data_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, iov_offset, offset,
-                                data_length);
+      producer_->SaveStreamData(id, iov, iov_count, iov_offset, data_length);
     }
     return QuicPacketCreator::ConsumeData(id, data_length, iov_offset, offset,
                                           fin, needs_full_padding,
@@ -228,9 +227,10 @@
       int num_padding_bytes,
       EncryptionLevel encryption_level,
       QuicPacketNumberLength packet_number_length) {
-    return QuicPendingRetransmission(
-        1u, NOT_RETRANSMISSION, retransmittable_frames, has_crypto_handshake,
-        num_padding_bytes, encryption_level, packet_number_length);
+    return QuicPendingRetransmission(QuicPacketNumber(1u), NOT_RETRANSMISSION,
+                                     retransmittable_frames,
+                                     has_crypto_handshake, num_padding_bytes,
+                                     encryption_level, packet_number_length);
   }
 
   bool IsDefaultTestConfiguration() {
@@ -269,7 +269,7 @@
   for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
     EncryptionLevel level = static_cast<EncryptionLevel>(i);
     creator_.set_encryption_level(level);
-    frames_.push_back(QuicFrame(new QuicAckFrame()));
+    frames_.push_back(QuicFrame(new QuicAckFrame(InitAckFrame(1))));
     frames_.push_back(QuicFrame(QuicStreamFrame(
         QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), false,
         0u, QuicStringPiece())));
@@ -290,21 +290,11 @@
       EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
       EXPECT_CALL(framer_visitor_, OnAckFrameStart(_, _))
           .WillOnce(Return(true));
-      // This test includes an ack frame with largest_acked == 0 and
-      // the size of the first ack-block == 1 (serialized as
-      // 0). This is an invalid format for pre-version99, valid
-      // for version 99.
-      if (client_framer_.transport_version() != QUIC_VERSION_99) {
-        // pre-version 99; ensure that the error is gracefully
-        // handled.
-        EXPECT_CALL(framer_visitor_, OnAckRange(1, 1)).WillOnce(Return(true));
-        EXPECT_CALL(framer_visitor_, OnAckFrameEnd(1)).WillOnce(Return(true));
-      } else {
-        // version 99; ensure that the correct packet is signalled
-        // properly.
-        EXPECT_CALL(framer_visitor_, OnAckRange(0, 1)).WillOnce(Return(true));
-        EXPECT_CALL(framer_visitor_, OnAckFrameEnd(0)).WillOnce(Return(true));
-      }
+      EXPECT_CALL(framer_visitor_,
+                  OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)))
+          .WillOnce(Return(true));
+      EXPECT_CALL(framer_visitor_, OnAckFrameEnd(QuicPacketNumber(1)))
+          .WillOnce(Return(true));
       EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
       EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
       EXPECT_CALL(framer_visitor_, OnPacketComplete());
@@ -394,7 +384,7 @@
   MakeIOVector("fake handshake message data", &iov_);
   producer_.SaveStreamData(
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
-      1u, 0u, 0u, iov_.iov_len);
+      1u, 0u, iov_.iov_len);
   QuicPacketCreatorPeer::CreateStreamFrame(
       &creator_,
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
@@ -417,7 +407,7 @@
   MakeIOVector("fake message data", &iov_);
   producer_.SaveStreamData(
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
-      1u, 0u, 0u, iov_.iov_len);
+      1u, 0u, iov_.iov_len);
   QuicPacketCreatorPeer::CreateStreamFrame(
       &creator_,
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
@@ -483,7 +473,7 @@
     SimpleDataProducer producer;
     producer.SaveStreamData(
         QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
-        1u, 0u, 0u, iov_.iov_len);
+        1u, 0u, iov_.iov_len);
     QuicPacketCreatorPeer::framer(&creator_)->set_data_producer(&producer);
     QuicPacketCreatorPeer::CreateStreamFrame(
         &creator_,
@@ -523,8 +513,8 @@
   frames.push_back(QuicFrame(&frame));
   SerializedPacket serialized = SerializeAllFrames(frames);
   EXPECT_EQ(ENCRYPTION_NONE, serialized.encryption_level);
-  ASSERT_EQ(1u, serialized.packet_number);
-  ASSERT_EQ(1u, creator_.packet_number());
+  ASSERT_EQ(QuicPacketNumber(1u), serialized.packet_number);
+  ASSERT_EQ(QuicPacketNumber(1u), creator_.packet_number());
 
   InSequence s;
   EXPECT_CALL(framer_visitor_, OnPacket());
@@ -1026,28 +1016,33 @@
   }
 
   QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64);
-  creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(2),
+                                    10000 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
   QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256);
-  creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(2),
+                                    10000 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
   QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 * 256);
-  creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(2),
+                                    10000 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
   QuicPacketCreatorPeer::SetPacketNumber(&creator_,
                                          UINT64_C(64) * 256 * 256 * 256 * 256);
-  creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(2),
+                                    10000 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 }
 
 TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
+  QuicPacketCreatorPeer::SetPacketNumber(&creator_, 1);
   if (GetParam().version.transport_version > QUIC_VERSION_43 &&
       GetParam().version.transport_version != QUIC_VERSION_99) {
     EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
@@ -1058,21 +1053,24 @@
               QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
   }
 
-  creator_.UpdatePacketNumberLength(1, 10000 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(1),
+                                    10000 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
-  creator_.UpdatePacketNumberLength(1, 10000 * 256 / kDefaultMaxPacketSize);
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(1),
+                                    10000 * 256 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
-  creator_.UpdatePacketNumberLength(1,
+  creator_.UpdatePacketNumberLength(QuicPacketNumber(1),
                                     10000 * 256 * 256 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 
   creator_.UpdatePacketNumberLength(
-      1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
+      QuicPacketNumber(1),
+      UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
   EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
             QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
 }
@@ -1191,7 +1189,7 @@
   ASSERT_EQ(1u, retransmittable.size());
   EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
   EXPECT_TRUE(serialized_packet_.has_ack);
-  EXPECT_EQ(10u, serialized_packet_.largest_acked);
+  EXPECT_EQ(QuicPacketNumber(10u), serialized_packet_.largest_acked);
   DeleteSerializedPacket();
 
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -1217,7 +1215,7 @@
   MakeIOVector("test", &iov_);
   producer_.SaveStreamData(
       QuicUtils::GetHeadersStreamId(client_framer_.transport_version()), &iov_,
-      1u, 0u, 0u, iov_.iov_len);
+      1u, 0u, iov_.iov_len);
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
   size_t num_bytes_consumed;
@@ -1357,7 +1355,7 @@
   MakeIOVector("fake handshake message data", &iov_);
   producer_.SaveStreamData(
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
-      1u, 0u, 0u, iov_.iov_len);
+      1u, 0u, iov_.iov_len);
   QuicPacketCreatorPeer::CreateStreamFrame(
       &creator_,
       QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
@@ -1476,7 +1474,9 @@
 // failure. While this test is not applicable to versions other than version 99,
 // it should still work. Hence, it is not made version-specific.
 TEST_P(QuicPacketCreatorTest, IetfAckGapErrorRegression) {
-  QuicAckFrame ack_frame = InitAckFrame({{60, 61}, {125, 126}});
+  QuicAckFrame ack_frame =
+      InitAckFrame({{QuicPacketNumber(60), QuicPacketNumber(61)},
+                    {QuicPacketNumber(125), QuicPacketNumber(126)}});
   frames_.push_back(QuicFrame(&ack_frame));
   SerializeAllFrames(frames_);
 }
@@ -1563,7 +1563,7 @@
   creator_.set_can_set_transmission_type(true);
   creator_.SetTransmissionType(NOT_RETRANSMISSION);
 
-  QuicAckFrame temp_ack_frame;
+  QuicAckFrame temp_ack_frame = InitAckFrame(1);
   QuicFrame ack_frame(&temp_ack_frame);
   ASSERT_FALSE(QuicUtils::IsRetransmittableFrame(ack_frame.type));
 
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc
index 5c1c330..12978a3 100644
--- a/quic/core/quic_packet_generator.cc
+++ b/quic/core/quic_packet_generator.cc
@@ -26,7 +26,8 @@
       flusher_attached_(false),
       should_send_ack_(false),
       should_send_stop_waiting_(false),
-      random_generator_(random_generator) {}
+      random_generator_(random_generator),
+      fully_pad_crypto_handshake_packets_(true) {}
 
 QuicPacketGenerator::~QuicPacketGenerator() {
   DeleteFrames(&queued_control_frames_);
@@ -93,10 +94,13 @@
                                HAS_RETRANSMITTABLE_DATA,
                                has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
     QuicFrame frame;
+    bool needs_full_padding =
+        has_handshake && fully_pad_crypto_handshake_packets_;
+
     if (!packet_creator_.ConsumeData(id, write_length, total_bytes_consumed,
                                      offset + total_bytes_consumed, fin,
-                                     has_handshake, next_transmission_type_,
-                                     &frame)) {
+                                     needs_full_padding,
+                                     next_transmission_type_, &frame)) {
       // The creator is always flushed if there's not enough room for a new
       // stream frame before ConsumeData, so ConsumeData should always succeed.
       QUIC_BUG << "Failed to ConsumeData, stream:" << id;
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h
index 18e102c..572d170 100644
--- a/quic/core/quic_packet_generator.h
+++ b/quic/core/quic_packet_generator.h
@@ -221,6 +221,14 @@
 
   bool should_send_ack() const { return should_send_ack_; }
 
+  void set_fully_pad_crypto_hadshake_packets(bool new_value) {
+    fully_pad_crypto_handshake_packets_ = new_value;
+  }
+
+  bool fully_pad_crypto_handshake_packets() const {
+    return fully_pad_crypto_handshake_packets_;
+  }
+
  private:
   friend class test::QuicPacketGeneratorPeer;
 
@@ -265,6 +273,9 @@
   QuicStopWaitingFrame pending_stop_waiting_frame_;
 
   QuicRandom* random_generator_;
+
+  // Whether crypto handshake packets should be fully padded.
+  bool fully_pad_crypto_handshake_packets_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_packet_generator_test.cc b/quic/core/quic_packet_generator_test.cc
index b824a5c..b85a4f7 100644
--- a/quic/core/quic_packet_generator_test.cc
+++ b/quic/core/quic_packet_generator_test.cc
@@ -121,7 +121,7 @@
                                        bool fin) {
     // Save data before data is consumed.
     if (total_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, 0, offset, total_length);
+      producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
     }
     return QuicPacketGenerator::ConsumeDataFastPath(id, total_length, offset,
                                                     fin, 0);
@@ -135,7 +135,7 @@
                                StreamSendingState state) {
     // Save data before data is consumed.
     if (total_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, 0, offset, total_length);
+      producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
     }
     return QuicPacketGenerator::ConsumeData(id, total_length, offset, state);
   }
@@ -154,7 +154,8 @@
                    &random_generator_,
                    &delegate_,
                    &producer_),
-        creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {
+        creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)),
+        ack_frame_(InitAckFrame(1)) {
     EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
     creator_->SetEncrypter(
         ENCRYPTION_FORWARD_SECURE,
@@ -470,6 +471,35 @@
   EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
 }
 
+// Test the behavior of ConsumeData when the data is for the crypto handshake
+// stream, but padding is disabled.
+TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) {
+  generator_.set_fully_pad_crypto_hadshake_packets(false);
+
+  delegate_.SetCanWriteAnything();
+
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+  MakeIOVector("foo", &iov_);
+  QuicConsumedData consumed = generator_.ConsumeData(
+      QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iov_, 1u,
+      iov_.iov_len, 0, NO_FIN);
+  EXPECT_EQ(3u, consumed.bytes_consumed);
+  EXPECT_FALSE(generator_.HasQueuedFrames());
+  EXPECT_FALSE(generator_.HasRetransmittableFrames());
+
+  PacketContents contents;
+  contents.num_stream_frames = 1;
+  contents.num_padding_frames = 0;
+  CheckPacketContains(contents, 0);
+
+  ASSERT_EQ(1u, packets_.size());
+
+  // Packet is not fully padded, but we want to future packets to be larger.
+  ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength());
+  EXPECT_EQ(27, packets_[0].encrypted_length);
+}
+
 TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
   EXPECT_QUIC_BUG(generator_.ConsumeData(QuicUtils::GetHeadersStreamId(
                                              framer_.transport_version()),
@@ -829,7 +859,7 @@
   QuicConsumedData consumed =
       generator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
   EXPECT_EQ(data_len, consumed.bytes_consumed);
-  ASSERT_EQ(0, creator_->BytesFree())
+  ASSERT_EQ(0u, creator_->BytesFree())
       << "Test setup failed: Please increase data_len to "
       << data_len + creator_->BytesFree() << " bytes.";
 
@@ -846,9 +876,9 @@
   EXPECT_EQ(data_len, consumed.bytes_consumed);
 
   // Ensure the packet is successfully created.
-  ASSERT_EQ(1, packets_.size());
+  ASSERT_EQ(1u, packets_.size());
   ASSERT_TRUE(packets_[0].encrypted_buffer);
-  ASSERT_EQ(1, packets_[0].retransmittable_frames.size());
+  ASSERT_EQ(1u, packets_[0].retransmittable_frames.size());
   EXPECT_EQ(stream1_id,
             packets_[0].retransmittable_frames[0].stream_frame.stream_id);
   if (GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)) {
diff --git a/quic/core/quic_packet_number.cc b/quic/core/quic_packet_number.cc
new file mode 100644
index 0000000..f0a497f
--- /dev/null
+++ b/quic/core/quic_packet_number.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2019 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/third_party/quiche/src/quic/core/quic_packet_number.h"
+
+namespace quic {
+
+QuicPacketNumber::QuicPacketNumber()
+    : packet_number_(UninitializedPacketNumber()) {}
+
+QuicPacketNumber::QuicPacketNumber(uint64_t packet_number)
+    : packet_number_(packet_number) {
+  DCHECK_NE(UninitializedPacketNumber(), packet_number)
+      << "Use default constructor for uninitialized packet number";
+}
+
+void QuicPacketNumber::Clear() {
+  packet_number_ = UninitializedPacketNumber();
+}
+
+uint64_t QuicPacketNumber::Hash() const {
+  DCHECK(IsInitialized());
+  return packet_number_;
+}
+
+uint64_t QuicPacketNumber::ToUint64() const {
+  DCHECK(IsInitialized());
+  return packet_number_;
+}
+
+bool QuicPacketNumber::IsInitialized() const {
+  return packet_number_ != UninitializedPacketNumber();
+}
+
+QuicPacketNumber& QuicPacketNumber::operator++() {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_LT(ToUint64(), std::numeric_limits<uint64_t>::max() - 1);
+  } else {
+    DCHECK_LT(ToUint64(), std::numeric_limits<uint64_t>::max());
+  }
+#endif
+  packet_number_++;
+  return *this;
+}
+
+QuicPacketNumber QuicPacketNumber::operator++(int) {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_LT(ToUint64(), std::numeric_limits<uint64_t>::max() - 1);
+  } else {
+    DCHECK_LT(ToUint64(), std::numeric_limits<uint64_t>::max());
+  }
+#endif
+  QuicPacketNumber previous(*this);
+  packet_number_++;
+  return previous;
+}
+
+QuicPacketNumber& QuicPacketNumber::operator--() {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GE(ToUint64(), 1);
+  } else {
+    DCHECK_GT(ToUint64(), 1);
+  }
+#endif
+  packet_number_--;
+  return *this;
+}
+
+QuicPacketNumber QuicPacketNumber::operator--(int) {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GE(ToUint64(), 1);
+  } else {
+    DCHECK_GT(ToUint64(), 1);
+  }
+#endif
+  QuicPacketNumber previous(*this);
+  packet_number_--;
+  return previous;
+}
+
+QuicPacketNumber& QuicPacketNumber::operator+=(uint64_t delta) {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GT(std::numeric_limits<uint64_t>::max() - ToUint64(), delta);
+  } else {
+    DCHECK_GE(std::numeric_limits<uint64_t>::max() - ToUint64(), delta);
+  }
+#endif
+  packet_number_ += delta;
+  return *this;
+}
+
+QuicPacketNumber& QuicPacketNumber::operator-=(uint64_t delta) {
+#ifndef NDEBUG
+  DCHECK(IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GE(ToUint64(), delta);
+  } else {
+    DCHECK_GT(ToUint64(), delta);
+  }
+#endif
+  packet_number_ -= delta;
+  return *this;
+}
+
+std::ostream& operator<<(std::ostream& os, const QuicPacketNumber& p) {
+  if (p.IsInitialized()) {
+    os << p.packet_number_;
+  } else {
+    os << "uninitialized";
+  }
+  return os;
+}
+
+// static
+uint64_t QuicPacketNumber::UninitializedPacketNumber() {
+  return GetQuicRestartFlag(quic_uint64max_uninitialized_pn)
+             ? std::numeric_limits<uint64_t>::max()
+             : 0;
+}
+
+}  // namespace quic
diff --git a/quic/core/quic_packet_number.h b/quic/core/quic_packet_number.h
new file mode 100644
index 0000000..6797e3c
--- /dev/null
+++ b/quic/core/quic_packet_number.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_PACKET_NUMBER_H_
+#define QUICHE_QUIC_CORE_QUIC_PACKET_NUMBER_H_
+
+#include <limits>
+#include <ostream>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
+
+namespace quic {
+
+// QuicPacketNumber can either initialized or uninitialized. An initialized
+// packet number is simply an ordinal number. A sentinel value is used to
+// represent an uninitialized packet number.
+class QUIC_EXPORT_PRIVATE QuicPacketNumber {
+ public:
+  // Construct an uninitialized packet number.
+  QuicPacketNumber();
+  // Construct a packet number from uint64_t. |packet_number| cannot equal the
+  // sentinel value.
+  explicit QuicPacketNumber(uint64_t packet_number);
+
+  // Packet number becomes uninitialized after calling this function.
+  void Clear();
+
+  // REQUIRES: IsInitialized() == true.
+  uint64_t Hash() const;
+
+  // Converts packet number to uint64_t.
+  // REQUIRES: IsInitialized() == true.
+  uint64_t ToUint64() const;
+
+  // Returns true if packet number is considered initialized.
+  bool IsInitialized() const;
+
+  // REQUIRES: IsInitialized() == true && ToUint64() <
+  // numeric_limits<uint64_t>::max() - 1.
+  QuicPacketNumber& operator++();
+  QuicPacketNumber operator++(int);
+  // REQUIRES: IsInitialized() == true && ToUint64() >= 1.
+  QuicPacketNumber& operator--();
+  QuicPacketNumber operator--(int);
+
+  // REQUIRES: IsInitialized() == true && numeric_limits<uint64_t>::max() -
+  // ToUint64() > |delta|.
+  QuicPacketNumber& operator+=(uint64_t delta);
+  // REQUIRES: IsInitialized() == true && ToUint64() >= |delta|.
+  QuicPacketNumber& operator-=(uint64_t delta);
+
+  QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(
+      std::ostream& os,
+      const QuicPacketNumber& p);
+
+ private:
+  // All following operators REQUIRE operands.Initialized() == true.
+  friend inline bool operator==(QuicPacketNumber lhs, QuicPacketNumber rhs);
+  friend inline bool operator!=(QuicPacketNumber lhs, QuicPacketNumber rhs);
+  friend inline bool operator<(QuicPacketNumber lhs, QuicPacketNumber rhs);
+  friend inline bool operator<=(QuicPacketNumber lhs, QuicPacketNumber rhs);
+  friend inline bool operator>(QuicPacketNumber lhs, QuicPacketNumber rhs);
+  friend inline bool operator>=(QuicPacketNumber lhs, QuicPacketNumber rhs);
+
+  // REQUIRES: numeric_limits<uint64_t>::max() - lhs.ToUint64() > |delta|.
+  friend inline QuicPacketNumber operator+(QuicPacketNumber lhs,
+                                           uint64_t delta);
+  // REQUIRES: lhs.ToUint64() >= |delta|.
+  friend inline QuicPacketNumber operator-(QuicPacketNumber lhs,
+                                           uint64_t delta);
+  // REQUIRES: lhs >= rhs.
+  friend inline uint64_t operator-(QuicPacketNumber lhs, QuicPacketNumber rhs);
+
+  // The sentinel value representing an uninitialized packet number.
+  static uint64_t UninitializedPacketNumber();
+
+  uint64_t packet_number_;
+};
+
+class QuicPacketNumberHash {
+ public:
+  uint64_t operator()(QuicPacketNumber packet_number) const noexcept {
+    return packet_number.Hash();
+  }
+};
+
+inline bool operator==(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ == rhs.packet_number_;
+}
+
+inline bool operator!=(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ != rhs.packet_number_;
+}
+
+inline bool operator<(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ < rhs.packet_number_;
+}
+
+inline bool operator<=(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ <= rhs.packet_number_;
+}
+
+inline bool operator>(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ > rhs.packet_number_;
+}
+
+inline bool operator>=(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized()) << lhs << " vs. " << rhs;
+  return lhs.packet_number_ >= rhs.packet_number_;
+}
+
+inline QuicPacketNumber operator+(QuicPacketNumber lhs, uint64_t delta) {
+#ifndef NDEBUG
+  DCHECK(lhs.IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GT(std::numeric_limits<uint64_t>::max() - lhs.ToUint64(), delta);
+  } else {
+    DCHECK_GE(std::numeric_limits<uint64_t>::max() - lhs.ToUint64(), delta);
+  }
+#endif
+  return QuicPacketNumber(lhs.packet_number_ + delta);
+}
+
+inline QuicPacketNumber operator-(QuicPacketNumber lhs, uint64_t delta) {
+#ifndef NDEBUG
+  DCHECK(lhs.IsInitialized());
+  if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    DCHECK_GE(lhs.ToUint64(), delta);
+  } else {
+    DCHECK_GT(lhs.ToUint64(), delta);
+  }
+#endif
+  return QuicPacketNumber(lhs.packet_number_ - delta);
+}
+
+inline uint64_t operator-(QuicPacketNumber lhs, QuicPacketNumber rhs) {
+  DCHECK(lhs.IsInitialized() && rhs.IsInitialized() && lhs >= rhs)
+      << lhs << " vs. " << rhs;
+  return lhs.packet_number_ - rhs.packet_number_;
+}
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_QUIC_PACKET_NUMBER_H_
diff --git a/quic/core/quic_packet_number_test.cc b/quic/core/quic_packet_number_test.cc
new file mode 100644
index 0000000..5e32b8c
--- /dev/null
+++ b/quic/core/quic_packet_number_test.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2019 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/third_party/quiche/src/quic/core/quic_packet_number.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+
+namespace test {
+
+namespace {
+
+TEST(QuicPacketNumberTest, BasicTest) {
+  QuicPacketNumber num;
+  EXPECT_FALSE(num.IsInitialized());
+
+  QuicPacketNumber num2(10);
+  EXPECT_TRUE(num2.IsInitialized());
+  EXPECT_EQ(10u, num2.ToUint64());
+  EXPECT_EQ(10u, num2.Hash());
+  num2.Clear();
+  EXPECT_FALSE(num2.IsInitialized());
+
+  if (!GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    QuicPacketNumber num3(std::numeric_limits<uint64_t>::max());
+    EXPECT_TRUE(num3.IsInitialized());
+    EXPECT_EQ(std::numeric_limits<uint64_t>::max(), num3.ToUint64());
+    EXPECT_EQ(std::numeric_limits<uint64_t>::max(), num3.Hash());
+    num3.Clear();
+    EXPECT_FALSE(num3.IsInitialized());
+    return;
+  }
+
+  QuicPacketNumber num4(0);
+  EXPECT_TRUE(num4.IsInitialized());
+  EXPECT_EQ(0u, num4.ToUint64());
+  EXPECT_EQ(0u, num4.Hash());
+  num4.Clear();
+  EXPECT_FALSE(num4.IsInitialized());
+}
+
+TEST(QuicPacketNumberTest, Operators) {
+  QuicPacketNumber num(100);
+  EXPECT_EQ(QuicPacketNumber(100), num++);
+  EXPECT_EQ(QuicPacketNumber(101), num);
+  EXPECT_EQ(QuicPacketNumber(101), num--);
+  EXPECT_EQ(QuicPacketNumber(100), num);
+
+  EXPECT_EQ(QuicPacketNumber(101), ++num);
+  EXPECT_EQ(QuicPacketNumber(100), --num);
+
+  if (!GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) {
+    QuicPacketNumber num2(std::numeric_limits<uint64_t>::max());
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max()), num2--);
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max() - 1), num2);
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max() - 2),
+              --num2);
+
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max() - 2),
+              num2++);
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max() - 1), num2);
+    EXPECT_EQ(QuicPacketNumber(std::numeric_limits<uint64_t>::max()), ++num2);
+    return;
+  }
+
+  QuicPacketNumber num3(0);
+  EXPECT_EQ(QuicPacketNumber(0), num3++);
+  EXPECT_EQ(QuicPacketNumber(1), num3);
+  EXPECT_EQ(QuicPacketNumber(2), ++num3);
+
+  EXPECT_EQ(QuicPacketNumber(2), num3--);
+  EXPECT_EQ(QuicPacketNumber(1), num3);
+  EXPECT_EQ(QuicPacketNumber(0), --num3);
+}
+
+}  // namespace
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc
index ca0ad6d..5e3ba76 100644
--- a/quic/core/quic_packets.cc
+++ b/quic/core/quic_packets.cc
@@ -33,8 +33,8 @@
       // Long header.
       return kPacketHeaderTypeSize + kConnectionIdLengthSize +
              destination_connection_id_length + source_connection_id_length +
-             (version == QUIC_VERSION_99 ? packet_number_length
-                                         : PACKET_4BYTE_PACKET_NUMBER) +
+             (version > QUIC_VERSION_46 ? packet_number_length
+                                        : PACKET_4BYTE_PACKET_NUMBER) +
              kQuicVersionSize +
              (include_diversification_nonce ? kDiversificationNonceSize : 0);
     }
@@ -74,10 +74,8 @@
       version_flag(false),
       has_possible_stateless_reset_token(false),
       packet_number_length(PACKET_4BYTE_PACKET_NUMBER),
-      version(
-          ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)),
+      version(UnsupportedQuicVersion()),
       nonce(nullptr),
-      packet_number(kInvalidPacketNumber),
       form(GOOGLE_QUIC_PACKET),
       long_packet_type(INITIAL),
       possible_stateless_reset_token(0) {}
@@ -294,9 +292,7 @@
       encryption_level(ENCRYPTION_NONE),
       has_ack(has_ack),
       has_stop_waiting(has_stop_waiting),
-      transmission_type(NOT_RETRANSMISSION),
-      original_packet_number(kInvalidPacketNumber),
-      largest_acked(kInvalidPacketNumber) {}
+      transmission_type(NOT_RETRANSMISSION) {}
 
 SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
 
@@ -327,7 +323,7 @@
   }
   serialized_packet->encrypted_buffer = nullptr;
   serialized_packet->encrypted_length = 0;
-  serialized_packet->largest_acked = kInvalidPacketNumber;
+  serialized_packet->largest_acked.Clear();
 }
 
 char* CopyBuffer(const SerializedPacket& packet) {
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index d33c756..8189ff8 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -25,8 +25,7 @@
 }  // namespace
 
 QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats)
-    : peer_least_packet_awaiting_ack_(0),
-      ack_frame_updated_(false),
+    : ack_frame_updated_(false),
       max_ack_ranges_(0),
       time_largest_observed_(QuicTime::Zero()),
       save_timestamps_(false),
@@ -44,7 +43,8 @@
   }
   ack_frame_updated_ = true;
 
-  if (LargestAcked(ack_frame_) > packet_number) {
+  if (LargestAcked(ack_frame_).IsInitialized() &&
+      LargestAcked(ack_frame_) > packet_number) {
     // Record how out of order stats.
     ++stats_->packets_reordered;
     stats_->max_sequence_reordering =
@@ -55,7 +55,8 @@
     stats_->max_time_reordering_us =
         std::max(stats_->max_time_reordering_us, reordering_time_us);
   }
-  if (packet_number > LargestAcked(ack_frame_)) {
+  if (!LargestAcked(ack_frame_).IsInitialized() ||
+      packet_number > LargestAcked(ack_frame_)) {
     ack_frame_.largest_acked = packet_number;
     time_largest_observed_ = receipt_time;
   }
@@ -77,7 +78,8 @@
 }
 
 bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) {
-  return packet_number < LargestAcked(ack_frame_) &&
+  return LargestAcked(ack_frame_).IsInitialized() &&
+         packet_number < LargestAcked(ack_frame_) &&
          !ack_frame_.packets.Contains(packet_number);
 }
 
@@ -120,9 +122,14 @@
 
 void QuicReceivedPacketManager::DontWaitForPacketsBefore(
     QuicPacketNumber least_unacked) {
+  if (!least_unacked.IsInitialized()) {
+    return;
+  }
   // ValidateAck() should fail if peer_least_packet_awaiting_ack shrinks.
-  DCHECK_LE(peer_least_packet_awaiting_ack_, least_unacked);
-  if (least_unacked > peer_least_packet_awaiting_ack_) {
+  DCHECK(!peer_least_packet_awaiting_ack_.IsInitialized() ||
+         peer_least_packet_awaiting_ack_ <= least_unacked);
+  if (!peer_least_packet_awaiting_ack_.IsInitialized() ||
+      least_unacked > peer_least_packet_awaiting_ack_) {
     peer_least_packet_awaiting_ack_ = least_unacked;
     bool packets_updated = ack_frame_.packets.RemoveUpTo(least_unacked);
     if (packets_updated) {
@@ -132,14 +139,23 @@
     }
   }
   DCHECK(ack_frame_.packets.Empty() ||
+         !peer_least_packet_awaiting_ack_.IsInitialized() ||
          ack_frame_.packets.Min() >= peer_least_packet_awaiting_ack_);
 }
 
 bool QuicReceivedPacketManager::HasMissingPackets() const {
-  return ack_frame_.packets.NumIntervals() > 1 ||
-         (!ack_frame_.packets.Empty() &&
-          ack_frame_.packets.Min() >
-              std::max(QuicPacketNumber(1), peer_least_packet_awaiting_ack_));
+  if (ack_frame_.packets.Empty()) {
+    return false;
+  }
+  if (ack_frame_.packets.NumIntervals() > 1) {
+    return true;
+  }
+  // TODO(fayang): Fix this as this check assumes first sent packet by peer
+  // is 1.
+  return ack_frame_.packets.Min() >
+         (peer_least_packet_awaiting_ack_.IsInitialized()
+              ? peer_least_packet_awaiting_ack_
+              : QuicPacketNumber(1));
 }
 
 bool QuicReceivedPacketManager::HasNewMissingPackets() const {
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc
index 7d8c811..b8264a5 100644
--- a/quic/core/quic_received_packet_manager_test.cc
+++ b/quic/core/quic_received_packet_manager_test.cc
@@ -42,14 +42,13 @@
     received_manager_.set_save_timestamps(true);
   }
 
-  void RecordPacketReceipt(QuicPacketNumber packet_number) {
+  void RecordPacketReceipt(uint64_t packet_number) {
     RecordPacketReceipt(packet_number, QuicTime::Zero());
   }
 
-  void RecordPacketReceipt(QuicPacketNumber packet_number,
-                           QuicTime receipt_time) {
+  void RecordPacketReceipt(uint64_t packet_number, QuicTime receipt_time) {
     QuicPacketHeader header;
-    header.packet_number = packet_number;
+    header.packet_number = QuicPacketNumber(packet_number);
     received_manager_.RecordPacketReceived(header, receipt_time);
   }
 
@@ -63,20 +62,20 @@
 
 TEST_P(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
   QuicPacketHeader header;
-  header.packet_number = 2u;
+  header.packet_number = QuicPacketNumber(2u);
   received_manager_.RecordPacketReceived(header, QuicTime::Zero());
-  header.packet_number = 7u;
+  header.packet_number = QuicPacketNumber(7u);
   received_manager_.RecordPacketReceived(header, QuicTime::Zero());
-  EXPECT_TRUE(received_manager_.IsAwaitingPacket(3u));
-  EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
-  received_manager_.DontWaitForPacketsBefore(4);
-  EXPECT_FALSE(received_manager_.IsAwaitingPacket(3u));
-  EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
+  EXPECT_TRUE(received_manager_.IsAwaitingPacket(QuicPacketNumber(3u)));
+  EXPECT_TRUE(received_manager_.IsAwaitingPacket(QuicPacketNumber(6u)));
+  received_manager_.DontWaitForPacketsBefore(QuicPacketNumber(4));
+  EXPECT_FALSE(received_manager_.IsAwaitingPacket(QuicPacketNumber(3u)));
+  EXPECT_TRUE(received_manager_.IsAwaitingPacket(QuicPacketNumber(6u)));
 }
 
 TEST_P(QuicReceivedPacketManagerTest, GetUpdatedAckFrame) {
   QuicPacketHeader header;
-  header.packet_number = 2u;
+  header.packet_number = QuicPacketNumber(2u);
   QuicTime two_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
   EXPECT_FALSE(received_manager_.ack_frame_updated());
   received_manager_.RecordPacketReceived(header, two_ms);
@@ -99,11 +98,11 @@
   // And received packet times won't have change.
   EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
 
-  header.packet_number = 999u;
+  header.packet_number = QuicPacketNumber(999u);
   received_manager_.RecordPacketReceived(header, two_ms);
-  header.packet_number = 4u;
+  header.packet_number = QuicPacketNumber(4u);
   received_manager_.RecordPacketReceived(header, two_ms);
-  header.packet_number = 1000u;
+  header.packet_number = QuicPacketNumber(1000u);
   received_manager_.RecordPacketReceived(header, two_ms);
   EXPECT_TRUE(received_manager_.ack_frame_updated());
   ack = received_manager_.GetUpdatedAckFrame(two_ms);
@@ -134,11 +133,16 @@
     EXPECT_TRUE(received_manager_.ack_frame_updated());
     received_manager_.GetUpdatedAckFrame(QuicTime::Zero());
     EXPECT_GE(10u, received_manager_.ack_frame().packets.NumIntervals());
-    EXPECT_EQ(1u + 2 * i, received_manager_.ack_frame().packets.Max());
+    EXPECT_EQ(QuicPacketNumber(1u + 2 * i),
+              received_manager_.ack_frame().packets.Max());
     for (int j = 0; j < std::min(10, i + 1); ++j) {
-      EXPECT_TRUE(
-          received_manager_.ack_frame().packets.Contains(1 + (i - j) * 2));
-      EXPECT_FALSE(received_manager_.ack_frame().packets.Contains((i - j) * 2));
+      ASSERT_GE(i, j);
+      EXPECT_TRUE(received_manager_.ack_frame().packets.Contains(
+          QuicPacketNumber(1 + (i - j) * 2)));
+      if (i > j) {
+        EXPECT_FALSE(received_manager_.ack_frame().packets.Contains(
+            QuicPacketNumber((i - j) * 2)));
+      }
     }
   }
 }
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 783a78c..4bbe070 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -86,7 +86,6 @@
       loss_algorithm_(&general_loss_algorithm_),
       general_loss_algorithm_(loss_type),
       n_connection_simulation_(false),
-      first_rto_transmission_(0),
       consecutive_rto_count_(0),
       consecutive_tlp_count_(0),
       consecutive_crypto_retransmission_count_(0),
@@ -103,10 +102,8 @@
           QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs)),
       ietf_style_tlp_(false),
       ietf_style_2x_tlp_(false),
-      largest_newly_acked_(0),
       largest_mtu_acked_(0),
       handshake_confirmed_(false),
-      largest_packet_peer_knows_is_acked_(0),
       delayed_ack_time_(
           QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
       rtt_updated_(false),
@@ -452,7 +449,7 @@
   } else {
     // Clear the recorded first packet sent after loss when version or
     // encryption changes.
-    transmission_info->retransmission = kInvalidPacketNumber;
+    transmission_info->retransmission.Clear();
   }
 }
 
@@ -479,7 +476,7 @@
     return;
   }
   QuicPacketNumber retransmission = info.retransmission;
-  while (retransmission != kInvalidPacketNumber) {
+  while (retransmission.IsInitialized()) {
     const QuicTransmissionInfo& retransmit_info =
         unacked_packets_.GetTransmissionInfo(retransmission);
     retransmission = retransmit_info.retransmission;
@@ -529,7 +526,7 @@
     return packet_number;
   }
   QuicPacketNumber retransmission = transmission_info.retransmission;
-  while (retransmission != kInvalidPacketNumber) {
+  while (retransmission.IsInitialized()) {
     packet_number = retransmission;
     retransmission =
         unacked_packets_.GetTransmissionInfo(retransmission).retransmission;
@@ -607,12 +604,12 @@
     TransmissionType transmission_type,
     HasRetransmittableData has_retransmittable_data) {
   QuicPacketNumber packet_number = serialized_packet->packet_number;
-  DCHECK_LT(0u, packet_number);
+  DCHECK_LE(FirstSendingPacketNumber(), packet_number);
   DCHECK(!unacked_packets_.IsUnacked(packet_number));
   QUIC_BUG_IF(serialized_packet->encrypted_length == 0)
       << "Cannot send empty packets.";
 
-  if (original_packet_number != kInvalidPacketNumber) {
+  if (original_packet_number.IsInitialized()) {
     pending_retransmissions_.erase(original_packet_number);
   }
 
@@ -758,7 +755,7 @@
     }
     // Abandon non-retransmittable data that's in flight to ensure it doesn't
     // fill up the congestion window.
-    bool has_retransmissions = it->retransmission != kInvalidPacketNumber;
+    bool has_retransmissions = it->retransmission.IsInitialized();
     if (session_decides_what_to_write()) {
       has_retransmissions = it->state != OUTSTANDING;
     }
@@ -1051,21 +1048,23 @@
   DCHECK_LE(largest_acked, unacked_packets_.largest_sent_packet());
   rtt_updated_ =
       MaybeUpdateRTT(largest_acked, ack_delay_time, ack_receive_time);
-  DCHECK_GE(largest_acked, unacked_packets_.largest_acked());
+  DCHECK(!unacked_packets_.largest_acked().IsInitialized() ||
+         largest_acked >= unacked_packets_.largest_acked());
   last_ack_frame_.ack_delay_time = ack_delay_time;
   acked_packets_iter_ = last_ack_frame_.packets.rbegin();
 }
 
 void QuicSentPacketManager::OnAckRange(QuicPacketNumber start,
                                        QuicPacketNumber end) {
-  if (end > last_ack_frame_.largest_acked + 1) {
+  if (!last_ack_frame_.largest_acked.IsInitialized() ||
+      end > last_ack_frame_.largest_acked + 1) {
     // Largest acked increases.
     unacked_packets_.IncreaseLargestAcked(end - 1);
     last_ack_frame_.largest_acked = end - 1;
   }
   // Drop ack ranges which ack packets below least_unacked.
   QuicPacketNumber least_unacked = unacked_packets_.GetLeastUnacked();
-  if (end <= least_unacked) {
+  if (least_unacked.IsInitialized() && end <= least_unacked) {
     return;
   }
   start = std::max(start, least_unacked);
@@ -1079,6 +1078,9 @@
       // Check if end is above the current range. If so add newly acked packets
       // in descending order.
       packets_acked_.push_back(AckedPacket(acked, 0, QuicTime::Zero()));
+      if (acked == FirstSendingPacketNumber()) {
+        break;
+      }
     }
     if (acked_packets_iter_ == last_ack_frame_.packets.rend() ||
         start > acked_packets_iter_->min()) {
@@ -1125,9 +1127,13 @@
     QUIC_DVLOG(1) << ENDPOINT << "Got an ack for packet "
                   << acked_packet.packet_number;
     last_ack_frame_.packets.Add(acked_packet.packet_number);
-    if (info->largest_acked > kInvalidPacketNumber) {
-      largest_packet_peer_knows_is_acked_ =
-          std::max(largest_packet_peer_knows_is_acked_, info->largest_acked);
+    if (info->largest_acked.IsInitialized()) {
+      if (largest_packet_peer_knows_is_acked_.IsInitialized()) {
+        largest_packet_peer_knows_is_acked_ =
+            std::max(largest_packet_peer_knows_is_acked_, info->largest_acked);
+      } else {
+        largest_packet_peer_knows_is_acked_ = info->largest_acked;
+      }
     }
     // If data is associated with the most recent transmission of this
     // packet, then inform the caller.
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index 7b2501a..aad16e2 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -368,7 +368,9 @@
     LOSS_MODE,
   };
 
-  typedef QuicLinkedHashMap<QuicPacketNumber, TransmissionType>
+  typedef QuicLinkedHashMap<QuicPacketNumber,
+                            TransmissionType,
+                            QuicPacketNumberHash>
       PendingRetransmissionMap;
 
   // Returns the current retransmission mode.
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 865f181..97e1697 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -38,7 +38,8 @@
 
 // Matcher to check that the packet number matches the second argument.
 MATCHER(PacketNumberEq, "") {
-  return ::testing::get<0>(arg).packet_number == ::testing::get<1>(arg);
+  return ::testing::get<0>(arg).packet_number ==
+         QuicPacketNumber(::testing::get<1>(arg));
 }
 
 class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate {
@@ -54,25 +55,26 @@
 
 class QuicSentPacketManagerTest : public QuicTestWithParam<bool> {
  public:
-  void RetransmitCryptoPacket(QuicPacketNumber packet_number) {
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA));
+  void RetransmitCryptoPacket(uint64_t packet_number) {
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, BytesInFlight(), QuicPacketNumber(packet_number),
+                     kDefaultLength, HAS_RETRANSMITTABLE_DATA));
     SerializedPacket packet(CreatePacket(packet_number, false));
     packet.retransmittable_frames.push_back(
         QuicFrame(QuicStreamFrame(1, false, 0, QuicStringPiece())));
     packet.has_crypto_handshake = IS_HANDSHAKE;
-    manager_.OnPacketSent(&packet, 0, clock_.Now(), HANDSHAKE_RETRANSMISSION,
-                          HAS_RETRANSMITTABLE_DATA);
+    manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                          HANDSHAKE_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
   }
 
-  void RetransmitDataPacket(QuicPacketNumber packet_number,
-                            TransmissionType type) {
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA));
+  void RetransmitDataPacket(uint64_t packet_number, TransmissionType type) {
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, BytesInFlight(), QuicPacketNumber(packet_number),
+                     kDefaultLength, HAS_RETRANSMITTABLE_DATA));
     SerializedPacket packet(CreatePacket(packet_number, true));
-    manager_.OnPacketSent(&packet, 0, clock_.Now(), type,
+    manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(), type,
                           HAS_RETRANSMITTABLE_DATA);
   }
 
@@ -111,7 +113,7 @@
   QuicByteCount BytesInFlight() {
     return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_);
   }
-  void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
+  void VerifyUnackedPackets(uint64_t* packets, size_t num_packets) {
     if (num_packets == 0) {
       EXPECT_TRUE(manager_.unacked_packets().empty());
       EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetNumRetransmittablePackets(
@@ -120,15 +122,14 @@
     }
 
     EXPECT_FALSE(manager_.unacked_packets().empty());
-    EXPECT_EQ(packets[0], manager_.GetLeastUnacked());
+    EXPECT_EQ(QuicPacketNumber(packets[0]), manager_.GetLeastUnacked());
     for (size_t i = 0; i < num_packets; ++i) {
       EXPECT_TRUE(QuicSentPacketManagerPeer::IsUnacked(&manager_, packets[i]))
           << packets[i];
     }
   }
 
-  void VerifyRetransmittablePackets(QuicPacketNumber* packets,
-                                    size_t num_packets) {
+  void VerifyRetransmittablePackets(uint64_t* packets, size_t num_packets) {
     EXPECT_EQ(
         num_packets,
         QuicSentPacketManagerPeer::GetNumRetransmittablePackets(&manager_));
@@ -139,7 +140,7 @@
     }
   }
 
-  void ExpectAck(QuicPacketNumber largest_observed) {
+  void ExpectAck(uint64_t largest_observed) {
     EXPECT_CALL(
         *send_algorithm_,
         // Ensure the AckedPacketVector argument contains largest_observed.
@@ -149,15 +150,15 @@
     EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
   }
 
-  void ExpectUpdatedRtt(QuicPacketNumber largest_observed) {
+  void ExpectUpdatedRtt(uint64_t largest_observed) {
     EXPECT_CALL(*send_algorithm_,
                 OnCongestionEvent(true, _, _, IsEmpty(), IsEmpty()));
     EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
   }
 
   void ExpectAckAndLoss(bool rtt_updated,
-                        QuicPacketNumber largest_observed,
-                        QuicPacketNumber lost_packet) {
+                        uint64_t largest_observed,
+                        uint64_t lost_packet) {
     EXPECT_CALL(
         *send_algorithm_,
         OnCongestionEvent(rtt_updated, _, _,
@@ -168,17 +169,17 @@
 
   // |packets_acked| and |packets_lost| should be in packet number order.
   void ExpectAcksAndLosses(bool rtt_updated,
-                           QuicPacketNumber* packets_acked,
+                           uint64_t* packets_acked,
                            size_t num_packets_acked,
-                           QuicPacketNumber* packets_lost,
+                           uint64_t* packets_lost,
                            size_t num_packets_lost) {
     std::vector<QuicPacketNumber> ack_vector;
     for (size_t i = 0; i < num_packets_acked; ++i) {
-      ack_vector.push_back(packets_acked[i]);
+      ack_vector.push_back(QuicPacketNumber(packets_acked[i]));
     }
     std::vector<QuicPacketNumber> lost_vector;
     for (size_t i = 0; i < num_packets_lost; ++i) {
-      lost_vector.push_back(packets_lost[i]);
+      lost_vector.push_back(QuicPacketNumber(packets_lost[i]));
     }
     EXPECT_CALL(*send_algorithm_,
                 OnCongestionEvent(rtt_updated, _, _,
@@ -188,14 +189,14 @@
         .Times(AnyNumber());
   }
 
-  void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
-                               QuicPacketNumber new_packet_number) {
+  void RetransmitAndSendPacket(uint64_t old_packet_number,
+                               uint64_t new_packet_number) {
     RetransmitAndSendPacket(old_packet_number, new_packet_number,
                             TLP_RETRANSMISSION);
   }
 
-  void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
-                               QuicPacketNumber new_packet_number,
+  void RetransmitAndSendPacket(uint64_t old_packet_number,
+                               uint64_t new_packet_number,
                                TransmissionType transmission_type) {
     bool is_lost = false;
     if (manager_.session_decides_what_to_write()) {
@@ -219,38 +220,42 @@
       if (!is_lost) {
         return;
       }
-      EXPECT_CALL(*send_algorithm_,
-                  OnPacketSent(_, BytesInFlight(), new_packet_number,
-                               kDefaultLength, HAS_RETRANSMITTABLE_DATA));
+      EXPECT_CALL(
+          *send_algorithm_,
+          OnPacketSent(_, BytesInFlight(), QuicPacketNumber(new_packet_number),
+                       kDefaultLength, HAS_RETRANSMITTABLE_DATA));
       SerializedPacket packet(CreatePacket(new_packet_number, true));
-      manager_.OnPacketSent(&packet, 0, clock_.Now(), transmission_type,
-                            HAS_RETRANSMITTABLE_DATA);
+      manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                            transmission_type, HAS_RETRANSMITTABLE_DATA);
       return;
     }
     EXPECT_TRUE(manager_.HasPendingRetransmissions());
     QuicPendingRetransmission next_retransmission =
         manager_.NextPendingRetransmission();
-    EXPECT_EQ(old_packet_number, next_retransmission.packet_number);
+    EXPECT_EQ(QuicPacketNumber(old_packet_number),
+              next_retransmission.packet_number);
     EXPECT_EQ(transmission_type, next_retransmission.transmission_type);
 
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), new_packet_number,
-                             kDefaultLength, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, BytesInFlight(), QuicPacketNumber(new_packet_number),
+                     kDefaultLength, HAS_RETRANSMITTABLE_DATA));
     SerializedPacket packet(CreatePacket(new_packet_number, false));
-    manager_.OnPacketSent(&packet, old_packet_number, clock_.Now(),
-                          transmission_type, HAS_RETRANSMITTABLE_DATA);
+    manager_.OnPacketSent(&packet, QuicPacketNumber(old_packet_number),
+                          clock_.Now(), transmission_type,
+                          HAS_RETRANSMITTABLE_DATA);
     EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_,
                                                             new_packet_number));
   }
 
-  SerializedPacket CreateDataPacket(QuicPacketNumber packet_number) {
+  SerializedPacket CreateDataPacket(uint64_t packet_number) {
     return CreatePacket(packet_number, true);
   }
 
-  SerializedPacket CreatePacket(QuicPacketNumber packet_number,
-                                bool retransmittable) {
-    SerializedPacket packet(packet_number, PACKET_4BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, false, false);
+  SerializedPacket CreatePacket(uint64_t packet_number, bool retransmittable) {
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            false, false);
     if (retransmittable) {
       packet.retransmittable_frames.push_back(
           QuicFrame(QuicStreamFrame(kStreamId, false, 0, QuicStringPiece())));
@@ -258,47 +263,50 @@
     return packet;
   }
 
-  void SendDataPacket(QuicPacketNumber packet_number) {
+  void SendDataPacket(uint64_t packet_number) {
     EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), packet_number, _, _));
+                OnPacketSent(_, BytesInFlight(),
+                             QuicPacketNumber(packet_number), _, _));
     SerializedPacket packet(CreateDataPacket(packet_number));
-    manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION,
-                          HAS_RETRANSMITTABLE_DATA);
+    manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                          NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
   }
 
-  void SendCryptoPacket(QuicPacketNumber packet_number) {
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA));
+  void SendCryptoPacket(uint64_t packet_number) {
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, BytesInFlight(), QuicPacketNumber(packet_number),
+                     kDefaultLength, HAS_RETRANSMITTABLE_DATA));
     SerializedPacket packet(CreatePacket(packet_number, false));
     packet.retransmittable_frames.push_back(
         QuicFrame(QuicStreamFrame(1, false, 0, QuicStringPiece())));
     packet.has_crypto_handshake = IS_HANDSHAKE;
-    manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION,
-                          HAS_RETRANSMITTABLE_DATA);
+    manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                          NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
     if (manager_.session_decides_what_to_write()) {
       EXPECT_CALL(notifier_, HasUnackedCryptoData())
           .WillRepeatedly(Return(true));
     }
   }
 
-  void SendAckPacket(QuicPacketNumber packet_number,
-                     QuicPacketNumber largest_acked) {
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
-                             NO_RETRANSMITTABLE_DATA));
+  void SendAckPacket(uint64_t packet_number, uint64_t largest_acked) {
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, BytesInFlight(), QuicPacketNumber(packet_number),
+                     kDefaultLength, NO_RETRANSMITTABLE_DATA));
     SerializedPacket packet(CreatePacket(packet_number, false));
-    packet.largest_acked = largest_acked;
-    manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION,
-                          NO_RETRANSMITTABLE_DATA);
+    packet.largest_acked = QuicPacketNumber(largest_acked);
+    manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                          NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
   }
 
   // Based on QuicConnection's WritePendingRetransmissions.
-  void RetransmitNextPacket(QuicPacketNumber retransmission_packet_number) {
+  void RetransmitNextPacket(uint64_t retransmission_packet_number) {
     EXPECT_TRUE(manager_.HasPendingRetransmissions());
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, _, retransmission_packet_number, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA));
+    EXPECT_CALL(
+        *send_algorithm_,
+        OnPacketSent(_, _, QuicPacketNumber(retransmission_packet_number),
+                     kDefaultLength, HAS_RETRANSMITTABLE_DATA));
     const QuicPendingRetransmission pending =
         manager_.NextPendingRetransmission();
     SerializedPacket packet(CreatePacket(retransmission_packet_number, false));
@@ -320,9 +328,9 @@
   VerifyUnackedPackets(nullptr, 0);
   SendDataPacket(1);
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  QuicPacketNumber retransmittable[] = {1};
+  uint64_t retransmittable[] = {1};
   VerifyRetransmittablePackets(retransmittable,
                                QUIC_ARRAYSIZE(retransmittable));
 }
@@ -332,9 +340,9 @@
   RetransmitAndSendPacket(1, 2);
 
   EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_, 2));
-  QuicPacketNumber unacked[] = {1, 2};
+  uint64_t unacked[] = {1, 2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  std::vector<QuicPacketNumber> retransmittable;
+  std::vector<uint64_t> retransmittable;
   if (manager_.session_decides_what_to_write()) {
     retransmittable = {1, 2};
   } else {
@@ -349,14 +357,15 @@
 
   // Ack 2 but not 1.
   ExpectAck(2);
-  manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(2, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
   }
   // Packet 1 is unacked, pending, but not retransmittable.
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   VerifyRetransmittablePackets(nullptr, 0);
@@ -379,8 +388,9 @@
   }
   // Ack 1.
   ExpectAck(1);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   // There should no longer be a pending retransmission.
@@ -388,7 +398,7 @@
 
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
-    QuicPacketNumber unacked[] = {2};
+    uint64_t unacked[] = {2};
     VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
     // We do not know packet 2 is a spurious retransmission until it gets acked.
   } else {
@@ -418,7 +428,7 @@
   // There should no longer be a pending retransmission.
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
   EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted);
@@ -432,14 +442,15 @@
 
   // Ack 1 but not 2.
   ExpectAck(1);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
   }
   // 2 remains unacked, but no packets have retransmittable data.
-  QuicPacketNumber unacked[] = {2};
+  uint64_t unacked[] = {2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   VerifyRetransmittablePackets(nullptr, 0);
@@ -447,8 +458,9 @@
     // Ack 2 causes 2 be considered as spurious retransmission.
     EXPECT_CALL(notifier_, OnFrameAcked(_, _)).WillOnce(Return(false));
     ExpectAck(2);
-    manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
-    manager_.OnAckRange(1, 3);
+    manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+                             clock_.Now());
+    manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
     EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   }
 
@@ -463,8 +475,9 @@
 
   // First, ACK packet 1 which makes packet 2 non-retransmittable.
   ExpectAck(1);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   SendDataPacket(3);
@@ -474,15 +487,17 @@
 
   // Next, NACK packet 2 three times.
   ExpectAck(3);
-  manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 4);
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   ExpectAck(4);
-  manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 5);
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   ExpectAckAndLoss(true, 5, 2);
@@ -495,14 +510,15 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
     }
   }
-  manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 6);
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   if (manager_.session_decides_what_to_write() &&
       GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
-    QuicPacketNumber unacked[] = {2};
+    uint64_t unacked[] = {2};
     VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   } else {
     // No packets remain unacked.
@@ -532,12 +548,13 @@
   // send algorithm is not informed that it has been ACK'd.
   ExpectUpdatedRtt(1);
   EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout());
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
-  QuicPacketNumber unacked[] = {2};
+  uint64_t unacked[] = {2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   VerifyRetransmittablePackets(nullptr, 0);
@@ -568,8 +585,9 @@
 
   // Ack 1 but not 2 or 3.
   ExpectAck(1);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   if (manager_.session_decides_what_to_write()) {
     // Frames in packets 2 and 3 are acked.
@@ -579,7 +597,7 @@
   }
 
   // 2 and 3 remain unacked, but no packets have retransmittable data.
-  QuicPacketNumber unacked[] = {2, 3};
+  uint64_t unacked[] = {2, 3};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
   VerifyRetransmittablePackets(nullptr, 0);
@@ -592,20 +610,22 @@
         .WillOnce(Return(false))
         .WillRepeatedly(Return(true));
   }
-  QuicPacketNumber acked[] = {3, 4};
+  uint64_t acked[] = {3, 4};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
-  manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 5);
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
-  QuicPacketNumber unacked2[] = {2};
+  uint64_t unacked2[] = {2};
   VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
   EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
 
   SendDataPacket(5);
   ExpectAckAndLoss(true, 5, 2);
-  EXPECT_CALL(debug_delegate, OnPacketLoss(2, LOSS_RETRANSMISSION, _));
+  EXPECT_CALL(debug_delegate,
+              OnPacketLoss(QuicPacketNumber(2), LOSS_RETRANSMISSION, _));
   if (manager_.session_decides_what_to_write()) {
     // Frames in all packets are acked.
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
@@ -615,14 +635,15 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1);
     }
   }
-  manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 6);
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   if (manager_.session_decides_what_to_write() &&
       GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
-    QuicPacketNumber unacked[] = {2};
+    uint64_t unacked[] = {2};
     VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   } else {
     VerifyUnackedPackets(nullptr, 0);
@@ -649,8 +670,9 @@
   {
     ExpectAck(1);
     EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
-    manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-    manager_.OnAckRange(1, 2);
+    manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                             clock_.Now());
+    manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
     EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   }
 
@@ -660,22 +682,25 @@
   {
     ExpectAck(4);
     EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
-    manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
-    manager_.OnAckRange(4, 5);
-    manager_.OnAckRange(1, 2);
+    manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+                             clock_.Now());
+    manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(5));
+    manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
     EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
     RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
   }
 
   // Ack 3, which causes SpuriousRetransmitDetected to be called.
   {
-    QuicPacketNumber acked[] = {3};
+    uint64_t acked[] = {3};
     ExpectAcksAndLosses(false, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
     EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
-    EXPECT_CALL(*loss_algorithm, SpuriousRetransmitDetected(_, _, _, 5));
-    manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
-    manager_.OnAckRange(3, 5);
-    manager_.OnAckRange(1, 2);
+    EXPECT_CALL(*loss_algorithm,
+                SpuriousRetransmitDetected(_, _, _, QuicPacketNumber(5)));
+    manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
+                             clock_.Now());
+    manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
+    manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
     EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
     if (manager_.session_decides_what_to_write()) {
       // Ack 3 will not cause 5 be considered as a spurious retransmission. Ack
@@ -684,57 +709,60 @@
       ExpectAck(5);
       EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
       EXPECT_CALL(notifier_, OnFrameAcked(_, _)).WillOnce(Return(false));
-      manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
-      manager_.OnAckRange(3, 6);
-      manager_.OnAckRange(1, 2);
+      manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
+                               clock_.Now());
+      manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
+      manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
       EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
     }
   }
 }
 
 TEST_P(QuicSentPacketManagerTest, GetLeastUnacked) {
-  EXPECT_EQ(1u, manager_.GetLeastUnacked());
+  EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked());
 }
 
 TEST_P(QuicSentPacketManagerTest, GetLeastUnackedUnacked) {
   SendDataPacket(1);
-  EXPECT_EQ(1u, manager_.GetLeastUnacked());
+  EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked());
 }
 
 TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) {
-  EXPECT_EQ(0u, manager_.largest_packet_peer_knows_is_acked());
+  EXPECT_FALSE(manager_.largest_packet_peer_knows_is_acked().IsInitialized());
   SendDataPacket(1);
   SendAckPacket(2, 1);
 
   // Now ack the ack and expect an RTT update.
-  QuicPacketNumber acked[] = {1, 2};
+  uint64_t acked[] = {1, 2};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
-  manager_.OnAckFrameStart(2, QuicTime::Delta::FromMilliseconds(5),
-                           clock_.Now());
-  manager_.OnAckRange(1, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2),
+                           QuicTime::Delta::FromMilliseconds(5), clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
-  EXPECT_EQ(1u, manager_.largest_packet_peer_knows_is_acked());
+  EXPECT_EQ(QuicPacketNumber(1), manager_.largest_packet_peer_knows_is_acked());
 
   SendAckPacket(3, 3);
 
   // Now ack the ack and expect only an RTT update.
-  QuicPacketNumber acked2[] = {3};
+  uint64_t acked2[] = {3};
   ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), nullptr, 0);
-  manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 4);
+  manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
-  EXPECT_EQ(3u, manager_.largest_packet_peer_knows_is_acked());
+  EXPECT_EQ(QuicPacketNumber(3u),
+            manager_.largest_packet_peer_knows_is_acked());
 }
 
 TEST_P(QuicSentPacketManagerTest, Rtt) {
-  QuicPacketNumber packet_number = 1;
   QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(20);
-  SendDataPacket(packet_number);
+  SendDataPacket(1);
   clock_.AdvanceTime(expected_rtt);
 
-  ExpectAck(packet_number);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  ExpectAck(1);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
 }
@@ -743,15 +771,14 @@
   // Expect that the RTT is equal to the local time elapsed, since the
   // ack_delay_time is larger than the local time elapsed
   // and is hence invalid.
-  QuicPacketNumber packet_number = 1;
   QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
-  SendDataPacket(packet_number);
+  SendDataPacket(1);
   clock_.AdvanceTime(expected_rtt);
 
-  ExpectAck(packet_number);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::FromMilliseconds(11),
-                           clock_.Now());
-  manager_.OnAckRange(1, 2);
+  ExpectAck(1);
+  manager_.OnAckFrameStart(QuicPacketNumber(1),
+                           QuicTime::Delta::FromMilliseconds(11), clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
 }
@@ -759,14 +786,14 @@
 TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) {
   // Expect that the RTT is equal to the local time elapsed, since the
   // ack_delay_time is infinite, and is hence invalid.
-  QuicPacketNumber packet_number = 1;
   QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
-  SendDataPacket(packet_number);
+  SendDataPacket(1);
   clock_.AdvanceTime(expected_rtt);
 
-  ExpectAck(packet_number);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  ExpectAck(1);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
 }
@@ -774,14 +801,14 @@
 TEST_P(QuicSentPacketManagerTest, RttZeroDelta) {
   // Expect that the RTT is the time between send and receive since the
   // ack_delay_time is zero.
-  QuicPacketNumber packet_number = 1;
   QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
-  SendDataPacket(packet_number);
+  SendDataPacket(1);
   clock_.AdvanceTime(expected_rtt);
 
-  ExpectAck(packet_number);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Zero(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  ExpectAck(1);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Zero(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
 }
@@ -790,8 +817,7 @@
   QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
 
   // Send 1 packet.
-  QuicPacketNumber packet_number = 1;
-  SendDataPacket(packet_number);
+  SendDataPacket(1);
 
   // The first tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
@@ -830,8 +856,9 @@
   // Ack the third and ensure the first two are still pending.
   ExpectAck(3);
 
-  manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 4);
+  manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
@@ -839,8 +866,8 @@
   // Acking two more packets will lose both of them due to nacks.
   SendDataPacket(4);
   SendDataPacket(5);
-  QuicPacketNumber acked[] = {4, 5};
-  QuicPacketNumber lost[] = {1, 2};
+  uint64_t acked[] = {4, 5};
+  uint64_t lost[] = {1, 2};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost,
                       QUIC_ARRAYSIZE(lost));
   if (manager_.session_decides_what_to_write()) {
@@ -852,8 +879,9 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2);
     }
   }
-  manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 6);
+  manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -945,7 +973,7 @@
     EXPECT_TRUE(manager_.HasPendingRetransmissions());
     RetransmitNextPacket(103);
   }
-  QuicPacketNumber largest_acked = 103;
+  QuicPacketNumber largest_acked = QuicPacketNumber(103);
   EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
   EXPECT_CALL(*send_algorithm_,
               OnCongestionEvent(
@@ -974,8 +1002,9 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101);
     }
   }
-  manager_.OnAckFrameStart(103, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(103, 104);
+  manager_.OnAckFrameStart(QuicPacketNumber(103), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(103), QuicPacketNumber(104));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   // All packets before 103 should be lost.
   if (manager_.session_decides_what_to_write()) {
@@ -1032,15 +1061,16 @@
 
   // Now ack the two crypto packets and the speculatively encrypted request,
   // and ensure the first four crypto packets get abandoned, but not lost.
-  QuicPacketNumber acked[] = {3, 4, 5, 8, 9};
+  uint64_t acked[] = {3, 4, 5, 8, 9};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, HasUnackedCryptoData())
         .WillRepeatedly(Return(false));
   }
-  manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(8, 10);
-  manager_.OnAckRange(3, 6);
+  manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
@@ -1090,9 +1120,11 @@
     RetransmitDataPacket(12, ALL_UNACKED_RETRANSMISSION);
   } else {
     ASSERT_TRUE(manager_.HasPendingRetransmissions());
-    EXPECT_EQ(6u, manager_.NextPendingRetransmission().packet_number);
+    EXPECT_EQ(QuicPacketNumber(6u),
+              manager_.NextPendingRetransmission().packet_number);
     RetransmitNextPacket(8);
-    EXPECT_EQ(7u, manager_.NextPendingRetransmission().packet_number);
+    EXPECT_EQ(QuicPacketNumber(7u),
+              manager_.NextPendingRetransmission().packet_number);
     RetransmitNextPacket(9);
     EXPECT_TRUE(manager_.HasPendingRetransmissions());
     // Send 3 more data packets and ensure the least unacked is raised.
@@ -1102,19 +1134,20 @@
     EXPECT_FALSE(manager_.HasPendingRetransmissions());
   }
 
-  EXPECT_EQ(1u, manager_.GetLeastUnacked());
+  EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked());
   // Least unacked isn't raised until an ack is received, so ack the
   // crypto packets.
-  QuicPacketNumber acked[] = {8, 9};
+  uint64_t acked[] = {8, 9};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
-  manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(8, 10);
+  manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, HasUnackedCryptoData())
         .WillRepeatedly(Return(false));
   }
-  EXPECT_EQ(10u, manager_.GetLeastUnacked());
+  EXPECT_EQ(QuicPacketNumber(10u), manager_.GetLeastUnacked());
 }
 
 TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
@@ -1144,19 +1177,20 @@
 
   // Now ack the second crypto packet, and ensure the first gets removed, but
   // the third does not.
-  QuicPacketNumber acked[] = {2};
+  uint64_t acked[] = {2};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
   if (manager_.session_decides_what_to_write()) {
     EXPECT_CALL(notifier_, HasUnackedCryptoData())
         .WillRepeatedly(Return(false));
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
   }
-  manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(2, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-  QuicPacketNumber unacked[] = {3};
+  uint64_t unacked[] = {3};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
 }
 
@@ -1214,7 +1248,7 @@
   } else {
     // Packet 2 is useful because it does not get retransmitted and still has
     // retransmittable frames.
-    QuicPacketNumber unacked[] = {1, 2};
+    uint64_t unacked[] = {1, 2};
     VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
     EXPECT_TRUE(manager_.HasPendingRetransmissions());
   }
@@ -1260,7 +1294,7 @@
     EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
   }
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-  QuicPacketNumber unacked[] = {1, 2, 3};
+  uint64_t unacked[] = {1, 2, 3};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -1268,10 +1302,11 @@
   EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
 
   // Ensure both packets get discarded when packet 2 is acked.
-  QuicPacketNumber acked[] = {3};
+  uint64_t acked[] = {3};
   ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
-  manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(3, 4);
+  manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   VerifyUnackedPackets(nullptr, 0);
   VerifyRetransmittablePackets(nullptr, 0);
@@ -1314,7 +1349,7 @@
 
   // Ack a retransmission.
   // Ensure no packets are lost.
-  QuicPacketNumber largest_acked = 102;
+  QuicPacketNumber largest_acked = QuicPacketNumber(102);
   EXPECT_CALL(*send_algorithm_,
               OnCongestionEvent(true, _, _,
                                 Pointwise(PacketNumberEq(), {largest_acked}),
@@ -1324,7 +1359,8 @@
   // RTO's use loss detection instead of immediately declaring retransmitted
   // packets lost.
   for (int i = 1; i <= 99; ++i) {
-    EXPECT_CALL(debug_delegate, OnPacketLoss(i, LOSS_RETRANSMISSION, _));
+    EXPECT_CALL(debug_delegate,
+                OnPacketLoss(QuicPacketNumber(i), LOSS_RETRANSMISSION, _));
   }
   if (manager_.session_decides_what_to_write()) {
     if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) {
@@ -1349,8 +1385,9 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
     }
   }
-  manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now());
-  manager_.OnAckRange(102, 103);
+  manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 }
 
@@ -1448,7 +1485,7 @@
 
   // Ack a retransmission and expect no call to OnRetransmissionTimeout.
   // This will include packets in the lost packet map.
-  QuicPacketNumber largest_acked = 102;
+  QuicPacketNumber largest_acked = QuicPacketNumber(102);
   EXPECT_CALL(*send_algorithm_,
               OnCongestionEvent(true, _, _,
                                 Pointwise(PacketNumberEq(), {largest_acked}),
@@ -1477,8 +1514,9 @@
       EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98);
     }
   }
-  manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now());
-  manager_.OnAckRange(102, 103);
+  manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 }
 
@@ -1524,8 +1562,9 @@
   // Ack a retransmission and ensure OnRetransmissionTimeout is called.
   EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
   ExpectAck(2);
-  manager_.OnAckFrameStart(2, QuicTime::Delta::Zero(), clock_.Now());
-  manager_.OnAckRange(2, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Zero(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   // The original packet and newest should be outstanding.
@@ -1575,8 +1614,9 @@
   // Ack a retransmission and ensure OnRetransmissionTimeout is called.
   EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
   ExpectAck(3);
-  manager_.OnAckFrameStart(3, QuicTime::Delta::Zero(), clock_.Now());
-  manager_.OnAckRange(3, 4);
+  manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Zero(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   // The first two packets should still be outstanding.
@@ -1776,8 +1816,9 @@
   // Ack a packet before the first RTO and ensure the RTO timeout returns to the
   // original value and OnRetransmissionTimeout is not called or reverted.
   ExpectAck(2);
-  manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(2, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   EXPECT_EQ(5 * kDefaultLength,
@@ -1910,8 +1951,9 @@
   // set the loss timeout.
   ExpectAck(2);
   EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
-  manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(2, 3);
+  manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10));
@@ -2416,19 +2458,21 @@
 }
 
 TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) {
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), 1, _, _));
-  SerializedPacket packet(1, PACKET_4BYTE_PACKET_NUMBER, nullptr,
-                          kDefaultLength + 100, false, false);
-  manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION,
-                        HAS_RETRANSMITTABLE_DATA);
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, BytesInFlight(), QuicPacketNumber(1), _, _));
+  SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER,
+                          nullptr, kDefaultLength + 100, false, false);
+  manager_.OnPacketSent(&packet, QuicPacketNumber(), clock_.Now(),
+                        NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
 
   // Ack the large packet and expect the path MTU to increase.
   ExpectAck(1);
   EXPECT_CALL(*network_change_visitor_,
               OnPathMtuIncreased(kDefaultLength + 100));
   QuicAckFrame ack_frame = InitAckFrame(1);
-  manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(1, 2);
+  manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 }
 
@@ -2438,26 +2482,28 @@
     SendDataPacket(i);
   }
   // Ack [5, 7), [10, 12), [15, 17).
-  QuicPacketNumber acked1[] = {5, 6, 10, 11, 15, 16};
-  QuicPacketNumber lost1[] = {1, 2, 3, 4, 7, 8, 9, 12, 13};
+  uint64_t acked1[] = {5, 6, 10, 11, 15, 16};
+  uint64_t lost1[] = {1, 2, 3, 4, 7, 8, 9, 12, 13};
   ExpectAcksAndLosses(true, acked1, QUIC_ARRAYSIZE(acked1), lost1,
                       QUIC_ARRAYSIZE(lost1));
   EXPECT_CALL(notifier_, OnFrameLost(_)).Times(AnyNumber());
-  manager_.OnAckFrameStart(16, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(15, 17);
-  manager_.OnAckRange(10, 12);
-  manager_.OnAckRange(5, 7);
+  manager_.OnAckFrameStart(QuicPacketNumber(16), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(15), QuicPacketNumber(17));
+  manager_.OnAckRange(QuicPacketNumber(10), QuicPacketNumber(12));
+  manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(7));
   // Make sure empty range does not harm.
-  manager_.OnAckRange(4, 4);
+  manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(4));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 
   // Ack [4, 8), [9, 13), [14, 21).
-  QuicPacketNumber acked2[] = {4, 7, 9, 12, 14, 17, 18, 19, 20};
+  uint64_t acked2[] = {4, 7, 9, 12, 14, 17, 18, 19, 20};
   ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), nullptr, 0);
-  manager_.OnAckFrameStart(20, QuicTime::Delta::Infinite(), clock_.Now());
-  manager_.OnAckRange(14, 21);
-  manager_.OnAckRange(9, 13);
-  manager_.OnAckRange(4, 8);
+  manager_.OnAckFrameStart(QuicPacketNumber(20), QuicTime::Delta::Infinite(),
+                           clock_.Now());
+  manager_.OnAckRange(QuicPacketNumber(14), QuicPacketNumber(21));
+  manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13));
+  manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8));
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
 }
 
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 0eae3d4..b5e88ff 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -88,10 +88,6 @@
   connection_->SetDataProducer(this);
   connection_->SetFromConfig(config_);
 
-  // Make sure connection and control frame manager latch the same flag values.
-  connection_->set_donot_retransmit_old_window_updates(
-      control_frame_manager_.donot_retransmit_old_window_updates());
-
   DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()),
             GetMutableCryptoStream()->id());
   RegisterStaticStream(
@@ -189,6 +185,10 @@
     return false;
   }
 
+  if (visitor_) {
+    visitor_->OnStopSendingReceived(frame);
+  }
+
   // If stream is closed, ignore the frame
   if (IsClosedStream(stream_id)) {
     QUIC_DVLOG(1)
@@ -223,8 +223,15 @@
     return true;
   }
   stream->OnStopSending(frame.application_error_code);
-  // TODO(fkastenholz): Add in code to start rst-stream in the opposite
-  // direction once we add IETF-QUIC semantics for rst-stream.
+
+  stream->set_stream_error(
+      static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
+  SendRstStreamInner(
+      stream->id(),
+      static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
+      stream->stream_bytes_written(),
+      /*close_write_side_only=*/true);
+  stream->set_rst_sent(true);
 
   return true;
 }
@@ -561,26 +568,34 @@
 void QuicSession::SendRstStream(QuicStreamId id,
                                 QuicRstStreamErrorCode error,
                                 QuicStreamOffset bytes_written) {
-  if (QuicContainsKey(static_stream_map_, id)) {
-    QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
-    return;
-  }
+  SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
+}
 
+void QuicSession::SendRstStreamInner(QuicStreamId id,
+                                     QuicRstStreamErrorCode error,
+                                     QuicStreamOffset bytes_written,
+                                     bool close_write_side_only) {
   if (connection()->connected()) {
-    // Only send a RST_STREAM frame if still connected.
-    // Send a RST_STREAM frame. If version 99, will include
-    // an IETF-QUIC STOP_SENDING frame in the packet so that
-    // the peer also shuts down and sends a RST_STREAM back.
-    QuicConnection::ScopedPacketFlusher* flusher =
-        (connection_->transport_version() == QUIC_VERSION_99)
-            ? new QuicConnection::ScopedPacketFlusher(
-                  connection(), QuicConnection::SEND_ACK_IF_QUEUED)
-            : nullptr;
-    control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error,
-                                                             bytes_written);
-    if (flusher) {
-      delete flusher;
-      flusher = nullptr;
+    // Only send if still connected.
+    if (close_write_side_only) {
+      DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
+      // Send a RST_STREAM frame.
+      control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
+    } else {
+      // Send a RST_STREAM frame plus, if version 99, an IETF
+      // QUIC STOP_SENDING frame. Both sre sent to emulate
+      // the two-way close that Google QUIC's RST_STREAM does.
+      QuicConnection::ScopedPacketFlusher* flusher =
+          (connection_->transport_version() == QUIC_VERSION_99)
+              ? new QuicConnection::ScopedPacketFlusher(
+                    connection(), QuicConnection::SEND_ACK_IF_QUEUED)
+              : nullptr;
+      control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error,
+                                                               bytes_written);
+      if (flusher) {
+        delete flusher;
+        flusher = nullptr;
+      }
     }
     connection_->OnStreamReset(id, error);
   }
@@ -588,7 +603,18 @@
     OnStreamDoneWaitingForAcks(id);
     return;
   }
-  CloseStreamInner(id, true);
+  if (close_write_side_only) {
+    DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
+    DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
+    if (it != dynamic_stream_map_.end()) {
+      QuicStream* stream = it->second.get();
+      if (stream) {
+        stream->CloseWriteSide();
+      }
+    }
+  } else {
+    CloseStreamInner(id, true);
+  }
 }
 
 void QuicSession::SendGoAway(QuicErrorCode error_code,
@@ -671,7 +697,6 @@
     InsertLocallyClosedStreamsHighestOffset(
         stream_id, stream->flow_controller()->highest_received_byte_offset());
   }
-
   dynamic_stream_map_.erase(it);
   if (IsIncomingStream(stream_id)) {
     --num_dynamic_incoming_streams_;
@@ -719,6 +744,7 @@
   if (pending_stream_map_.find(stream_id) != pending_stream_map_.end()) {
     pending_stream_map_.erase(stream_id);
   }
+
   --num_dynamic_incoming_streams_;
 
   if (connection_->transport_version() == QUIC_VERSION_99) {
@@ -952,10 +978,7 @@
       // Discard originally encrypted packets, since they can't be decrypted by
       // the peer.
       NeuterUnencryptedData();
-      if (GetQuicReloadableFlag(quic_optimize_encryption_established)) {
-        QUIC_RELOADABLE_FLAG_COUNT(quic_optimize_encryption_established);
-        is_handshake_confirmed_ = true;
-      }
+      is_handshake_confirmed_ = true;
       break;
 
     default:
@@ -1468,6 +1491,14 @@
   return WRITE_FAILED;
 }
 
+bool QuicSession::WriteCryptoData(EncryptionLevel level,
+                                  QuicStreamOffset offset,
+                                  QuicByteCount data_length,
+                                  QuicDataWriter* writer) {
+  QUIC_BUG << "QuicSession::WriteCryptoData is unimplemented";
+  return false;
+}
+
 QuicUint128 QuicSession::GetStatelessResetToken() const {
   if (!QuicConnectionIdSupportsVariableLength(perspective())) {
     return QuicConnectionIdToUInt64(connection_->connection_id());
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index c542977..23778e7 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -62,6 +62,10 @@
 
     // Called when the session receives reset on a stream from the peer.
     virtual void OnRstStreamReceived(const QuicRstStreamFrame& frame) = 0;
+
+    // Called when the session receives a STOP_SENDING for a stream from the
+    // peer.
+    virtual void OnStopSendingReceived(const QuicStopSendingFrame& frame) = 0;
   };
 
   // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
@@ -130,6 +134,10 @@
                                         QuicStreamOffset offset,
                                         QuicByteCount data_length,
                                         QuicDataWriter* writer) override;
+  bool WriteCryptoData(EncryptionLevel level,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
 
   // SessionNotifierInterface methods:
   bool OnFrameAcked(const QuicFrame& frame,
@@ -498,9 +506,6 @@
     return stream_id_manager_;
   }
 
- private:
-  friend class test::QuicSessionPeer;
-
   // A StreamHandler represents an object which can receive a STREAM or
   // or RST_STREAM frame.
   struct StreamHandler {
@@ -524,6 +529,11 @@
     };
   };
 
+  StreamHandler GetOrCreateStreamImpl(QuicStreamId stream_id, bool may_buffer);
+
+ private:
+  friend class test::QuicSessionPeer;
+
   // Called in OnConfigNegotiated when we receive a new stream level flow
   // control window in a negotiated config. Closes the connection if invalid.
   void OnNewStreamFlowControlWindow(QuicStreamOffset new_window);
@@ -551,7 +561,6 @@
   // closed.
   QuicStream* GetStream(QuicStreamId id) const;
 
-  StreamHandler GetOrCreateStreamImpl(QuicStreamId stream_id, bool may_buffer);
   StreamHandler GetOrCreateDynamicStreamImpl(QuicStreamId stream_id,
                                              bool may_buffer);
 
@@ -562,6 +571,17 @@
   // Closes the pending stream |stream_id| before it has been created.
   void ClosePendingStream(QuicStreamId stream_id);
 
+  // Does actual work of sending reset-stream or reset-stream&stop-sending
+  // If the connection is not version 99/IETF QUIC, will always send a
+  // RESET_STREAM and close_write_side_only is ignored. If the connection is
+  // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if
+  // close_write_side_only is false, just a RESET_STREAM if
+  // close_write_side_only is true.
+  void SendRstStreamInner(QuicStreamId id,
+                          QuicRstStreamErrorCode error,
+                          QuicStreamOffset bytes_written,
+                          bool close_write_side_only);
+
   // Keep track of highest received byte offset of locally closed streams, while
   // waiting for a definitive final highest offset from the peer.
   std::map<QuicStreamId, QuicStreamOffset>
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 3baae32..6bf26ab 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -1291,18 +1291,30 @@
       1 + kInitialSessionFlowControlWindowForTest / 2;
 
   if (transport_version() == QUIC_VERSION_99) {
+    // Two more control frames than in Google QUIC, one is the STOP_SENDING
+    // frame, the other is the RST_STREAM generated in response.
     EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(3)
+        .Times(4)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)).Times(2);
   } else {
     EXPECT_CALL(*connection_, SendControlFrame(_))
         .Times(2)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   }
-  EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
                                QUIC_STREAM_CANCELLED, kByteOffset);
   session_.OnRstStream(rst_frame);
+  if (transport_version() == QUIC_VERSION_99) {
+    // The test is predicated on the stream being fully closed. For V99, the
+    // RST_STREAM only does one side (the read side from the perspective of the
+    // node receiving the RST_STREAM). This is needed to fully close the
+    // stream and therefore fulfill all of the expects.
+    QuicStopSendingFrame frame(kInvalidControlFrameId, stream->id(),
+                               QUIC_STREAM_CANCELLED);
+    EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  }
   EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
 }
 
@@ -1732,16 +1744,26 @@
   if (transport_version() == QUIC_VERSION_99) {
     // Once for the RST_STREAM, once for the STOP_SENDING
     EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(2)
+        .Times(3)
         .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_, OnStreamReset(stream2->id(), _)).Times(2);
   } else {
     // Just for the RST_STREAM
     EXPECT_CALL(*connection_, SendControlFrame(_))
         .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT));
   }
-  EXPECT_CALL(*connection_,
-              OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT));
   stream2->OnStreamReset(rst_frame);
+  if (transport_version() == QUIC_VERSION_99) {
+    // The test is predicated on the stream being fully closed. For V99, the
+    // RST_STREAM only does one side (the read side from the perspective of the
+    // node receiving the RST_STREAM). This is needed to fully close the
+    // stream and therefore fulfill all of the expects.
+    QuicStopSendingFrame frame(kInvalidControlFrameId, stream2->id(),
+                               QUIC_STREAM_CANCELLED);
+    EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  }
   EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
   ASSERT_EQ(1u, session_.closed_streams()->size());
   EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
@@ -1759,6 +1781,10 @@
   EXPECT_CALL(*connection_,
               OnStreamReset(stream4->id(), QUIC_STREAM_CANCELLED));
   stream4->WriteOrBufferData(body, false, nullptr);
+  // Note well: Reset() actually closes the stream in both directions. For
+  // GOOGLE QUIC it sends a RST_STREAM (which does a 2-way close), for IETF
+  // QUIC/V99 it sends both a RST_STREAM and a STOP_SENDING (each of which
+  // closes in only one direction).
   stream4->Reset(QUIC_STREAM_CANCELLED);
   EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id()));
   EXPECT_EQ(2u, session_.closed_streams()->size());
@@ -2279,10 +2305,24 @@
   }
 
   TestStream* stream = session_.CreateOutgoingBidirectionalStream();
+
+  // Ensure that the stream starts out open in both directions.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream));
+
   QuicStreamId stream_id = stream->id();
   QuicStopSendingFrame frame(1, stream_id, 123);
   EXPECT_CALL(*stream, OnStopSending(123));
+  // Expect a reset to come back out.xxxxx
+  EXPECT_CALL(*connection_, SendControlFrame(_));
+  EXPECT_CALL(
+      *connection_,
+      OnStreamReset(stream_id, static_cast<QuicRstStreamErrorCode>(123)));
   EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  // When the STOP_SENDING is received, the node generates a RST_STREAM,
+  // which closes the stream in the write direction. Ensure this.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream));
 }
 
 }  // namespace
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 30c02e0..6c8ea8d 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -293,12 +293,15 @@
       (kMaxStreamLength - frame.offset < frame.data_length);
   if (is_stream_too_long) {
     // Close connection if stream becomes too long.
-    QUIC_PEER_BUG
-        << "Receive stream frame reaches max stream length. frame offset "
-        << frame.offset << " length " << frame.data_length;
+    QUIC_PEER_BUG << "Receive stream frame on stream " << id_
+                  << " reaches max stream length. frame offset " << frame.offset
+                  << " length " << frame.data_length << ". "
+                  << sequencer_.DebugString();
     CloseConnectionWithDetails(
         QUIC_STREAM_LENGTH_OVERFLOW,
-        "Peer sends more data than allowed on this stream.");
+        QuicStrCat("Peer sends more data than allowed on stream ", id_,
+                   ". frame: offset = ", frame.offset, ", length = ",
+                   frame.data_length, ". ", sequencer_.DebugString()));
     return;
   }
   if (frame.fin) {
@@ -364,7 +367,11 @@
   }
 
   stream_error_ = frame.error_code;
-  CloseWriteSide();
+  // Google QUIC closes both sides of the stream in response to a
+  // RESET_STREAM, IETF QUIC closes only the read side.
+  if (transport_version() != QUIC_VERSION_99) {
+    CloseWriteSide();
+  }
   CloseReadSide();
 }
 
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h
index bc440d3..13a6b2c 100644
--- a/quic/core/quic_stream.h
+++ b/quic/core/quic_stream.h
@@ -45,7 +45,8 @@
 class QuicStream;
 
 // Buffers frames for a stream until the first byte of that frame arrives.
-class PendingStream : public QuicStreamSequencer::StreamInterface {
+class QUIC_EXPORT_PRIVATE PendingStream
+    : public QuicStreamSequencer::StreamInterface {
  public:
   PendingStream(QuicStreamId id, QuicSession* session);
   PendingStream(const PendingStream&) = delete;
@@ -70,6 +71,9 @@
   // If the final offset violates flow control, the connection will be closed.
   void OnRstStreamFrame(const QuicRstStreamFrame& frame);
 
+  // Returns the number of bytes read on this stream.
+  uint64_t stream_bytes_read() { return stream_bytes_read_; }
+
  private:
   friend class QuicStream;
 
@@ -341,6 +345,11 @@
   // QuicStream class.
   virtual void OnStopSending(uint16_t code);
 
+  // Close the write side of the socket.  Further writes will fail.
+  // Can be called by the subclass or internally.
+  // Does not send a FIN.  May cause the stream to be closed.
+  virtual void CloseWriteSide();
+
  protected:
   // Sends as many bytes in the first |count| buffers of |iov| to the connection
   // as the connection will consume. If FIN is consumed, the write side is
@@ -358,11 +367,6 @@
                                            QuicStreamOffset offset,
                                            bool fin);
 
-  // Close the write side of the socket.  Further writes will fail.
-  // Can be called by the subclass or internally.
-  // Does not send a FIN.  May cause the stream to be closed.
-  virtual void CloseWriteSide();
-
   // Close the read side of the socket.  May cause the stream to be closed.
   // Subclasses and consumers should use StopReading to terminate reading early
   // if expecting a FIN. Can be used directly by subclasses if not expecting a
diff --git a/quic/core/quic_stream_frame_data_producer.h b/quic/core/quic_stream_frame_data_producer.h
index 56922b1..ab67d54 100644
--- a/quic/core/quic_stream_frame_data_producer.h
+++ b/quic/core/quic_stream_frame_data_producer.h
@@ -24,6 +24,14 @@
                                                 QuicStreamOffset offset,
                                                 QuicByteCount data_length,
                                                 QuicDataWriter* writer) = 0;
+
+  // Writes the data for a CRYPTO frame to |writer| for a frame at encryption
+  // level |level| starting at offset |offset| for |data_length| bytes. Returns
+  // whether writing the data was successful.
+  virtual bool WriteCryptoData(EncryptionLevel level,
+                               QuicStreamOffset offset,
+                               QuicByteCount data_length,
+                               QuicDataWriter* writer) = 0;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_stream_id_manager.cc b/quic/core/quic_stream_id_manager.cc
index ede2056..ce08e59 100644
--- a/quic/core/quic_stream_id_manager.cc
+++ b/quic/core/quic_stream_id_manager.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
diff --git a/quic/core/quic_stream_id_manager.h b/quic/core/quic_stream_id_manager.h
index d30f5cd..95951c0 100644
--- a/quic/core/quic_stream_id_manager.h
+++ b/quic/core/quic_stream_id_manager.h
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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.
 #ifndef QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_
 #define QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_
 
diff --git a/quic/core/quic_stream_id_manager_test.cc b/quic/core/quic_stream_id_manager_test.cc
index 80252c3..5647d75 100644
--- a/quic/core/quic_stream_id_manager_test.cc
+++ b/quic/core/quic_stream_id_manager_test.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
 
 #include <cstdint>
diff --git a/quic/core/quic_stream_sequencer.h b/quic/core/quic_stream_sequencer.h
index 00ead04..dfe5e7d 100644
--- a/quic/core/quic_stream_sequencer.h
+++ b/quic/core/quic_stream_sequencer.h
@@ -20,8 +20,6 @@
 class QuicStreamSequencerPeer;
 }  // namespace test
 
-class QuicStream;
-
 // Buffers frames until we have something which can be passed
 // up to the next layer.
 class QUIC_EXPORT_PRIVATE QuicStreamSequencer {
diff --git a/quic/core/quic_stream_sequencer_buffer.cc b/quic/core/quic_stream_sequencer_buffer.cc
index 6e720e0..b96a89a 100644
--- a/quic/core/quic_stream_sequencer_buffer.cc
+++ b/quic/core/quic_stream_sequencer_buffer.cc
@@ -91,7 +91,7 @@
       // Extend the right edge of last interval.
       // TODO(fayang): Encapsulate this into a future version of QuicIntervalSet
       // if this is more efficient than Add.
-      const_cast<QuicInterval<QuicPacketNumber>*>(&(*bytes_received_.rbegin()))
+      const_cast<QuicInterval<QuicStreamOffset>*>(&(*bytes_received_.rbegin()))
           ->SetMax(starting_offset + size);
     } else {
       bytes_received_.Add(starting_offset, starting_offset + size);
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc
index 3b49f72..e8338b3 100644
--- a/quic/core/quic_stream_test.cc
+++ b/quic/core/quic_stream_test.cc
@@ -8,6 +8,7 @@
 
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -126,6 +127,18 @@
     return true;
   }
 
+  bool ClearResetStreamFrame(const QuicFrame& frame) {
+    EXPECT_EQ(RST_STREAM_FRAME, frame.type);
+    DeleteFrame(&const_cast<QuicFrame&>(frame));
+    return true;
+  }
+
+  bool ClearStopSendingFrame(const QuicFrame& frame) {
+    EXPECT_EQ(STOP_SENDING_FRAME, frame.type);
+    DeleteFrame(&const_cast<QuicFrame&>(frame));
+    return true;
+  }
+
  protected:
   MockQuicConnectionHelper helper_;
   MockAlarmFactory alarm_factory_;
@@ -686,7 +699,8 @@
   QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength,
                                QuicStringPiece("."));
   EXPECT_QUIC_PEER_BUG(stream_->OnStreamFrame(stream_frame),
-                       "Receive stream frame reaches max stream length");
+                       QuicStrCat("Receive stream frame on stream ",
+                                  stream_->id(), " reaches max stream length"));
 }
 
 TEST_P(QuicParameterizedStreamTest, SetDrainingIncomingOutgoing) {
@@ -1067,7 +1081,6 @@
   QuicConsumedData consumed = stream_->WriteMemSlices(storage.ToSpan(), false);
   EXPECT_EQ(data.length(), consumed.bytes_consumed);
   struct iovec iov2 = {const_cast<char*>(data.data()), 1u};
-  SimpleBufferAllocator allocator2;
   QuicMemSliceStorage storage2(
       &iov2, 1,
       session_->connection()->helper()->GetStreamSendBufferAllocator(), 1024);
@@ -1445,6 +1458,10 @@
 TEST_P(QuicParameterizedStreamTest, CheckStopSending) {
   Initialize();
   const int kStopSendingCode = 123;
+  // These must start as false.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  // Expect to actually see a stop sending if and only if we are in version 99.
   if (connection_->transport_version() == QUIC_VERSION_99) {
     EXPECT_CALL(*session_, SendStopSending(kStopSendingCode, stream_->id()))
         .Times(1);
@@ -1452,6 +1469,74 @@
     EXPECT_CALL(*session_, SendStopSending(_, _)).Times(0);
   }
   stream_->SendStopSending(kStopSendingCode);
+  // Sending a STOP_SENDING does not actually close the local stream.
+  // Our implementation waits for the responding RESET_STREAM to effect the
+  // closes. Therefore, read- and write-side closes should both be false.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+}
+
+// Test that OnStreamReset does one-way (read) closes if version 99, two way
+// (read and write) if not version 99.
+TEST_P(QuicStreamTest, OnStreamResetReadOrReadWrite) {
+  Initialize();
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+
+  QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
+                               QUIC_STREAM_CANCELLED, 1234);
+  stream_->OnStreamReset(rst_frame);
+  if (connection_->transport_version() == QUIC_VERSION_99) {
+    // Version 99/IETF QUIC should close just the read side.
+    EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
+    EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  } else {
+    // Google QUIC should close both sides of the stream.
+    EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
+    EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
+  }
+}
+
+// Test that receiving a STOP_SENDING just closes the write side of the stream.
+// If not V99, the test is a noop (no STOP_SENDING in Google QUIC).
+TEST_P(QuicStreamTest, OnStopSendingReadOrReadWrite) {
+  Initialize();
+  if (connection_->transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+
+  // Simulate receipt of a STOP_SENDING.
+  stream_->OnStopSending(123);
+
+  // Should close just the read side.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
+}
+
+// SendOnlyRstStream must only send a RESET_STREAM (no bundled STOP_SENDING).
+TEST_P(QuicStreamTest, SendOnlyRstStream) {
+  Initialize();
+  if (connection_->transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  EXPECT_CALL(*connection_,
+              OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .Times(1)
+      .WillOnce(Invoke(this, &QuicStreamTest::ClearResetStreamFrame));
+
+  QuicSessionPeer::SendRstStreamInner(session_.get(), stream_->id(),
+                                      QUIC_BAD_APPLICATION_PAYLOAD,
+                                      stream_->stream_bytes_written(),
+                                      /*close_write_side_only=*/true);
+
+  // ResetStreamOnly should just close the write side.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
 }
 
 }  // namespace
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc
index 86be54d..731df3e 100644
--- a/quic/core/quic_time_wait_list_manager.cc
+++ b/quic/core/quic_time_wait_list_manager.cc
@@ -12,6 +12,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_framer.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -245,11 +246,11 @@
     result = writer_->Flush();
   }
 
-  if (result.status == WRITE_STATUS_BLOCKED) {
+  if (IsWriteBlockedStatus(result.status)) {
     // If blocked and unbuffered, return false to retry sending.
     DCHECK(writer_->IsWriteBlocked());
     visitor_->OnWriteBlocked(this);
-    return writer_->IsWriteBlockedDataBuffered();
+    return result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED;
   } else if (IsWriteError(result.status)) {
     QUIC_LOG_FIRST_N(WARNING, 1)
         << "Received unknown error while sending termination packet to "
diff --git a/quic/core/quic_time_wait_list_manager_test.cc b/quic/core/quic_time_wait_list_manager_test.cc
index 0fced02..0d3244b 100644
--- a/quic/core/quic_time_wait_list_manager_test.cc
+++ b/quic/core/quic_time_wait_list_manager_test.cc
@@ -185,7 +185,7 @@
   QuicEncryptedPacket* ConstructEncryptedPacket(
       QuicConnectionId destination_connection_id,
       QuicConnectionId source_connection_id,
-      QuicPacketNumber packet_number) {
+      uint64_t packet_number) {
     return quic::test::ConstructEncryptedPacket(destination_connection_id,
                                                 source_connection_id, false,
                                                 false, packet_number, "data");
@@ -406,9 +406,8 @@
   QuicConnectionId connection_id = TestConnectionId(1);
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(connection_id));
   AddConnectionId(connection_id, QuicTimeWaitListManager::SEND_STATELESS_RESET);
-  QuicPacketNumber packet_number = 234;
   std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
-      connection_id, EmptyQuicConnectionId(), packet_number));
+      connection_id, EmptyQuicConnectionId(), /*packet_number=*/234));
   // Let first write through.
   EXPECT_CALL(writer_,
               WritePacket(_, _, self_address_.host(), peer_address_, _))
@@ -433,9 +432,8 @@
   EXPECT_CALL(visitor_, OnConnectionAddedToTimeWaitList(other_connection_id));
   AddConnectionId(other_connection_id,
                   QuicTimeWaitListManager::SEND_STATELESS_RESET);
-  QuicPacketNumber other_packet_number = 23423;
   std::unique_ptr<QuicEncryptedPacket> other_packet(ConstructEncryptedPacket(
-      other_connection_id, EmptyQuicConnectionId(), other_packet_number));
+      other_connection_id, EmptyQuicConnectionId(), /*packet_number=*/23423));
   EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0);
   EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
   ProcessPacket(other_connection_id);
diff --git a/quic/core/quic_trace_visitor.cc b/quic/core/quic_trace_visitor.cc
index 08363e2..b0fc8ae 100644
--- a/quic/core/quic_trace_visitor.cc
+++ b/quic/core/quic_trace_visitor.cc
@@ -59,7 +59,7 @@
   quic_trace::Event* event = trace_.add_events();
   event->set_event_type(quic_trace::PACKET_SENT);
   event->set_time_us(ConvertTimestampToRecordedFormat(sent_time));
-  event->set_packet_number(serialized_packet.packet_number);
+  event->set_packet_number(serialized_packet.packet_number.ToUint64());
   event->set_packet_size(serialized_packet.encrypted_length);
   event->set_encryption_level(
       EncryptionLevelToProto(serialized_packet.encryption_level));
@@ -140,8 +140,8 @@
         quic_trace::AckBlock* block = info->add_acked_packets();
         // We record intervals as [a, b], whereas the in-memory representation
         // we currently use is [a, b).
-        block->set_first_packet(interval.min());
-        block->set_last_packet(interval.max() - 1);
+        block->set_first_packet(interval.min().ToUint64());
+        block->set_last_packet(interval.max().ToUint64() - 1);
       }
       break;
     }
@@ -240,7 +240,7 @@
   quic_trace::Event* event = trace_.add_events();
   event->set_time_us(ConvertTimestampToRecordedFormat(ack_receive_time));
   event->set_packet_number(
-      connection_->received_packet_manager().GetLargestObserved());
+      connection_->received_packet_manager().GetLargestObserved().ToUint64());
   event->set_event_type(quic_trace::PACKET_RECEIVED);
 
   // TODO(vasilvv): consider removing this copy.
@@ -255,7 +255,7 @@
   quic_trace::Event* event = trace_.add_events();
   event->set_time_us(ConvertTimestampToRecordedFormat(detection_time));
   event->set_event_type(quic_trace::PACKET_LOST);
-  event->set_packet_number(lost_packet_number);
+  event->set_packet_number(lost_packet_number.ToUint64());
   PopulateTransportState(event->mutable_transport_state());
 }
 
@@ -265,7 +265,7 @@
   event->set_time_us(ConvertTimestampToRecordedFormat(receive_time));
   event->set_event_type(quic_trace::PACKET_RECEIVED);
   event->set_packet_number(
-      connection_->received_packet_manager().GetLargestObserved());
+      connection_->received_packet_manager().GetLargestObserved().ToUint64());
 
   // TODO(vasilvv): consider removing this copy.
   QuicWindowUpdateFrame copy_of_update = frame;
diff --git a/quic/core/quic_trace_visitor_test.cc b/quic/core/quic_trace_visitor_test.cc
index 5d98d55..402fa77 100644
--- a/quic/core/quic_trace_visitor_test.cc
+++ b/quic/core/quic_trace_visitor_test.cc
@@ -135,20 +135,22 @@
 
         const quic_trace::AckInfo& info = frame.ack_info();
         for (const auto& block : info.acked_packets()) {
-          packets.Add(block.first_packet(), block.last_packet() + 1);
+          packets.Add(QuicPacketNumber(block.first_packet()),
+                      QuicPacketNumber(block.last_packet()) + 1);
         }
       }
     }
     if (packet.event_type() == quic_trace::PACKET_LOST) {
-      packets.Add(packet.packet_number(), packet.packet_number() + 1);
+      packets.Add(QuicPacketNumber(packet.packet_number()),
+                  QuicPacketNumber(packet.packet_number()) + 1);
     }
   }
 
   ASSERT_EQ(1u, packets.Size());
-  EXPECT_EQ(1u, packets.begin()->min());
+  EXPECT_EQ(QuicPacketNumber(1u), packets.begin()->min());
   // We leave some room (20 packets) for the packets which did not receive
   // conclusive status at the end of simulation.
-  EXPECT_GT(packets.rbegin()->max(), packets_sent_ - 20);
+  EXPECT_GT(packets.rbegin()->max(), QuicPacketNumber(packets_sent_ - 20));
 }
 
 TEST_F(QuicTraceVisitorTest, TransportState) {
diff --git a/quic/core/quic_transmission_info.cc b/quic/core/quic_transmission_info.cc
index 582f939..6e9d02c 100644
--- a/quic/core/quic_transmission_info.cc
+++ b/quic/core/quic_transmission_info.cc
@@ -15,9 +15,7 @@
       in_flight(false),
       state(OUTSTANDING),
       has_crypto_handshake(false),
-      num_padding_bytes(0),
-      retransmission(kInvalidPacketNumber),
-      largest_acked(kInvalidPacketNumber) {}
+      num_padding_bytes(0) {}
 
 QuicTransmissionInfo::QuicTransmissionInfo(
     EncryptionLevel level,
@@ -35,9 +33,7 @@
       in_flight(false),
       state(OUTSTANDING),
       has_crypto_handshake(has_crypto_handshake),
-      num_padding_bytes(num_padding_bytes),
-      retransmission(kInvalidPacketNumber),
-      largest_acked(kInvalidPacketNumber) {}
+      num_padding_bytes(num_padding_bytes) {}
 
 QuicTransmissionInfo::QuicTransmissionInfo(const QuicTransmissionInfo& other) =
     default;
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 47811c7..7718468 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_number.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 
@@ -27,7 +28,6 @@
 
 typedef uint64_t QuicByteCount;
 typedef uint64_t QuicPacketCount;
-typedef uint64_t QuicPacketNumber;
 typedef uint64_t QuicPublicResetNonceProof;
 typedef uint64_t QuicStreamOffset;
 typedef std::array<char, 32> DiversificationNonce;
@@ -80,7 +80,10 @@
 // TODO(wtc): see if WriteStatus can be replaced by QuicAsyncStatus.
 enum WriteStatus {
   WRITE_STATUS_OK,
+  // Write is blocked, caller needs to retry.
   WRITE_STATUS_BLOCKED,
+  // Write is blocked but the packet data is buffered, caller should not retry.
+  WRITE_STATUS_BLOCKED_DATA_BUFFERED,
   // To make the IsWriteError(WriteStatus) function work properly:
   // - Non-errors MUST be added before WRITE_STATUS_ERROR.
   // - Errors MUST be added after WRITE_STATUS_ERROR.
@@ -89,6 +92,11 @@
   WRITE_STATUS_NUM_VALUES,
 };
 
+inline bool IsWriteBlockedStatus(WriteStatus status) {
+  return status == WRITE_STATUS_BLOCKED ||
+         status == WRITE_STATUS_BLOCKED_DATA_BUFFERED;
+}
+
 inline bool IsWriteError(WriteStatus status) {
   return status >= WRITE_STATUS_ERROR;
 }
@@ -107,6 +115,7 @@
       case WRITE_STATUS_OK:
         return bytes_written == other.bytes_written;
       case WRITE_STATUS_BLOCKED:
+      case WRITE_STATUS_BLOCKED_DATA_BUFFERED:
         return true;
       default:
         return error_code == other.error_code;
@@ -208,32 +217,41 @@
 // encodings.
 enum QuicIetfFrameType : uint8_t {
   IETF_PADDING = 0x00,
-  IETF_RST_STREAM = 0x01,
-  IETF_CONNECTION_CLOSE = 0x02,
-  IETF_APPLICATION_CLOSE = 0x03,
-  IETF_MAX_DATA = 0x04,
-  IETF_MAX_STREAM_DATA = 0x05,
-  IETF_MAX_STREAM_ID = 0x06,
-  IETF_PING = 0x07,
-  IETF_BLOCKED = 0x08,
-  IETF_STREAM_BLOCKED = 0x09,
-  IETF_STREAM_ID_BLOCKED = 0x0a,
-  IETF_NEW_CONNECTION_ID = 0x0b,
-  IETF_STOP_SENDING = 0x0c,
-  IETF_RETIRE_CONNECTION_ID = 0x0d,
-  IETF_PATH_CHALLENGE = 0x0e,
-  IETF_PATH_RESPONSE = 0x0f,
+  IETF_PING = 0x01,
+  IETF_ACK = 0x02,
+  IETF_ACK_ECN = 0x03,
+  IETF_RST_STREAM = 0x04,
+  IETF_STOP_SENDING = 0x05,
+  IETF_CRYPTO = 0x06,
+  IETF_NEW_TOKEN = 0x07,
   // the low-3 bits of the stream frame type value are actually flags
   // declaring what parts of the frame are/are-not present, as well as
   // some other control information. The code would then do something
-  // along the lines of "if ((frame_type & 0xf8) == 0x10)" to determine
+  // along the lines of "if ((frame_type & 0xf8) == 0x08)" to determine
   // whether the frame is a stream frame or not, and then examine each
   // bit specifically when/as needed.
-  IETF_STREAM = 0x10,
-  IETF_CRYPTO = 0x18,
-  IETF_NEW_TOKEN = 0x19,
-  IETF_ACK = 0x1a,
-  IETF_ACK_ECN = 0x1b,
+  IETF_STREAM = 0x08,
+  // 0x09 through 0x0f are various flag settings of the IETF_STREAM frame.
+  IETF_MAX_DATA = 0x10,
+  IETF_MAX_STREAM_DATA = 0x11,
+  IETF_MAX_STREAM_ID = 0x12,  // TODO(fkastenholz): Will become IETF_MAX_STREAMS
+  // 0x13 reserved, a flag setting for IETF_MAX_STREAMS.
+  IETF_BLOCKED = 0x14,  // TODO(fkastenholz): Should, eventually, be renamed to
+                        // IETF_DATA_BLOCKED
+  IETF_STREAM_BLOCKED = 0x15,  // TODO(fkastenholz): Should, eventually, be
+                               // renamed to IETF_STREAM_DATA_BLOCKED
+  IETF_STREAM_ID_BLOCKED =
+      0x16,  // TODO(fkastenholz): Will become IETF_STREAMS_BLOCKED
+  // 0x17 reserved, a flag setting for IETF_STREAMS_BLOCKED
+  IETF_NEW_CONNECTION_ID = 0x18,
+  IETF_RETIRE_CONNECTION_ID = 0x19,
+  IETF_PATH_CHALLENGE = 0x1a,
+  IETF_PATH_RESPONSE = 0x1b,
+  IETF_CONNECTION_CLOSE = 0x1c,
+  // 0x1d reserved, a flag setting for IETF_CONNECTION_CLOSE
+  // TODO(fkastenholz): IETF_APPLICATION_CLOSE disappears in the next version of
+  // QUIC. It is retained temporarily
+  IETF_APPLICATION_CLOSE = 0x1d,
 
   // MESSAGE frame type is not yet determined, use 0x2x temporarily to give
   // stream frame some wiggle room.
@@ -256,7 +274,7 @@
 enum QuicPacketNumberLength : uint8_t {
   PACKET_1BYTE_PACKET_NUMBER = 1,
   PACKET_2BYTE_PACKET_NUMBER = 2,
-  PACKET_3BYTE_PACKET_NUMBER = 3,  // Only used in v99.
+  PACKET_3BYTE_PACKET_NUMBER = 3,  // Used in version > QUIC_VERSION_46.
   PACKET_4BYTE_PACKET_NUMBER = 4,
   // TODO(rch): Remove this when we remove QUIC_VERSION_39.
   PACKET_6BYTE_PACKET_NUMBER = 6,
diff --git a/quic/core/quic_unacked_packet_map.cc b/quic/core/quic_unacked_packet_map.cc
index 3da540e..32fd272 100644
--- a/quic/core/quic_unacked_packet_map.cc
+++ b/quic/core/quic_unacked_packet_map.cc
@@ -25,11 +25,7 @@
 }  // namespace
 
 QuicUnackedPacketMap::QuicUnackedPacketMap()
-    : largest_sent_packet_(0),
-      largest_sent_retransmittable_packet_(0),
-      largest_sent_largest_acked_(0),
-      largest_acked_(0),
-      least_unacked_(1),
+    : least_unacked_(FirstSendingPacketNumber()),
       bytes_in_flight_(0),
       pending_crypto_packet_count_(0),
       last_crypto_packet_sent_time_(QuicTime::Zero()),
@@ -49,7 +45,10 @@
                                          bool set_in_flight) {
   QuicPacketNumber packet_number = packet->packet_number;
   QuicPacketLength bytes_sent = packet->encrypted_length;
-  QUIC_BUG_IF(largest_sent_packet_ >= packet_number) << packet_number;
+  QUIC_BUG_IF(largest_sent_packet_.IsInitialized() &&
+              largest_sent_packet_ >= packet_number)
+      << "largest_sent_packet_: " << largest_sent_packet_
+      << ", packet_number: " << packet_number;
   DCHECK_GE(packet_number, least_unacked_ + unacked_packets_.size());
   while (least_unacked_ + unacked_packets_.size() < packet_number) {
     unacked_packets_.push_back(QuicTransmissionInfo());
@@ -62,9 +61,13 @@
       packet->encryption_level, packet->packet_number_length, transmission_type,
       sent_time, bytes_sent, has_crypto_handshake, packet->num_padding_bytes);
   info.largest_acked = packet->largest_acked;
-  largest_sent_largest_acked_ =
-      std::max(largest_sent_largest_acked_, packet->largest_acked);
-  if (old_packet_number > 0) {
+  if (packet->largest_acked.IsInitialized()) {
+    largest_sent_largest_acked_ =
+        largest_sent_largest_acked_.IsInitialized()
+            ? std::max(largest_sent_largest_acked_, packet->largest_acked)
+            : packet->largest_acked;
+  }
+  if (old_packet_number.IsInitialized()) {
     TransferRetransmissionInfo(old_packet_number, packet_number,
                                transmission_type, &info);
   }
@@ -78,7 +81,7 @@
   unacked_packets_.push_back(info);
   // Swap the retransmittable frames to avoid allocations.
   // TODO(ianswett): Could use emplace_back when Chromium can.
-  if (old_packet_number == kInvalidPacketNumber) {
+  if (!old_packet_number.IsInitialized()) {
     if (has_crypto_handshake) {
       ++pending_crypto_packet_count_;
       last_crypto_packet_sent_time_ = sent_time;
@@ -180,12 +183,12 @@
     QuicTransmissionInfo* info) {
   if (session_decides_what_to_write_) {
     DeleteFrames(&info->retransmittable_frames);
-    info->retransmission = kInvalidPacketNumber;
+    info->retransmission.Clear();
     return;
   }
-  while (info->retransmission != kInvalidPacketNumber) {
+  while (info->retransmission.IsInitialized()) {
     const QuicPacketNumber retransmission = info->retransmission;
-    info->retransmission = kInvalidPacketNumber;
+    info->retransmission.Clear();
     info = &unacked_packets_[retransmission - least_unacked_];
   }
 
@@ -209,7 +212,7 @@
 
 void QuicUnackedPacketMap::IncreaseLargestAcked(
     QuicPacketNumber largest_acked) {
-  DCHECK_LE(largest_acked_, largest_acked);
+  DCHECK(!largest_acked_.IsInitialized() || largest_acked_ <= largest_acked);
   largest_acked_ = largest_acked;
 }
 
@@ -218,7 +221,8 @@
     const QuicTransmissionInfo& info) const {
   // Packet can be used for RTT measurement if it may yet be acked as the
   // largest observed packet by the receiver.
-  return QuicUtils::IsAckable(info.state) && packet_number > largest_acked_;
+  return QuicUtils::IsAckable(info.state) &&
+         (!largest_acked_.IsInitialized() || packet_number > largest_acked_);
 }
 
 bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
@@ -233,15 +237,16 @@
     // Packet may have retransmittable frames, or the data may have been
     // retransmitted with a new packet number.
     // Allow for an extra 1 RTT before stopping to track old packets.
-    return info.retransmission > largest_acked_ ||
+    return (info.retransmission.IsInitialized() &&
+            (!largest_acked_.IsInitialized() ||
+             info.retransmission > largest_acked_)) ||
            HasRetransmittableFrames(info);
   }
 
   // Wait for 1 RTT before giving up on the lost packet.
-  if (info.retransmission > largest_acked_) {
-    return true;
-  }
-  return false;
+  return info.retransmission.IsInitialized() &&
+         (!largest_acked_.IsInitialized() ||
+          info.retransmission > largest_acked_);
 }
 
 bool QuicUnackedPacketMap::IsPacketUseless(
@@ -472,7 +477,7 @@
 
 void QuicUnackedPacketMap::SetSessionDecideWhatToWrite(
     bool session_decides_what_to_write) {
-  if (largest_sent_packet_ > 0) {
+  if (largest_sent_packet_.IsInitialized()) {
     QUIC_BUG << "Cannot change session_decide_what_to_write with packets sent.";
     return;
   }
diff --git a/quic/core/quic_unacked_packet_map_test.cc b/quic/core/quic_unacked_packet_map_test.cc
index a4d0289..df14321 100644
--- a/quic/core/quic_unacked_packet_map_test.cc
+++ b/quic/core/quic_unacked_packet_map_test.cc
@@ -46,30 +46,31 @@
 
   ~QuicUnackedPacketMapTest() override {}
 
-  SerializedPacket CreateRetransmittablePacket(QuicPacketNumber packet_number) {
+  SerializedPacket CreateRetransmittablePacket(uint64_t packet_number) {
     return CreateRetransmittablePacketForStream(
         packet_number, QuicUtils::GetHeadersStreamId(
                            CurrentSupportedVersions()[0].transport_version));
   }
 
   SerializedPacket CreateRetransmittablePacketForStream(
-      QuicPacketNumber packet_number,
+      uint64_t packet_number,
       QuicStreamId stream_id) {
-    SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, false, false);
+    SerializedPacket packet(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            false, false);
     QuicStreamFrame frame;
     frame.stream_id = stream_id;
     packet.retransmittable_frames.push_back(QuicFrame(frame));
     return packet;
   }
 
-  SerializedPacket CreateNonRetransmittablePacket(
-      QuicPacketNumber packet_number) {
-    return SerializedPacket(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr,
-                            kDefaultLength, false, false);
+  SerializedPacket CreateNonRetransmittablePacket(uint64_t packet_number) {
+    return SerializedPacket(QuicPacketNumber(packet_number),
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            false, false);
   }
 
-  void VerifyInFlightPackets(QuicPacketNumber* packets, size_t num_packets) {
+  void VerifyInFlightPackets(uint64_t* packets, size_t num_packets) {
     unacked_packets_.RemoveObsoletePackets();
     if (num_packets == 0) {
       EXPECT_FALSE(unacked_packets_.HasInFlightPackets());
@@ -79,12 +80,16 @@
     if (num_packets == 1) {
       EXPECT_TRUE(unacked_packets_.HasInFlightPackets());
       EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
-      ASSERT_TRUE(unacked_packets_.IsUnacked(packets[0]));
-      EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[0]).in_flight);
+      ASSERT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(packets[0])));
+      EXPECT_TRUE(
+          unacked_packets_.GetTransmissionInfo(QuicPacketNumber(packets[0]))
+              .in_flight);
     }
     for (size_t i = 0; i < num_packets; ++i) {
-      ASSERT_TRUE(unacked_packets_.IsUnacked(packets[i]));
-      EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[i]).in_flight);
+      ASSERT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(packets[i])));
+      EXPECT_TRUE(
+          unacked_packets_.GetTransmissionInfo(QuicPacketNumber(packets[i]))
+              .in_flight);
     }
     size_t in_flight_count = 0;
     for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
@@ -96,7 +101,7 @@
     EXPECT_EQ(num_packets, in_flight_count);
   }
 
-  void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
+  void VerifyUnackedPackets(uint64_t* packets, size_t num_packets) {
     unacked_packets_.RemoveObsoletePackets();
     if (num_packets == 0) {
       EXPECT_TRUE(unacked_packets_.empty());
@@ -107,13 +112,13 @@
     }
     EXPECT_FALSE(unacked_packets_.empty());
     for (size_t i = 0; i < num_packets; ++i) {
-      EXPECT_TRUE(unacked_packets_.IsUnacked(packets[i])) << packets[i];
+      EXPECT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(packets[i])))
+          << packets[i];
     }
     EXPECT_EQ(num_packets, unacked_packets_.GetNumUnackedPacketsDebugOnly());
   }
 
-  void VerifyRetransmittablePackets(QuicPacketNumber* packets,
-                                    size_t num_packets) {
+  void VerifyRetransmittablePackets(uint64_t* packets, size_t num_packets) {
     unacked_packets_.RemoveObsoletePackets();
     size_t num_retransmittable_packets = 0;
     for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
@@ -124,29 +129,33 @@
     }
     EXPECT_EQ(num_packets, num_retransmittable_packets);
     for (size_t i = 0; i < num_packets; ++i) {
-      EXPECT_TRUE(unacked_packets_.HasRetransmittableFrames(packets[i]))
+      EXPECT_TRUE(unacked_packets_.HasRetransmittableFrames(
+          QuicPacketNumber(packets[i])))
           << " packets[" << i << "]:" << packets[i];
     }
   }
 
-  void UpdatePacketState(QuicPacketNumber packet_number,
-                         SentPacketState state) {
-    unacked_packets_.GetMutableTransmissionInfo(packet_number)->state = state;
+  void UpdatePacketState(uint64_t packet_number, SentPacketState state) {
+    unacked_packets_
+        .GetMutableTransmissionInfo(QuicPacketNumber(packet_number))
+        ->state = state;
   }
 
-  void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
-                               QuicPacketNumber new_packet_number,
+  void RetransmitAndSendPacket(uint64_t old_packet_number,
+                               uint64_t new_packet_number,
                                TransmissionType transmission_type) {
-    DCHECK(unacked_packets_.HasRetransmittableFrames(old_packet_number));
+    DCHECK(unacked_packets_.HasRetransmittableFrames(
+        QuicPacketNumber(old_packet_number)));
     if (!unacked_packets_.session_decides_what_to_write()) {
       SerializedPacket packet(
           CreateNonRetransmittablePacket(new_packet_number));
-      unacked_packets_.AddSentPacket(&packet, old_packet_number,
+      unacked_packets_.AddSentPacket(&packet,
+                                     QuicPacketNumber(old_packet_number),
                                      transmission_type, now_, true);
       return;
     }
-    QuicTransmissionInfo* info =
-        unacked_packets_.GetMutableTransmissionInfo(old_packet_number);
+    QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo(
+        QuicPacketNumber(old_packet_number));
     QuicStreamId stream_id = QuicUtils::GetHeadersStreamId(
         CurrentSupportedVersions()[0].transport_version);
     for (const auto& frame : info->retransmittable_frames) {
@@ -158,10 +167,11 @@
     UpdatePacketState(
         old_packet_number,
         QuicUtils::RetransmissionTypeToPacketState(transmission_type));
-    info->retransmission = new_packet_number;
+    info->retransmission = QuicPacketNumber(new_packet_number);
     SerializedPacket packet(
         CreateRetransmittablePacketForStream(new_packet_number, stream_id));
-    unacked_packets_.AddSentPacket(&packet, 0, transmission_type, now_, true);
+    unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                   transmission_type, now_, true);
   }
   QuicUnackedPacketMap unacked_packets_;
   QuicTime now_;
@@ -173,14 +183,15 @@
 TEST_P(QuicUnackedPacketMapTest, RttOnly) {
   // Acks are only tracked for RTT measurement purposes.
   SerializedPacket packet(CreateNonRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, false);
+  unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, false);
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(nullptr, 0);
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.IncreaseLargestAcked(1);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(1));
   VerifyUnackedPackets(nullptr, 0);
   VerifyInFlightPackets(nullptr, 0);
   VerifyRetransmittablePackets(nullptr, 0);
@@ -189,24 +200,25 @@
 TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
   // Simulate a retransmittable packet being sent and acked.
   SerializedPacket packet(CreateRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(unacked, QUIC_ARRAYSIZE(unacked));
 
-  unacked_packets_.RemoveRetransmittability(1);
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(1));
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.IncreaseLargestAcked(1);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(1));
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.RemoveFromInFlight(1);
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
   VerifyUnackedPackets(nullptr, 0);
   VerifyInFlightPackets(nullptr, 0);
   VerifyRetransmittablePackets(nullptr, 0);
@@ -215,12 +227,13 @@
 TEST_P(QuicUnackedPacketMapTest, StopRetransmission) {
   const QuicStreamId stream_id = 2;
   SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
-  unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  QuicPacketNumber retransmittable[] = {1};
+  uint64_t retransmittable[] = {1};
   VerifyRetransmittablePackets(retransmittable,
                                QUIC_ARRAYSIZE(retransmittable));
 
@@ -237,12 +250,13 @@
 TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) {
   const QuicStreamId stream_id = 2;
   SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
-  unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked[] = {1};
+  uint64_t unacked[] = {1};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  QuicPacketNumber retransmittable[] = {1};
+  uint64_t retransmittable[] = {1};
   VerifyRetransmittablePackets(retransmittable,
                                QUIC_ARRAYSIZE(retransmittable));
 
@@ -259,13 +273,14 @@
 TEST_P(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) {
   const QuicStreamId stream_id = 2;
   SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id));
-  unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION);
 
-  QuicPacketNumber unacked[] = {1, 2};
+  uint64_t unacked[] = {1, 2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  std::vector<QuicPacketNumber> retransmittable;
+  std::vector<uint64_t> retransmittable;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable = {1, 2};
   } else {
@@ -287,13 +302,14 @@
   // Simulate a retransmittable packet being sent, retransmitted, and the first
   // transmission being acked.
   SerializedPacket packet1(CreateRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION);
 
-  QuicPacketNumber unacked[] = {1, 2};
+  uint64_t unacked[] = {1, 2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  std::vector<QuicPacketNumber> retransmittable;
+  std::vector<uint64_t> retransmittable;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable = {1, 2};
   } else {
@@ -302,23 +318,23 @@
   VerifyRetransmittablePackets(&retransmittable[0], retransmittable.size());
 
   EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
-  unacked_packets_.RemoveRetransmittability(1);
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(1));
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.IncreaseLargestAcked(2);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.RemoveFromInFlight(2);
-  QuicPacketNumber unacked2[] = {1};
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  uint64_t unacked2[] = {1};
   VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
   VerifyInFlightPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
   VerifyRetransmittablePackets(nullptr, 0);
 
-  unacked_packets_.RemoveFromInFlight(1);
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
   VerifyUnackedPackets(nullptr, 0);
   VerifyInFlightPackets(nullptr, 0);
   VerifyRetransmittablePackets(nullptr, 0);
@@ -327,31 +343,34 @@
 TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
   // Simulate a retransmittable packet being sent and retransmitted twice.
   SerializedPacket packet1(CreateRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   SerializedPacket packet2(CreateRetransmittablePacket(2));
-  unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet2, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked[] = {1, 2};
+  uint64_t unacked[] = {1, 2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  QuicPacketNumber retransmittable[] = {1, 2};
+  uint64_t retransmittable[] = {1, 2};
   VerifyRetransmittablePackets(retransmittable,
                                QUIC_ARRAYSIZE(retransmittable));
 
   // Early retransmit 1 as 3 and send new data as 4.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  unacked_packets_.RemoveRetransmittability(2);
-  unacked_packets_.RemoveFromInFlight(1);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
   RetransmitAndSendPacket(1, 3, LOSS_RETRANSMISSION);
   SerializedPacket packet4(CreateRetransmittablePacket(4));
-  unacked_packets_.AddSentPacket(&packet4, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet4, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked2[] = {1, 3, 4};
+  uint64_t unacked2[] = {1, 3, 4};
   VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
-  QuicPacketNumber pending2[] = {3, 4};
+  uint64_t pending2[] = {3, 4};
   VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2));
-  std::vector<QuicPacketNumber> retransmittable2;
+  std::vector<uint64_t> retransmittable2;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable2 = {1, 3, 4};
   } else {
@@ -360,15 +379,16 @@
   VerifyRetransmittablePackets(&retransmittable2[0], retransmittable2.size());
 
   // Early retransmit 3 (formerly 1) as 5, and remove 1 from unacked.
-  unacked_packets_.IncreaseLargestAcked(4);
-  unacked_packets_.RemoveFromInFlight(4);
-  unacked_packets_.RemoveRetransmittability(4);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(4));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(4));
   RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
   SerializedPacket packet6(CreateRetransmittablePacket(6));
-  unacked_packets_.AddSentPacket(&packet6, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet6, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  std::vector<QuicPacketNumber> unacked3;
-  std::vector<QuicPacketNumber> retransmittable3;
+  std::vector<uint64_t> unacked3;
+  std::vector<uint64_t> retransmittable3;
   if (unacked_packets_.session_decides_what_to_write()) {
     unacked3 = {3, 5, 6};
     retransmittable3 = {3, 5, 6};
@@ -378,17 +398,17 @@
   }
   VerifyUnackedPackets(&unacked3[0], unacked3.size());
   VerifyRetransmittablePackets(&retransmittable3[0], retransmittable3.size());
-  QuicPacketNumber pending3[] = {3, 5, 6};
+  uint64_t pending3[] = {3, 5, 6};
   VerifyInFlightPackets(pending3, QUIC_ARRAYSIZE(pending3));
 
   // Early retransmit 5 as 7 and ensure in flight packet 3 is not removed.
-  unacked_packets_.IncreaseLargestAcked(6);
-  unacked_packets_.RemoveFromInFlight(6);
-  unacked_packets_.RemoveRetransmittability(6);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(6));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(6));
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(6));
   RetransmitAndSendPacket(5, 7, LOSS_RETRANSMISSION);
 
-  std::vector<QuicPacketNumber> unacked4;
-  std::vector<QuicPacketNumber> retransmittable4;
+  std::vector<uint64_t> unacked4;
+  std::vector<uint64_t> retransmittable4;
   if (unacked_packets_.session_decides_what_to_write()) {
     unacked4 = {3, 5, 7};
     retransmittable4 = {3, 5, 7};
@@ -398,42 +418,44 @@
   }
   VerifyUnackedPackets(&unacked4[0], unacked4.size());
   VerifyRetransmittablePackets(&retransmittable4[0], retransmittable4.size());
-  QuicPacketNumber pending4[] = {3, 5, 7};
+  uint64_t pending4[] = {3, 5, 7};
   VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4));
 
   // Remove the older two transmissions from in flight.
-  unacked_packets_.RemoveFromInFlight(3);
-  unacked_packets_.RemoveFromInFlight(5);
-  QuicPacketNumber pending5[] = {7};
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  uint64_t pending5[] = {7};
   VerifyInFlightPackets(pending5, QUIC_ARRAYSIZE(pending5));
 }
 
 TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) {
   // Simulate a retransmittable packet being sent and retransmitted twice.
   SerializedPacket packet1(CreateRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   SerializedPacket packet2(CreateRetransmittablePacket(2));
-  unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet2, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked[] = {1, 2};
+  uint64_t unacked[] = {1, 2};
   VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked));
   VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked));
-  QuicPacketNumber retransmittable[] = {1, 2};
+  uint64_t retransmittable[] = {1, 2};
   VerifyRetransmittablePackets(retransmittable,
                                QUIC_ARRAYSIZE(retransmittable));
 
   // Early retransmit 1 as 3.
-  unacked_packets_.IncreaseLargestAcked(2);
-  unacked_packets_.RemoveFromInFlight(2);
-  unacked_packets_.RemoveRetransmittability(2);
-  unacked_packets_.RemoveFromInFlight(1);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(2));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1));
   RetransmitAndSendPacket(1, 3, LOSS_RETRANSMISSION);
 
-  QuicPacketNumber unacked2[] = {1, 3};
+  uint64_t unacked2[] = {1, 3};
   VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
-  QuicPacketNumber pending2[] = {3};
+  uint64_t pending2[] = {3};
   VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2));
-  std::vector<QuicPacketNumber> retransmittable2;
+  std::vector<uint64_t> retransmittable2;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable2 = {1, 3};
   } else {
@@ -444,13 +466,14 @@
   // TLP 3 (formerly 1) as 4, and don't remove 1 from unacked.
   RetransmitAndSendPacket(3, 4, TLP_RETRANSMISSION);
   SerializedPacket packet5(CreateRetransmittablePacket(5));
-  unacked_packets_.AddSentPacket(&packet5, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet5, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
 
-  QuicPacketNumber unacked3[] = {1, 3, 4, 5};
+  uint64_t unacked3[] = {1, 3, 4, 5};
   VerifyUnackedPackets(unacked3, QUIC_ARRAYSIZE(unacked3));
-  QuicPacketNumber pending3[] = {3, 4, 5};
+  uint64_t pending3[] = {3, 4, 5};
   VerifyInFlightPackets(pending3, QUIC_ARRAYSIZE(pending3));
-  std::vector<QuicPacketNumber> retransmittable3;
+  std::vector<uint64_t> retransmittable3;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable3 = {1, 3, 4, 5};
   } else {
@@ -459,23 +482,23 @@
   VerifyRetransmittablePackets(&retransmittable3[0], retransmittable3.size());
 
   // Early retransmit 4 as 6 and ensure in flight packet 3 is removed.
-  unacked_packets_.IncreaseLargestAcked(5);
-  unacked_packets_.RemoveFromInFlight(5);
-  unacked_packets_.RemoveRetransmittability(5);
-  unacked_packets_.RemoveFromInFlight(3);
-  unacked_packets_.RemoveFromInFlight(4);
+  unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(5));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(5));
+  unacked_packets_.RemoveRetransmittability(QuicPacketNumber(5));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
+  unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
   RetransmitAndSendPacket(4, 6, LOSS_RETRANSMISSION);
 
-  std::vector<QuicPacketNumber> unacked4;
+  std::vector<uint64_t> unacked4;
   if (unacked_packets_.session_decides_what_to_write()) {
     unacked4 = {4, 6};
   } else {
     unacked4 = {4, 6};
   }
   VerifyUnackedPackets(&unacked4[0], unacked4.size());
-  QuicPacketNumber pending4[] = {6};
+  uint64_t pending4[] = {6};
   VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4));
-  std::vector<QuicPacketNumber> retransmittable4;
+  std::vector<uint64_t> retransmittable4;
   if (unacked_packets_.session_decides_what_to_write()) {
     retransmittable4 = {4, 6};
   } else {
@@ -488,18 +511,20 @@
   // Simulate a retransmittable packet being sent, retransmitted, and the first
   // transmission being acked.
   SerializedPacket packet1(CreateRetransmittablePacket(1));
-  unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet1, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   SerializedPacket packet3(CreateRetransmittablePacket(3));
-  unacked_packets_.AddSentPacket(&packet3, 0, NOT_RETRANSMISSION, now_, true);
+  unacked_packets_.AddSentPacket(&packet3, QuicPacketNumber(),
+                                 NOT_RETRANSMISSION, now_, true);
   RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
 
-  EXPECT_EQ(1u, unacked_packets_.GetLeastUnacked());
-  EXPECT_TRUE(unacked_packets_.IsUnacked(1));
-  EXPECT_FALSE(unacked_packets_.IsUnacked(2));
-  EXPECT_TRUE(unacked_packets_.IsUnacked(3));
-  EXPECT_FALSE(unacked_packets_.IsUnacked(4));
-  EXPECT_TRUE(unacked_packets_.IsUnacked(5));
-  EXPECT_EQ(5u, unacked_packets_.largest_sent_packet());
+  EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.GetLeastUnacked());
+  EXPECT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(1)));
+  EXPECT_FALSE(unacked_packets_.IsUnacked(QuicPacketNumber(2)));
+  EXPECT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(3)));
+  EXPECT_FALSE(unacked_packets_.IsUnacked(QuicPacketNumber(4)));
+  EXPECT_TRUE(unacked_packets_.IsUnacked(QuicPacketNumber(5)));
+  EXPECT_EQ(QuicPacketNumber(5u), unacked_packets_.largest_sent_packet());
 }
 
 TEST_P(QuicUnackedPacketMapTest, AggregateContiguousAckedStreamFrames) {
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index a08328c..be6eeea 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -443,6 +443,37 @@
                           QUIC_ARRAYSIZE(connection_id_bytes));
 }
 
+// static
+bool QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+    QuicTransportVersion version) {
+  // TODO(dschinazi): Allow in appropriate version when supported.
+  return false;
+}
+
+// static
+QuicConnectionId QuicUtils::CreateZeroConnectionId(
+    QuicTransportVersion version) {
+  if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER) ||
+      !QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) {
+    return QuicConnectionIdFromUInt64(0);
+  }
+  if (!VariableLengthConnectionIdAllowedForVersion(version)) {
+    char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    return QuicConnectionId(static_cast<char*>(connection_id_bytes),
+                            QUIC_ARRAYSIZE(connection_id_bytes));
+  }
+  return EmptyQuicConnectionId();
+}
+
+// static
+bool QuicUtils::IsConnectionIdValidForVersion(QuicConnectionId connection_id,
+                                              QuicTransportVersion version) {
+  if (VariableLengthConnectionIdAllowedForVersion(version)) {
+    return true;
+  }
+  return connection_id.length() == kQuicDefaultConnectionIdLength;
+}
+
 QuicUint128 QuicUtils::GenerateStatelessResetToken(
     QuicConnectionId connection_id) {
   if (!QuicConnectionIdUseNetworkByteOrder()) {
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 114465e..111080a 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -151,6 +151,19 @@
   static QuicConnectionId CreateRandomConnectionId(QuicRandom* random,
                                                    Perspective perspective);
 
+  // Returns true if the QUIC version allows variable length connection IDs.
+  static bool VariableLengthConnectionIdAllowedForVersion(
+      QuicTransportVersion version);
+
+  // Returns true if the connection ID is valid for this QUIC version.
+  static bool IsConnectionIdValidForVersion(QuicConnectionId connection_id,
+                                            QuicTransportVersion version);
+
+  // Returns a connection ID suitable for QUIC use-cases that do not need the
+  // connection ID for multiplexing. If the version allows variable lengths,
+  // a connection of length zero is returned, otherwise 64bits set to zero.
+  static QuicConnectionId CreateZeroConnectionId(QuicTransportVersion version);
+
   // Generates a 128bit stateless reset token based on a connection ID.
   static QuicUint128 GenerateStatelessResetToken(
       QuicConnectionId connection_id);
diff --git a/quic/core/quic_utils_test.cc b/quic/core/quic_utils_test.cc
index d725e72..d1b5268 100644
--- a/quic/core/quic_utils_test.cc
+++ b/quic/core/quic_utils_test.cc
@@ -183,6 +183,23 @@
   EXPECT_NE(connection_id, TestConnectionId(1));
 }
 
+TEST_F(QuicUtilsTest, VariableLengthConnectionId) {
+  EXPECT_FALSE(
+      QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_35));
+  EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion(
+      QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35), QUIC_VERSION_35));
+  EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion(
+      QuicUtils::CreateZeroConnectionId(QUIC_VERSION_99), QUIC_VERSION_99));
+  if (!QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_SERVER) ||
+      !QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_CLIENT)) {
+    return;
+  }
+  EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35),
+            EmptyQuicConnectionId());
+  EXPECT_FALSE(QuicUtils::IsConnectionIdValidForVersion(EmptyQuicConnectionId(),
+                                                        QUIC_VERSION_35));
+}
+
 TEST_F(QuicUtilsTest, StatelessResetToken) {
   QuicConnectionId connection_id1a = test::TestConnectionId(1);
   QuicConnectionId connection_id1b = test::TestConnectionId(1);
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 7d5e3f3..064e932 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -15,6 +15,7 @@
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
     : enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)),
+      enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)),
       enable_version_46_(GetQuicReloadableFlag(quic_enable_version_46)),
       enable_version_45_(GetQuicReloadableFlag(quic_enable_version_45)),
       enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)),
@@ -39,12 +40,14 @@
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
   if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) ||
+      enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) ||
       enable_version_46_ != GetQuicReloadableFlag(quic_enable_version_46) ||
       enable_version_45_ != GetQuicReloadableFlag(quic_enable_version_45) ||
       enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) ||
       enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) ||
       disable_version_35_ != GetQuicReloadableFlag(quic_disable_version_35)) {
     enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99);
+    enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47);
     enable_version_46_ = GetQuicReloadableFlag(quic_enable_version_46);
     enable_version_45_ = GetQuicReloadableFlag(quic_enable_version_45);
     enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44);
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index d3b18fe..1196c31 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -37,6 +37,8 @@
  private:
   // quic_enable_version_99 flag
   bool enable_version_99_;
+  // quic_enable_version_47 flag
+  bool enable_version_47_;
   // quic_enable_version_46 flag
   bool enable_version_46_;
   // quic_enable_version_45 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index d70b852..b734b89 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -16,9 +16,10 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
@@ -58,11 +59,18 @@
                                         QUIC_VERSION_39, QUIC_VERSION_35}),
             manager.GetSupportedTransportVersions());
 
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  EXPECT_EQ(
+      QuicTransportVersionVector(
+          {QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
+           QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
+      manager.GetSupportedTransportVersions());
+
   SetQuicReloadableFlag(quic_enable_version_99, true);
   EXPECT_EQ(
       QuicTransportVersionVector(
-          {QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
-           QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
+          {QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
+           QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
       manager.GetSupportedTransportVersions());
 
   // Ensure that all versions are now supported.
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 7db4254..6f050dd 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -66,6 +66,8 @@
       return MakeVersionLabel(proto, '0', '4', '5');
     case QUIC_VERSION_46:
       return MakeVersionLabel(proto, '0', '4', '6');
+    case QUIC_VERSION_47:
+      return MakeVersionLabel(proto, '0', '4', '7');
     case QUIC_VERSION_99:
       return MakeVersionLabel(proto, '0', '9', '9');
     default:
@@ -103,7 +105,7 @@
   // Reading from the client so this should not be considered an ERROR.
   QUIC_DLOG(INFO) << "Unsupported QuicVersionLabel version: "
                   << QuicVersionLabelToString(version_label);
-  return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+  return UnsupportedQuicVersion();
 }
 
 QuicTransportVersionVector AllSupportedTransportVersions() {
@@ -159,6 +161,15 @@
   for (ParsedQuicVersion version : versions) {
     if (version.transport_version == QUIC_VERSION_99) {
       if (GetQuicReloadableFlag(quic_enable_version_99) &&
+          GetQuicReloadableFlag(quic_enable_version_47) &&
+          GetQuicReloadableFlag(quic_enable_version_46) &&
+          GetQuicReloadableFlag(quic_enable_version_45) &&
+          GetQuicReloadableFlag(quic_enable_version_44) &&
+          GetQuicReloadableFlag(quic_enable_version_43)) {
+        filtered_versions.push_back(version);
+      }
+    } else if (version.transport_version == QUIC_VERSION_47) {
+      if (GetQuicReloadableFlag(quic_enable_version_47) &&
           GetQuicReloadableFlag(quic_enable_version_46) &&
           GetQuicReloadableFlag(quic_enable_version_45) &&
           GetQuicReloadableFlag(quic_enable_version_44) &&
@@ -219,8 +230,7 @@
   if (index >= 0 && index < version_count) {
     version.push_back(versions[index]);
   } else {
-    version.push_back(
-        ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED));
+    version.push_back(UnsupportedQuicVersion());
   }
   return version;
 }
@@ -286,6 +296,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_44);
     RETURN_STRING_LITERAL(QUIC_VERSION_45);
     RETURN_STRING_LITERAL(QUIC_VERSION_46);
+    RETURN_STRING_LITERAL(QUIC_VERSION_47);
     RETURN_STRING_LITERAL(QUIC_VERSION_99);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
@@ -327,9 +338,7 @@
 }
 
 ParsedQuicVersion UnsupportedQuicVersion() {
-  static const ParsedQuicVersion kUnsupportedQuicVersion(
-      PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
-  return kUnsupportedQuicVersion;
+  return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
 }
 
 #undef RETURN_STRING_LITERAL  // undef for jumbo builds
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index 2f780ab..2c3ba1f 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -102,6 +102,8 @@
   QUIC_VERSION_44 = 44,  // Use IETF header format.
   QUIC_VERSION_45 = 45,  // Added MESSAGE frame.
   QUIC_VERSION_46 = 46,  // Use CRYPTO frames for QuicCryptoStreams.
+  QUIC_VERSION_47 = 47,  // Use IETF draft-17 header format with demultiplexing
+                         // bit.
   QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not
                          // yet ready for production.
 };
@@ -164,8 +166,8 @@
 //
 // See go/new-quic-version for more details on how to roll out new versions.
 static const QuicTransportVersion kSupportedTransportVersions[] = {
-    QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
-    QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+    QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
+    QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
 
 // This vector contains all crypto handshake protocols that are supported.
 static const HandshakeProtocol kSupportedHandshakeProtocols[] = {
@@ -206,8 +208,7 @@
 VersionOfIndex(const QuicTransportVersionVector& versions, int index);
 
 // Returns QUIC version of |index| in result of |versions|. Returns
-// ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED) if |index|
-// is out of bounds.
+// UnsupportedQuicVersion() if |index| is out of bounds.
 QUIC_EXPORT_PRIVATE ParsedQuicVersionVector
 ParsedVersionOfIndex(const ParsedQuicVersionVector& versions, int index);
 
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index e9e1854..a0f664e 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -53,8 +53,10 @@
   CREATE_QUIC_MOCK_LOG(log);
   log.StartCapturingLogs();
 
-  EXPECT_QUIC_LOG_CALL_CONTAINS(log, ERROR,
-                                "Unsupported QuicTransportVersion: 0");
+  if (QUIC_LOG_ERROR_IS_ON()) {
+    EXPECT_QUIC_LOG_CALL_CONTAINS(log, ERROR,
+                                  "Unsupported QuicTransportVersion: 0");
+  }
 
   EXPECT_EQ(0u, QuicVersionToQuicVersionLabel(QUIC_VERSION_UNSUPPORTED));
 }
@@ -90,11 +92,11 @@
 
 TEST_F(QuicVersionsTest, QuicVersionLabelToQuicVersionUnsupported) {
   CREATE_QUIC_MOCK_LOG(log);
-#if QUIC_DLOG_INFO_IS_ON
-  EXPECT_QUIC_LOG_CALL_CONTAINS(log, INFO,
-                                "Unsupported QuicVersionLabel version: EKAF")
-      .Times(1);
-#endif
+  if (QUIC_DLOG_INFO_IS_ON()) {
+    EXPECT_QUIC_LOG_CALL_CONTAINS(log, INFO,
+                                  "Unsupported QuicVersionLabel version: EKAF")
+        .Times(1);
+  }
   log.StartCapturingLogs();
 
   EXPECT_EQ(QUIC_VERSION_UNSUPPORTED,
@@ -119,11 +121,11 @@
   EXPECT_EQ(PROTOCOL_TLS1_3, QuicVersionLabelToHandshakeProtocol(tls_tag));
 
   FLAGS_quic_supports_tls_handshake = false;
-#if QUIC_DLOG_INFO_IS_ON
-  EXPECT_QUIC_LOG_CALL_CONTAINS(log, INFO,
-                                "Unsupported QuicVersionLabel version: T043")
-      .Times(1);
-#endif
+  if (QUIC_DLOG_INFO_IS_ON()) {
+    EXPECT_QUIC_LOG_CALL_CONTAINS(log, INFO,
+                                  "Unsupported QuicVersionLabel version: T043")
+        .Times(1);
+  }
   EXPECT_EQ(PROTOCOL_UNSUPPORTED, QuicVersionLabelToHandshakeProtocol(tls_tag));
 }
 
@@ -140,6 +142,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '5')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+            ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '7')));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -155,20 +159,24 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
 
   FLAGS_quic_supports_tls_handshake = false;
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
+  EXPECT_EQ(UnsupportedQuicVersion(),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
 }
 
 TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
@@ -190,6 +198,9 @@
   EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)));
+  EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '7'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47)));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -211,20 +222,25 @@
   EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46)));
+  EXPECT_EQ(MakeVersionLabel('T', '0', '4', '7'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47)));
 
   FLAGS_quic_supports_tls_handshake = false;
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+  EXPECT_EQ(UnsupportedQuicVersion(),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
+  EXPECT_EQ(UnsupportedQuicVersion(),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
 }
 
 TEST_F(QuicVersionsTest, QuicVersionLabelToString) {
@@ -274,7 +290,7 @@
 }
 
 TEST_F(QuicVersionsTest, ParsedQuicVersionToString) {
-  ParsedQuicVersion unsupported(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+  ParsedQuicVersion unsupported = UnsupportedQuicVersion();
   ParsedQuicVersion version35(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35);
   EXPECT_EQ("Q035", ParsedQuicVersionToString(version35));
   EXPECT_EQ("0", ParsedQuicVersionToString(unsupported));
@@ -313,14 +329,15 @@
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
     parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
   }
   QuicTransportVersionVector expected_versions = {
-      QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
-      QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+      QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45,
+      QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
   ParsedQuicVersionVector expected_parsed_versions;
   for (QuicTransportVersion version : expected_versions) {
     expected_parsed_versions.push_back(
@@ -338,6 +355,33 @@
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  SetQuicReloadableFlag(quic_enable_version_99, false);
+  ParsedQuicVersionVector parsed_versions;
+  for (QuicTransportVersion version : all_versions) {
+    parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+  QuicTransportVersionVector expected_versions = {
+      QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
+      QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+  ParsedQuicVersionVector expected_parsed_versions;
+  for (QuicTransportVersion version : expected_versions) {
+    expected_parsed_versions.push_back(
+        ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+
+  ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
+  ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
+}
+
+TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) {
+  QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  SetQuicReloadableFlag(quic_disable_version_35, false);
+  SetQuicReloadableFlag(quic_enable_version_43, true);
+  SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -363,6 +407,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
   SetQuicReloadableFlag(quic_enable_version_46, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -388,6 +433,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_46, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -412,6 +458,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_46, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -436,6 +483,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_46, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -460,6 +508,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_46, false);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -495,9 +544,8 @@
     if (i >= 0 && i < version_count) {
       EXPECT_EQ(all_versions[i], ParsedVersionOfIndex(all_versions, i)[0]);
     } else {
-      EXPECT_EQ(
-          ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-          ParsedVersionOfIndex(all_versions, i)[0]);
+      EXPECT_EQ(UnsupportedQuicVersion(),
+                ParsedVersionOfIndex(all_versions, i)[0]);
     }
   }
 }
@@ -516,7 +564,7 @@
 // yet a typo was made in doing the #defines and it was caught
 // only in some test far removed from here... Better safe than sorry.
 TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_35, 35);
   EXPECT_EQ(QUIC_VERSION_39, 39);
@@ -524,6 +572,7 @@
   EXPECT_EQ(QUIC_VERSION_44, 44);
   EXPECT_EQ(QUIC_VERSION_45, 45);
   EXPECT_EQ(QUIC_VERSION_46, 46);
+  EXPECT_EQ(QUIC_VERSION_47, 47);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
 }  // namespace
diff --git a/quic/core/stateless_rejector_test.cc b/quic/core/stateless_rejector_test.cc
index 609c6a0..497fe54 100644
--- a/quic/core/stateless_rejector_test.cc
+++ b/quic/core/stateless_rejector_test.cc
@@ -52,8 +52,7 @@
 
 // Test various combinations of QUIC version and flag state.
 struct TestParams {
-  ParsedQuicVersion version =
-      ParsedQuicVersion{PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED};
+  ParsedQuicVersion version = UnsupportedQuicVersion();
   FlagsMode flags;
 };
 
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index dd52515..5edce8a 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -65,8 +65,9 @@
 
 bool TlsClientHandshaker::CryptoConnect() {
   CrypterPair crypters;
-  CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT,
-                                        session()->connection_id(), &crypters);
+  CryptoUtils::CreateTlsInitialCrypters(
+      Perspective::IS_CLIENT, session()->connection()->transport_version(),
+      session()->connection_id(), &crypters);
   session()->connection()->SetEncrypter(ENCRYPTION_NONE,
                                         std::move(crypters.encrypter));
   session()->connection()->SetDecrypter(ENCRYPTION_NONE,
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index f7a3242..a96e406 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -62,8 +62,9 @@
       proof_source_(proof_source),
       crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {
   CrypterPair crypters;
-  CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_SERVER,
-                                        session->connection_id(), &crypters);
+  CryptoUtils::CreateTlsInitialCrypters(
+      Perspective::IS_SERVER, session->connection()->transport_version(),
+      session->connection_id(), &crypters);
   session->connection()->SetEncrypter(ENCRYPTION_NONE,
                                       std::move(crypters.encrypter));
   session->connection()->SetDecrypter(ENCRYPTION_NONE,
diff --git a/quic/core/uber_quic_stream_id_manager.cc b/quic/core/uber_quic_stream_id_manager.cc
index 7531952..51ea994 100644
--- a/quic/core/uber_quic_stream_id_manager.cc
+++ b/quic/core/uber_quic_stream_id_manager.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
diff --git a/quic/core/uber_quic_stream_id_manager.h b/quic/core/uber_quic_stream_id_manager.h
index f07694a..bf5a588 100644
--- a/quic/core/uber_quic_stream_id_manager.h
+++ b/quic/core/uber_quic_stream_id_manager.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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.
+
 #ifndef QUICHE_QUIC_CORE_UBER_QUIC_STREAM_ID_MANAGER_H_
 #define QUICHE_QUIC_CORE_UBER_QUIC_STREAM_ID_MANAGER_H_
 
diff --git a/quic/core/uber_quic_stream_id_manager_test.cc b/quic/core/uber_quic_stream_id_manager_test.cc
index 258b157..a413a0b 100644
--- a/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/quic/core/uber_quic_stream_id_manager_test.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
diff --git a/quic/platform/api/quic_cert_utils.h b/quic/platform/api/quic_cert_utils.h
new file mode 100644
index 0000000..1c660b5
--- /dev/null
+++ b/quic/platform/api/quic_cert_utils.h
@@ -0,0 +1,23 @@
+// Copyright 2016 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._
+
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/quic/platform/impl/quic_cert_utils_impl.h"
+
+namespace quic {
+
+class QuicCertUtils {
+ public:
+  static bool ExtractSubjectNameFromDERCert(QuicStringPiece cert,
+                                            QuicStringPiece* subject_out) {
+    return QuicCertUtilsImpl::ExtractSubjectNameFromDERCert(cert, subject_out);
+  }
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_
diff --git a/quic/platform/api/quic_client_stats.h b/quic/platform/api/quic_client_stats.h
index d1a3154..b780ba6 100644
--- a/quic/platform/api/quic_client_stats.h
+++ b/quic/platform/api/quic_client_stats.h
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
 #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_CLIENT_STATS_H_
 #define QUICHE_QUIC_PLATFORM_API_QUIC_CLIENT_STATS_H_
 
diff --git a/quic/platform/api/quic_epoll.h b/quic/platform/api/quic_epoll.h
new file mode 100644
index 0000000..c289ef4
--- /dev/null
+++ b/quic/platform/api/quic_epoll.h
@@ -0,0 +1,15 @@
+#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
+#define QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
+
+#include "net/quic/platform/impl/quic_epoll_impl.h"
+
+namespace quic {
+
+using QuicEpollServer = QuicEpollServerImpl;
+using QuicEpollEvent = QuicEpollEventImpl;
+using QuicEpollAlarmBase = QuicEpollAlarmBaseImpl;
+using QuicEpollCallbackInterface = QuicEpollCallbackInterfaceImpl;
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
diff --git a/quic/platform/api/quic_file_utils.cc b/quic/platform/api/quic_file_utils.cc
new file mode 100644
index 0000000..5492b83
--- /dev/null
+++ b/quic/platform/api/quic_file_utils.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2019 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/third_party/quiche/src/quic/platform/api/quic_file_utils.h"
+
+#include "net/quic/platform/impl/quic_file_utils_impl.h"
+
+namespace quic {
+
+// Traverses the directory |dirname| and retuns all of the files
+// it contains.
+std::vector<QuicString> ReadFileContents(const QuicString& dirname) {
+  return ReadFileContentsImpl(dirname);
+}
+
+// Reads the contents of |filename| as a string into |contents|.
+void ReadFileContents(QuicStringPiece filename, QuicString* contents) {
+  ReadFileContentsImpl(filename, contents);
+}
+
+}  // namespace quic
diff --git a/quic/platform/api/quic_file_utils.h b/quic/platform/api/quic_file_utils.h
index 463af0d..0f270ef 100644
--- a/quic/platform/api/quic_file_utils.h
+++ b/quic/platform/api/quic_file_utils.h
@@ -7,22 +7,20 @@
 
 #include <vector>
 
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/quic/platform/impl/quic_file_utils_impl.h"
 
 namespace quic {
 
 // Traverses the directory |dirname| and retuns all of the files
 // it contains.
-std::vector<QuicString> ReadFileContents(const QuicString& dirname) {
-  return ReadFileContentsImpl(dirname);
-}
+QUIC_EXPORT_PRIVATE std::vector<QuicString> ReadFileContents(
+    const QuicString& dirname);
 
 // Reads the contents of |filename| as a string into |contents|.
-void ReadFileContents(QuicStringPiece filename, QuicString* contents) {
-  ReadFileContentsImpl(filename, contents);
-}
+QUIC_EXPORT_PRIVATE void ReadFileContents(QuicStringPiece filename,
+                                          QuicString* contents);
 
 }  // namespace quic
 
diff --git a/quic/platform/api/quic_goog_cc_sender.h b/quic/platform/api/quic_goog_cc_sender.h
deleted file mode 100644
index ba08cb3..0000000
--- a/quic/platform/api/quic_goog_cc_sender.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2018 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.
-
-#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_GOOG_CC_SENDER_H_
-#define QUICHE_QUIC_PLATFORM_API_QUIC_GOOG_CC_SENDER_H_
-
-#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
-#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
-#include "net/quic/platform/impl/quic_goog_cc_sender_impl.h"
-
-namespace quic {
-
-// Interface for creating a GoogCC SendAlgorithmInterface.
-// TODO(b/122312335): Remove this file.
-SendAlgorithmInterface* CreateGoogCcSender(
-    const QuicClock* clock,
-    const RttStats* rtt_stats,
-    const QuicUnackedPacketMap* unacked_packets,
-    QuicRandom* random,
-    QuicConnectionStats* stats,
-    QuicPacketCount initial_congestion_window,
-    QuicPacketCount max_congestion_window) {
-  return CreateGoogCcSenderImpl(clock, rtt_stats, unacked_packets, random,
-                                stats, initial_congestion_window,
-                                max_congestion_window);
-}
-
-}  // namespace quic
-
-#endif  // QUICHE_QUIC_PLATFORM_API_QUIC_GOOG_CC_SENDER_H_
diff --git a/quic/platform/api/quic_hostname_utils.h b/quic/platform/api/quic_hostname_utils.h
index 61958c2..7f2b98a 100644
--- a/quic/platform/api/quic_hostname_utils.h
+++ b/quic/platform/api/quic_hostname_utils.h
@@ -5,7 +5,6 @@
 #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_HOSTNAME_UTILS_H_
 #define QUICHE_QUIC_PLATFORM_API_QUIC_HOSTNAME_UTILS_H_
 
-#include "base/macros.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
diff --git a/quic/platform/api/quic_logging.h b/quic/platform/api/quic_logging.h
index d8dc682..ba48dc1 100644
--- a/quic/platform/api/quic_logging.h
+++ b/quic/platform/api/quic_logging.h
@@ -31,8 +31,9 @@
 
 #define QUIC_PLOG(severity) QUIC_PLOG_IMPL(severity)
 
-#define QUIC_DLOG_INFO_IS_ON QUIC_DLOG_INFO_IS_ON_IMPL
-#define QUIC_LOG_INFO_IS_ON QUIC_LOG_INFO_IS_ON_IMPL
-#define QUIC_LOG_WARNING_IS_ON QUIC_LOG_WARNING_IS_ON_IMPL
+#define QUIC_DLOG_INFO_IS_ON() QUIC_DLOG_INFO_IS_ON_IMPL()
+#define QUIC_LOG_INFO_IS_ON() QUIC_LOG_INFO_IS_ON_IMPL()
+#define QUIC_LOG_WARNING_IS_ON() QUIC_LOG_WARNING_IS_ON_IMPL()
+#define QUIC_LOG_ERROR_IS_ON() QUIC_LOG_ERROR_IS_ON_IMPL()
 
 #endif  // QUICHE_QUIC_PLATFORM_API_QUIC_LOGGING_H_
diff --git a/quic/platform/api/quic_lru_cache.h b/quic/platform/api/quic_lru_cache.h
deleted file mode 100644
index 7789670..0000000
--- a/quic/platform/api/quic_lru_cache.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2016 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.
-
-#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_LRU_CACHE_H_
-#define QUICHE_QUIC_PLATFORM_API_QUIC_LRU_CACHE_H_
-
-#include <memory>
-
-#include "net/quic/platform/impl/quic_lru_cache_impl.h"
-
-namespace quic {
-
-// A LRU cache that maps from type Key to Value* in QUIC.
-// This cache CANNOT be shared by multiple threads (even with locks) because
-// Value* returned by Lookup() can be invalid if the entry is evicted by other
-// threads.
-template <class K, class V>
-class QuicLRUCacheOld {
- public:
-  explicit QuicLRUCacheOld(int64_t total_units) : impl_(total_units) {}
-  QuicLRUCacheOld(const QuicLRUCacheOld&) = delete;
-  QuicLRUCacheOld& operator=(const QuicLRUCacheOld&) = delete;
-
-  // Inserts one unit of |key|, |value| pair to the cache. Cache takes ownership
-  // of inserted |value|.
-  void Insert(const K& key, std::unique_ptr<V> value) {
-    impl_.Insert(key, std::move(value));
-  }
-
-  // If cache contains an entry for |key|, return a pointer to it. This returned
-  // value is guaranteed to be valid until Insert or Clear.
-  // Else return nullptr.
-  V* Lookup(const K& key) { return impl_.Lookup(key); }
-
-  // Removes all entries from the cache. This method MUST be called before
-  // destruction.
-  void Clear() { impl_.Clear(); }
-
-  // Returns maximum size of the cache.
-  int64_t MaxSize() const { return impl_.MaxSize(); }
-
-  // Returns current size of the cache.
-  int64_t Size() const { return impl_.Size(); }
-
- private:
-  QuicLRUCacheImpl<K, V> impl_;
-};
-
-}  // namespace quic
-
-#endif  // QUICHE_QUIC_PLATFORM_API_QUIC_LRU_CACHE_H_
diff --git a/quic/platform/api/quic_mem_slice_span.h b/quic/platform/api/quic_mem_slice_span.h
index 890556b..39436be 100644
--- a/quic/platform/api/quic_mem_slice_span.h
+++ b/quic/platform/api/quic_mem_slice_span.h
@@ -6,7 +6,6 @@
 #define QUICHE_QUIC_PLATFORM_API_QUIC_MEM_SLICE_SPAN_H_
 
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
 #include "net/quic/platform/impl/quic_mem_slice_span_impl.h"
 
 namespace quic {
diff --git a/quic/platform/api/quic_mutex.h b/quic/platform/api/quic_mutex.h
index c57a937..162863a 100644
--- a/quic/platform/api/quic_mutex.h
+++ b/quic/platform/api/quic_mutex.h
@@ -5,7 +5,6 @@
 #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_MUTEX_H_
 #define QUICHE_QUIC_PLATFORM_API_QUIC_MUTEX_H_
 
-#include "base/macros.h"
 #include "net/quic/platform/impl/quic_mutex_impl.h"
 
 namespace quic {
diff --git a/quic/platform/api/quic_server_stats.h b/quic/platform/api/quic_server_stats.h
index d3b49ee..5364844 100644
--- a/quic/platform/api/quic_server_stats.h
+++ b/quic/platform/api/quic_server_stats.h
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
 #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_SERVER_STATS_H_
 #define QUICHE_QUIC_PLATFORM_API_QUIC_SERVER_STATS_H_
 
diff --git a/quic/quartc/quartc_factory.cc b/quic/quartc/quartc_factory.cc
index bff445f..ee637e5 100644
--- a/quic/quartc/quartc_factory.cc
+++ b/quic/quartc/quartc_factory.cc
@@ -35,7 +35,10 @@
   SetQuicReloadableFlag(quic_fix_spurious_ack_alarm, true);
 
   // Enable version 45+ to enable SendMessage API.
+  // Enable version 47+ to enable 'quic bit' per draft 17.
   SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
 
   // Fix for inconsistent reporting of crypto handshake.
   SetQuicReloadableFlag(quic_fix_has_pending_crypto_data, true);
diff --git a/quic/quartc/quartc_interval_counter.h b/quic/quartc/quartc_interval_counter.h
index 0597f76..a9b827c 100644
--- a/quic/quartc/quartc_interval_counter.h
+++ b/quic/quartc/quartc_interval_counter.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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.
+
 #ifndef QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
 #define QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
 
diff --git a/quic/quartc/quartc_interval_counter_test.cc b/quic/quartc/quartc_interval_counter_test.cc
index c0edccb..9ba14b2 100644
--- a/quic/quartc/quartc_interval_counter_test.cc
+++ b/quic/quartc/quartc_interval_counter_test.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/quartc/quartc_interval_counter.h"
 
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/quic/quartc/quartc_session.cc b/quic/quartc/quartc_session.cc
index ebd7a7d..37d2cbe 100644
--- a/quic/quartc/quartc_session.cc
+++ b/quic/quartc/quartc_session.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quiche/src/quic/quartc/quartc_session.h"
 
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
 #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -104,8 +105,9 @@
 }  // namespace
 
 QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject(
+    QuicTransportVersion version,
     QuicConnectionId connection_id) const {
-  return EmptyQuicConnectionId();
+  return QuicUtils::CreateZeroConnectionId(version);
 }
 
 bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
@@ -142,6 +144,8 @@
     std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier);
     quic_crypto_client_config_ = QuicMakeUnique<QuicCryptoClientConfig>(
         std::move(proof_verifier), TlsClientHandshaker::CreateSslCtx());
+    quic_crypto_client_config_->set_pad_inchoate_hello(false);
+    quic_crypto_client_config_->set_pad_full_hello(false);
   } else {
     std::unique_ptr<ProofSource> proof_source(new DummyProofSource);
     // Generate a random source address token secret. For long-running servers
@@ -154,6 +158,29 @@
         QuicString(source_address_token_secret, kInputKeyingMaterialLength),
         helper_->GetRandomGenerator(), std::move(proof_source),
         KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx());
+
+    // Effectively disables the anti-amplification measures (we don't need
+    // them because we use ICE, and we need to disable them because we disable
+    // padding of crypto packets).
+    // This multiplier must be large enough so that the crypto handshake packet
+    // (approx. 300 bytes) multiplied by this multiplier is larger than a fully
+    // sized packet (currently 1200 bytes).
+    // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and
+    // your largest MTU would be below 1500 bytes, 1500*1 >=
+    // any_packet_that_you_can_imagine_sending.
+    // (again, we hardcode packet size to 1200, so we are not dealing with jumbo
+    // frames).
+    quic_crypto_server_config_->set_chlo_multiplier(1500);
+
+    // We are sending small client hello, we must not validate its size.
+    quic_crypto_server_config_->set_validate_chlo_size(false);
+
+    // We run QUIC over ICE, and ICE is verifying remote side with STUN pings.
+    // We disable source address token validation in order to allow for 0-rtt
+    // setup (plus source ip addresses are changing even during the connection
+    // when ICE is used).
+    quic_crypto_server_config_->set_validate_source_address_token(false);
+
     // Provide server with serialized config string to prove ownership.
     QuicCryptoServerConfig::ConfigOptions options;
     // The |message| is used to handle the return value of AddDefaultConfig
@@ -161,6 +188,8 @@
     std::unique_ptr<CryptoHandshakeMessage> message(
         quic_crypto_server_config_->AddDefaultConfig(
             helper_->GetRandomGenerator(), helper_->GetClock(), options));
+    quic_crypto_server_config_->set_pad_rej(false);
+    quic_crypto_server_config_->set_pad_shlo(false);
   }
 }
 
@@ -257,12 +286,25 @@
 
 void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
   QuicSession::OnCryptoHandshakeEvent(event);
-  if (event == HANDSHAKE_CONFIRMED) {
-    DCHECK(IsEncryptionEstablished());
-    DCHECK(IsCryptoHandshakeConfirmed());
+  switch (event) {
+    case ENCRYPTION_FIRST_ESTABLISHED:
+    case ENCRYPTION_REESTABLISHED:
+      // 1-rtt setup triggers 'ENCRYPTION_REESTABLISHED' (after REJ, when the
+      // CHLO is sent).
+      DCHECK(IsEncryptionEstablished());
+      DCHECK(session_delegate_);
+      session_delegate_->OnConnectionWritable();
+      break;
+    case HANDSHAKE_CONFIRMED:
+      // On the server, handshake confirmed is the first time when you can start
+      // writing packets.
+      DCHECK(IsEncryptionEstablished());
+      DCHECK(IsCryptoHandshakeConfirmed());
 
-    DCHECK(session_delegate_);
-    session_delegate_->OnCryptoHandshakeComplete();
+      DCHECK(session_delegate_);
+      session_delegate_->OnConnectionWritable();
+      session_delegate_->OnCryptoHandshakeComplete();
+      break;
   }
 }
 
diff --git a/quic/quartc/quartc_session.h b/quic/quartc/quartc_session.h
index fbbf111..411c94c 100644
--- a/quic/quartc/quartc_session.h
+++ b/quic/quartc/quartc_session.h
@@ -24,6 +24,7 @@
 class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
  public:
   QuicConnectionId GenerateConnectionIdForReject(
+      QuicTransportVersion version,
       QuicConnectionId connection_id) const override;
 
   bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
@@ -126,9 +127,18 @@
    public:
     virtual ~Delegate() {}
 
-    // Called when the crypto handshake is complete.
+    // Called when the crypto handshake is complete. Crypto handshake on the
+    // client is only completed _after_ SHLO is received, but we can actually
+    // start sending media data right after CHLO is sent.
     virtual void OnCryptoHandshakeComplete() = 0;
 
+    // Connection can be writable even before crypto handshake is complete.
+    // In particular, on the client, we can start sending data after sending
+    // full CHLO, without waiting for SHLO. This reduces a send delay by 1-rtt.
+    //
+    // This may be called multiple times.
+    virtual void OnConnectionWritable() = 0;
+
     // Called when a new stream is received from the remote endpoint.
     virtual void OnIncomingStream(QuartcStream* stream) = 0;
 
diff --git a/quic/quartc/quartc_session_test.cc b/quic/quartc/quartc_session_test.cc
index f3e4978..78efa9e 100644
--- a/quic/quartc/quartc_session_test.cc
+++ b/quic/quartc/quartc_session_test.cc
@@ -6,11 +6,11 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
 #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -31,18 +31,30 @@
 
 class FakeQuartcSessionDelegate : public QuartcSession::Delegate {
  public:
-  explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate)
-      : stream_delegate_(stream_delegate) {}
+  explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate,
+                                     const QuicClock* clock)
+      : stream_delegate_(stream_delegate), clock_(clock) {}
+
+  void OnConnectionWritable() override {
+    LOG(INFO) << "Connection writable!";
+    if (!writable_time_.IsInitialized()) {
+      writable_time_ = clock_->Now();
+    }
+  }
+
   // Called when peers have established forward-secure encryption
   void OnCryptoHandshakeComplete() override {
     LOG(INFO) << "Crypto handshake complete!";
+    crypto_handshake_time_ = clock_->Now();
   }
+
   // Called when connection closes locally, or remotely by peer.
   void OnConnectionClosed(QuicErrorCode error_code,
                           const QuicString& error_details,
                           ConnectionCloseSource source) override {
     connected_ = false;
   }
+
   // Called when an incoming QUIC stream is created.
   void OnIncomingStream(QuartcStream* quartc_stream) override {
     last_incoming_stream_ = quartc_stream;
@@ -65,12 +77,17 @@
   }
 
   bool connected() { return connected_; }
+  QuicTime writable_time() const { return writable_time_; }
+  QuicTime crypto_handshake_time() const { return crypto_handshake_time_; }
 
  private:
   QuartcStream* last_incoming_stream_;
   std::vector<QuicString> incoming_messages_;
   bool connected_ = true;
   QuartcStream::Delegate* stream_delegate_;
+  QuicTime writable_time_ = QuicTime::Zero();
+  QuicTime crypto_handshake_time_ = QuicTime::Zero();
+  const QuicClock* clock_;
 };
 
 class FakeQuartcStreamDelegate : public QuartcStream::Delegate {
@@ -128,11 +145,11 @@
 
     client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
     client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
-        client_stream_delegate_.get());
+        client_stream_delegate_.get(), simulator_.GetClock());
 
     server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
     server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
-        server_stream_delegate_.get());
+        server_stream_delegate_.get(), simulator_.GetClock());
 
     QuartcFactoryConfig factory_config;
     factory_config.alarm_factory = simulator_.GetAlarmFactory();
@@ -358,6 +375,29 @@
   TestSendLongMessage();
 }
 
+TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) {
+  CreateClientAndServerSessions(QuartcSessionConfig());
+
+  StartHandshake();
+
+  RunTasks();
+
+  ASSERT_TRUE(client_session_delegate_->writable_time().IsInitialized());
+  ASSERT_TRUE(
+      client_session_delegate_->crypto_handshake_time().IsInitialized());
+  // On client, we are writable 1-rtt before crypto handshake is complete.
+  ASSERT_LT(client_session_delegate_->writable_time(),
+            client_session_delegate_->crypto_handshake_time());
+
+  ASSERT_TRUE(server_session_delegate_->writable_time().IsInitialized());
+  ASSERT_TRUE(
+      server_session_delegate_->crypto_handshake_time().IsInitialized());
+  // On server, the writable time and crypto handshake are the same. (when SHLO
+  // is sent).
+  ASSERT_EQ(server_session_delegate_->writable_time(),
+            server_session_delegate_->crypto_handshake_time());
+}
+
 TEST_F(QuartcSessionTest, PreSharedKeyHandshake) {
   CreateClientAndServerSessions(QuartcSessionConfig());
   client_peer_->SetPreSharedKey("foo");
diff --git a/quic/quartc/quartc_stream_test.cc b/quic/quartc/quartc_stream_test.cc
index f560185..075aca1 100644
--- a/quic/quartc/quartc_stream_test.cc
+++ b/quic/quartc/quartc_stream_test.cc
@@ -24,6 +24,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
@@ -225,9 +226,10 @@
     alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>();
 
     connection_ = QuicMakeUnique<QuicConnection>(
-        EmptyQuicConnectionId(), QuicSocketAddress(ip, 0),
-        this /*QuicConnectionHelperInterface*/, alarm_factory_.get(),
-        new DummyPacketWriter(), owns_writer, perspective,
+        QuicUtils::CreateZeroConnectionId(
+            CurrentSupportedVersions()[0].transport_version),
+        QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
+        alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective,
         ParsedVersionOfIndex(CurrentSupportedVersions(), 0));
     clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
     session_ = QuicMakeUnique<MockQuicSession>(connection_.get(), QuicConfig(),
@@ -589,16 +591,16 @@
   EXPECT_EQ("Foo bar", write_buffer_);
 
   stream_->OnStreamFrameLost(0, 4, false);
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 4);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 4);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 4u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 4u);
 
   stream_->OnStreamFrameLost(4, 3, false);
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 7);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 7);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 7u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 7u);
 
   stream_->OnCanWrite();
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
 
   EXPECT_EQ("Foo barFoo bar", write_buffer_);
   EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR);
@@ -615,16 +617,16 @@
   EXPECT_EQ("Foo bar", write_buffer_);
 
   stream_->OnStreamFrameLost(0, 4, false);
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
 
   stream_->OnStreamFrameLost(4, 3, false);
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
 
   stream_->OnCanWrite();
-  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0);
-  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
 
   EXPECT_EQ("Foo bar", write_buffer_);
   EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED);
diff --git a/quic/test_tools/crypto_test_utils.cc b/quic/test_tools/crypto_test_utils.cc
index 1f14306..fd270c3 100644
--- a/quic/test_tools/crypto_test_utils.cc
+++ b/quic/test_tools/crypto_test_utils.cc
@@ -407,7 +407,7 @@
                                    testing::_, testing::_))
       .Times(testing::AnyNumber());
   EXPECT_CALL(*server_session.helper(),
-              GenerateConnectionIdForReject(testing::_))
+              GenerateConnectionIdForReject(testing::_, testing::_))
       .Times(testing::AnyNumber());
   EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
   EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
@@ -783,8 +783,6 @@
   EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
                                            kSampleOutputLength,
                                            &server_key_extraction));
-  EXPECT_TRUE(client->ExportTokenBindingKeyingMaterial(&client_tb_ekm));
-  EXPECT_TRUE(server->ExportTokenBindingKeyingMaterial(&server_tb_ekm));
 
   CompareCharArraysWithHexError("client write key", client_encrypter_key.data(),
                                 client_encrypter_key.length(),
@@ -1002,11 +1000,8 @@
   QuicStringPiece orbit;
   CHECK(msg->GetStringPiece(kORBT, &orbit));
   QuicString nonce;
-  CryptoUtils::GenerateNonce(
-      clock->WallNow(), QuicRandom::GetInstance(),
-      QuicStringPiece(reinterpret_cast<const char*>(orbit.data()),
-                      sizeof(static_cast<int64>(orbit.size()))),
-      &nonce);
+  CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
+                             &nonce);
   return ("#" + QuicTextUtils::HexEncode(nonce));
 }
 
diff --git a/quic/test_tools/crypto_test_utils_test.cc b/quic/test_tools/crypto_test_utils_test.cc
index c6be73a..601103c 100644
--- a/quic/test_tools/crypto_test_utils_test.cc
+++ b/quic/test_tools/crypto_test_utils_test.cc
@@ -135,11 +135,8 @@
   QuicStringPiece orbit;
   ASSERT_TRUE(msg->GetStringPiece(kORBT, &orbit));
   QuicString nonce;
-  CryptoUtils::GenerateNonce(
-      clock.WallNow(), QuicRandom::GetInstance(),
-      QuicStringPiece(reinterpret_cast<const char*>(orbit.data()),
-                      sizeof(static_cast<int64>(orbit.size()))),
-      &nonce);
+  CryptoUtils::GenerateNonce(clock.WallNow(), QuicRandom::GetInstance(), orbit,
+                             &nonce);
   QuicString nonce_hex = "#" + QuicTextUtils::HexEncode(nonce);
 
   char public_value[32];
diff --git a/quic/test_tools/limited_mtu_test_writer.cc b/quic/test_tools/limited_mtu_test_writer.cc
index cd9be17..bc71c7c 100644
--- a/quic/test_tools/limited_mtu_test_writer.cc
+++ b/quic/test_tools/limited_mtu_test_writer.cc
@@ -9,7 +9,7 @@
 
 LimitedMtuTestWriter::LimitedMtuTestWriter(QuicByteCount mtu) : mtu_(mtu) {}
 
-LimitedMtuTestWriter::~LimitedMtuTestWriter() {}
+LimitedMtuTestWriter::~LimitedMtuTestWriter() = default;
 
 WriteResult LimitedMtuTestWriter::WritePacket(
     const char* buffer,
diff --git a/quic/test_tools/mock_quic_session_visitor.cc b/quic/test_tools/mock_quic_session_visitor.cc
index e8d2b66..fea8414 100644
--- a/quic/test_tools/mock_quic_session_visitor.cc
+++ b/quic/test_tools/mock_quic_session_visitor.cc
@@ -7,13 +7,13 @@
 namespace quic {
 namespace test {
 
-MockQuicSessionVisitor::MockQuicSessionVisitor() {}
+MockQuicSessionVisitor::MockQuicSessionVisitor() = default;
 
-MockQuicSessionVisitor::~MockQuicSessionVisitor() {}
+MockQuicSessionVisitor::~MockQuicSessionVisitor() = default;
 
-MockQuicCryptoServerStreamHelper::MockQuicCryptoServerStreamHelper() {}
+MockQuicCryptoServerStreamHelper::MockQuicCryptoServerStreamHelper() = default;
 
-MockQuicCryptoServerStreamHelper::~MockQuicCryptoServerStreamHelper() {}
+MockQuicCryptoServerStreamHelper::~MockQuicCryptoServerStreamHelper() = default;
 
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/mock_quic_session_visitor.h b/quic/test_tools/mock_quic_session_visitor.h
index a75a852..fb01da6 100644
--- a/quic/test_tools/mock_quic_session_visitor.h
+++ b/quic/test_tools/mock_quic_session_visitor.h
@@ -27,6 +27,7 @@
   MOCK_METHOD1(OnWriteBlocked,
                void(QuicBlockedWriterInterface* blocked_writer));
   MOCK_METHOD1(OnRstStreamReceived, void(const QuicRstStreamFrame& frame));
+  MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
   MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
                void(QuicConnectionId connection_id));
 };
@@ -39,8 +40,9 @@
   MockQuicCryptoServerStreamHelper& operator=(
       const MockQuicCryptoServerStreamHelper&) = delete;
   ~MockQuicCryptoServerStreamHelper() override;
-  MOCK_CONST_METHOD1(GenerateConnectionIdForReject,
-                     QuicConnectionId(QuicConnectionId connection_id));
+  MOCK_CONST_METHOD2(GenerateConnectionIdForReject,
+                     QuicConnectionId(QuicTransportVersion version,
+                                      QuicConnectionId connection_id));
   MOCK_CONST_METHOD5(CanAcceptClientHello,
                      bool(const CryptoHandshakeMessage& message,
                           const QuicSocketAddress& client_address,
diff --git a/quic/test_tools/mock_quic_time_wait_list_manager.cc b/quic/test_tools/mock_quic_time_wait_list_manager.cc
index bf3d075..ec63558 100644
--- a/quic/test_tools/mock_quic_time_wait_list_manager.cc
+++ b/quic/test_tools/mock_quic_time_wait_list_manager.cc
@@ -26,7 +26,7 @@
                            QuicTimeWaitListManager_AddConnectionIdToTimeWait));
 }
 
-MockTimeWaitListManager::~MockTimeWaitListManager() {}
+MockTimeWaitListManager::~MockTimeWaitListManager() = default;
 
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/mock_random.cc b/quic/test_tools/mock_random.cc
index 683e504..a01a5a7 100644
--- a/quic/test_tools/mock_random.cc
+++ b/quic/test_tools/mock_random.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
 
+#include <string.h>
+
 namespace quic {
 namespace test {
 
diff --git a/quic/test_tools/packet_dropping_test_writer.cc b/quic/test_tools/packet_dropping_test_writer.cc
index 51d8fed..d296367 100644
--- a/quic/test_tools/packet_dropping_test_writer.cc
+++ b/quic/test_tools/packet_dropping_test_writer.cc
@@ -15,7 +15,7 @@
 
 // An alarm that is scheduled if a blocked socket is simulated to indicate
 // it's writable again.
-class WriteUnblockedAlarm : public quic::QuicAlarm::Delegate {
+class WriteUnblockedAlarm : public QuicAlarm::Delegate {
  public:
   explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
       : writer_(writer) {}
@@ -31,7 +31,7 @@
 
 // An alarm that is scheduled every time a new packet is to be written at a
 // later point.
-class DelayAlarm : public quic::QuicAlarm::Delegate {
+class DelayAlarm : public QuicAlarm::Delegate {
  public:
   explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
 
@@ -58,12 +58,12 @@
       fake_bandwidth_(QuicBandwidth::Zero()),
       buffer_size_(0),
       num_consecutive_packet_lost_(0) {
-  uint32_t seed = RandomBase::WeakSeed32();
+  uint64_t seed = QuicRandom::GetInstance()->RandUint64();
   QUIC_LOG(INFO) << "Seeding packet loss with " << seed;
   simple_random_.set_seed(seed);
 }
 
-PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
+PacketDroppingTestWriter::~PacketDroppingTestWriter() = default;
 
 void PacketDroppingTestWriter::Initialize(
     QuicConnectionHelperInterface* helper,
diff --git a/quic/test_tools/packet_dropping_test_writer.h b/quic/test_tools/packet_dropping_test_writer.h
index ae1df42..404be81 100644
--- a/quic/test_tools/packet_dropping_test_writer.h
+++ b/quic/test_tools/packet_dropping_test_writer.h
@@ -16,7 +16,6 @@
 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
 
 namespace quic {
-
 namespace test {
 
 // Simulates a connection that drops packets a configured percentage of the time
@@ -143,17 +142,17 @@
     ~DelayedWrite();
 
     QuicString buffer;
-    const QuicIpAddress self_address;
-    const QuicSocketAddress peer_address;
+    QuicIpAddress self_address;
+    QuicSocketAddress peer_address;
     std::unique_ptr<PerPacketOptions> options;
     QuicTime send_time;
   };
 
   typedef std::list<DelayedWrite> DelayedPacketList;
 
-  const quic::QuicClock* clock_;
-  std::unique_ptr<quic::QuicAlarm> write_unblocked_alarm_;
-  std::unique_ptr<quic::QuicAlarm> delay_alarm_;
+  const QuicClock* clock_;
+  std::unique_ptr<QuicAlarm> write_unblocked_alarm_;
+  std::unique_ptr<QuicAlarm> delay_alarm_;
   std::unique_ptr<Delegate> on_can_write_;
   SimpleRandom simple_random_;
   // Stored packets delayed by fake packet delay or bandwidth restrictions.
diff --git a/quic/test_tools/quic_client_peer.h b/quic/test_tools/quic_client_peer.h
index 934495a..66987e4 100644
--- a/quic/test_tools/quic_client_peer.h
+++ b/quic/test_tools/quic_client_peer.h
@@ -10,7 +10,6 @@
 namespace quic {
 
 class QuicClient;
-class QuicCryptoClientConfig;
 class QuicPacketWriter;
 
 namespace test {
diff --git a/quic/test_tools/quic_connection_peer.cc b/quic/test_tools/quic_connection_peer.cc
index dde870b..e813c1e 100644
--- a/quic/test_tools/quic_connection_peer.cc
+++ b/quic/test_tools/quic_connection_peer.cc
@@ -275,9 +275,8 @@
 }
 
 // static
-bool QuicConnectionPeer::HasRetransmittableFrames(
-    QuicConnection* connection,
-    QuicPacketNumber packet_number) {
+bool QuicConnectionPeer::HasRetransmittableFrames(QuicConnection* connection,
+                                                  uint64_t packet_number) {
   return QuicSentPacketManagerPeer::HasRetransmittableFrames(
       GetSentPacketManager(connection), packet_number);
 }
diff --git a/quic/test_tools/quic_connection_peer.h b/quic/test_tools/quic_connection_peer.h
index 58bdec9..d58d1d7 100644
--- a/quic/test_tools/quic_connection_peer.h
+++ b/quic/test_tools/quic_connection_peer.h
@@ -123,7 +123,7 @@
   static void SetAckDecimationDelay(QuicConnection* connection,
                                     float ack_decimation_delay);
   static bool HasRetransmittableFrames(QuicConnection* connection,
-                                       QuicPacketNumber packet_number);
+                                       uint64_t packet_number);
   static bool GetNoStopWaitingFrames(QuicConnection* connection);
   static void SetNoStopWaitingFrames(QuicConnection* connection,
                                      bool no_stop_waiting_frames);
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc
index 6202669..20cbc49 100644
--- a/quic/test_tools/quic_framer_peer.cc
+++ b/quic/test_tools/quic_framer_peer.cc
@@ -12,11 +12,11 @@
 namespace test {
 
 // static
-QuicPacketNumber QuicFramerPeer::CalculatePacketNumberFromWire(
+uint64_t QuicFramerPeer::CalculatePacketNumberFromWire(
     QuicFramer* framer,
     QuicPacketNumberLength packet_number_length,
     QuicPacketNumber last_packet_number,
-    QuicPacketNumber packet_number) {
+    uint64_t packet_number) {
   return framer->CalculatePacketNumberFromWire(
       packet_number_length, last_packet_number, packet_number);
 }
@@ -338,5 +338,12 @@
                                     packet_number_length);
 }
 
+// static
+void QuicFramerPeer::SetFirstSendingPacketNumber(QuicFramer* framer,
+                                                 uint64_t packet_number) {
+  *const_cast<QuicPacketNumber*>(&framer->first_sending_packet_number_) =
+      QuicPacketNumber(packet_number);
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
index 57a05aa..1fa7351 100644
--- a/quic/test_tools/quic_framer_peer.h
+++ b/quic/test_tools/quic_framer_peer.h
@@ -18,11 +18,11 @@
  public:
   QuicFramerPeer() = delete;
 
-  static QuicPacketNumber CalculatePacketNumberFromWire(
+  static uint64_t CalculatePacketNumberFromWire(
       QuicFramer* framer,
       QuicPacketNumberLength packet_number_length,
       QuicPacketNumber last_packet_number,
-      QuicPacketNumber packet_number);
+      uint64_t packet_number);
   static void SetLastSerializedConnectionId(QuicFramer* framer,
                                             QuicConnectionId connection_id);
   static void SetLargestPacketNumber(QuicFramer* framer,
@@ -161,6 +161,8 @@
                                    const QuicFrame& frame,
                                    bool last_frame_in_packet,
                                    QuicPacketNumberLength packet_number_length);
+  static void SetFirstSendingPacketNumber(QuicFramer* framer,
+                                          uint64_t packet_number);
 };
 
 }  // namespace test
diff --git a/quic/test_tools/quic_packet_creator_peer.cc b/quic/test_tools/quic_packet_creator_peer.cc
index 5168688..efcda92 100644
--- a/quic/test_tools/quic_packet_creator_peer.cc
+++ b/quic/test_tools/quic_packet_creator_peer.cc
@@ -44,8 +44,14 @@
 }
 
 void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator,
-                                            QuicPacketNumber s) {
-  creator->packet_.packet_number = s;
+                                            uint64_t s) {
+  DCHECK_NE(0u, s);
+  creator->packet_.packet_number = QuicPacketNumber(s);
+}
+
+// static
+void QuicPacketCreatorPeer::ClearPacketNumber(QuicPacketCreator* creator) {
+  creator->packet_.packet_number.Clear();
 }
 
 // static
diff --git a/quic/test_tools/quic_packet_creator_peer.h b/quic/test_tools/quic_packet_creator_peer.h
index add0712..94c461a 100644
--- a/quic/test_tools/quic_packet_creator_peer.h
+++ b/quic/test_tools/quic_packet_creator_peer.h
@@ -27,7 +27,8 @@
       QuicPacketNumberLength packet_number_length);
   static QuicPacketNumberLength GetPacketNumberLength(
       QuicPacketCreator* creator);
-  static void SetPacketNumber(QuicPacketCreator* creator, QuicPacketNumber s);
+  static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s);
+  static void ClearPacketNumber(QuicPacketCreator* creator);
   static void FillPacketHeader(QuicPacketCreator* creator,
                                QuicPacketHeader* header);
   static void CreateStreamFrame(QuicPacketCreator* creator,
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc
index 7699520..469fa40 100644
--- a/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -85,18 +85,19 @@
 // static
 bool QuicSentPacketManagerPeer::IsRetransmission(
     QuicSentPacketManager* sent_packet_manager,
-    QuicPacketNumber packet_number) {
+    uint64_t packet_number) {
   DCHECK(HasRetransmittableFrames(sent_packet_manager, packet_number));
   if (!HasRetransmittableFrames(sent_packet_manager, packet_number)) {
     return false;
   }
   if (sent_packet_manager->session_decides_what_to_write()) {
     return sent_packet_manager->unacked_packets_
-               .GetTransmissionInfo(packet_number)
+               .GetTransmissionInfo(QuicPacketNumber(packet_number))
                .transmission_type != NOT_RETRANSMISSION;
   }
   for (auto transmission_info : sent_packet_manager->unacked_packets_) {
-    if (transmission_info.retransmission == packet_number) {
+    if (transmission_info.retransmission.IsInitialized() &&
+        transmission_info.retransmission == QuicPacketNumber(packet_number)) {
       return true;
     }
   }
@@ -106,9 +107,10 @@
 // static
 void QuicSentPacketManagerPeer::MarkForRetransmission(
     QuicSentPacketManager* sent_packet_manager,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     TransmissionType transmission_type) {
-  sent_packet_manager->MarkForRetransmission(packet_number, transmission_type);
+  sent_packet_manager->MarkForRetransmission(QuicPacketNumber(packet_number),
+                                             transmission_type);
 }
 
 // static
@@ -198,16 +200,17 @@
 // static
 bool QuicSentPacketManagerPeer::IsUnacked(
     QuicSentPacketManager* sent_packet_manager,
-    QuicPacketNumber packet_number) {
-  return sent_packet_manager->unacked_packets_.IsUnacked(packet_number);
+    uint64_t packet_number) {
+  return sent_packet_manager->unacked_packets_.IsUnacked(
+      QuicPacketNumber(packet_number));
 }
 
 // static
 bool QuicSentPacketManagerPeer::HasRetransmittableFrames(
     QuicSentPacketManager* sent_packet_manager,
-    QuicPacketNumber packet_number) {
+    uint64_t packet_number) {
   return sent_packet_manager->unacked_packets_.HasRetransmittableFrames(
-      packet_number);
+      QuicPacketNumber(packet_number));
 }
 
 // static
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.h b/quic/test_tools/quic_sent_packet_manager_peer.h
index 9f9f6a1..b8ec1d3 100644
--- a/quic/test_tools/quic_sent_packet_manager_peer.h
+++ b/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -52,10 +52,10 @@
 
   // Returns true if |packet_number| is a retransmission of a packet.
   static bool IsRetransmission(QuicSentPacketManager* sent_packet_manager,
-                               QuicPacketNumber packet_number);
+                               uint64_t packet_number);
 
   static void MarkForRetransmission(QuicSentPacketManager* sent_packet_manager,
-                                    QuicPacketNumber packet_number,
+                                    uint64_t packet_number,
                                     TransmissionType transmission_type);
 
   static QuicTime::Delta GetRetransmissionDelay(
@@ -93,11 +93,11 @@
   static bool UsingPacing(const QuicSentPacketManager* sent_packet_manager);
 
   static bool IsUnacked(QuicSentPacketManager* sent_packet_manager,
-                        QuicPacketNumber packet_number);
+                        uint64_t packet_number);
 
   static bool HasRetransmittableFrames(
       QuicSentPacketManager* sent_packet_manager,
-      QuicPacketNumber packet_number);
+      uint64_t packet_number);
 
   static QuicUnackedPacketMap* GetUnackedPacketMap(
       QuicSentPacketManager* sent_packet_manager);
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc
index 6bacca9..37e5013 100644
--- a/quic/test_tools/quic_session_peer.cc
+++ b/quic/test_tools/quic_session_peer.cc
@@ -184,5 +184,14 @@
   return &session->v99_streamid_manager_.unidirectional_stream_id_manager_;
 }
 
+// static
+void QuicSessionPeer::SendRstStreamInner(QuicSession* session,
+                                         QuicStreamId id,
+                                         QuicRstStreamErrorCode error,
+                                         QuicStreamOffset bytes_written,
+                                         bool close_write_side_only) {
+  session->SendRstStreamInner(id, error, bytes_written, close_write_side_only);
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h
index 917d203..8c2e72c 100644
--- a/quic/test_tools/quic_session_peer.h
+++ b/quic/test_tools/quic_session_peer.h
@@ -67,6 +67,11 @@
       QuicSession* session);
   static QuicStreamIdManager* v99_unidirectional_stream_id_manager(
       QuicSession* session);
+  static void SendRstStreamInner(QuicSession* session,
+                                 QuicStreamId id,
+                                 QuicRstStreamErrorCode error,
+                                 QuicStreamOffset bytes_written,
+                                 bool close_write_side_only);
 };
 
 }  // namespace test
diff --git a/quic/test_tools/quic_stream_id_manager_peer.cc b/quic/test_tools/quic_stream_id_manager_peer.cc
index 8bdfd16..705ee27 100644
--- a/quic/test_tools/quic_stream_id_manager_peer.cc
+++ b/quic/test_tools/quic_stream_id_manager_peer.cc
@@ -1,3 +1,6 @@
+// Copyright (c) 2018 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/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
diff --git a/quic/test_tools/quic_stream_id_manager_peer.h b/quic/test_tools/quic_stream_id_manager_peer.h
index 7b42888..2ec07b1 100644
--- a/quic/test_tools/quic_stream_id_manager_peer.h
+++ b/quic/test_tools/quic_stream_id_manager_peer.h
@@ -1,7 +1,10 @@
+// Copyright (c) 2018 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.
 #ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_
 #define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_
 
-#include "base/macros.h"
+#include <stddef.h>
 
 namespace quic {
 
diff --git a/quic/test_tools/quic_stream_peer.cc b/quic/test_tools/quic_stream_peer.cc
index d5ac1e4..e512ba4 100644
--- a/quic/test_tools/quic_stream_peer.cc
+++ b/quic/test_tools/quic_stream_peer.cc
@@ -33,6 +33,11 @@
 }
 
 // static
+bool QuicStreamPeer::write_side_closed(QuicStream* stream) {
+  return stream->write_side_closed();
+}
+
+// static
 void QuicStreamPeer::CloseReadSide(QuicStream* stream) {
   stream->CloseReadSide();
 }
diff --git a/quic/test_tools/quic_stream_peer.h b/quic/test_tools/quic_stream_peer.h
index fbbbbb6..e1ba33a 100644
--- a/quic/test_tools/quic_stream_peer.h
+++ b/quic/test_tools/quic_stream_peer.h
@@ -27,6 +27,7 @@
   static void SetWriteSideClosed(bool value, QuicStream* stream);
   static void SetStreamBytesWritten(QuicStreamOffset stream_bytes_written,
                                     QuicStream* stream);
+  static bool write_side_closed(QuicStream* stream);
   static bool read_side_closed(QuicStream* stream);
   static void CloseReadSide(QuicStream* stream);
 
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
index 878ac83..a6298a6 100644
--- a/quic/test_tools/quic_test_client.cc
+++ b/quic/test_tools/quic_test_client.cc
@@ -120,7 +120,7 @@
     : public QuicClientEpollNetworkHelper {
  public:
   using QuicClientEpollNetworkHelper::QuicClientEpollNetworkHelper;
-  ~MockableQuicClientEpollNetworkHelper() override {}
+  ~MockableQuicClientEpollNetworkHelper() override = default;
 
   void ProcessPacket(const QuicSocketAddress& self_address,
                      const QuicSocketAddress& peer_address,
@@ -172,7 +172,7 @@
     QuicSocketAddress server_address,
     const QuicServerId& server_id,
     const ParsedQuicVersionVector& supported_versions,
-    gfe2::EpollServer* epoll_server)
+    QuicEpollServer* epoll_server)
     : MockableQuicClient(server_address,
                          server_id,
                          QuicConfig(),
@@ -184,7 +184,7 @@
     const QuicServerId& server_id,
     const QuicConfig& config,
     const ParsedQuicVersionVector& supported_versions,
-    gfe2::EpollServer* epoll_server)
+    QuicEpollServer* epoll_server)
     : MockableQuicClient(server_address,
                          server_id,
                          config,
@@ -197,7 +197,7 @@
     const QuicServerId& server_id,
     const QuicConfig& config,
     const ParsedQuicVersionVector& supported_versions,
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     std::unique_ptr<ProofVerifier> proof_verifier)
     : QuicClient(
           server_address,
@@ -209,7 +209,8 @@
                                                                this),
           QuicWrapUnique(
               new RecordingProofVerifier(std::move(proof_verifier)))),
-      override_connection_id_(EmptyQuicConnectionId()) {}
+      override_connection_id_(EmptyQuicConnectionId()),
+      connection_id_overridden_(false) {}
 
 MockableQuicClient::~MockableQuicClient() {
   if (connected()) {
@@ -230,12 +231,12 @@
 }
 
 QuicConnectionId MockableQuicClient::GenerateNewConnectionId() {
-  return !override_connection_id_.IsEmpty()
-             ? override_connection_id_
-             : QuicClient::GenerateNewConnectionId();
+  return connection_id_overridden_ ? override_connection_id_
+                                   : QuicClient::GenerateNewConnectionId();
 }
 
 void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
+  connection_id_overridden_ = true;
   override_connection_id_ = connection_id;
 }
 
@@ -294,7 +295,7 @@
   Initialize();
 }
 
-QuicTestClient::QuicTestClient() {}
+QuicTestClient::QuicTestClient() = default;
 
 QuicTestClient::~QuicTestClient() {
   for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
@@ -805,7 +806,7 @@
       test_client_(test_client),
       ack_listener_(std::move(ack_listener)) {}
 
-QuicTestClient::TestClientDataToResend::~TestClientDataToResend() {}
+QuicTestClient::TestClientDataToResend::~TestClientDataToResend() = default;
 
 void QuicTestClient::TestClientDataToResend::Resend() {
   test_client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_,
@@ -847,7 +848,7 @@
       bytes_written(bytes_written),
       response_body_size(response_body_size) {}
 
-QuicTestClient::PerStreamState::~PerStreamState() {}
+QuicTestClient::PerStreamState::~PerStreamState() = default;
 
 bool QuicTestClient::PopulateHeaderBlockFromUrl(
     const QuicString& uri,
diff --git a/quic/test_tools/quic_test_client.h b/quic/test_tools/quic_test_client.h
index 08f8808..9142fd9 100644
--- a/quic/test_tools/quic_test_client.h
+++ b/quic/test_tools/quic_test_client.h
@@ -15,6 +15,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quiche/src/quic/tools/quic_client.h"
@@ -34,19 +35,19 @@
   MockableQuicClient(QuicSocketAddress server_address,
                      const QuicServerId& server_id,
                      const ParsedQuicVersionVector& supported_versions,
-                     gfe2::EpollServer* epoll_server);
+                     QuicEpollServer* epoll_server);
 
   MockableQuicClient(QuicSocketAddress server_address,
                      const QuicServerId& server_id,
                      const QuicConfig& config,
                      const ParsedQuicVersionVector& supported_versions,
-                     gfe2::EpollServer* epoll_server);
+                     QuicEpollServer* epoll_server);
 
   MockableQuicClient(QuicSocketAddress server_address,
                      const QuicServerId& server_id,
                      const QuicConfig& config,
                      const ParsedQuicVersionVector& supported_versions,
-                     gfe2::EpollServer* epoll_server,
+                     QuicEpollServer* epoll_server,
                      std::unique_ptr<ProofVerifier> proof_verifier);
   MockableQuicClient(const MockableQuicClient&) = delete;
   MockableQuicClient& operator=(const MockableQuicClient&) = delete;
@@ -68,7 +69,9 @@
   const MockableQuicClientEpollNetworkHelper* mockable_network_helper() const;
 
  private:
-  QuicConnectionId override_connection_id_;  // ConnectionId to use, if nonzero
+  // ConnectionId to use, if connection_id_overridden_
+  QuicConnectionId override_connection_id_;
+  bool connection_id_overridden_;
   CachedNetworkParameters cached_network_paramaters_;
 };
 
@@ -253,7 +256,7 @@
 
   void WaitForWriteToFlush();
 
-  gfe2::EpollServer* epoll_server() { return &epoll_server_; }
+  QuicEpollServer* epoll_server() { return &epoll_server_; }
 
   size_t num_requests() const { return num_requests_; }
 
@@ -356,7 +359,7 @@
   // tracking its state.
   void SetLatestCreatedStream(QuicSpdyClientStream* stream);
 
-  gfe2::EpollServer epoll_server_;
+  QuicEpollServer epoll_server_;
   std::unique_ptr<MockableQuicClient> client_;  // The actual client
   QuicSpdyClientStream* latest_created_stream_;
   std::map<QuicStreamId, QuicSpdyClientStream*> open_streams_;
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index 49b871d..da76b33 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -66,7 +66,7 @@
   DCHECK_GT(ack_blocks.size(), 0u);
 
   QuicAckFrame ack;
-  QuicPacketNumber end_of_previous_block = 1;
+  QuicPacketNumber end_of_previous_block(1);
   for (const QuicAckBlock& block : ack_blocks) {
     DCHECK_GE(block.start, end_of_previous_block);
     DCHECK_GT(block.limit, block.start);
@@ -79,17 +79,22 @@
   return ack;
 }
 
+QuicAckFrame InitAckFrame(uint64_t largest_acked) {
+  return InitAckFrame(QuicPacketNumber(largest_acked));
+}
+
 QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) {
-  return InitAckFrame({{1, largest_acked + 1}});
+  return InitAckFrame({{QuicPacketNumber(1), largest_acked + 1}});
 }
 
 QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
-                                       QuicPacketNumber least_unacked) {
+                                       uint64_t least_unacked) {
   QuicAckFrame ack;
-  ack.largest_acked = 2 * num_ack_blocks + least_unacked;
+  ack.largest_acked = QuicPacketNumber(2 * num_ack_blocks + least_unacked);
   // Add enough received packets to get num_ack_blocks ack blocks.
-  for (QuicPacketNumber i = 2; i < 2 * num_ack_blocks + 1; i += 2) {
-    ack.packets.Add(least_unacked + i);
+  for (QuicPacketNumber i = QuicPacketNumber(2);
+       i < QuicPacketNumber(2 * num_ack_blocks + 1); i += 2) {
+    ack.packets.Add(i + least_unacked);
   }
   return ack;
 }
@@ -464,7 +469,7 @@
   // Transfer ownership of the packet to the SentPacketManager and the
   // ack notifier to the AckNotifierManager.
   QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent(
-      packet, 0, QuicTime::Zero(), NOT_RETRANSMISSION,
+      packet, QuicPacketNumber(), QuicTime::Zero(), NOT_RETRANSMISSION,
       HAS_RETRANSMITTABLE_DATA);
 }
 
@@ -600,7 +605,7 @@
                             crypto_config,
                             compressed_certs_cache) {
   Initialize();
-  ON_CALL(helper_, GenerateConnectionIdForReject(_))
+  ON_CALL(helper_, GenerateConnectionIdForReject(_, _))
       .WillByDefault(testing::Return(
           QuicUtils::CreateRandomConnectionId(connection->random_generator())));
   ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _))
@@ -786,7 +791,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data) {
   return ConstructEncryptedPacket(
       destination_connection_id, source_connection_id, version_flag, reset_flag,
@@ -799,7 +804,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -815,7 +820,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -832,7 +837,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -847,7 +852,7 @@
   header.version_flag = version_flag;
   header.reset_flag = reset_flag;
   header.packet_number_length = packet_number_length;
-  header.packet_number = packet_number;
+  header.packet_number = QuicPacketNumber(packet_number);
   QuicFrame frame(QuicStreamFrame(
       QuicUtils::GetCryptoStreamId(
           versions != nullptr
@@ -864,8 +869,9 @@
       BuildUnsizedDataPacket(&framer, header, frames));
   EXPECT_TRUE(packet != nullptr);
   char* buffer = new char[kMaxPacketSize];
-  size_t encrypted_length = framer.EncryptPayload(
-      ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize);
+  size_t encrypted_length =
+      framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number),
+                            *packet, buffer, kMaxPacketSize);
   EXPECT_NE(0u, encrypted_length);
   return new QuicEncryptedPacket(buffer, encrypted_length, true);
 }
@@ -884,7 +890,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -899,7 +905,7 @@
   header.version_flag = version_flag;
   header.reset_flag = reset_flag;
   header.packet_number_length = packet_number_length;
-  header.packet_number = packet_number;
+  header.packet_number = QuicPacketNumber(packet_number);
   QuicFrame frame(QuicStreamFrame(1, false, 0, QuicStringPiece(data)));
   QuicFrames frames;
   frames.push_back(frame);
@@ -918,8 +924,9 @@
       false /* no diversification nonce */, packet_number_length)] = 0x1F;
 
   char* buffer = new char[kMaxPacketSize];
-  size_t encrypted_length = framer.EncryptPayload(
-      ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize);
+  size_t encrypted_length =
+      framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number),
+                            *packet, buffer, kMaxPacketSize);
   EXPECT_NE(0u, encrypted_length);
   return new QuicEncryptedPacket(buffer, encrypted_length, true);
 }
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 61b60e4..8b52d4f 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -77,7 +77,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -94,7 +94,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -107,7 +107,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -121,7 +121,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data);
 
 // Constructs a received packet for testing. The caller must take ownership of
@@ -140,7 +140,7 @@
     QuicConnectionId source_connection_id,
     bool version_flag,
     bool reset_flag,
-    QuicPacketNumber packet_number,
+    uint64_t packet_number,
     const QuicString& data,
     QuicConnectionIdLength destination_connection_id_length,
     QuicConnectionIdLength source_connection_id_length,
@@ -195,12 +195,13 @@
 // Testing convenience method to construct a QuicAckFrame with 1 ack block which
 // covers packet number range [1, |largest_acked| + 1).
 // Equivalent to InitAckFrame({{1, largest_acked + 1}})
+QuicAckFrame InitAckFrame(uint64_t largest_acked);
 QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked);
 
 // Testing convenience method to construct a QuicAckFrame with |num_ack_blocks|
 // ack blocks of width 1 packet, starting from |least_unacked| + 2.
 QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
-                                       QuicPacketNumber least_unacked);
+                                       uint64_t least_unacked);
 
 // Returns a QuicPacket that is owned by the caller, and
 // is populated with the fields in |header| and |frames|, or is nullptr if the
@@ -553,6 +554,7 @@
     QuicConnection::SendConnectivityProbingResponsePacket(peer_address);
   }
   MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&));
+  MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
 };
 
 class PacketSavingConnection : public MockQuicConnection {
diff --git a/quic/test_tools/quic_test_utils_test.cc b/quic/test_tools/quic_test_utils_test.cc
index c9627c2..01791e0 100644
--- a/quic/test_tools/quic_test_utils_test.cc
+++ b/quic/test_tools/quic_test_utils_test.cc
@@ -18,8 +18,8 @@
   EXPECT_EQ(TestConnectionId(), TestConnectionId());
   EXPECT_EQ(TestConnectionId(33), TestConnectionId(33));
   EXPECT_NE(TestConnectionId(0xdead), TestConnectionId(0xbeef));
-  EXPECT_EQ(0x1337, TestConnectionIdToUInt64(TestConnectionId(0x1337)));
-  EXPECT_NE(0xdead, TestConnectionIdToUInt64(TestConnectionId(0xbeef)));
+  EXPECT_EQ(0x1337u, TestConnectionIdToUInt64(TestConnectionId(0x1337)));
+  EXPECT_NE(0xdeadu, TestConnectionIdToUInt64(TestConnectionId(0xbeef)));
 }
 
 TEST_F(QuicTestUtilsTest, BasicApproxEq) {
diff --git a/quic/test_tools/simple_data_producer.cc b/quic/test_tools/simple_data_producer.cc
index 1b010eb..ab98fd1 100644
--- a/quic/test_tools/simple_data_producer.cc
+++ b/quic/test_tools/simple_data_producer.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h"
 
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -13,13 +15,13 @@
 namespace test {
 
 SimpleDataProducer::SimpleDataProducer() {}
+
 SimpleDataProducer::~SimpleDataProducer() {}
 
 void SimpleDataProducer::SaveStreamData(QuicStreamId id,
                                         const struct iovec* iov,
                                         int iov_count,
                                         size_t iov_offset,
-                                        QuicStreamOffset offset,
                                         QuicByteCount data_length) {
   if (data_length == 0) {
     return;
@@ -30,6 +32,13 @@
   send_buffer_map_[id]->SaveStreamData(iov, iov_count, iov_offset, data_length);
 }
 
+void SimpleDataProducer::SaveCryptoData(EncryptionLevel level,
+                                        QuicStreamOffset offset,
+                                        QuicStringPiece data) {
+  auto key = std::make_pair(level, offset);
+  crypto_buffer_map_[key] = data;
+}
+
 WriteStreamDataResult SimpleDataProducer::WriteStreamData(
     QuicStreamId id,
     QuicStreamOffset offset,
@@ -45,6 +54,17 @@
   return WRITE_FAILED;
 }
 
+bool SimpleDataProducer::WriteCryptoData(EncryptionLevel level,
+                                         QuicStreamOffset offset,
+                                         QuicByteCount data_length,
+                                         QuicDataWriter* writer) {
+  auto it = crypto_buffer_map_.find(std::make_pair(level, offset));
+  if (it == crypto_buffer_map_.end() || it->second.length() != data_length) {
+    return false;
+  }
+  return writer->WriteStringPiece(it->second);
+}
+
 }  // namespace test
 
 }  // namespace quic
diff --git a/quic/test_tools/simple_data_producer.h b/quic/test_tools/simple_data_producer.h
index 88622c1..d51ec69 100644
--- a/quic/test_tools/simple_data_producer.h
+++ b/quic/test_tools/simple_data_producer.h
@@ -21,26 +21,67 @@
   SimpleDataProducer();
   ~SimpleDataProducer() override;
 
+  // Saves data to be provided when WriteStreamData is called. Data of length
+  // |data_length| is buffered to be provided for stream |id|. Multiple calls to
+  // SaveStreamData for the same stream ID append to the buffer for that stream.
+  // The data to be buffered is provided in |iov_count| iovec structs, with
+  // |iov| pointing to the first, and |iov_offset| indicating how many bytes
+  // into the iovec structs the data starts.
   void SaveStreamData(QuicStreamId id,
                       const struct iovec* iov,
                       int iov_count,
                       size_t iov_offset,
-                      QuicStreamOffset offset,
                       QuicByteCount data_length);
 
+  void SaveCryptoData(EncryptionLevel level,
+                      QuicStreamOffset offset,
+                      QuicStringPiece data);
+
   // QuicStreamFrameDataProducer
   WriteStreamDataResult WriteStreamData(QuicStreamId id,
                                         QuicStreamOffset offset,
                                         QuicByteCount data_length,
                                         QuicDataWriter* writer) override;
+  bool WriteCryptoData(EncryptionLevel level,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
+
+  // TODO(wub): Allow QuicDefaultHasher to accept a pair. Then remove this.
+  class PairHash {
+   public:
+    template <class T1, class T2>
+    size_t operator()(const std::pair<T1, T2>& pair) const {
+      return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
+    }
+  };
 
  private:
   using SendBufferMap =
       QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>;
 
+  using CryptoBufferMap =
+      QuicUnorderedMap<std::pair<EncryptionLevel, QuicStreamOffset>,
+                       QuicStringPiece,
+                       PairHash>;
+
   SimpleBufferAllocator allocator_;
 
   SendBufferMap send_buffer_map_;
+
+  // |crypto_buffer_map_| stores data provided by SaveCryptoData to later write
+  // in WriteCryptoData. The level and data passed into SaveCryptoData are used
+  // as the key to identify the data when WriteCryptoData is called.
+  // WriteCryptoData will only succeed if there is data in the map for the
+  // provided level and offset, and the data in the map matches the data_length
+  // passed into WriteCryptoData.
+  //
+  // Unlike SaveStreamData/WriteStreamData which uses a map of
+  // QuicStreamSendBuffers (for each stream ID), this map provides data for
+  // specific offsets. Using a QuicStreamSendBuffer requires that all data
+  // before an offset exist, whereas this allows providing data that exists at
+  // arbitrary offsets for testing.
+  CryptoBufferMap crypto_buffer_map_;
 };
 
 }  // namespace test
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc
index 4cf236b..2867d82 100644
--- a/quic/test_tools/simulator/quic_endpoint.cc
+++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -222,6 +222,7 @@
   // Sanity check against very pathological connections.
   DCHECK_LE(offsets_received_.Size(), 1000u);
 }
+
 void QuicEndpoint::OnCanWrite() {
   if (notifier_ != nullptr) {
     notifier_->OnCanWrite();
@@ -354,6 +355,14 @@
   return WRITE_SUCCESS;
 }
 
+bool QuicEndpoint::DataProducer::WriteCryptoData(EncryptionLevel leve,
+                                                 QuicStreamOffset offset,
+                                                 QuicByteCount data_length,
+                                                 QuicDataWriter* writer) {
+  QUIC_BUG << "QuicEndpoint::DataProducer::WriteCryptoData is unimplemented";
+  return false;
+}
+
 void QuicEndpoint::WriteStreamData() {
   // Instantiate a flusher which would normally be here due to QuicSession.
   QuicConnection::ScopedPacketFlusher flusher(
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index 1a31ab2..600a1d1 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -166,6 +166,10 @@
                                           QuicStreamOffset offset,
                                           QuicByteCount data_length,
                                           QuicDataWriter* writer) override;
+    bool WriteCryptoData(EncryptionLevel level,
+                         QuicStreamOffset offset,
+                         QuicByteCount data_length,
+                         QuicDataWriter* writer) override;
   };
 
   // Write stream data until |bytes_to_transfer_| is zero or the connection is
diff --git a/quic/test_tools/simulator/simulator_test.cc b/quic/test_tools/simulator/simulator_test.cc
index cb0c3a6..b2221c7 100644
--- a/quic/test_tools/simulator/simulator_test.cc
+++ b/quic/test_tools/simulator/simulator_test.cc
@@ -310,10 +310,9 @@
   saturator.SetTxPort(&local_link);
   queue.set_tx_port(&bottleneck_link);
 
-  const QuicPacketCount packets_received = 1000;
-  simulator.RunUntil([&counter, packets_received]() {
-    return counter.packets() == packets_received;
-  });
+  static const QuicPacketCount packets_received = 1000;
+  simulator.RunUntil(
+      [&counter]() { return counter.packets() == packets_received; });
   const double loss_ratio = 1 - static_cast<double>(packets_received) /
                                     saturator.packets_transmitted();
   EXPECT_NEAR(loss_ratio, 0.9, 0.001);
diff --git a/quic/tools/quic_client.cc b/quic/tools/quic_client.cc
index 84e1844..7705907 100644
--- a/quic/tools/quic_client.cc
+++ b/quic/tools/quic_client.cc
@@ -35,7 +35,7 @@
 QuicClient::QuicClient(QuicSocketAddress server_address,
                        const QuicServerId& server_id,
                        const ParsedQuicVersionVector& supported_versions,
-                       gfe2::EpollServer* epoll_server,
+                       QuicEpollServer* epoll_server,
                        std::unique_ptr<ProofVerifier> proof_verifier)
     : QuicClient(
           server_address,
@@ -50,7 +50,7 @@
     QuicSocketAddress server_address,
     const QuicServerId& server_id,
     const ParsedQuicVersionVector& supported_versions,
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     std::unique_ptr<QuicClientEpollNetworkHelper> network_helper,
     std::unique_ptr<ProofVerifier> proof_verifier)
     : QuicClient(server_address,
@@ -66,7 +66,7 @@
     const QuicServerId& server_id,
     const ParsedQuicVersionVector& supported_versions,
     const QuicConfig& config,
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     std::unique_ptr<QuicClientEpollNetworkHelper> network_helper,
     std::unique_ptr<ProofVerifier> proof_verifier)
     : QuicSpdyClientBase(
@@ -80,7 +80,7 @@
   set_server_address(server_address);
 }
 
-QuicClient::~QuicClient() {}
+QuicClient::~QuicClient() = default;
 
 std::unique_ptr<QuicSession> QuicClient::CreateQuicClientSession(
     const ParsedQuicVersionVector& supported_versions,
diff --git a/quic/tools/quic_client.h b/quic/tools/quic_client.h
index 71ff7f4..03a029d 100644
--- a/quic/tools/quic_client.h
+++ b/quic/tools/quic_client.h
@@ -21,6 +21,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packet_reader.h"
 #include "net/third_party/quiche/src/quic/core/quic_process_packet_interface.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/tools/quic_client_epoll_network_helper.h"
 #include "net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h"
 
@@ -38,20 +39,20 @@
   QuicClient(QuicSocketAddress server_address,
              const QuicServerId& server_id,
              const ParsedQuicVersionVector& supported_versions,
-             gfe2::EpollServer* epoll_server,
+             QuicEpollServer* epoll_server,
              std::unique_ptr<ProofVerifier> proof_verifier);
   // This will take ownership of a passed in network primitive.
   QuicClient(QuicSocketAddress server_address,
              const QuicServerId& server_id,
              const ParsedQuicVersionVector& supported_versions,
-             gfe2::EpollServer* epoll_server,
+             QuicEpollServer* epoll_server,
              std::unique_ptr<QuicClientEpollNetworkHelper> network_helper,
              std::unique_ptr<ProofVerifier> proof_verifier);
   QuicClient(QuicSocketAddress server_address,
              const QuicServerId& server_id,
              const ParsedQuicVersionVector& supported_versions,
              const QuicConfig& config,
-             gfe2::EpollServer* epoll_server,
+             QuicEpollServer* epoll_server,
              std::unique_ptr<QuicClientEpollNetworkHelper> network_helper,
              std::unique_ptr<ProofVerifier> proof_verifier);
   QuicClient(const QuicClient&) = delete;
diff --git a/quic/tools/quic_client_base.cc b/quic/tools/quic_client_base.cc
index 8a469a6..f824811 100644
--- a/quic/tools/quic_client_base.cc
+++ b/quic/tools/quic_client_base.cc
@@ -86,7 +86,7 @@
       // Resend any previously queued data.
       ResendSavedData();
     }
-    ParsedQuicVersion version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+    ParsedQuicVersion version = UnsupportedQuicVersion();
     if (session() != nullptr &&
         session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT &&
         !CanReconnectWithDifferentVersion(&version)) {
@@ -110,8 +110,7 @@
   DCHECK(initialized_);
   DCHECK(!connected());
   QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
-  ParsedQuicVersion mutual_version(PROTOCOL_UNSUPPORTED,
-                                   QUIC_VERSION_UNSUPPORTED);
+  ParsedQuicVersion mutual_version = UnsupportedQuicVersion();
   const bool can_reconnect_with_different_version =
       CanReconnectWithDifferentVersion(&mutual_version);
   if (connected_or_attempting_connect()) {
@@ -180,7 +179,7 @@
   network_helper_->RunEventLoop();
 
   DCHECK(session() != nullptr);
-  ParsedQuicVersion version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+  ParsedQuicVersion version = UnsupportedQuicVersion();
   if (!connected() &&
       (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT ||
        CanReconnectWithDifferentVersion(&version))) {
diff --git a/quic/tools/quic_client_base.h b/quic/tools/quic_client_base.h
index 8257cef..c751bfd 100644
--- a/quic/tools/quic_client_base.h
+++ b/quic/tools/quic_client_base.h
@@ -136,17 +136,6 @@
     crypto_config_.SetChannelIDSource(source);
   }
 
-  // UseTokenBinding enables token binding negotiation in the client.  This
-  // should only be called before the initial Connect().  The client will still
-  // need to check that token binding is negotiated with the server, and add
-  // token binding headers to requests if so.  server, and add token binding
-  // headers to requests if so.  The negotiated token binding parameters can be
-  // found on the QuicCryptoNegotiatedParameters object in
-  // token_binding_key_param.
-  void UseTokenBinding() {
-    crypto_config_.tb_key_params = QuicTagVector{kTB10};
-  }
-
   const ParsedQuicVersionVector& supported_versions() const {
     return supported_versions_;
   }
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc
index dc82b0f..629b980 100644
--- a/quic/tools/quic_client_bin.cc
+++ b/quic/tools/quic_client_bin.cc
@@ -124,9 +124,13 @@
               "for_connecting_to_google/roots.pem",
               "Path to the root certificate which the server's certificate is "
               "required to chain to.");
-ABSL_FLAG(bool, disable_certificate_verification, false,
+ABSL_FLAG(bool,
+          disable_certificate_verification,
+          false,
           "If true, don't verify the server certificate.");
-ABSL_FLAG(bool, drop_response_body, false,
+ABSL_FLAG(bool,
+          drop_response_body,
+          false,
           "If true, drop response body immediately after it is received.");
 
 using quic::QuicStringPiece;
@@ -169,7 +173,7 @@
   cout << "Resolved " << host << " to " << host_port << endl;
 
   // Build the client, and try to connect.
-  gfe2::EpollServer epoll_server;
+  quic::QuicEpollServer epoll_server;
   quic::QuicServerId server_id(url.host(), port, false);
   quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
   if (FLAGS_quic_version != -1) {
diff --git a/quic/tools/quic_client_epoll_network_helper.cc b/quic/tools/quic_client_epoll_network_helper.cc
index b12148c..6a48ad3 100644
--- a/quic/tools/quic_client_epoll_network_helper.cc
+++ b/quic/tools/quic_client_epoll_network_helper.cc
@@ -36,7 +36,7 @@
 }  // namespace
 
 QuicClientEpollNetworkHelper::QuicClientEpollNetworkHelper(
-    gfe2::EpollServer* epoll_server,
+    QuicEpollServer* epoll_server,
     QuicClientBase* client)
     : epoll_server_(epoll_server),
       packets_dropped_(0),
@@ -120,14 +120,14 @@
   epoll_server_->WaitForEventsAndExecuteCallbacks();
 }
 
-void QuicClientEpollNetworkHelper::OnRegistration(gfe2::EpollServer* eps,
+void QuicClientEpollNetworkHelper::OnRegistration(QuicEpollServer* eps,
                                                   int fd,
                                                   int event_mask) {}
 void QuicClientEpollNetworkHelper::OnModification(int fd, int event_mask) {}
 void QuicClientEpollNetworkHelper::OnUnregistration(int fd, bool replaced) {}
-void QuicClientEpollNetworkHelper::OnShutdown(gfe2::EpollServer* eps, int fd) {}
+void QuicClientEpollNetworkHelper::OnShutdown(QuicEpollServer* eps, int fd) {}
 
-void QuicClientEpollNetworkHelper::OnEvent(int fd, gfe2::EpollEvent* event) {
+void QuicClientEpollNetworkHelper::OnEvent(int fd, QuicEpollEvent* event) {
   DCHECK_EQ(fd, GetLatestFD());
 
   if (event->in_events & EPOLLIN) {
diff --git a/quic/tools/quic_client_epoll_network_helper.h b/quic/tools/quic_client_epoll_network_helper.h
index 23a1c91..5871cd0 100644
--- a/quic/tools/quic_client_epoll_network_helper.h
+++ b/quic/tools/quic_client_epoll_network_helper.h
@@ -21,6 +21,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packet_reader.h"
 #include "net/third_party/quiche/src/quic/core/quic_process_packet_interface.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h"
 
 namespace quic {
@@ -32,12 +33,12 @@
 // An implementation of the QuicClientBase::NetworkHelper based off
 // the epoll server.
 class QuicClientEpollNetworkHelper : public QuicClientBase::NetworkHelper,
-                                     public gfe2::EpollCallbackInterface,
+                                     public QuicEpollCallbackInterface,
                                      public ProcessPacketInterface {
  public:
   // Create a quic client, which will have events managed by an externally owned
   // EpollServer.
-  QuicClientEpollNetworkHelper(gfe2::EpollServer* epoll_server,
+  QuicClientEpollNetworkHelper(QuicEpollServer* epoll_server,
                                QuicClientBase* client);
   QuicClientEpollNetworkHelper(const QuicClientEpollNetworkHelper&) = delete;
   QuicClientEpollNetworkHelper& operator=(const QuicClientEpollNetworkHelper&) =
@@ -49,14 +50,14 @@
   QuicString Name() const override;
 
   // From EpollCallbackInterface
-  void OnRegistration(gfe2::EpollServer* eps, int fd, int event_mask) override;
+  void OnRegistration(QuicEpollServer* eps, int fd, int event_mask) override;
   void OnModification(int fd, int event_mask) override;
-  void OnEvent(int fd, gfe2::EpollEvent* event) override;
+  void OnEvent(int fd, QuicEpollEvent* event) override;
   // |fd_| can be unregistered without the client being disconnected. This
   // happens in b3m QuicProber where we unregister |fd_| to feed in events to
   // the client from the SelectServer.
   void OnUnregistration(int fd, bool replaced) override;
-  void OnShutdown(gfe2::EpollServer* eps, int fd) override;
+  void OnShutdown(QuicEpollServer* eps, int fd) override;
 
   // From ProcessPacketInterface. This will be called for each received
   // packet.
@@ -75,7 +76,7 @@
 
   // Accessors provided for convenience, not part of any interface.
 
-  gfe2::EpollServer* epoll_server() { return epoll_server_; }
+  QuicEpollServer* epoll_server() { return epoll_server_; }
 
   const QuicLinkedHashMap<int, QuicSocketAddress>& fd_address_map() const {
     return fd_address_map_;
@@ -110,7 +111,7 @@
   void CleanUpUDPSocketImpl(int fd);
 
   // Listens for events on the client socket.
-  gfe2::EpollServer* epoll_server_;
+  QuicEpollServer* epoll_server_;
 
   // Map mapping created UDP sockets to their addresses. By using linked hash
   // map, the order of socket creation can be recorded.
diff --git a/quic/tools/quic_client_test.cc b/quic/tools/quic_client_test.cc
index 1c8c7ad..4f139b3 100644
--- a/quic/tools/quic_client_test.cc
+++ b/quic/tools/quic_client_test.cc
@@ -17,8 +17,6 @@
 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
 
-using gfe2::EpollServer;
-
 namespace quic {
 namespace test {
 namespace {
@@ -51,7 +49,7 @@
 
 // Creates a new QuicClient and Initializes it. Caller is responsible for
 // deletion.
-QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) {
+QuicClient* CreateAndInitializeQuicClient(QuicEpollServer* eps, uint16_t port) {
   QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
   QuicServerId server_id("hostname", server_address.port(), false);
   ParsedQuicVersionVector versions = AllSupportedVersions();
@@ -69,7 +67,7 @@
   // port exhaustion in long running processes which repeatedly create clients.
 
   // Record initial number of FDs, after creation of EpollServer.
-  EpollServer eps;
+  QuicEpollServer eps;
   size_t number_of_open_fds = NumOpenSocketFDs();
 
   // Create a number of clients, initialize them, and verify this has resulted
@@ -88,7 +86,7 @@
 }
 
 TEST_F(QuicClientTest, CreateAndCleanUpUDPSockets) {
-  EpollServer eps;
+  QuicEpollServer eps;
   size_t number_of_open_fds = NumOpenSocketFDs();
 
   std::unique_ptr<QuicClient> client(
diff --git a/quic/tools/quic_memory_cache_backend.cc b/quic/tools/quic_memory_cache_backend.cc
index 94d795a..fa80e7e 100644
--- a/quic/tools/quic_memory_cache_backend.cc
+++ b/quic/tools/quic_memory_cache_backend.cc
@@ -107,9 +107,9 @@
   host_ = base.substr(0, path_start);
   size_t query_start = base.find_first_of(',');
   if (query_start > 0) {
-    path_ = absl::ClippedSubstr(base, path_start, query_start - 1);
+    path_ = base.substr(path_start, query_start - 1);
   } else {
-    path_ = absl::ClippedSubstr(base, path_start);
+    path_ = base.substr(path_start);
   }
 }
 
diff --git a/quic/tools/quic_server.cc b/quic/tools/quic_server.cc
index 7e8dc95..eaec5d4 100644
--- a/quic/tools/quic_server.cc
+++ b/quic/tools/quic_server.cc
@@ -182,7 +182,7 @@
   fd_ = -1;
 }
 
-void QuicServer::OnEvent(int fd, gfe2::EpollEvent* event) {
+void QuicServer::OnEvent(int fd, QuicEpollEvent* event) {
   DCHECK_EQ(fd, fd_);
   event->out_ready_mask = 0;
 
diff --git a/quic/tools/quic_server.h b/quic/tools/quic_server.h
index 712eceb..af60f95 100644
--- a/quic/tools/quic_server.h
+++ b/quic/tools/quic_server.h
@@ -21,6 +21,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_framer.h"
 #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
 #include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h"
 
@@ -33,7 +34,7 @@
 class QuicDispatcher;
 class QuicPacketReader;
 
-class QuicServer : public gfe2::EpollCallbackInterface {
+class QuicServer : public QuicEpollCallbackInterface {
  public:
   QuicServer(std::unique_ptr<ProofSource> proof_source,
              QuicSimpleServerBackend* quic_simple_server_backend);
@@ -62,13 +63,12 @@
   virtual void Shutdown();
 
   // From EpollCallbackInterface
-  void OnRegistration(gfe2::EpollServer* eps, int fd, int event_mask) override {
-  }
+  void OnRegistration(QuicEpollServer* eps, int fd, int event_mask) override {}
   void OnModification(int fd, int event_mask) override {}
-  void OnEvent(int fd, gfe2::EpollEvent* event) override;
+  void OnEvent(int fd, QuicEpollEvent* event) override;
   void OnUnregistration(int fd, bool replaced) override {}
 
-  void OnShutdown(gfe2::EpollServer* eps, int fd) override {}
+  void OnShutdown(QuicEpollServer* eps, int fd) override {}
 
   void SetChloMultiplier(size_t multiplier) {
     crypto_config_.set_chlo_multiplier(multiplier);
@@ -91,7 +91,7 @@
 
   const QuicConfig& config() const { return config_; }
   const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
-  gfe2::EpollServer* epoll_server() { return &epoll_server_; }
+  QuicEpollServer* epoll_server() { return &epoll_server_; }
 
   QuicDispatcher* dispatcher() { return dispatcher_.get(); }
 
@@ -112,7 +112,7 @@
   // Accepts data from the framer and demuxes clients to sessions.
   std::unique_ptr<QuicDispatcher> dispatcher_;
   // Frames incoming packets and hands them to the dispatcher.
-  gfe2::EpollServer epoll_server_;
+  QuicEpollServer epoll_server_;
 
   // The port the server is listening on.
   int port_;
diff --git a/quic/tools/quic_server_test.cc b/quic/tools/quic_server_test.cc
index a3c0fb0..f549ad4 100644
--- a/quic/tools/quic_server_test.cc
+++ b/quic/tools/quic_server_test.cc
@@ -28,7 +28,6 @@
 namespace quic {
 namespace test {
 
-using gfe2::EpollServer;
 using ::testing::_;
 
 namespace {
@@ -228,7 +227,7 @@
   QuicConfig config_;
   QuicCryptoServerConfig crypto_config_;
   QuicVersionManager version_manager_;
-  EpollServer eps_;
+  QuicEpollServer eps_;
   QuicMemoryCacheBackend quic_simple_server_backend_;
   MockQuicDispatcher dispatcher_;
 };
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper.cc b/quic/tools/quic_simple_crypto_server_stream_helper.cc
index af4e152..567c670 100644
--- a/quic/tools/quic_simple_crypto_server_stream_helper.cc
+++ b/quic/tools/quic_simple_crypto_server_stream_helper.cc
@@ -17,6 +17,7 @@
 
 QuicConnectionId
 QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject(
+    QuicTransportVersion /*version*/,
     QuicConnectionId /*connection_id*/) const {
   return QuicUtils::CreateRandomConnectionId(random_, Perspective::IS_SERVER);
 }
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper.h b/quic/tools/quic_simple_crypto_server_stream_helper.h
index 2c1e19a..c058f1a 100644
--- a/quic/tools/quic_simple_crypto_server_stream_helper.h
+++ b/quic/tools/quic_simple_crypto_server_stream_helper.h
@@ -20,13 +20,14 @@
   ~QuicSimpleCryptoServerStreamHelper() override;
 
   QuicConnectionId GenerateConnectionIdForReject(
+      QuicTransportVersion /*version*/,
       QuicConnectionId /*connection_id*/) const override;
 
   bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
                             const QuicSocketAddress& client_address,
                             const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
-                            string* error_details) const override;
+                            QuicString* error_details) const override;
 
  private:
   QuicRandom* random_;  // Unowned.
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
index e64ba69..652f282 100644
--- a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
+++ b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
@@ -14,7 +14,12 @@
   QuicSimpleCryptoServerStreamHelper helper(&random);
 
   EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random),
-            helper.GenerateConnectionIdForReject(test::TestConnectionId()));
+            helper.GenerateConnectionIdForReject(QUIC_VERSION_35,
+                                                 test::TestConnectionId()));
+
+  EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random),
+            helper.GenerateConnectionIdForReject(QUIC_VERSION_99,
+                                                 test::TestConnectionId()));
 }
 
 }  // namespace quic
diff --git a/quic/tools/quic_simple_server_session.cc b/quic/tools/quic_simple_server_session.cc
index 685d9f5..a3e8208 100644
--- a/quic/tools/quic_simple_server_session.cc
+++ b/quic/tools/quic_simple_server_session.cc
@@ -13,8 +13,6 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h"
 
-using spdy::SpdyHeaderBlock;
-
 namespace quic {
 
 QuicSimpleServerSession::QuicSimpleServerSession(
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc
index a76facd..1ba330d 100644
--- a/quic/tools/quic_simple_server_session_test.cc
+++ b/quic/tools/quic_simple_server_session_test.cc
@@ -251,6 +251,25 @@
         *session_, n);
   }
 
+  void InjectStopSending(QuicStreamId stream_id,
+                         QuicRstStreamErrorCode rst_stream_code) {
+    // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+    // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+    // a one-way close.
+    if (connection_->transport_version() != QUIC_VERSION_99) {
+      // Only needed for version 99/IETF QUIC.
+      return;
+    }
+    EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_id,
+        static_cast<QuicApplicationErrorCode>(rst_stream_code));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+    session_->OnStopSendingFrame(stop_sending);
+  }
+
   StrictMock<MockQuicSessionVisitor> owner_;
   StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
   MockQuicConnectionHelper helper_;
@@ -287,6 +306,11 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send the same two bytes of payload in a new packet.
@@ -310,6 +334,12 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send two bytes of payload.
@@ -344,6 +374,11 @@
               OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
                             QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
 
   // If we were tracking, we'd probably want to reject this because it's data
   // past the reset point of stream 3.  As it's a closed stream we just drop the
@@ -794,6 +829,10 @@
         QuicMaxStreamIdFrame(0, GetNthServerInitiatedUnidirectionalId(10)));
   }
   visitor_->OnRstStream(rst);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(stream_got_reset, QUIC_STREAM_CANCELLED);
 }
 
 }  // namespace
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index 3916bd8..4e9e68d 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -170,6 +170,8 @@
 
   using QuicSession::ActivateStream;
 
+  MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
+
   spdy::SpdyHeaderBlock original_request_headers_;
 };
 
@@ -197,7 +199,8 @@
                  &memory_cache_backend_),
         quic_response_(new QuicBackendResponse),
         body_("hello world"),
-        is_verion_99_(connection_->transport_version() == QUIC_VERSION_99) {
+        is_version_99_(connection_->transport_version() == QUIC_VERSION_99) {
+    connection_->set_visitor(&session_);
     header_list_.OnHeaderBlockStart();
     header_list_.OnHeader(":authority", "www.google.com");
     header_list_.OnHeader(":path", "/");
@@ -245,7 +248,7 @@
   QuicString body_;
   QuicHeaderList header_list_;
   HttpEncoder encoder_;
-  bool is_verion_99_;
+  bool is_version_99_;
 };
 
 INSTANTIATE_TEST_CASE_P(Tests,
@@ -261,7 +264,7 @@
   QuicByteCount header_length =
       encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
   QuicString header = QuicString(buffer.get(), header_length);
-  QuicString data = is_verion_99_ ? header + body_ : body_;
+  QuicString data = is_version_99_ ? header + body_ : body_;
   stream_->OnStreamFrame(
       QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
   EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -280,7 +283,7 @@
   QuicByteCount header_length =
       encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
   QuicString header = QuicString(buffer.get(), header_length);
-  QuicString data = is_verion_99_ ? header + body_ : body_;
+  QuicString data = is_version_99_ ? header + body_ : body_;
   stream_->OnStreamFrame(
       QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
   EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -310,7 +313,7 @@
 
   // We'll automatically write out an error (headers + body)
   EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .WillOnce(Invoke(MockQuicSession::ConsumeData));
   }
@@ -324,7 +327,7 @@
   QuicByteCount header_length =
       encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
   QuicString header = QuicString(buffer.get(), header_length);
-  QuicString data = is_verion_99_ ? header + body_ : body_;
+  QuicString data = is_version_99_ ? header + body_ : body_;
 
   stream_->OnStreamFrame(
       QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
@@ -333,7 +336,7 @@
   header_length =
       encoder_.SerializeDataFrameHeader(large_body.length(), &buffer);
   header = QuicString(buffer.get(), header_length);
-  QuicString data2 = is_verion_99_ ? header + large_body : large_body;
+  QuicString data2 = is_version_99_ ? header + large_body : large_body;
   stream_->OnStreamFrame(
       QuicStreamFrame(stream_->id(), /*fin=*/true, data.size(), data2));
   EXPECT_EQ("11", StreamHeadersValue("content-length"));
@@ -365,7 +368,7 @@
 
   InSequence s;
   EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(header_length, false)));
@@ -405,7 +408,7 @@
 
   InSequence s;
   EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(header_length, false)));
@@ -474,7 +477,7 @@
 
   InSequence s;
   EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(header_length, false)));
@@ -523,7 +526,7 @@
               session_, 0),
           _));
   EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(header_length, false)));
@@ -588,7 +591,7 @@
                                server_initiated_stream->priority(), _));
 
   InSequence s;
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(header_length, false)));
@@ -612,7 +615,7 @@
 
   InSequence s;
   EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _));
-  if (is_verion_99_) {
+  if (is_version_99_) {
     EXPECT_CALL(session_, WritevData(_, _, _, _, _))
         .Times(1)
         .WillOnce(Return(QuicConsumedData(2, false)));
@@ -685,7 +688,12 @@
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
   stream_->OnStreamReset(rst_frame);
-
+  if (connection_->transport_version() == QUIC_VERSION_99) {
+    // For V99 receiving a RST_STREAM causes a 1-way close; the test requires
+    // a full close. A CloseWriteSide closes the other half of the stream.
+    // Everything should then work properly.
+    stream_->CloseWriteSide();
+  }
   EXPECT_TRUE(stream_->reading_stopped());
   EXPECT_TRUE(stream_->write_side_closed());
 }
diff --git a/quic/tools/quic_spdy_client_base.cc b/quic/tools/quic_spdy_client_base.cc
index 22db8df..f03b678 100644
--- a/quic/tools/quic_spdy_client_base.cc
+++ b/quic/tools/quic_spdy_client_base.cc
@@ -27,7 +27,7 @@
     bool fin)
     : headers_(std::move(headers)), body_(body), fin_(fin) {}
 
-QuicSpdyClientBase::QuicDataToResend::~QuicDataToResend() {}
+QuicSpdyClientBase::QuicDataToResend::~QuicDataToResend() = default;
 
 QuicSpdyClientBase::QuicSpdyClientBase(
     const QuicServerId& server_id,
diff --git a/spdy/core/hpack/hpack_constants.cc b/spdy/core/hpack/hpack_constants.cc
index da41c0e..9c1498a 100644
--- a/spdy/core/hpack/hpack_constants.cc
+++ b/spdy/core/hpack/hpack_constants.cc
@@ -6,13 +6,12 @@
 
 #include <cstddef>
 #include <memory>
+#include <vector>
 
 #include "base/logging.h"
-#include "base/once.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_arraysize.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 
 namespace spdy {
 
@@ -26,7 +25,7 @@
 // HpackHuffmanSymbol entries are initialized as {code, length, id}.
 // Codes are specified in the |length| most-significant bits of |code|.
 const std::vector<HpackHuffmanSymbol>& HpackHuffmanCodeVector() {
-  static const std::vector<HpackHuffmanSymbol> kHpackHuffmanCode = {
+  static const auto* kHpackHuffmanCode = new std::vector<HpackHuffmanSymbol>{
       {0xffc00000ul, 13, 0},    //     11111111|11000
       {0xffffb000ul, 23, 1},    //     11111111|11111111|1011000
       {0xfffffe20ul, 28, 2},    //     11111111|11111111|11111110|0010
@@ -285,7 +284,7 @@
       {0xfffffb80ul, 26, 255},  //     11111111|11111111|11111011|10
       {0xfffffffcul, 30, 256},  // EOS 11111111|11111111|11111111|111111
   };
-  return kHpackHuffmanCode;
+  return *kHpackHuffmanCode;
 }
 
 // The "constructor" for a HpackStaticEntry that computes the lengths at
@@ -294,7 +293,7 @@
   { name, SPDY_ARRAYSIZE(name) - 1, value, SPDY_ARRAYSIZE(value) - 1 }
 
 const std::vector<HpackStaticEntry>& HpackStaticTableVector() {
-  static const std::vector<HpackStaticEntry> kHpackStaticTable = {
+  static const auto* kHpackStaticTable = new std::vector<HpackStaticEntry>{
       STATIC_ENTRY(":authority", ""),                    // 1
       STATIC_ENTRY(":method", "GET"),                    // 2
       STATIC_ENTRY(":method", "POST"),                   // 3
@@ -357,7 +356,7 @@
       STATIC_ENTRY("via", ""),                           // 60
       STATIC_ENTRY("www-authenticate", ""),              // 61
   };
-  return kHpackStaticTable;
+  return *kHpackStaticTable;
 }
 
 #undef STATIC_ENTRY
diff --git a/spdy/core/hpack/hpack_decoder_adapter.cc b/spdy/core/hpack/hpack_decoder_adapter.cc
index 77ff703..309af39 100644
--- a/spdy/core/hpack/hpack_decoder_adapter.cc
+++ b/spdy/core/hpack/hpack_decoder_adapter.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_status.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 
 using ::http2::DecodeBuffer;
 using ::http2::HpackEntryType;
@@ -107,6 +108,10 @@
   hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes);
 }
 
+size_t HpackDecoderAdapter::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(hpack_decoder_);
+}
+
 HpackDecoderAdapter::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {}
 HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default;
 
diff --git a/spdy/core/hpack/hpack_decoder_adapter.h b/spdy/core/hpack/hpack_decoder_adapter.h
index 3f2ba88..b497fe7 100644
--- a/spdy/core/hpack/hpack_decoder_adapter.h
+++ b/spdy/core/hpack/hpack_decoder_adapter.h
@@ -80,6 +80,8 @@
   // of individual transport buffers.
   void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes);
 
+  size_t EstimateMemoryUsage() const;
+
  private:
   class SPDY_EXPORT_PRIVATE ListenerAdapter
       : public http2::HpackDecoderListener,
diff --git a/spdy/core/hpack/hpack_decoder_adapter_test.cc b/spdy/core/hpack/hpack_decoder_adapter_test.cc
index bef5c65..765c2ea 100644
--- a/spdy/core/hpack/hpack_decoder_adapter_test.cc
+++ b/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -6,16 +6,19 @@
 
 // Tests of HpackDecoderAdapter.
 
+#include <stdint.h>
+
+#include <tuple>
 #include <utility>
 #include <vector>
 
 #include "base/logging.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "testing/base/public/googletest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h"
 #include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h"
 #include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h"
+#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
@@ -23,12 +26,12 @@
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_arraysize.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
-#include "util/random/mt_random.h"
 
 using ::http2::HpackEntryType;
 using ::http2::HpackString;
 using ::http2::HpackStringPair;
 using ::http2::test::HpackBlockBuilder;
+using ::http2::test::HpackDecoderPeer;
 using ::testing::ElementsAre;
 using ::testing::Pair;
 
@@ -58,8 +61,6 @@
 namespace spdy {
 namespace test {
 
-using ::http2::test::HpackDecoderPeer;
-
 class HpackDecoderAdapterPeer {
  public:
   explicit HpackDecoderAdapterPeer(HpackDecoderAdapter* decoder)
@@ -112,14 +113,8 @@
 
 class HpackDecoderAdapterTest
     : public ::testing::TestWithParam<std::tuple<StartChoice, bool>> {
- public:
-  static void SetUpTestCase() {
-    LOG(INFO) << "Flag --test_random_seed=" << FLAGS_test_random_seed;
-  }
-
  protected:
-  HpackDecoderAdapterTest()
-      : random_(FLAGS_test_random_seed), decoder_(), decoder_peer_(&decoder_) {}
+  HpackDecoderAdapterTest() : decoder_(), decoder_peer_(&decoder_) {}
 
   void SetUp() override {
     std::tie(start_choice_, randomly_split_input_buffer_) = GetParam();
@@ -254,7 +249,7 @@
     return result;
   }
 
-  MTRandom random_;
+  http2::test::Http2Random random_;
   HpackDecoderAdapter decoder_;
   test::HpackDecoderAdapterPeer decoder_peer_;
   TestHeadersHandler handler_;
@@ -407,13 +402,14 @@
   decoder_.HandleControlFrameHeadersComplete(nullptr);
 
   // Resulting decoded headers are in the same order as the inputs.
-  EXPECT_THAT(decoded_block(),
-              ElementsAre(Pair("cookie", " part 1; part 2 ; part3;  fin!"),
-                          Pair("passed-through", SpdyString("foo\0baz", 7)),
-                          Pair("joined", "not joined"),
-                          Pair("joineD", SpdyString("value 1\0value 2", 15)),
-                          Pair("empty", ""),
-                          Pair("empty-joined", SpdyString("\0foo\0\0", 6))));
+  EXPECT_THAT(
+      decoded_block(),
+      ElementsAre(Pair("cookie", " part 1; part 2 ; part3;  fin!"),
+                  Pair("passed-through", SpdyStringPiece("foo\0baz", 7)),
+                  Pair("joined", "not joined"),
+                  Pair("joineD", SpdyStringPiece("value 1\0value 2", 15)),
+                  Pair("empty", ""),
+                  Pair("empty-joined", SpdyStringPiece("\0foo\0\0", 6))));
 }
 
 // Decoding indexed static table field should work.
@@ -678,8 +674,7 @@
 
   SpdyString first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff");
   EXPECT_TRUE(DecodeHeaderBlock(first));
-  first[1] = 0x8d;
-  first.push_back(0xff);
+  first = SpdyHexDecode("418df1e3c2e5f23a6ba0ab90f4ffff");
   EXPECT_FALSE(DecodeHeaderBlock(first));
 }
 
@@ -705,8 +700,9 @@
 // RFC 7541, Section C.4: Request Examples with Huffman Coding
 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.4
 TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) {
-  // TODO(jamessynge): Use gfe/http2/hpack/tools/hpack_example.h to parse the
+  // TODO(jamessynge): Use http2/hpack/tools/hpack_example.h to parse the
   // example directly, instead of having it as a comment.
+  //
   // 82                                      | == Indexed - Add ==
   //                                         |   idx = 2
   //                                         | -> :method: GET
diff --git a/spdy/core/hpack/hpack_encoder.cc b/spdy/core/hpack/hpack_encoder.cc
index 7608b06..a9981b9 100644
--- a/spdy/core/hpack/hpack_encoder.cc
+++ b/spdy/core/hpack/hpack_encoder.cc
@@ -12,6 +12,7 @@
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 
 namespace spdy {
@@ -123,6 +124,12 @@
   should_emit_table_size_ = true;
 }
 
+size_t HpackEncoder::EstimateMemoryUsage() const {
+  // |huffman_table_| is a singleton. It's accounted for in spdy_session_pool.cc
+  return SpdyEstimateMemoryUsage(header_table_) +
+         SpdyEstimateMemoryUsage(output_stream_);
+}
+
 void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
                                          SpdyString* output) {
   MaybeEmitTableSize();
@@ -228,18 +235,17 @@
   if (first == SpdyStringPiece::npos) {
     cookie_value = SpdyStringPiece();
   } else {
-    cookie_value = absl::ClippedSubstr(cookie_value, first, (last - first) + 1);
+    cookie_value = cookie_value.substr(first, (last - first) + 1);
   }
   for (size_t pos = 0;;) {
     size_t end = cookie_value.find(";", pos);
 
     if (end == SpdyStringPiece::npos) {
-      out->push_back(
-          std::make_pair(cookie.first, absl::ClippedSubstr(cookie_value, pos)));
+      out->push_back(std::make_pair(cookie.first, cookie_value.substr(pos)));
       break;
     }
-    out->push_back(std::make_pair(
-        cookie.first, absl::ClippedSubstr(cookie_value, pos, end - pos)));
+    out->push_back(
+        std::make_pair(cookie.first, cookie_value.substr(pos, end - pos)));
 
     // Consume next space if present.
     pos = end + 1;
@@ -258,8 +264,8 @@
     end = header_field.second.find('\0', pos);
     out->push_back(std::make_pair(
         header_field.first,
-        absl::ClippedSubstr(header_field.second, pos,
-                            end == SpdyStringPiece::npos ? end : end - pos)));
+        header_field.second.substr(
+            pos, end == SpdyStringPiece::npos ? end : end - pos)));
     pos = end + 1;
   }
 }
diff --git a/spdy/core/hpack/hpack_encoder.h b/spdy/core/hpack/hpack_encoder.h
index 22bed4e..486d536 100644
--- a/spdy/core/hpack/hpack_encoder.h
+++ b/spdy/core/hpack/hpack_encoder.h
@@ -97,6 +97,9 @@
 
   void DisableCompression() { enable_compression_ = false; }
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
  private:
   friend class test::HpackEncoderPeer;
 
diff --git a/spdy/core/hpack/hpack_encoder_test.cc b/spdy/core/hpack/hpack_encoder_test.cc
index e639650..8ead1c2 100644
--- a/spdy/core/hpack/hpack_encoder_test.cc
+++ b/spdy/core/hpack/hpack_encoder_test.cc
@@ -7,12 +7,11 @@
 #include <cstdint>
 #include <map>
 
-#include "base/arena.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/absl/random/random.h"
+#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h"
-#include "util/random/acmrandom.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_unsafe_arena.h"
 
 namespace spdy {
 
@@ -86,11 +85,11 @@
     std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator =
         encoder->EncodeHeaderSet(header_set);
     SpdyString output_buffer;
-    ACMRandom random(FLAGS_test_random_seed);
-    encoderator->Next(absl::Uniform<uint32_t>(random, 0, 16), &output_buffer);
+    http2::test::Http2Random random;
+    encoderator->Next(random.UniformInRange(0, 16), &output_buffer);
     while (encoderator->HasNext()) {
       SpdyString second_buffer;
-      encoderator->Next(absl::Uniform<uint32_t>(random, 0, 16), &second_buffer);
+      encoderator->Next(random.UniformInRange(0, 16), &second_buffer);
       output_buffer.append(second_buffer);
     }
     *output = std::move(output_buffer);
@@ -201,7 +200,7 @@
   const HpackEntry* cookie_a_;
   const HpackEntry* cookie_c_;
 
-  UnsafeArena headers_storage_;
+  SpdyUnsafeArena headers_storage_;
   std::vector<std::pair<SpdyStringPiece, SpdyStringPiece>> headers_observed_;
 
   HpackOutputStream expected_;
diff --git a/spdy/core/hpack/hpack_entry.h b/spdy/core/hpack/hpack_entry.h
index 2b4c427..28dee47 100644
--- a/spdy/core/hpack/hpack_entry.h
+++ b/spdy/core/hpack/hpack_entry.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_SPDY_CORE_HPACK_HPACK_ENTRY_H_
 #define QUICHE_SPDY_CORE_HPACK_HPACK_ENTRY_H_
 
+#include <cstddef>
 #include <cstdint>
 
 #include "base/macros.h"
diff --git a/spdy/core/hpack/hpack_header_table.cc b/spdy/core/hpack/hpack_header_table.cc
index e08ca8f..dbe565f 100644
--- a/spdy/core/hpack/hpack_header_table.cc
+++ b/spdy/core/hpack/hpack_header_table.cc
@@ -9,15 +9,14 @@
 #include "base/logging.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
-#include "util/hash/hash.h"
 
 namespace spdy {
 
 size_t HpackHeaderTable::EntryHasher::operator()(
     const HpackEntry* entry) const {
-  return GoodFastHash<std::pair<SpdyStringPiece, SpdyStringPiece>>()(
-      std::make_pair(entry->name(), entry->value()));
+  return SpdyHashStringPair(entry->name(), entry->value());
 }
 
 bool HpackHeaderTable::EntriesEq::operator()(const HpackEntry* lhs,
diff --git a/spdy/core/hpack/hpack_header_table.h b/spdy/core/hpack/hpack_header_table.h
index 2529551..e85edb7 100644
--- a/spdy/core/hpack/hpack_header_table.h
+++ b/spdy/core/hpack/hpack_header_table.h
@@ -14,8 +14,8 @@
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_macros.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-#include "util/hash/hash.h"
 
 // All section references below are to http://tools.ietf.org/html/rfc7541.
 
@@ -54,10 +54,12 @@
 
   // HpackHeaderTable takes advantage of the deque property that references
   // remain valid, so long as insertions & deletions are at the head & tail.
-  // If this changes (eg we start to drop entries from the middle of the table),
-  // this needs to be a std::list, in which case |*_index_| can be trivially
-  // extended to map to list iterators.
-  typedef std::deque<HpackEntry> EntryTable;
+  // This precludes the use of base::circular_deque.
+  //
+  // If this changes (we want to change to circular_deque or we start to drop
+  // entries from the middle of the table), this should to be a std::list, in
+  // which case |*_index_| can be trivially extended to map to list iterators.
+  using EntryTable = std::deque<HpackEntry>;
 
   struct SPDY_EXPORT_PRIVATE EntryHasher {
     size_t operator()(const HpackEntry* entry) const;
@@ -66,7 +68,8 @@
     bool operator()(const HpackEntry* lhs, const HpackEntry* rhs) const;
   };
   using UnorderedEntrySet = SpdyHashSet<HpackEntry*, EntryHasher, EntriesEq>;
-  using NameToEntryMap = SpdyHashMap<SpdyStringPiece, const HpackEntry*>;
+  using NameToEntryMap =
+      SpdyHashMap<SpdyStringPiece, const HpackEntry*, SpdyStringPieceHash>;
 
   HpackHeaderTable();
   HpackHeaderTable(const HpackHeaderTable&) = delete;
@@ -117,7 +120,7 @@
   // evicted and the empty table is of insufficent size for the representation.
   const HpackEntry* TryAddEntry(SpdyStringPiece name, SpdyStringPiece value);
 
-  void DebugLogTableState() const ABSL_ATTRIBUTE_UNUSED;
+  void DebugLogTableState() const SPDY_UNUSED;
 
   void set_debug_visitor(std::unique_ptr<DebugVisitorInterface> visitor) {
     debug_visitor_ = std::move(visitor);
diff --git a/spdy/core/hpack/hpack_huffman_table.cc b/spdy/core/hpack/hpack_huffman_table.cc
index 2ff2101..c917767 100644
--- a/spdy/core/hpack/hpack_huffman_table.cc
+++ b/spdy/core/hpack/hpack_huffman_table.cc
@@ -6,10 +6,12 @@
 
 #include <algorithm>
 #include <cmath>
+#include <limits>
 #include <memory>
 
 #include "base/logging.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 
 namespace spdy {
 
@@ -35,6 +37,7 @@
 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols,
                                    size_t symbol_count) {
   CHECK(!IsInitialized());
+  DCHECK_LE(symbol_count, std::numeric_limits<uint16_t>::max());
 
   std::vector<Symbol> symbols(symbol_count);
   // Validate symbol id sequence, and copy into |symbols|.
@@ -140,4 +143,9 @@
   return bit_count / 8;
 }
 
+size_t HpackHuffmanTable::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(code_by_id_) +
+         SpdyEstimateMemoryUsage(length_by_id_);
+}
+
 }  // namespace spdy
diff --git a/spdy/core/hpack/hpack_huffman_table.h b/spdy/core/hpack/hpack_huffman_table.h
index efa5e2d..80d9e52 100644
--- a/spdy/core/hpack/hpack_huffman_table.h
+++ b/spdy/core/hpack/hpack_huffman_table.h
@@ -51,6 +51,9 @@
   // Returns the encoded size of the input string.
   size_t EncodedSize(SpdyStringPiece in) const;
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
  private:
   // Expects symbols ordered on ID ascending.
   void BuildEncodeTable(const std::vector<Symbol>& symbols);
diff --git a/spdy/core/hpack/hpack_output_stream.cc b/spdy/core/hpack/hpack_output_stream.cc
index 77fea53..30b5662 100644
--- a/spdy/core/hpack/hpack_output_stream.cc
+++ b/spdy/core/hpack/hpack_output_stream.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 
 namespace spdy {
 
@@ -89,4 +90,8 @@
   }
 }
 
+size_t HpackOutputStream::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(buffer_);
+}
+
 }  // namespace spdy
diff --git a/spdy/core/hpack/hpack_output_stream.h b/spdy/core/hpack/hpack_output_stream.h
index d2a0804..450803f 100644
--- a/spdy/core/hpack/hpack_output_stream.h
+++ b/spdy/core/hpack/hpack_output_stream.h
@@ -59,6 +59,9 @@
   // Size in bytes of stream's internal buffer.
   size_t size() const { return buffer_.size(); }
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
  private:
   // The internal bit buffer.
   SpdyString buffer_;
diff --git a/spdy/core/hpack/hpack_round_trip_test.cc b/spdy/core/hpack/hpack_round_trip_test.cc
index 105566a..4b3a848 100644
--- a/spdy/core/hpack/hpack_round_trip_test.cc
+++ b/spdy/core/hpack/hpack_round_trip_test.cc
@@ -8,16 +8,16 @@
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/absl/random/random.h"
+#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
-#include "util/random/mt_random.h"
 
 namespace spdy {
 namespace test {
+
 namespace {
 
 // Supports testing with the input split at every byte boundary.
@@ -73,7 +73,7 @@
                             sanity_bound);
   }
 
-  MTRandom random_;
+  http2::test::Http2Random random_;
   HpackEncoder encoder_;
   HpackDecoderAdapter decoder_;
 };
@@ -170,10 +170,6 @@
   values.push_back("baz=bing; foo=bar; garbage");
   values.push_back("baz=bing; fizzle=fazzle; garbage");
 
-  uint32_t seed = absl::Uniform<uint32_t>(random_);
-  LOG(INFO) << "Seeding with " << seed << "";
-  random_.Reset(seed);
-
   for (size_t i = 0; i != 2000; ++i) {
     SpdyHeaderBlock headers;
 
diff --git a/spdy/core/hpack/hpack_static_table.cc b/spdy/core/hpack/hpack_static_table.cc
index f462fa4..14e282e 100644
--- a/spdy/core/hpack/hpack_static_table.cc
+++ b/spdy/core/hpack/hpack_static_table.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
 
 namespace spdy {
@@ -40,4 +41,10 @@
   return !static_entries_.empty();
 }
 
+size_t HpackStaticTable::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(static_entries_) +
+         SpdyEstimateMemoryUsage(static_index_) +
+         SpdyEstimateMemoryUsage(static_name_index_);
+}
+
 }  // namespace spdy
diff --git a/spdy/core/hpack/hpack_static_table.h b/spdy/core/hpack/hpack_static_table.h
index 2f2a6dd..f354a12 100644
--- a/spdy/core/hpack/hpack_static_table.h
+++ b/spdy/core/hpack/hpack_static_table.h
@@ -40,6 +40,9 @@
     return static_name_index_;
   }
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
  private:
   HpackHeaderTable::EntryTable static_entries_;
   HpackHeaderTable::UnorderedEntrySet static_index_;
diff --git a/spdy/core/hpack/hpack_static_table_test.cc b/spdy/core/hpack/hpack_static_table_test.cc
index c5f8403..4550be0 100644
--- a/spdy/core/hpack/hpack_static_table_test.cc
+++ b/spdy/core/hpack/hpack_static_table_test.cc
@@ -9,7 +9,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_arraysize.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
 
 namespace spdy {
diff --git a/spdy/core/http2_frame_decoder_adapter.cc b/spdy/core/http2_frame_decoder_adapter.cc
index 5c05fd1..c4e728d 100644
--- a/spdy/core/http2_frame_decoder_adapter.cc
+++ b/spdy/core/http2_frame_decoder_adapter.cc
@@ -16,7 +16,6 @@
 #include <utility>
 
 #include "base/logging.h"
-#include "strings/escaping.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
 #include "net/third_party/quiche/src/http2/decoder/decode_status.h"
 #include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder.h"
@@ -27,17 +26,16 @@
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_endianness_util.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_flags.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
-#include "util/endian/endian.h"
-#include "util/gtl/labs/optional.h"
 
-using absl::nullopt;
 using ::spdy::ExtensionVisitorInterface;
 using ::spdy::HpackDecoderAdapter;
 using ::spdy::HpackHeaderTable;
@@ -45,6 +43,7 @@
 using ::spdy::ParseFrameType;
 using ::spdy::SpdyAltSvcWireFormat;
 using ::spdy::SpdyErrorCode;
+using ::spdy::SpdyEstimateMemoryUsage;
 using ::spdy::SpdyFramerDebugVisitorInterface;
 using ::spdy::SpdyFramerVisitorInterface;
 using ::spdy::SpdyFrameType;
@@ -71,7 +70,7 @@
 uint64_t ToSpdyPingId(const Http2PingFields& ping) {
   uint64_t v;
   std::memcpy(&v, ping.opaque_bytes, Http2PingFields::EncodedSize());
-  return gntohll(v);
+  return spdy::SpdyNetToHost64(v);
 }
 
 // Overwrites the fields of the header with invalid values, for the purpose
@@ -248,6 +247,13 @@
   return latched_probable_http_response_;
 }
 
+size_t Http2DecoderAdapter::EstimateMemoryUsage() const {
+  // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as
+  // they don't allocate.
+  return SpdyEstimateMemoryUsage(alt_svc_origin_) +
+         SpdyEstimateMemoryUsage(alt_svc_value_);
+}
+
 // ===========================================================================
 // Implementations of the methods declared by Http2FrameDecoderListener.
 
@@ -354,7 +360,7 @@
   if (frame_header().IsEndStream()) {
     visitor()->OnStreamEnd(frame_header().stream_id);
   }
-  opt_pad_length_ = nullopt;
+  opt_pad_length_.reset();
 }
 
 void Http2DecoderAdapter::OnHeadersStart(const Http2FrameHeader& header) {
@@ -407,7 +413,7 @@
 void Http2DecoderAdapter::OnHeadersEnd() {
   DVLOG(1) << "OnHeadersEnd";
   CommonHpackFragmentEnd();
-  opt_pad_length_ = nullopt;
+  opt_pad_length_.reset();
 }
 
 void Http2DecoderAdapter::OnPriorityFrame(const Http2FrameHeader& header,
@@ -521,7 +527,7 @@
 void Http2DecoderAdapter::OnPushPromiseEnd() {
   DVLOG(1) << "OnPushPromiseEnd";
   CommonHpackFragmentEnd();
-  opt_pad_length_ = nullopt;
+  opt_pad_length_.reset();
 }
 
 void Http2DecoderAdapter::OnPing(const Http2FrameHeader& header,
diff --git a/spdy/core/http2_frame_decoder_adapter.h b/spdy/core/http2_frame_decoder_adapter.h
index b2bf31a..02deafd 100644
--- a/spdy/core/http2_frame_decoder_adapter.h
+++ b/spdy/core/http2_frame_decoder_adapter.h
@@ -11,13 +11,13 @@
 #include <memory>
 
 #include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_optional.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-#include "util/gtl/labs/optional.h"
 
 namespace spdy {
 
@@ -137,6 +137,9 @@
   // has responded with an HTTP/1.1 (or earlier) response.
   bool probable_http_response() const;
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
   spdy::HpackDecoderAdapter* GetHpackDecoder();
 
   bool HasError() const;
@@ -242,7 +245,7 @@
 
   // Amount of trailing padding. Currently used just as an indicator of whether
   // OnPadLength has been called.
-  absl::optional<size_t> opt_pad_length_;
+  Http2Optional<size_t> opt_pad_length_;
 
   // Temporary buffers for the AltSvc fields.
   Http2String alt_svc_origin_;
diff --git a/spdy/core/priority_write_scheduler.h b/spdy/core/priority_write_scheduler.h
index 25f8b49..d5c3c44 100644
--- a/spdy/core/priority_write_scheduler.h
+++ b/spdy/core/priority_write_scheduler.h
@@ -6,16 +6,19 @@
 #define QUICHE_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_
 
 #include <algorithm>
+#include <cstddef>
 #include <cstdint>
-#include <deque>
 #include <tuple>
 #include <unordered_map>
 #include <utility>
+#include <vector>
 
 #include "base/logging.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_containers.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 #include "net/third_party/quiche/src/spdy/core/write_scheduler.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_macros.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
 
@@ -52,7 +55,8 @@
     // parent_id not used here, but may as well validate it.  However,
     // parent_id may legitimately not be registered yet--see b/15676312.
     StreamIdType parent_id = precedence.parent_id();
-    VLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
+    SPDY_DVLOG_IF(
+        1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
         << "Parent stream " << parent_id << " not registered";
 
     if (stream_id == kHttp2RootStreamId) {
@@ -88,7 +92,7 @@
       StreamIdType stream_id) const override {
     auto it = stream_infos_.find(stream_id);
     if (it == stream_infos_.end()) {
-      VLOG(1) << "Stream " << stream_id << " not registered";
+      DVLOG(1) << "Stream " << stream_id << " not registered";
       return StreamPrecedenceType(kV3LowestPriority);
     }
     return StreamPrecedenceType(it->second.priority);
@@ -102,13 +106,14 @@
     // parent_id not used here, but may as well validate it.  However,
     // parent_id may legitimately not be registered yet--see b/15676312.
     StreamIdType parent_id = precedence.parent_id();
-    VLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
+    SPDY_DVLOG_IF(
+        1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
         << "Parent stream " << parent_id << " not registered";
 
     auto it = stream_infos_.find(stream_id);
     if (it == stream_infos_.end()) {
       // TODO(mpw): add to stream_infos_ on demand--see b/15676312.
-      VLOG(1) << "Stream " << stream_id << " not registered";
+      DVLOG(1) << "Stream " << stream_id << " not registered";
       return;
     }
     StreamInfo& stream_info = it->second;
@@ -278,8 +283,8 @@
     bool ready;
   };
 
-  // 0(1) size lookup, 0(1) insert at front or back.
-  typedef std::deque<StreamInfo*> ReadyList;
+  // O(1) size lookup, O(1) insert at front or back (amortized).
+  using ReadyList = http2::Http2Deque<StreamInfo*>;
 
   // State kept for each priority level.
   struct PriorityInfo {
diff --git a/spdy/core/priority_write_scheduler_test.cc b/spdy/core/priority_write_scheduler_test.cc
index 127ab17..a285cb2 100644
--- a/spdy/core/priority_write_scheduler_test.cc
+++ b/spdy/core/priority_write_scheduler_test.cc
@@ -4,9 +4,7 @@
 
 #include "net/third_party/quiche/src/spdy/core/priority_write_scheduler.h"
 
-#include "testing/base/public/benchmark.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/base/public/test_utils.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
 
@@ -203,7 +201,7 @@
   EXPECT_SPDY_BUG(scheduler_.MarkStreamReady(1, false),
                   "Stream 1 not registered");
   EXPECT_FALSE(scheduler_.HasReadyStreams());
-  EXPECT_SPDY_BUG(EXPECT_EQ(0, scheduler_.PopNextReadyStream()),
+  EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()),
                   "No ready streams available");
 
   // Add a bunch of ready streams to tail of per-priority lists.
diff --git a/spdy/core/spdy_alt_svc_wire_format.h b/spdy/core/spdy_alt_svc_wire_format.h
index 5e12ead..ac834bc 100644
--- a/spdy/core/spdy_alt_svc_wire_format.h
+++ b/spdy/core/spdy_alt_svc_wire_format.h
@@ -13,11 +13,10 @@
 #include <cstdint>
 #include <vector>
 
-#include "third_party/absl/container/inlined_vector.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-#include "util/gtl/inlined_vector.h"
 
 namespace spdy {
 
@@ -27,11 +26,12 @@
 
 class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat {
  public:
-  using VersionVector = absl::InlinedVector<uint32_t, 8>;
+  using VersionVector = SpdyInlinedVector<uint32_t, 8>;
 
   struct SPDY_EXPORT_PRIVATE AlternativeService {
     SpdyString protocol_id;
     SpdyString host;
+
     // Default is 0: invalid port.
     uint16_t port = 0;
     // Default is one day.
diff --git a/spdy/core/spdy_alt_svc_wire_format_test.cc b/spdy/core/spdy_alt_svc_wire_format_test.cc
index e145b83..c2595f0 100644
--- a/spdy/core/spdy_alt_svc_wire_format_test.cc
+++ b/spdy/core/spdy_alt_svc_wire_format_test.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "testing/base/public/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace spdy {
 
diff --git a/spdy/core/spdy_bug_tracker.h b/spdy/core/spdy_bug_tracker.h
deleted file mode 100644
index 06e3204..0000000
--- a/spdy/core/spdy_bug_tracker.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2016 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.
-
-#ifndef QUICHE_SPDY_CORE_SPDY_BUG_TRACKER_H_
-#define QUICHE_SPDY_CORE_SPDY_BUG_TRACKER_H_
-
-// Defined in Blaze when targetting non-production platforms (iOS, Android, etc)
-// The fallback implimentation is the same as in Chromium which simply delegates
-// to LOG(DFATAL) which is part of PG3.
-#if SPDY_GENERIC_BUG
-
-#define SPDY_BUG LOG(DFATAL)
-#define SPDY_BUG_IF(condition) LOG_IF(DFATAL, condition)
-#define FLAGS_spdy_always_log_bugs_for_tests true
-
-#else
-
-#include "gfe/gfe2/base/bug_utils.h"
-
-// For external SPDY, SPDY_BUG should be #defined to LOG(DFATAL) and
-// SPDY_BUG_IF(condition) to LOG_IF(DFATAL, condition) as client-side log rate
-// limiting is less important and chrome doesn't LOG_FIRST_N anyway.
-//
-// This file should change infrequently if ever, so update cost should be
-// minimal. Meanwhile we do want different macros so we can rate limit server
-// side, so the google3 shared code increments GFE varz, and chrome can have its
-// own custom hooks.
-#define SPDY_BUG GFE_BUG
-#define SPDY_BUG_IF GFE_BUG_IF
-#define FLAGS_spdy_always_log_bugs_for_tests FLAGS_gfe_always_log_bug_for_tests
-
-#endif  // __ANDROID__
-
-#endif  // QUICHE_SPDY_CORE_SPDY_BUG_TRACKER_H_
diff --git a/spdy/core/spdy_deframer_visitor.cc b/spdy/core/spdy_deframer_visitor.cc
index 8a30f79..76188e9 100644
--- a/spdy/core/spdy_deframer_visitor.cc
+++ b/spdy/core/spdy_deframer_visitor.cc
@@ -7,13 +7,13 @@
 #include <stdlib.h>
 
 #include <algorithm>
+#include <cstdint>
 #include <limits>
 #include <memory>
 
-#include "base/log_severity.h"
 #include "base/logging.h"
-#include "strings/cord.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h"
@@ -35,7 +35,7 @@
 enum class HeaderDirection { REQUEST, RESPONSE };
 
 // Types of HTTP/2 frames, per RFC 7540.
-// TODO(jamessynge): Switch to using //gfe/http2/http2_constants.h when ready.
+// TODO(jamessynge): Switch to using http2/http2_constants.h when ready.
 enum Http2FrameType {
   DATA = 0,
   HEADERS = 1,
@@ -54,7 +54,7 @@
   UNKNOWN = -2,
 };
 
-// TODO(jamessynge): Switch to using //gfe/http2/http2_constants.h when ready.
+// TODO(jamessynge): Switch to using http2/http2_constants.h when ready.
 const char* Http2FrameTypeToString(Http2FrameType v) {
   switch (v) {
     case DATA:
@@ -88,7 +88,7 @@
   }
 }
 
-// TODO(jamessynge): Switch to using //gfe/http2/http2_constants.h when ready.
+// TODO(jamessynge): Switch to using http2/http2_constants.h when ready.
 inline std::ostream& operator<<(std::ostream& out, Http2FrameType v) {
   return out << Http2FrameTypeToString(v);
 }
@@ -97,7 +97,7 @@
 // (see https://httpwg.github.io/specs/rfc7540.html#FrameHeader for details on
 // the fixed 9-octet header structure shared by all frames).
 // Flag bits are only valid for specified frame types.
-// TODO(jamessynge): Switch to using //gfe/http2/http2_constants.h when ready.
+// TODO(jamessynge): Switch to using http2/http2_constants.h when ready.
 enum Http2HeaderFlag {
   NO_FLAGS = 0,
 
@@ -109,7 +109,7 @@
 };
 
 // Returns name of frame type.
-// TODO(jamessynge): Switch to using //gfe/http2/http2_constants.h when ready.
+// TODO(jamessynge): Switch to using http2/http2_constants.h when ready.
 const char* Http2FrameTypeToString(Http2FrameType v);
 
 void SpdyDeframerVisitorInterface::OnPingAck(
@@ -268,7 +268,7 @@
 void SpdyTestDeframerImpl::AtGoAwayEnd() {
   DVLOG(1) << "AtDataEnd";
   CHECK_EQ(frame_type_, GOAWAY);
-  if (ABSL_DIE_IF_NULL(goaway_description_)->empty()) {
+  if (HTTP2_DIE_IF_NULL(goaway_description_)->empty()) {
     listener_->OnGoAway(std::move(goaway_ir_));
   } else {
     listener_->OnGoAway(SpdyMakeUnique<SpdyGoAwayIR>(
@@ -751,7 +751,7 @@
   CHECK(frame_type_ == HEADERS || frame_type_ == PUSH_PROMISE)
       << "   frame_type_=" << Http2FrameTypeToString(frame_type_);
   CHECK(headers_ != nullptr);
-  CHECK_EQ(headers_->size(), 0u);
+  CHECK_EQ(0u, headers_->size());
   got_hpack_end_ = false;
 }
 
@@ -761,8 +761,8 @@
         frame_type_ == PUSH_PROMISE)
       << "   frame_type_=" << Http2FrameTypeToString(frame_type_);
   CHECK(!got_hpack_end_);
-  ABSL_DIE_IF_NULL(headers_)->emplace_back(SpdyString(key), SpdyString(value));
-  ABSL_DIE_IF_NULL(headers_handler_)->OnHeader(key, value);
+  HTTP2_DIE_IF_NULL(headers_)->emplace_back(SpdyString(key), SpdyString(value));
+  HTTP2_DIE_IF_NULL(headers_handler_)->OnHeader(key, value);
 }
 
 void SpdyTestDeframerImpl::OnHeaderBlockEnd(
@@ -896,11 +896,11 @@
   return *this;
 }
 
-::testing::AssertionResult CollectedFrame::VerifyHasHeaders(
+AssertionResult CollectedFrame::VerifyHasHeaders(
     const StringPairVector& expected_headers) const {
   VERIFY_NE(headers.get(), nullptr);
   VERIFY_THAT(*headers, ::testing::ContainerEq(expected_headers));
-  return ::testing::AssertionSuccess();
+  return AssertionSuccess();
 }
 
 AssertionResult CollectedFrame::VerifyHasSettings(
@@ -912,7 +912,7 @@
 
 DeframerCallbackCollector::DeframerCallbackCollector(
     std::vector<CollectedFrame>* collected_frames)
-    : collected_frames_(ABSL_DIE_IF_NULL(collected_frames)) {}
+    : collected_frames_(HTTP2_DIE_IF_NULL(collected_frames)) {}
 
 void DeframerCallbackCollector::OnAltSvc(
     std::unique_ptr<SpdyAltSvcIR> frame_ir) {
diff --git a/spdy/core/spdy_deframer_visitor.h b/spdy/core/spdy_deframer_visitor.h
index 6d57ffd..50d9987 100644
--- a/spdy/core/spdy_deframer_visitor.h
+++ b/spdy/core/spdy_deframer_visitor.h
@@ -111,7 +111,7 @@
   virtual ~SpdyDeframerVisitorInterface() {}
 
   // Wrap a visitor in another SpdyDeframerVisitorInterface that will
-  // VLOG each call, and will then forward the calls to the wrapped visitor
+  // DVLOG each call, and will then forward the calls to the wrapped visitor
   // (if provided; nullptr is OK). Takes ownership of the wrapped visitor.
   static std::unique_ptr<SpdyDeframerVisitorInterface> LogBeforeVisiting(
       std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_visitor);
@@ -195,8 +195,7 @@
             typename X =
                 typename std::enable_if<std::is_base_of<SpdyFrameIR, T>::value>>
   ::testing::AssertionResult VerifyHasFrame(const T& expected_ir) const {
-    VERIFY_SUCCESS(VerifySpdyFrameIREquals(expected_ir, frame_ir.get()));
-    return ::testing::AssertionSuccess();
+    return VerifySpdyFrameIREquals(expected_ir, frame_ir.get());
   }
 
   // Compare the collected headers against a StringPairVector. Ignores
diff --git a/spdy/core/spdy_deframer_visitor_test.cc b/spdy/core/spdy_deframer_visitor_test.cc
index e1accec..ede1a20 100644
--- a/spdy/core/spdy_deframer_visitor_test.cc
+++ b/spdy/core/spdy_deframer_visitor_test.cc
@@ -8,14 +8,10 @@
 
 #include <algorithm>
 #include <limits>
-#include <memory>
-#include <utility>
 
-#include "base/log_severity.h"
 #include "base/logging.h"
-#include "strings/cord.h"
-#include "testing/base/public/googletest.h"  // for FLAGS_test_random_seed
 #include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
@@ -25,7 +21,6 @@
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
-#include "util/random/mt_random.h"
 
 namespace spdy {
 namespace test {
@@ -33,11 +28,7 @@
 
 class SpdyDeframerVisitorTest : public ::testing::Test {
  protected:
-  SpdyDeframerVisitorTest()
-      : encoder_(SpdyFramer::ENABLE_COMPRESSION),
-        random_(FLAGS_test_random_seed) {
-    DLOG(INFO) << "Random seed (--test_random_seed): "
-               << FLAGS_test_random_seed;
+  SpdyDeframerVisitorTest() : encoder_(SpdyFramer::ENABLE_COMPRESSION) {
     decoder_.set_process_single_input_frame(true);
     auto collector =
         SpdyMakeUnique<DeframerCallbackCollector>(&collected_frames_);
@@ -77,7 +68,7 @@
   std::unique_ptr<SpdyTestDeframer> deframer_;
 
  private:
-  MTRandom random_;
+  http2::test::Http2Random random_;
 };
 
 TEST_F(SpdyDeframerVisitorTest, DataFrame) {
@@ -161,12 +152,12 @@
 
 TEST_F(SpdyDeframerVisitorTest, PriorityFrame) {
   const char kFrameData[] = {
-      0x00, 0x00, 0x05,        // Length: 5
-      0x02,                    //   Type: PRIORITY
-      0x00,                    //  Flags: none
-      0x00, 0x00, 0x00, 0x65,  // Stream: 101
-      0x80, 0x00, 0x00, 0x01,  // Parent: 1 (Exclusive)
-      0x10,                    // Weight: 17
+      0x00,   0x00, 0x05,        // Length: 5
+      0x02,                      //   Type: PRIORITY
+      0x00,                      //  Flags: none
+      0x00,   0x00, 0x00, 0x65,  // Stream: 101
+      '\x80', 0x00, 0x00, 0x01,  // Parent: 1 (Exclusive)
+      0x10,                      // Weight: 17
   };
 
   EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
@@ -194,14 +185,14 @@
   // values. The last one will be in the decoded SpdySettingsIR, but the vector
   // of settings will have both, in the same order.
   const char kFrameData[] = {
-      0x00, 0x00, 0x0c,        // Length
-      0x04,                    // Type (SETTINGS)
-      0x00,                    // Flags
-      0x00, 0x00, 0x00, 0x00,  // Stream id (must be zero)
-      0x00, 0x04,              // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
-      0x0a, 0x0b, 0x0c, 0x0d,  // Setting value
-      0x00, 0x04,              // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
-      0x00, 0x00, 0x00, 0xff,  // Setting value
+      0x00, 0x00, 0x0c,          // Length
+      0x04,                      // Type (SETTINGS)
+      0x00,                      // Flags
+      0x00, 0x00, 0x00, 0x00,    // Stream id (must be zero)
+      0x00, 0x04,                // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+      0x0a, 0x0b, 0x0c, 0x0d,    // Setting value
+      0x00, 0x04,                // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+      0x00, 0x00, 0x00, '\xff',  // Setting value
   };
 
   EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
diff --git a/spdy/core/spdy_frame_builder.cc b/spdy/core/spdy_frame_builder.cc
index 4a3753b..a056b70 100644
--- a/spdy/core/spdy_frame_builder.cc
+++ b/spdy/core/spdy_frame_builder.cc
@@ -10,9 +10,9 @@
 #include <new>
 
 #include "base/logging.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 #include "net/third_party/quiche/src/spdy/core/zero_copy_output_buffer.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
 
 namespace spdy {
 
@@ -90,7 +90,7 @@
   uint8_t raw_frame_type = SerializeFrameType(type);
   DCHECK(IsDefinedFrameType(raw_frame_type));
   DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
-  SPDY_BUG_IF(length > spdy::kHttp2DefaultFramePayloadLimit)
+  SPDY_BUG_IF(length > kHttp2DefaultFramePayloadLimit)
       << "Frame length  " << length_ << " is longer than frame size limit.";
   return BeginNewFrameInternal(raw_frame_type, flags, stream_id, length);
 }
diff --git a/spdy/core/spdy_frame_builder.h b/spdy/core/spdy_frame_builder.h
index e0a853c..c569c8c 100644
--- a/spdy/core/spdy_frame_builder.h
+++ b/spdy/core/spdy_frame_builder.h
@@ -5,17 +5,17 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
 #define QUICHE_SPDY_CORE_SPDY_FRAME_BUILDER_H_
 
+#include <cstddef>
 #include <cstdint>
 #include <memory>
 
-#include "base/logging.h"
-#include "testing/production_stub/public/gunit_prod.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 #include "net/third_party/quiche/src/spdy/core/zero_copy_output_buffer.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_endianness_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_utils_prod.h"
 
 namespace spdy {
 
@@ -88,23 +88,22 @@
     return WriteBytes(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1);
   }
   bool WriteUInt32(uint32_t value) {
-    value = htonl(value);
+    value = SpdyHostToNet32(value);
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteUInt64(uint64_t value) {
-    uint32_t upper = htonl(value >> 32);
-    uint32_t lower = htonl(static_cast<uint32_t>(value));
+    uint32_t upper = SpdyHostToNet32(static_cast<uint32_t>(value >> 32));
+    uint32_t lower = SpdyHostToNet32(static_cast<uint32_t>(value));
     return (WriteBytes(&upper, sizeof(upper)) &&
             WriteBytes(&lower, sizeof(lower)));
   }
   bool WriteStringPiece32(const SpdyStringPiece value);
-
   bool WriteBytes(const void* data, uint32_t data_len);
 
  private:
-  FRIEND_TEST(SpdyFrameBuilderTest, GetWritableBuffer);
-  FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutput);
-  FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutputNegative);
+  SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableBuffer);
+  SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutput);
+  SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutputNegative);
 
   // Populates this frame with a HTTP2 frame prefix with type and length
   // information.
diff --git a/spdy/core/spdy_frame_reader.h b/spdy/core/spdy_frame_reader.h
index 3ef69ea..dc6c064 100644
--- a/spdy/core/spdy_frame_reader.h
+++ b/spdy/core/spdy_frame_reader.h
@@ -7,7 +7,6 @@
 
 #include <cstdint>
 
-#include "base/basictypes.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
 
diff --git a/spdy/core/spdy_frame_reader_test.cc b/spdy/core/spdy_frame_reader_test.cc
index ad8c824..8caf60f 100644
--- a/spdy/core/spdy_frame_reader_test.cc
+++ b/spdy/core/spdy_frame_reader_test.cc
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h"
+
 #include <cstdint>
 
-#include "base/macros.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_arraysize.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_endianness_util.h"
@@ -37,7 +37,7 @@
   // Frame data in network byte order.
   const uint32_t kFrameData[] = {
       SpdyHostToNet32(1),
-      SpdyHostToNet32(static_cast<uint32_t>(1) << 31),
+      SpdyHostToNet32(0x80000000),
   };
 
   SpdyFrameReader frame_reader(reinterpret_cast<const char*>(kFrameData),
diff --git a/spdy/core/spdy_framer.cc b/spdy/core/spdy_framer.cc
index 7d60d84..fc9cc2e 100644
--- a/spdy/core/spdy_framer.cc
+++ b/spdy/core/spdy_framer.cc
@@ -10,21 +10,16 @@
 #include <list>
 #include <new>
 
-#include "base/casts.h"
-#include "base/commandlineflags.h"
 #include "base/logging.h"
-#include "base/macros.h"
-#include "gfe/gfe2/base/flag_utils.h"
-#include "strings/ascii_ctype.h"
-#include "third_party/absl/strings/case.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_bitmasks.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
-#include "util/gtl/lazy_static_ptr.h"
 
 namespace spdy {
 
@@ -134,7 +129,7 @@
   }
 
   if (!ret) {
-    DLOG(INFO) << "Failed to build HEADERS. Not enough space in output";
+    DLOG(WARNING) << "Failed to build HEADERS. Not enough space in output";
   }
   return ret;
 }
@@ -427,7 +422,7 @@
     }
     case SpdyFrameType::DATA: {
       DVLOG(1) << "Serialize a stream end DATA frame for VTL";
-      ABSL_FALLTHROUGH_INTENDED;
+      HTTP2_FALLTHROUGH;
     }
     default: {
       return SpdyMakeUnique<SpdyControlFrameIterator>(framer,
@@ -1293,4 +1288,8 @@
   GetHpackEncoder()->SetHeaderTableDebugVisitor(std::move(visitor));
 }
 
+size_t SpdyFramer::EstimateMemoryUsage() const {
+  return SpdyEstimateMemoryUsage(hpack_encoder_);
+}
+
 }  // namespace spdy
diff --git a/spdy/core/spdy_framer.h b/spdy/core/spdy_framer.h
index 9c59642..e268994 100644
--- a/spdy/core/spdy_framer.h
+++ b/spdy/core/spdy_framer.h
@@ -220,6 +220,9 @@
   // Get (and lazily initialize) the HPACK encoder state.
   HpackEncoder* GetHpackEncoder();
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const;
+
  protected:
   friend class test::SpdyFramerPeer;
   friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
diff --git a/spdy/core/spdy_framer_test.cc b/spdy/core/spdy_framer_test.cc
index 163a769..a08d7d7 100644
--- a/spdy/core/spdy_framer_test.cc
+++ b/spdy/core/spdy_framer_test.cc
@@ -12,14 +12,10 @@
 #include <tuple>
 #include <vector>
 
-#include "base/log_severity.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "strings/cord.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/base/public/mock-log.h"
-#include "testing/base/public/test_utils.h"
 #include "net/third_party/quiche/src/spdy/core/array_output_buffer.h"
 #include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h"
@@ -51,8 +47,6 @@
 char frame_list_char[buffer_size] = "";
 }  // namespace
 
-using ::spdy::operator==;
-
 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface {
  public:
   MOCK_METHOD4(OnSendCompressedFrame,
@@ -120,7 +114,7 @@
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -150,7 +144,7 @@
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -189,7 +183,7 @@
         framer, CloneSpdyPushPromiseIR(push_promise));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -222,7 +216,7 @@
         framer, CloneSpdyPushPromiseIR(push_promise));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -579,8 +573,8 @@
 // Exposes SpdyUnknownIR::set_length() for testing purposes.
 class TestSpdyUnknownIR : public SpdyUnknownIR {
  public:
-  using SpdyUnknownIR::SpdyUnknownIR;
   using SpdyUnknownIR::set_length;
+  using SpdyUnknownIR::SpdyUnknownIR;
 };
 
 enum Output { USE, NOT_USE };
@@ -1130,8 +1124,24 @@
       reinterpret_cast<unsigned char*>(control_frame.data()),
       control_frame.size());
 
-  EXPECT_THAT(visitor.headers_,
-              testing::ElementsAre(testing::Pair("name", value)));
+  EXPECT_THAT(visitor.headers_, testing::ElementsAre(testing::Pair(
+                                    "name", SpdyStringPiece(value))));
+}
+
+TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
+  // See https://crbug.com/172383/
+  SpdyHeadersIR headers(1);
+  headers.SetHeader("server", "SpdyServer 1.0");
+  headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST");
+  headers.SetHeader("status", "200");
+  headers.SetHeader("version", "HTTP/1.1");
+  headers.SetHeader("content-type", "text/html");
+  headers.SetHeader("content-length", "12");
+  headers.SetHeader("x-empty-header", "");
+
+  SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
+  SpdySerializedFrame frame1(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 }
 
 TEST_P(SpdyFramerTest, Basic) {
@@ -1539,11 +1549,15 @@
     SpdySerializedFrame frame(framer_.SerializeData(data_ir));
     CompareFrame(kDescription, frame, kH2FrameData,
                  SPDY_ARRAYSIZE(kH2FrameData));
+
+    frame = framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_ir);
+    CompareCharArraysWithHexError(
+        kDescription, reinterpret_cast<const unsigned char*>(frame.data()),
+        kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize);
   }
 
   {
     const char kDescription[] = "Data frame with max stream ID";
-    // clang-format on
     const unsigned char kH2FrameData[] = {
         0x00, 0x00, 0x05,        // Length: 5
         0x00,                    //   Type: DATA
@@ -1582,7 +1596,6 @@
 
   {
     const char kDescription[] = "RST_STREAM frame with max stream ID";
-    // clang-format off
     const unsigned char kH2FrameData[] = {
         0x00, 0x00, 0x04,        // Length: 4
         0x03,                    //   Type: RST_STREAM
@@ -1764,8 +1777,8 @@
         0x00, 0x00, 0x00, 0x00,  //  Error: NO_ERROR
         0x47, 0x41,              // Description
     };
-    SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 0,
-                           ERROR_CODE_NO_ERROR, "GA");
+    SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 0, ERROR_CODE_NO_ERROR,
+                           "GA");
     SpdySerializedFrame frame(framer_.SerializeGoAway(goaway_ir));
     if (use_output_) {
       ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_));
@@ -2068,8 +2081,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeWindowUpdate(
-          SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 1),
-          &output_));
+          SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 1), &output_));
       frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
     }
     CompareFrame(kDescription, frame, kH2FrameData,
@@ -2094,8 +2106,8 @@
           &output_));
       frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
     }
-    CompareFrame(
-        kDescription, frame, kH2FrameData, SPDY_ARRAYSIZE(kH2FrameData));
+    CompareFrame(kDescription, frame, kH2FrameData,
+                 SPDY_ARRAYSIZE(kH2FrameData));
   }
 
   {
@@ -2116,8 +2128,8 @@
           &output_));
       frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
     }
-    CompareFrame(
-        kDescription, frame, kH2FrameData, SPDY_ARRAYSIZE(kH2FrameData));
+    CompareFrame(kDescription, frame, kH2FrameData,
+                 SPDY_ARRAYSIZE(kH2FrameData));
   }
 }
 
@@ -3699,8 +3711,8 @@
   EXPECT_EQ(11u, kGetAltSvcFrameMinimumSize);
   EXPECT_EQ(9u, kFrameMinimumSize);
 
-  EXPECT_EQ(16384u, spdy::kHttp2DefaultFramePayloadLimit);
-  EXPECT_EQ(16393u, spdy::kHttp2DefaultFrameSizeLimit);
+  EXPECT_EQ(16384u, kHttp2DefaultFramePayloadLimit);
+  EXPECT_EQ(16393u, kHttp2DefaultFrameSizeLimit);
 }
 
 TEST_P(SpdyFramerTest, StateToStringTest) {
@@ -4145,7 +4157,7 @@
     headers_ir.SetHeader("foo", "bar");
     SpdySerializedFrame frame0;
     if (use_output_) {
-      EXPECT_GT(framer.SerializeHeaders(headers_ir, &output_), 0);
+      EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_));
       frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
     } else {
       frame0 = framer.SerializeHeaders(headers_ir);
@@ -4156,7 +4168,7 @@
     SpdySerializedFrame frame1;
     if (use_output_) {
       char* begin = output_.Begin() + output_.Size();
-      EXPECT_GT(framer.SerializeContinuation(continuation, &output_), 0);
+      ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
       frame1 =
           SpdySerializedFrame(begin, output_.Size() - frame0.size(), false);
     } else {
@@ -4283,7 +4295,8 @@
   SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
   altsvc_vector.push_back(altsvc1);
   altsvc_vector.push_back(altsvc2);
-  EXPECT_CALL(visitor, OnAltSvc(kStreamId, "o_r|g!n", altsvc_vector));
+  EXPECT_CALL(visitor,
+              OnAltSvc(kStreamId, SpdyStringPiece("o_r|g!n"), altsvc_vector));
 
   SpdyAltSvcIR altsvc_ir(kStreamId);
   altsvc_ir.set_origin("o_r|g!n");
@@ -4317,7 +4330,7 @@
   SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
   altsvc_vector.push_back(altsvc1);
   altsvc_vector.push_back(altsvc2);
-  EXPECT_CALL(visitor, OnAltSvc(kStreamId, "", altsvc_vector));
+  EXPECT_CALL(visitor, OnAltSvc(kStreamId, SpdyStringPiece(""), altsvc_vector));
 
   SpdyAltSvcIR altsvc_ir(kStreamId);
   altsvc_ir.add_altsvc(altsvc1);
@@ -4374,6 +4387,7 @@
   deframer_.set_visitor(&visitor);
   visitor.SimulateInFramer(kFrameDataOriginLenLargerThanFrame,
                            sizeof(kFrameDataOriginLenLargerThanFrame));
+
   EXPECT_EQ(1, visitor.error_count_);
   EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME,
             visitor.deframer_.spdy_framer_error());
diff --git a/spdy/core/spdy_header_block.cc b/spdy/core/spdy_header_block.cc
index a6f49b9..dcf84b9 100644
--- a/spdy/core/spdy_header_block.cc
+++ b/spdy/core/spdy_header_block.cc
@@ -9,12 +9,12 @@
 #include <algorithm>
 #include <utility>
 
-#include "base/arena.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_unsafe_arena.h"
 
 namespace spdy {
 namespace {
@@ -90,8 +90,13 @@
 
   size_t bytes_allocated() const { return arena_.status().bytes_allocated(); }
 
+  // TODO(xunjieli): https://crbug.com/669108. Merge this with bytes_allocated()
+  size_t EstimateMemoryUsage() const {
+    return arena_.status().bytes_allocated();
+  }
+
  private:
-  UnsafeArena arena_;
+  SpdyUnsafeArena arena_;
 };
 
 SpdyHeaderBlock::HeaderValue::HeaderValue(Storage* storage,
diff --git a/spdy/core/spdy_header_block.h b/spdy/core/spdy_header_block.h
index a63c52e..f453246 100644
--- a/spdy/core/spdy_header_block.h
+++ b/spdy/core/spdy_header_block.h
@@ -10,13 +10,14 @@
 #include <list>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/macros.h"
-#include "base/port.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_containers.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_macros.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-#include "util/gtl/linked_hash_map.h"
 
 namespace spdy {
 
@@ -81,7 +82,8 @@
     size_t separator_size_ = 0;
   };
 
-  typedef gtl::linked_hash_map<SpdyStringPiece, HeaderValue> MapType;
+  typedef SpdyLinkedHashMap<SpdyStringPiece, HeaderValue, SpdyStringPieceHash>
+      MapType;
 
  public:
   typedef std::pair<SpdyStringPiece, SpdyStringPiece> value_type;
@@ -179,10 +181,10 @@
                               const SpdyStringPiece value);
 
   // Allows either lookup or mutation of the value associated with a key.
-  ValueProxy operator[](const SpdyStringPiece key) ABSL_MUST_USE_RESULT;
+  ValueProxy operator[](const SpdyStringPiece key) SPDY_MUST_USE_RESULT;
 
   // This object provides automatic conversions that allow SpdyHeaderBlock to be
-  // nearly a drop-in replacement for linked_hash_map<SpdyString, SpdyString>.
+  // nearly a drop-in replacement for SpdyLinkedHashMap<SpdyString, SpdyString>.
   // It reads data from or writes data to a SpdyHeaderBlock::Storage.
   class SPDY_EXPORT_PRIVATE ValueProxy {
    public:
diff --git a/spdy/core/spdy_protocol.cc b/spdy/core/spdy_protocol.cc
index b9af3fe..f51dc6e 100644
--- a/spdy/core/spdy_protocol.cc
+++ b/spdy/core/spdy_protocol.cc
@@ -6,7 +6,7 @@
 
 #include <ostream>
 
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h"
 
diff --git a/spdy/core/spdy_protocol.h b/spdy/core/spdy_protocol.h
index c384f2e..d300d10 100644
--- a/spdy/core/spdy_protocol.h
+++ b/spdy/core/spdy_protocol.h
@@ -9,24 +9,25 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
 #define QUICHE_SPDY_CORE_SPDY_PROTOCOL_H_
 
+#include <cstddef>
 #include <cstdint>
 #include <iosfwd>
 #include <limits>
 #include <map>
 #include <memory>
+#include <new>
 #include <utility>
 
 #include "base/logging.h"
 #include "base/macros.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_bitmasks.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-#include "util/gtl/linked_hash_map.h"
 
 namespace spdy {
 
@@ -230,7 +231,7 @@
 
 // Reserved ID for root stream of HTTP/2 stream dependency tree, as specified
 // in RFC 7540 section 5.3.1.
-const int kHttp2RootStreamId = 0;
+const unsigned int kHttp2RootStreamId = 0;
 
 typedef uint64_t SpdyPingId;
 
@@ -668,7 +669,6 @@
 
   SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; }
   void set_last_good_stream_id(SpdyStreamId last_good_stream_id) {
-    DCHECK_LE(0u, last_good_stream_id);
     DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask);
     last_good_stream_id_ = last_good_stream_id;
   }
@@ -986,6 +986,9 @@
     return buffer;
   }
 
+  // Returns the estimate of dynamically allocated memory in bytes.
+  size_t EstimateMemoryUsage() const { return owns_buffer_ ? size_ : 0; }
+
  protected:
   char* frame_;
 
diff --git a/spdy/core/spdy_protocol_test.cc b/spdy/core/spdy_protocol_test.cc
index b1f999e..09a56cb 100644
--- a/spdy/core/spdy_protocol_test.cc
+++ b/spdy/core/spdy_protocol_test.cc
@@ -9,7 +9,6 @@
 #include <memory>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/base/public/test_utils.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_bitmasks.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
 
diff --git a/spdy/core/spdy_test_utils.cc b/spdy/core/spdy_test_utils.cc
index 7318e62..dd6c417 100644
--- a/spdy/core/spdy_test_utils.cc
+++ b/spdy/core/spdy_test_utils.cc
@@ -7,10 +7,11 @@
 #include <algorithm>
 #include <cstring>
 #include <memory>
+#include <new>
 #include <utility>
+#include <vector>
 
 #include "base/logging.h"
-#include "strings/strcat.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_endianness_util.h"
 
@@ -32,7 +33,7 @@
   }
 
   SpdyString hex;
-  for (const unsigned char *row = data; length > 0;
+  for (const unsigned char* row = data; length > 0;
        row += kColumns, length -= kColumns) {
     for (const unsigned char* p = row; p < row + 4; ++p) {
       if (p < row + length) {
diff --git a/spdy/core/spdy_test_utils.h b/spdy/core/spdy_test_utils.h
index a7375aa..bf62eeb 100644
--- a/spdy/core/spdy_test_utils.h
+++ b/spdy/core/spdy_test_utils.h
@@ -5,21 +5,17 @@
 #ifndef QUICHE_SPDY_CORE_SPDY_TEST_UTILS_H_
 #define QUICHE_SPDY_CORE_SPDY_TEST_UTILS_H_
 
+#include <cstddef>
 #include <cstdint>
 
-#include "gfe/gfe2/test_tools/failure.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_bug_tracker.h"
+#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h"
 #include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
-
-// EXPECT_SPDY_BUG is like EXPECT_DFATAL, except it ensures that no DFATAL
-// logging is skipped due to exponential backoff.
-//
-// For external SPDY, EXPECT_SPDY_BUG should be #defined to EXPECT_DFATAL.
-#define EXPECT_SPDY_BUG EXPECT_GFE_BUG
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h"
 
 namespace spdy {
 
diff --git a/spdy/platform/api/spdy_bug_tracker.h b/spdy/platform/api/spdy_bug_tracker.h
new file mode 100644
index 0000000..d750a21
--- /dev/null
+++ b/spdy/platform/api/spdy_bug_tracker.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_
+#define QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_
+
+#include "net/spdy/platform/impl/spdy_bug_tracker_impl.h"
+
+#define SPDY_BUG SPDY_BUG_IMPL
+#define SPDY_BUG_IF(condition) SPDY_BUG_IF_IMPL(condition)
+#define FLAGS_spdy_always_log_bugs_for_tests \
+  FLAGS_spdy_always_log_bugs_for_tests_impl
+
+#endif  // QUICHE_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_
diff --git a/spdy/platform/api/spdy_containers.h b/spdy/platform/api/spdy_containers.h
index 71a20de..e4f4c49 100644
--- a/spdy/platform/api/spdy_containers.h
+++ b/spdy/platform/api/spdy_containers.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_
 #define QUICHE_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_
 
+#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h"
 #include "net/spdy/platform/impl/spdy_containers_impl.h"
 
 namespace spdy {
@@ -22,6 +23,20 @@
 template <typename ElementType, typename Hasher, typename Eq>
 using SpdyHashSet = SpdyHashSetImpl<ElementType, Hasher, Eq>;
 
+// A map which offers insertion-ordered iteration.
+template <typename Key, typename Value, typename Hash = SpdyHash<Key>>
+using SpdyLinkedHashMap = SpdyLinkedHashMapImpl<Key, Value, Hash>;
+
+// A vector optimized for small sizes. Provides the same APIs as a std::vector.
+template <typename T, size_t N, typename A = std::allocator<T>>
+using SpdyInlinedVector = SpdyInlinedVectorImpl<T, N, A>;
+
+using SpdyStringPieceHash = SpdyStringPieceHashImpl;
+
+inline size_t SpdyHashStringPair(SpdyStringPiece a, SpdyStringPiece b) {
+  return SpdyHashStringPairImpl(a, b);
+}
+
 }  // namespace spdy
 
 #endif  // QUICHE_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_
diff --git a/spdy/platform/api/spdy_endianness_util.h b/spdy/platform/api/spdy_endianness_util.h
index 313a075..e4074d7 100644
--- a/spdy/platform/api/spdy_endianness_util.h
+++ b/spdy/platform/api/spdy_endianness_util.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 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.
+
 #ifndef QUICHE_SPDY_PLATFORM_API_SPDY_ENDIANNESS_UTIL_H_
 #define QUICHE_SPDY_PLATFORM_API_SPDY_ENDIANNESS_UTIL_H_
 
diff --git a/spdy/platform/api/spdy_macros.h b/spdy/platform/api/spdy_macros.h
new file mode 100644
index 0000000..a75c957
--- /dev/null
+++ b/spdy/platform/api/spdy_macros.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_MACROS_H_
+#define QUICHE_SPDY_PLATFORM_API_SPDY_MACROS_H_
+
+#include "net/spdy/platform/impl/spdy_macros_impl.h"
+
+#define SPDY_MUST_USE_RESULT SPDY_MUST_USE_RESULT_IMPL
+#define SPDY_UNUSED SPDY_UNUSED_IMPL
+
+#define SPDY_DVLOG_IF SPDY_DVLOG_IF_IMPL
+
+#endif  // QUICHE_SPDY_PLATFORM_API_SPDY_MACROS_H_
diff --git a/spdy/platform/api/spdy_test_helpers.h b/spdy/platform/api/spdy_test_helpers.h
new file mode 100644
index 0000000..367d330
--- /dev/null
+++ b/spdy/platform/api/spdy_test_helpers.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_
+#define QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_
+
+#include "net/spdy/platform/impl/spdy_test_helpers_impl.h"
+
+#define EXPECT_SPDY_BUG EXPECT_SPDY_BUG_IMPL
+
+#endif  // QUICHE_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_
diff --git a/spdy/platform/api/spdy_test_utils_prod.h b/spdy/platform/api/spdy_test_utils_prod.h
new file mode 100644
index 0000000..1466770
--- /dev/null
+++ b/spdy/platform/api/spdy_test_utils_prod.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_
+#define QUICHE_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_
+
+#include "net/spdy/platform/impl/spdy_test_utils_prod_impl.h"
+
+#define SPDY_FRIEND_TEST SPDY_FRIEND_TEST_IMPL
+
+#endif  // QUICHE_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_
diff --git a/spdy/platform/api/spdy_unsafe_arena.h b/spdy/platform/api/spdy_unsafe_arena.h
new file mode 100644
index 0000000..77185e1
--- /dev/null
+++ b/spdy/platform/api/spdy_unsafe_arena.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_
+#define QUICHE_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_
+
+#include "net/spdy/platform/impl/spdy_unsafe_arena_impl.h"
+
+namespace spdy {
+
+using SpdyUnsafeArena = SpdyUnsafeArenaImpl;
+
+}  // namespace spdy
+
+#endif  // QUICHE_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_