Introduce QUIC v49

This new version adds support for:
- client connection IDs
- latest QUIC invariants (length-prefixed connection IDs)
- long header lengths

gfe-relnote: add QUIC v49, protected by quic_enable_v49
PiperOrigin-RevId: 270337654
Change-Id: I563251f8ad170e38b356a9964cd92d89b9df47c8
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index f2114c2..2c757a4 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -934,11 +934,12 @@
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
   SetQuicReloadableFlag(quic_use_parse_public_header, true);
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
+  SetQuicReloadableFlag(quic_enable_version_49, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
 
   VerifyVersionNotSupported(QuicVersionReservedForNegotiation());
@@ -947,6 +948,16 @@
                                            QuicVersionMin().transport_version));
   VerifyVersionSupported(QuicVersionMax());
 
+  // Turn off version 49.
+  SetQuicReloadableFlag(quic_enable_version_49, false);
+  VerifyVersionNotSupported(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
+
+  // Turn on version 49.
+  SetQuicReloadableFlag(quic_enable_version_49, true);
+  VerifyVersionSupported(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
+
   // Turn off version 48.
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   VerifyVersionNotSupported(
@@ -979,7 +990,7 @@
 }
 
 TEST_F(QuicDispatcherTest, RejectDeprecatedVersionsWithVersionNegotiation) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Please add deprecated versions to this test");
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   CreateTimeWaitListManager();
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index deb66d3..fd8d287 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -1210,7 +1210,7 @@
       // padding frame
       0x00,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // public flags (long header with packet type HANDSHAKE and
     // 4-byte packet number)
     0xE3,
@@ -1232,9 +1232,9 @@
   // clang-format on
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_length = QUIC_ARRAYSIZE(packet46);
@@ -1440,7 +1440,7 @@
        {0x12, 0x34, 0x56, 0x78}},
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet49 = {
       // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes
       // packet number)
       {"Unable to read first byte.",
@@ -1467,8 +1467,8 @@
   // clang-format on
 
   PacketFragments& fragments =
-      framer_.transport_version() == QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() >= QUIC_VERSION_49
+          ? packet49
           : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
                                                             : packet);
   std::unique_ptr<QuicEncryptedPacket> encrypted(
@@ -1797,7 +1797,7 @@
     0x00, 0x00, 0x00, 0x00
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet
     // number.
     0xD0,
@@ -1831,9 +1831,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_49) {
+    p = packet49;
+    p_size = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_size = QUIC_ARRAYSIZE(packet46);
@@ -1884,7 +1884,7 @@
     0x00, 0x00, 0x00, 0x00
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
     0xD3,
     // version tag
@@ -1906,9 +1906,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_49) {
+    p = packet49;
+    p_size = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_size = QUIC_ARRAYSIZE(packet46);
@@ -2257,7 +2257,7 @@
         0x00,
     };
 
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
         // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number)
         0xD3,
         // version tag
@@ -2279,9 +2279,9 @@
 
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_length = QUIC_ARRAYSIZE(packet46);
@@ -2678,6 +2678,49 @@
          'r',  'l',  'd',  '!'}},
   };
 
+  PacketFragments packet49 = {
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      {"",
+       {0xD3}},
+      // version tag
+      {"",
+       {QUIC_VERSION_BYTES}},
+      // destination connection ID length
+      {"",
+       {0x08}},
+      // destination connection ID
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // source connection ID length
+      {"",
+       {0x00}},
+      // long header packet length
+      {"",
+       {0x1E}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (stream frame with fin)
+      {"",
+       {0xFE}},
+      // stream id
+      {"Long header payload length longer than packet.",
+       {0x02, 0x03, 0x04}},
+      // offset
+      {"Long header payload length longer than packet.",
+       {0x3A, 0x98, 0xFE, 0xDC,
+        0x32, 0x10, 0x76, 0x54}},
+      {"Long header payload length longer than packet.",
+       {
+         // 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)
@@ -2733,8 +2776,10 @@
   PacketFragments& fragments =
       VersionHasIetfQuicFrames(framer_.transport_version())
           ? packet99
-          : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
-                                                            : packet);
+          : (framer_.transport_version() >= QUIC_VERSION_49
+                 ? packet49
+                 : (framer_.transport_version() >= QUIC_VERSION_46 ? packet46
+                                                                   : packet));
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
@@ -2755,7 +2800,7 @@
   CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get());
 
   CheckFramingBoundaries(fragments,
-                         framer_.transport_version() == QUIC_VERSION_99
+                         framer_.transport_version() >= QUIC_VERSION_49
                              ? QUIC_INVALID_PACKET_HEADER
                              : QUIC_INVALID_STREAM_DATA);
 }
@@ -5330,7 +5375,7 @@
         'Q', '2', '.', '0'}},
   };
 
-  PacketFragments packet99 = {
+  PacketFragments packet49 = {
       // type (long header)
       {"",
        {0x8F}},
@@ -5354,8 +5399,8 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
 
   PacketFragments& fragments =
-      framer_.transport_version() >= QUIC_VERSION_99
-          ? packet99
+      framer_.transport_version() >= QUIC_VERSION_49
+          ? packet49
           : framer_.transport_version() > QUIC_VERSION_43 ? packet46 : packet;
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       AssemblePacketFromFragments(fragments));
@@ -5486,7 +5531,7 @@
       'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's',
       ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!',
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
       // public flags (long header with packet type RETRY)
       0xF0,
       // version
@@ -5509,9 +5554,9 @@
 
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   }
   QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
   EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -6131,6 +6176,32 @@
       'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!',
   };
 
+  unsigned char packet49[] = {
+      // type (long header with packet type ZERO_RTT_PROTECTED)
+      0xD3,
+      // version tag
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // length
+      0x40, 0x1D,
+      // 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,
@@ -6167,6 +6238,9 @@
   if (VersionHasIetfQuicFrames(framer_.transport_version())) {
     p = packet99;
     p_size = QUIC_ARRAYSIZE(packet99);
+  } else if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_size = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_size = QUIC_ARRAYSIZE(packet46);
@@ -6364,7 +6438,7 @@
       0xDA, 0x5A, 0x3A, 0x3A,
       QUIC_VERSION_BYTES,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
       // type (long header)
       0xC0,
       // version tag
@@ -6382,9 +6456,9 @@
   // 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);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_size = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() > QUIC_VERSION_43) {
     p = packet46;
     p_size = QUIC_ARRAYSIZE(packet46);
@@ -12134,6 +12208,64 @@
       0x1E,
       // packet number
       0x12, 0x34, 0x56, 0x78,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '!',
+    // second coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x79,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '?',
+  };
+  unsigned char packet99[] = {
+    // first coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
       // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
       0x08 | 0x01 | 0x02 | 0x04,
       // stream id
@@ -12179,7 +12311,14 @@
   };
   // clang-format on
 
-  QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+  unsigned char* p = packet;
+  size_t p_length = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_length = QUIC_ARRAYSIZE(packet99);
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
   EXPECT_TRUE(framer_.ProcessPacket(encrypted));
 
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -12261,7 +12400,7 @@
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // public flags (long header with packet type HANDSHAKE and
     // 4-byte packet number)
     0xE3,
@@ -12286,9 +12425,9 @@
   // clang-format on
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_length = QUIC_ARRAYSIZE(packet46);
@@ -12369,7 +12508,7 @@
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // public flags (long header with packet type HANDSHAKE and
     // 4-byte packet number)
     0xE3,
@@ -12394,9 +12533,9 @@
   // clang-format on
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_length = QUIC_ARRAYSIZE(packet46);
@@ -12458,6 +12597,64 @@
       0x1E,
       // packet number
       0x12, 0x34, 0x56, 0x78,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '!',
+    // second coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x79,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '?',
+  };
+  unsigned char packet99[] = {
+    // first coalesced packet
+      // public flags (long header with packet type HANDSHAKE and
+      // 4-byte packet number)
+      0xE3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
       // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
       0x08 | 0x01 | 0x02 | 0x04,
       // stream id
@@ -12504,7 +12701,15 @@
   // clang-format on
   const size_t length_of_first_coalesced_packet = 46;
 
-  QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+  unsigned char* p = packet;
+  size_t p_length = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_length = QUIC_ARRAYSIZE(packet99);
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
+
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
 
   EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
@@ -12515,10 +12720,10 @@
     ASSERT_EQ(1u, visitor_.undecryptable_has_decryption_keys_.size());
     // Make sure we only receive the first undecryptable packet and not the
     // full packet including the second coalesced packet.
-    CompareCharArraysWithHexError(
-        "undecryptable packet", visitor_.undecryptable_packets_[0]->data(),
-        visitor_.undecryptable_packets_[0]->length(), AsChars(packet),
-        length_of_first_coalesced_packet);
+    CompareCharArraysWithHexError("undecryptable packet",
+                                  visitor_.undecryptable_packets_[0]->data(),
+                                  visitor_.undecryptable_packets_[0]->length(),
+                                  AsChars(p), length_of_first_coalesced_packet);
     EXPECT_EQ(ENCRYPTION_HANDSHAKE,
               visitor_.undecryptable_decryption_levels_[0]);
     EXPECT_TRUE(visitor_.undecryptable_has_decryption_keys_[0]);
@@ -12567,6 +12772,64 @@
       0x1E,
       // packet number
       0x12, 0x34, 0x56, 0x78,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '!',
+    // second coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x79,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '?',
+  };
+  unsigned char packet99[] = {
+    // first coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
       // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
       0x08 | 0x01 | 0x02 | 0x04,
       // stream id
@@ -12612,7 +12875,15 @@
   };
   // clang-format on
 
-  QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+  unsigned char* p = packet;
+  size_t p_length = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_length = QUIC_ARRAYSIZE(packet99);
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
+
   EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
                        "Server: Received mismatched coalesced header.*");
 
@@ -12654,6 +12925,41 @@
       0x1E,
       // packet number
       0x12, 0x34, 0x56, 0x78,
+      // frame type (stream frame with fin)
+      0xFE,
+      // stream id
+      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',  '!',
+    // second coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version would be here but we cut off the invalid coalesced header.
+  };
+  unsigned char packet99[] = {
+    // first coalesced packet
+      // public flags (long header with packet type ZERO_RTT_PROTECTED and
+      // 4-byte packet number)
+      0xD3,
+      // version
+      QUIC_VERSION_BYTES,
+      // destination connection ID length
+      0x08,
+      // destination connection ID
+      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+      // source connection ID length
+      0x00,
+      // long header packet length
+      0x1E,
+      // packet number
+      0x12, 0x34, 0x56, 0x78,
       // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set)
       0x08 | 0x01 | 0x02 | 0x04,
       // stream id
@@ -12675,7 +12981,15 @@
   };
   // clang-format on
 
-  QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false);
+  unsigned char* p = packet;
+  size_t p_length = QUIC_ARRAYSIZE(packet);
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    p = packet99;
+    p_length = QUIC_ARRAYSIZE(packet99);
+  }
+
+  QuicEncryptedPacket encrypted(AsChars(p), p_length, false);
+
   EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)),
                        "Server: Failed to parse received coalesced header.*");
 
@@ -13240,8 +13554,9 @@
                                       sizeof(expected_packet));
   QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
                                 sizeof(packet), false);
-  if (framer_.transport_version() < QUIC_VERSION_99) {
-    // We can only parse the connection ID with a v99 parser.
+  if (!framer_.version().HasLengthPrefixedConnectionIds()) {
+    // We can only parse the connection ID with a parser expecting
+    // length-prefixed connection IDs.
     EXPECT_FALSE(framer_.ProcessPacket(encrypted));
     return;
   }
@@ -13529,7 +13844,7 @@
     // padding frame
     0x00,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // public flags (long header with packet type HANDSHAKE and
     // 4-byte packet number)
     0xE3,
@@ -13551,9 +13866,9 @@
   // clang-format on
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   }
   const bool parse_success =
       framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false));
@@ -13597,7 +13912,7 @@
     // padding frame
     0x00,
   };
-  unsigned char packet99[] = {
+  unsigned char packet49[] = {
     // public flags (long header with packet type HANDSHAKE and
     // 4-byte packet number)
     0xE3,
@@ -13617,9 +13932,9 @@
   // clang-format on
   unsigned char* p = packet;
   size_t p_length = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_length = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_49) {
+    p = packet49;
+    p_length = QUIC_ARRAYSIZE(packet49);
   }
   const bool parse_success =
       framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false));
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 6fd36b2..849dfc5 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -5,6 +5,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
 
 #include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.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"
 
@@ -15,11 +16,14 @@
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
     : enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)),
+      enable_version_49_(GetQuicReloadableFlag(quic_enable_version_49)),
       enable_version_48_(GetQuicReloadableFlag(quic_enable_version_48_2)),
       enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)),
       disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)),
       enable_tls_(GetQuicReloadableFlag(quic_supports_tls_handshake)),
       allowed_supported_versions_(std::move(supported_versions)) {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   RefilterSupportedVersions();
 }
 
@@ -37,12 +41,16 @@
 }
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) ||
+      enable_version_49_ != GetQuicReloadableFlag(quic_enable_version_49) ||
       enable_version_48_ != GetQuicReloadableFlag(quic_enable_version_48_2) ||
       enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) ||
       disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39) ||
       enable_tls_ != GetQuicReloadableFlag(quic_supports_tls_handshake)) {
     enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99);
+    enable_version_49_ = GetQuicReloadableFlag(quic_enable_version_49);
     enable_version_48_ = GetQuicReloadableFlag(quic_enable_version_48_2);
     enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47);
     disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39);
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index a0c2d6f..ffa2bb2 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -40,6 +40,8 @@
  private:
   // quic_enable_version_99 flag
   bool enable_version_99_;
+  // quic_enable_version_49 flag
+  bool enable_version_49_;
   // quic_enable_version_48_2 flag
   bool enable_version_48_;
   // quic_enable_version_47 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index 7afd55d..c8e4807 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) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_disable_version_39, true);
@@ -46,13 +47,20 @@
                                         QUIC_VERSION_39}),
             manager.GetSupportedTransportVersions());
 
-  SetQuicReloadableFlag(quic_enable_version_99, true);
+  SetQuicReloadableFlag(quic_enable_version_49, true);
   SetQuicReloadableFlag(quic_use_parse_public_header, true);
-  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_48,
+  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_49, QUIC_VERSION_48,
                                         QUIC_VERSION_47, QUIC_VERSION_46,
                                         QUIC_VERSION_43, QUIC_VERSION_39}),
             manager.GetSupportedTransportVersions());
 
+  SetQuicReloadableFlag(quic_enable_version_99, true);
+  EXPECT_EQ(
+      QuicTransportVersionVector(
+          {QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
+           QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
+      manager.GetSupportedTransportVersions());
+
   // Ensure that all versions are now supported.
   EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
             manager.GetSupportedTransportVersions());
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index c69452a..64cfcca 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -76,7 +76,7 @@
 }
 
 bool ParsedQuicVersion::SupportsClientConnectionIds() const {
-  return transport_version >= QUIC_VERSION_99;
+  return transport_version > QUIC_VERSION_48;
 }
 
 bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const {
@@ -90,7 +90,7 @@
 
 bool VersionHasLengthPrefixedConnectionIds(
     QuicTransportVersion transport_version) {
-  return transport_version >= QUIC_VERSION_99;
+  return transport_version > QUIC_VERSION_48;
 }
 
 std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) {
@@ -112,6 +112,8 @@
                << parsed_version.handshake_protocol;
       return 0;
   }
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   switch (parsed_version.transport_version) {
     case QUIC_VERSION_39:
       return MakeVersionLabel(proto, '0', '3', '9');
@@ -123,6 +125,8 @@
       return MakeVersionLabel(proto, '0', '4', '7');
     case QUIC_VERSION_48:
       return MakeVersionLabel(proto, '0', '4', '8');
+    case QUIC_VERSION_49:
+      return MakeVersionLabel(proto, '0', '4', '9');
     case QUIC_VERSION_99:
       if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
         return MakeVersionLabel(0xff, 0x00, 0x00, kQuicIetfDraftVersion);
@@ -264,6 +268,11 @@
           GetQuicReloadableFlag(quic_use_parse_public_header)) {
         filtered_versions.push_back(version);
       }
+    } else if (version.transport_version == QUIC_VERSION_49) {
+      if (GetQuicReloadableFlag(quic_enable_version_49) &&
+          GetQuicReloadableFlag(quic_use_parse_public_header)) {
+        filtered_versions.push_back(version);
+      }
     } else if (version.transport_version == QUIC_VERSION_48) {
       if (GetQuicReloadableFlag(quic_enable_version_48_2)) {
         filtered_versions.push_back(version);
@@ -363,12 +372,15 @@
     return #x
 
 std::string QuicVersionToString(QuicTransportVersion transport_version) {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   switch (transport_version) {
     RETURN_STRING_LITERAL(QUIC_VERSION_39);
     RETURN_STRING_LITERAL(QUIC_VERSION_43);
     RETURN_STRING_LITERAL(QUIC_VERSION_46);
     RETURN_STRING_LITERAL(QUIC_VERSION_47);
     RETURN_STRING_LITERAL(QUIC_VERSION_48);
+    RETURN_STRING_LITERAL(QUIC_VERSION_49);
     RETURN_STRING_LITERAL(QUIC_VERSION_99);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
@@ -418,7 +430,7 @@
   // version negotiation packets for those versions. This function keeps track
   // of the versions that ever supported the 4bit connection ID length encoding
   // that we know about. Google QUIC 43 and earlier used a different encoding,
-  // and Google QUIC 49 will start using the new length prefixed encoding.
+  // and Google QUIC 49 and later use the new length prefixed encoding.
   // Similarly, only IETF drafts 11 to 21 used this encoding.
 
   // Check Q044, Q045, Q046, Q047 and Q048.
@@ -469,11 +481,14 @@
   if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
     SetQuicReloadableFlag(quic_supports_tls_handshake, true);
   }
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   if (parsed_version.transport_version == QUIC_VERSION_99) {
     SetQuicReloadableFlag(quic_enable_version_99, true);
   }
+  if (parsed_version.transport_version == QUIC_VERSION_49) {
+    SetQuicReloadableFlag(quic_enable_version_49, true);
+  }
   if (parsed_version.transport_version == QUIC_VERSION_48) {
     SetQuicReloadableFlag(quic_enable_version_48_2, true);
   }
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index 8a992ec..2137677 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -105,6 +105,8 @@
                          // bit.
   QUIC_VERSION_47 = 47,  // Allow variable-length QUIC connection IDs.
   QUIC_VERSION_48 = 48,  // Use CRYPTO frames for the handshake.
+  QUIC_VERSION_49 = 49,  // Client connection IDs, long header lengths, IETF
+                         // header format from draft-ietf-quic-invariants-06.
   QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not
                          // yet ready for production.
   // QUIC_VERSION_RESERVED_FOR_NEGOTIATION is sent over the wire as ?a?a?a?a
@@ -212,7 +214,7 @@
 //
 // See go/new-quic-version for more details on how to roll out new versions.
 static const QuicTransportVersion kSupportedTransportVersions[] = {
-    QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47,
+    QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
     QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39,
 };
 
@@ -411,7 +413,7 @@
 // length field as defined by IETF QUIC draft-13 and later.
 QUIC_EXPORT_PRIVATE inline bool QuicVersionHasLongHeaderLengths(
     QuicTransportVersion transport_version) {
-  return transport_version == QUIC_VERSION_99;
+  return transport_version >= QUIC_VERSION_49;
 }
 
 // Returns whether |transport_version| uses CRYPTO frames for the handshake
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index d1b5032..a037639 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -293,9 +293,12 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
+  SetQuicReloadableFlag(quic_enable_version_49, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
   SetQuicReloadableFlag(quic_use_parse_public_header, true);
   ParsedQuicVersionVector parsed_versions;
@@ -303,7 +306,7 @@
     parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
   }
   QuicTransportVersionVector expected_versions = {
-      QUIC_VERSION_99, QUIC_VERSION_48, QUIC_VERSION_47,
+      QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
       QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
   ParsedQuicVersionVector expected_parsed_versions;
   for (QuicTransportVersion version : expected_versions) {
@@ -317,9 +320,39 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
+  SetQuicReloadableFlag(quic_enable_version_49, true);
+  SetQuicReloadableFlag(quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_use_parse_public_header, true);
+  ParsedQuicVersionVector parsed_versions;
+  for (QuicTransportVersion version : all_versions) {
+    parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+  QuicTransportVersionVector expected_versions = {
+      QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
+      QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
+  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, FilterSupportedTransportVersionsNo49) {
+  QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
+  SetQuicReloadableFlag(quic_disable_version_39, false);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  SetQuicReloadableFlag(quic_enable_version_48_2, true);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -340,9 +373,12 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -362,9 +398,12 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -384,9 +423,12 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, true);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -443,17 +485,20 @@
 // 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) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_39, 39);
   EXPECT_EQ(QUIC_VERSION_43, 43);
   EXPECT_EQ(QUIC_VERSION_46, 46);
   EXPECT_EQ(QUIC_VERSION_47, 47);
   EXPECT_EQ(QUIC_VERSION_48, 48);
+  EXPECT_EQ(QUIC_VERSION_49, 49);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
 
 TEST_F(QuicVersionsTest, AlpnForVersion) {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   ParsedQuicVersion parsed_version_q047 =
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47);
   ParsedQuicVersion parsed_version_t047 =
@@ -462,6 +507,10 @@
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48);
   ParsedQuicVersion parsed_version_t048 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48);
+  ParsedQuicVersion parsed_version_q049 =
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
+  ParsedQuicVersion parsed_version_t049 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_49);
   ParsedQuicVersion parsed_version_t099 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
 
@@ -469,10 +518,14 @@
   EXPECT_EQ("h3-T047", AlpnForVersion(parsed_version_t047));
   EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048));
   EXPECT_EQ("h3-T048", AlpnForVersion(parsed_version_t048));
+  EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049));
+  EXPECT_EQ("h3-T049", AlpnForVersion(parsed_version_t049));
   EXPECT_EQ("h3-23", AlpnForVersion(parsed_version_t099));
 }
 
 TEST_F(QuicVersionsTest, QuicEnableVersion) {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+                "Supported versions out of sync");
   SetQuicReloadableFlag(quic_supports_tls_handshake, true);
   ParsedQuicVersion parsed_version_q047 =
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47);
@@ -482,12 +535,17 @@
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48);
   ParsedQuicVersion parsed_version_t048 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48);
+  ParsedQuicVersion parsed_version_q049 =
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
+  ParsedQuicVersion parsed_version_t049 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_49);
   ParsedQuicVersion parsed_version_t099 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
   SetQuicReloadableFlag(quic_supports_tls_handshake, false);
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
+  SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
 
   {
@@ -528,6 +586,26 @@
 
   {
     QuicFlagSaver flag_saver;
+    QuicEnableVersion(parsed_version_q049);
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_49));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+  }
+
+  {
+    QuicFlagSaver flag_saver;
+    QuicEnableVersion(parsed_version_t049);
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_49));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+  }
+
+  {
+    QuicFlagSaver flag_saver;
     QuicEnableVersion(parsed_version_t099);
     EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));