Refactor QUIC version parsing

This CL fixes an oversight where QuicFramer::ParsePublicHeader was not parsing the version when parsing packets from versions <= 43. This was not an issue because there are only two clients of that method:
1) QuicFramer::ProcessIetfPacketHeader and that is not called for versions <= 43.
2) QuicDispatcher::ProcessPacket and that was parsing the version after the fact (this CL now removes that when the quic_use_parse_public_header flag is true which corresponds to when the dispatcher uses ParsePublicHeader.

This CL also adds a test to prevent this from regressing.

Since this CL only refactors code and does not change functionality, it is not flag protected.

gfe-relnote: refactor version parsing, not flag protected
PiperOrigin-RevId: 261792952
Change-Id: If5a1333590a41e8a03fd53c6f8cea70fa47e8fd4
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index 1782e4a..c944862 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -253,7 +253,9 @@
     QUIC_DLOG(ERROR) << detailed_error;
     return;
   }
-  packet_info.version = ParseQuicVersionLabel(packet_info.version_label);
+  if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
+    packet_info.version = ParseQuicVersionLabel(packet_info.version_label);
+  }
   if (packet_info.destination_connection_id.length() !=
           expected_server_connection_id_length_ &&
       !should_update_expected_server_connection_id_length_ &&
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 426f0de..ea9d9f5 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -6396,6 +6396,7 @@
     PacketHeaderFormat* format,
     bool* version_present,
     QuicVersionLabel* version_label,
+    ParsedQuicVersion* parsed_version,
     QuicConnectionId* destination_connection_id,
     std::string* detailed_error) {
   *format = GOOGLE_QUIC_PACKET;
@@ -6409,9 +6410,12 @@
     *detailed_error = "Unable to read ConnectionId.";
     return QUIC_INVALID_PACKET_HEADER;
   }
-  if (*version_present && !ProcessVersionLabel(reader, version_label)) {
-    *detailed_error = "Unable to read protocol version.";
-    return QUIC_INVALID_PACKET_HEADER;
+  if (*version_present) {
+    if (!ProcessVersionLabel(reader, version_label)) {
+      *detailed_error = "Unable to read protocol version.";
+      return QUIC_INVALID_PACKET_HEADER;
+    }
+    *parsed_version = ParseQuicVersionLabel(*version_label);
   }
   return QUIC_NO_ERROR;
 }
@@ -6542,7 +6546,7 @@
   if (!ietf_format) {
     return ParsePublicHeaderGoogleQuic(
         reader, first_byte, format, version_present, version_label,
-        destination_connection_id, detailed_error);
+        parsed_version, destination_connection_id, detailed_error);
   }
 
   *format = GetIetfPacketHeaderFormat(*first_byte);
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 33b9b37..be5f128 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -870,6 +870,7 @@
       PacketHeaderFormat* format,
       bool* version_present,
       QuicVersionLabel* version_label,
+      ParsedQuicVersion* parsed_version,
       QuicConnectionId* destination_connection_id,
       std::string* detailed_error);
 
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index a853829..99864ad 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -20,6 +20,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.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/platform/api/quic_arraysize.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"
@@ -1096,6 +1097,112 @@
   EXPECT_EQ(FramerTestConnectionIdPlusOne(), source_connection_id);
 }
 
+TEST_P(QuicFramerTest, ParsePublicHeader) {
+  const unsigned char type_byte =
+      framer_.transport_version() == QUIC_VERSION_44 ? 0xFD : 0xE3;
+  // clang-format off
+  unsigned char packet[] = {
+    // public flags (version included, 8-byte connection ID,
+    // 4-byte packet number)
+    0x29,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // version
+    QUIC_VERSION_BYTES,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+    // padding frame
+    0x00,
+  };
+  unsigned char packet44[] = {
+    // public flags (long header with packet type HANDSHAKE and
+    // 4-byte packet number)
+    type_byte,
+    // version
+    QUIC_VERSION_BYTES,
+    // connection ID lengths
+    0x50,
+    // destination connection ID
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // long header packet length
+    0x05,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+    // padding frame
+    0x00,
+  };
+  unsigned char packet99[] = {
+    // 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
+    0x05,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+    // padding frame
+    0x00,
+  };
+  // 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);
+  } else if (framer_.transport_version() >= QUIC_VERSION_44) {
+    p = packet44;
+    p_length = QUIC_ARRAYSIZE(packet44);
+  }
+
+  uint8_t first_byte = 0x33;
+  PacketHeaderFormat format = GOOGLE_QUIC_PACKET;
+  bool version_present = false, has_length_prefix = false;
+  QuicVersionLabel version_label = 0;
+  ParsedQuicVersion parsed_version = UnsupportedQuicVersion();
+  QuicConnectionId destination_connection_id = EmptyQuicConnectionId(),
+                   source_connection_id = EmptyQuicConnectionId();
+  QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+  QuicVariableLengthIntegerLength retry_token_length_length =
+      VARIABLE_LENGTH_INTEGER_LENGTH_4;
+  QuicStringPiece retry_token;
+  std::string detailed_error = "foobar";
+
+  QuicDataReader reader(AsChars(p), p_length);
+  const QuicErrorCode parse_error = QuicFramer::ParsePublicHeader(
+      &reader, kQuicDefaultConnectionIdLength,
+      /*ietf_format=*/
+      VersionHasIetfInvariantHeader(framer_.transport_version()), &first_byte,
+      &format, &version_present, &has_length_prefix, &version_label,
+      &parsed_version, &destination_connection_id, &source_connection_id,
+      &long_packet_type, &retry_token_length_length, &retry_token,
+      &detailed_error);
+  EXPECT_EQ(QUIC_NO_ERROR, parse_error);
+  EXPECT_EQ("", detailed_error);
+  EXPECT_EQ(p[0], first_byte);
+  EXPECT_TRUE(version_present);
+  EXPECT_EQ(framer_.version().HasLengthPrefixedConnectionIds(),
+            has_length_prefix);
+  EXPECT_EQ(CreateQuicVersionLabel(framer_.version()), version_label);
+  EXPECT_EQ(framer_.version(), parsed_version);
+  EXPECT_EQ(FramerTestConnectionId(), destination_connection_id);
+  EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id);
+  EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length);
+  EXPECT_EQ(QuicStringPiece(), retry_token);
+  if (VersionHasIetfInvariantHeader(framer_.transport_version())) {
+    EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+    EXPECT_EQ(HANDSHAKE, long_packet_type);
+  } else {
+    EXPECT_EQ(GOOGLE_QUIC_PACKET, format);
+  }
+}
+
 TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) {
   if (!framer_.version().SupportsClientConnectionIds()) {
     return;