gfe-relnote: In QUIC, do not use framer object in QuicDispatcher. Protected by gfe2_restart_flag_quic_no_framer_object_in_dispatcher.

Also, dispatcher does not parse and validate packet number anymore.

PiperOrigin-RevId: 247959538
Change-Id: Ia0f7901428537f392b05ffd6beb2984bffd00232
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index a9c6c4a..fa6fda7 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -10,6 +10,7 @@
 #include "net/third_party/quiche/src/quic/core/chlo_extractor.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
 #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -303,8 +304,14 @@
       last_error_(QUIC_NO_ERROR),
       new_sessions_allowed_per_event_loop_(0u),
       accept_new_connections_(true),
-      allow_short_initial_connection_ids_(false) {
-  framer_.set_visitor(this);
+      allow_short_initial_connection_ids_(false),
+      last_version_label_(0),
+      expected_connection_id_length_(expected_connection_id_length),
+      should_update_expected_connection_id_length_(false),
+      no_framer_(GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) {
+  if (!no_framer_) {
+    framer_.set_visitor(this);
+  }
 }
 
 QuicDispatcher::~QuicDispatcher() {
@@ -326,21 +333,60 @@
   // GetClientAddress must be called after current_peer_address_ is set.
   current_client_address_ = GetClientAddress();
   current_packet_ = &packet;
-  // ProcessPacket will cause the packet to be dispatched in
-  // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
-  // in OnUnauthenticatedHeader.
-  framer_.ProcessPacket(packet);
-  // TODO(rjshade): Return a status describing if/why a packet was dropped,
-  //                and log somehow.  Maybe expose as a varz.
-  // TODO(wub): Consider invalidate the current_* variables so processing of the
-  //            next packet does not use them incorrectly.
+  if (!no_framer_) {
+    // ProcessPacket will cause the packet to be dispatched in
+    // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
+    // in OnUnauthenticatedHeader.
+    framer_.ProcessPacket(packet);
+    // TODO(rjshade): Return a status describing if/why a packet was dropped,
+    //                and log somehow.  Maybe expose as a varz.
+    return;
+  }
+  QUIC_RESTART_FLAG_COUNT(quic_no_framer_object_in_dispatcher);
+  QuicPacketHeader header;
+  uint8_t destination_connection_id_length;
+  string detailed_error;
+  const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher(
+      packet, expected_connection_id_length_, &header.form,
+      &header.version_flag, &last_version_label_,
+      &destination_connection_id_length, &header.destination_connection_id,
+      &detailed_error);
+  if (error != QUIC_NO_ERROR) {
+    // Packet has framing error.
+    SetLastError(error);
+    QUIC_DLOG(ERROR) << detailed_error;
+    return;
+  }
+  header.version = ParseQuicVersionLabel(last_version_label_);
+  if (destination_connection_id_length != expected_connection_id_length_ &&
+      !should_update_expected_connection_id_length_ &&
+      !QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+          header.version.transport_version)) {
+    SetLastError(QUIC_INVALID_PACKET_HEADER);
+    QUIC_DLOG(ERROR) << "Invalid Connection Id Length";
+    return;
+  }
+  if (should_update_expected_connection_id_length_) {
+    expected_connection_id_length_ = destination_connection_id_length;
+  }
+  // TODO(fayang): Instead of passing in QuicPacketHeader, pass format,
+  // version_flag, version and destination_connection_id. Combine
+  // OnUnauthenticatedPublicHeader and OnUnauthenticatedHeader to a single
+  // function when deprecating quic_no_framer_object_in_dispatcher.
+  if (!OnUnauthenticatedPublicHeader(header)) {
+    return;
+  }
+  OnUnauthenticatedHeader(header);
+  // TODO(wub): Consider invalidate the current_* variables so processing of
+  //            the next packet does not use them incorrectly.
 }
 
 QuicConnectionId QuicDispatcher::MaybeReplaceConnectionId(
     QuicConnectionId connection_id,
     ParsedQuicVersion version) {
   const uint8_t expected_connection_id_length =
-      framer_.GetExpectedConnectionIdLength();
+      no_framer_ ? expected_connection_id_length_
+                 : framer_.GetExpectedConnectionIdLength();
   if (connection_id.length() == expected_connection_id_length) {
     return connection_id;
   }
@@ -383,16 +429,18 @@
   // connection ID, the dispatcher picks a new one of its expected length.
   // Therefore we should never receive a connection ID that is smaller
   // than 64 bits and smaller than what we expect.
+  const uint8_t expected_connection_id_length =
+      no_framer_ ? expected_connection_id_length_
+                 : framer_.GetExpectedConnectionIdLength();
   if (connection_id.length() < kQuicMinimumInitialConnectionIdLength &&
-      connection_id.length() < framer_.GetExpectedConnectionIdLength() &&
+      connection_id.length() < expected_connection_id_length &&
       !allow_short_initial_connection_ids_) {
     DCHECK(header.version_flag);
     DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
         header.version.transport_version));
     QUIC_DLOG(INFO) << "Packet with short destination connection ID "
                     << connection_id << " expected "
-                    << static_cast<int>(
-                           framer_.GetExpectedConnectionIdLength());
+                    << static_cast<int>(expected_connection_id_length);
     ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, header.form,
                                      header.version_flag, header.version);
     return false;
@@ -449,12 +497,14 @@
   ParsedQuicVersion version = GetSupportedVersions().front();
   if (header.version_flag) {
     ParsedQuicVersion packet_version = header.version;
-    if (framer_.supported_versions() != GetSupportedVersions()) {
+    if (!no_framer_ && framer_.supported_versions() != GetSupportedVersions()) {
       // Reset framer's version if version flags change in flight.
       framer_.SetSupportedVersions(GetSupportedVersions());
     }
-    if (!framer_.IsSupportedVersion(packet_version)) {
-      if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) {
+    if (!IsSupportedVersion(packet_version)) {
+      if (ShouldCreateSessionForUnknownVersion(
+              no_framer_ ? last_version_label_
+                         : framer_.last_version_label())) {
         return true;
       }
       if (!crypto_config()->validate_chlo_size() ||
@@ -470,8 +520,10 @@
     }
     version = packet_version;
   }
-  // Set the framer's version and continue processing.
-  framer_.set_version(version);
+  if (!no_framer_) {
+    // Set the framer's version and continue processing.
+    framer_.set_version(version);
+  }
 
   if (version.HasHeaderProtection()) {
     ProcessHeader(header);
@@ -573,6 +625,11 @@
     return kFateTimeWait;
   }
 
+  if (no_framer_) {
+    // Let the connection parse and validate packet number.
+    return kFateProcess;
+  }
+
   // initial packet number of 0 is always invalid.
   if (!framer_.version().HasHeaderProtection()) {
     if (!header.packet_number.IsInitialized()) {
@@ -797,7 +854,7 @@
   }
 
   // If the version is known and supported by framer, send a connection close.
-  if (framer_.IsSupportedVersion(version)) {
+  if (IsSupportedVersion(version)) {
     QUIC_DVLOG(1)
         << "Statelessly terminating " << connection_id
         << " based on an ietf-long packet, which has a supported version:"
@@ -852,6 +909,7 @@
 bool QuicDispatcher::OnProtocolVersionMismatch(
     ParsedQuicVersion /*received_version*/,
     PacketHeaderFormat /*form*/) {
+  DCHECK(!no_framer_);
   QUIC_BUG_IF(
       !time_wait_list_manager_->IsConnectionIdInTimeWait(
           current_connection_id_) &&
@@ -1146,7 +1204,7 @@
     EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
         current_connection_id_, form != GOOGLE_QUIC_PACKET, *current_packet_,
         current_self_address_, current_peer_address_,
-        /*is_chlo=*/true, current_alpn_, framer_.version());
+        /*is_chlo=*/true, current_alpn_, version);
     if (rs != EnqueuePacketResult::SUCCESS) {
       OnBufferPacketFailure(rs, current_connection_id_);
     }
@@ -1155,11 +1213,10 @@
 
   QuicConnectionId original_connection_id = current_connection_id_;
   current_connection_id_ =
-      MaybeReplaceConnectionId(current_connection_id_, framer_.version());
+      MaybeReplaceConnectionId(current_connection_id_, version);
   // Creates a new session and process all buffered packets for this connection.
-  QuicSession* session =
-      CreateQuicSession(current_connection_id_, current_peer_address_,
-                        current_alpn_, framer_.version());
+  QuicSession* session = CreateQuicSession(
+      current_connection_id_, current_peer_address_, current_alpn_, version);
   if (original_connection_id != current_connection_id_) {
     session->connection()->AddIncomingConnectionId(original_connection_id);
   }
@@ -1338,7 +1395,9 @@
   current_self_address_ = current_self_address;
   current_packet_ = current_packet.get();
   current_connection_id_ = rejector->connection_id();
-  framer_.set_version(first_version);
+  if (!no_framer_) {
+    framer_.set_version(first_version);
+  }
 
   // Stop buffering packets on this connection
   const auto num_erased =
@@ -1391,7 +1450,7 @@
       break;
 
     case StatelessRejector::REJECTED: {
-      QUIC_BUG_IF(first_version != framer_.version())
+      QUIC_BUG_IF(!no_framer_ && first_version != framer_.version())
           << "SREJ: Client's version: "
           << QuicVersionToString(first_version.transport_version)
           << " is different from current dispatcher framer's version: "
@@ -1438,7 +1497,22 @@
 }
 
 void QuicDispatcher::DisableFlagValidation() {
-  framer_.set_validate_flags(false);
+  if (!no_framer_) {
+    framer_.set_validate_flags(false);
+  }
+}
+
+bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) {
+  if (!no_framer_) {
+    return framer_.IsSupportedVersion(version);
+  }
+  for (const ParsedQuicVersion& supported_version :
+       version_manager_->GetSupportedVersions()) {
+    if (version == supported_version) {
+      return true;
+    }
+  }
+  return false;
 }
 
 }  // namespace quic
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 0c951ed..6adf5f3 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -131,6 +131,9 @@
 
   // QuicFramerVisitorInterface implementation. Not expected to be called
   // outside of this class.
+  // TODO(fayang): Make QuicDispatcher no longer implement
+  // QuicFramerVisitorInterface when deprecating
+  // quic_no_framer_object_in_dispatcher.
   void OnPacket() override;
   // Called when the public header has been parsed. Returns false when just the
   // public header is enough to dispatch the packet; true if the framer needs to
@@ -361,8 +364,13 @@
   // to the received destination connection ID length of all IETF long headers.
   void SetShouldUpdateExpectedConnectionIdLength(
       bool should_update_expected_connection_id_length) {
-    framer_.SetShouldUpdateExpectedConnectionIdLength(
-        should_update_expected_connection_id_length);
+    if (!no_framer_) {
+      framer_.SetShouldUpdateExpectedConnectionIdLength(
+          should_update_expected_connection_id_length);
+      return;
+    }
+    should_update_expected_connection_id_length_ =
+        should_update_expected_connection_id_length;
   }
 
   // If true, the dispatcher will allow incoming initial packets that have
@@ -435,6 +443,9 @@
   QuicConnectionId MaybeReplaceConnectionId(QuicConnectionId connection_id,
                                             ParsedQuicVersion version);
 
+  // Returns true if |version| is a supported protocol version.
+  bool IsSupportedVersion(const ParsedQuicVersion version);
+
   void set_new_sessions_allowed_per_event_loop(
       int16_t new_sessions_allowed_per_event_loop) {
     new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop;
@@ -515,6 +526,28 @@
   // If false, the dispatcher follows the IETF spec and rejects packets with
   // invalid connection IDs lengths below 64 bits. If true they are allowed.
   bool allow_short_initial_connection_ids_;
+
+  // The last QUIC version label received. Used when no_framer_ is true.
+  // TODO(fayang): remove this member variable, instead, add an argument to
+  // OnUnauthenticatedPublicHeader when deprecating
+  // quic_no_framer_object_in_dispatcher.
+  QuicVersionLabel last_version_label_;
+
+  // IETF short headers contain a destination connection ID but do not
+  // encode its length. This variable contains the length we expect to read.
+  // This is also used to signal an error when a long header packet with
+  // different destination connection ID length is received when
+  // should_update_expected_connection_id_length_ is false and packet's version
+  // does not allow variable length connection ID. Used when no_framer_ is true.
+  uint8_t expected_connection_id_length_;
+
+  // If true, change expected_connection_id_length_ to be the received
+  // destination connection ID length of all IETF long headers. Used when
+  // no_framer_ is true.
+  bool should_update_expected_connection_id_length_;
+
+  // Latched value of quic_no_framer_object_in_dispatcher.
+  const bool no_framer_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index 9c7cd1e..03b281b 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -815,7 +815,8 @@
 }
 
 TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
-  if (CurrentSupportedVersions().front().HasHeaderProtection()) {
+  if (CurrentSupportedVersions().front().HasHeaderProtection() ||
+      GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) {
     // When header protection is in use, we don't put packets in the time wait
     // list manager based on packet number.
     return;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 243529d..8d0dec2 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -449,6 +449,11 @@
                              "each time such a packet is dropped");
 }
 
+PacketHeaderFormat GetIetfPacketHeaderFormat(uint8_t type_byte) {
+  return type_byte & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET
+                                       : IETF_QUIC_SHORT_HEADER_PACKET;
+}
+
 }  // namespace
 
 QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions,
@@ -2511,8 +2516,7 @@
   }
   header->type_byte = type;
   // Determine whether this is a long or short header.
-  header->form = type & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET
-                                          : IETF_QUIC_SHORT_HEADER_PACKET;
+  header->form = GetIetfPacketHeaderFormat(type);
   if (header->form == IETF_QUIC_LONG_HEADER_PACKET) {
     // Version is always present in long headers.
     header->version_flag = true;
@@ -2610,13 +2614,19 @@
 }
 
 // static
-bool QuicFramer::ValidateIetfConnectionIdLength(
-    uint8_t connection_id_lengths_byte,
+bool QuicFramer::ProcessAndValidateIetfConnectionIdLength(
+    QuicDataReader* reader,
     ParsedQuicVersion version,
     bool should_update_expected_connection_id_length,
     uint8_t* expected_connection_id_length,
     uint8_t* destination_connection_id_length,
-    uint8_t* source_connection_id_length) {
+    uint8_t* source_connection_id_length,
+    std::string* detailed_error) {
+  uint8_t connection_id_lengths_byte;
+  if (!reader->ReadBytes(&connection_id_lengths_byte, 1)) {
+    *detailed_error = "Unable to read ConnectionId length.";
+    return false;
+  }
   uint8_t dcil =
       (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4;
   if (dcil != 0) {
@@ -2642,6 +2652,7 @@
     // OnProtocolVersionMismatch call is moved to before this is run.
     QUIC_DVLOG(1) << "dcil: " << static_cast<uint32_t>(dcil)
                   << ", scil: " << static_cast<uint32_t>(scil);
+    *detailed_error = "Invalid ConnectionId length.";
     return false;
   }
   *destination_connection_id_length = dcil;
@@ -2664,18 +2675,11 @@
           ? expected_connection_id_length_
           : 0;
   if (header->form == IETF_QUIC_LONG_HEADER_PACKET) {
-    // Read and validate connection ID length.
-    uint8_t connection_id_lengths_byte;
-    if (!reader->ReadBytes(&connection_id_lengths_byte, 1)) {
-      set_detailed_error("Unable to read ConnectionId length.");
-      return false;
-    }
-    if (!ValidateIetfConnectionIdLength(
-            connection_id_lengths_byte, header->version,
+    if (!ProcessAndValidateIetfConnectionIdLength(
+            reader, header->version,
             should_update_expected_connection_id_length_,
             &expected_connection_id_length_, &destination_connection_id_length,
-            &source_connection_id_length)) {
-      set_detailed_error("Invalid ConnectionId length.");
+            &source_connection_id_length, &detailed_error_)) {
       return false;
     }
   }
@@ -6054,5 +6058,75 @@
   supports_multiple_packet_number_spaces_ = true;
 }
 
+// static
+QuicErrorCode QuicFramer::ProcessPacketDispatcher(
+    const QuicEncryptedPacket& packet,
+    uint8_t expected_connection_id_length,
+    PacketHeaderFormat* format,
+    bool* version_flag,
+    QuicVersionLabel* version_label,
+    uint8_t* destination_connection_id_length,
+    QuicConnectionId* destination_connection_id,
+    std::string* detailed_error) {
+  QuicDataReader reader(packet.data(), packet.length());
+
+  uint8_t first_byte;
+  if (!reader.ReadBytes(&first_byte, 1)) {
+    *detailed_error = "Unable to read first byte.";
+    return QUIC_INVALID_PACKET_HEADER;
+  }
+  if (!QuicUtils::IsIetfPacketHeader(first_byte)) {
+    *format = GOOGLE_QUIC_PACKET;
+    *version_flag = (first_byte & PACKET_PUBLIC_FLAGS_VERSION) != 0;
+    *destination_connection_id_length =
+        first_byte & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
+    if (*destination_connection_id_length == 0 ||
+        !reader.ReadConnectionId(destination_connection_id,
+                                 *destination_connection_id_length)) {
+      *detailed_error = "Unable to read ConnectionId.";
+      return QUIC_INVALID_PACKET_HEADER;
+    }
+    if (*version_flag && !ProcessVersionLabel(&reader, version_label)) {
+      *detailed_error = "Unable to read protocol version.";
+      return QUIC_INVALID_PACKET_HEADER;
+    }
+    return QUIC_NO_ERROR;
+  }
+
+  *format = GetIetfPacketHeaderFormat(first_byte);
+  QUIC_DVLOG(1) << "Dispatcher: Processing IETF QUIC packet, format: "
+                << *format;
+  *version_flag = *format == IETF_QUIC_LONG_HEADER_PACKET;
+  if (*format == IETF_QUIC_LONG_HEADER_PACKET) {
+    if (!ProcessVersionLabel(&reader, version_label)) {
+      *detailed_error = "Unable to read protocol version.";
+      return QUIC_INVALID_PACKET_HEADER;
+    }
+    // Set should_update_expected_connection_id_length to true to bypass
+    // connection ID lengths validation.
+    uint8_t unused_source_connection_id_length = 0;
+    uint8_t unused_expected_connection_id_length = 0;
+    if (!ProcessAndValidateIetfConnectionIdLength(
+            &reader, ParseQuicVersionLabel(*version_label),
+            /*should_update_expected_connection_id_length=*/true,
+            &unused_expected_connection_id_length,
+            destination_connection_id_length,
+            &unused_source_connection_id_length, detailed_error)) {
+      return QUIC_INVALID_PACKET_HEADER;
+    }
+  } else {
+    // For short header packets, expected_connection_id_length is used to
+    // determine the destination_connection_id_length.
+    *destination_connection_id_length = expected_connection_id_length;
+  }
+  // Read destination connection ID.
+  if (!reader.ReadConnectionId(destination_connection_id,
+                               *destination_connection_id_length)) {
+    *detailed_error = "Unable to read Destination ConnectionId.";
+    return QUIC_INVALID_PACKET_HEADER;
+  }
+  return QUIC_NO_ERROR;
+}
+
 #undef ENDPOINT  // undef for jumbo builds
 }  // namespace quic
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index e2d7b4d..59e300c 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -373,6 +373,21 @@
       uint64_t retry_token_length,
       QuicVariableLengthIntegerLength length_length);
 
+  // Lightweight parsing of |packet| and populates |format|, |version_flag|,
+  // |version_label|, |destination_connection_id_length|,
+  // |destination_connection_id| and |detailed_error|. Please note,
+  // |expected_connection_id_length| is only used to determine IETF short header
+  // packet's destination connection ID length.
+  static QuicErrorCode ProcessPacketDispatcher(
+      const QuicEncryptedPacket& packet,
+      uint8_t expected_connection_id_length,
+      PacketHeaderFormat* format,
+      bool* version_flag,
+      QuicVersionLabel* version_label,
+      uint8_t* destination_connection_id_length,
+      QuicConnectionId* destination_connection_id,
+      std::string* detailed_error);
+
   // Serializes a packet containing |frames| into |buffer|.
   // Returns the length of the packet, which must not be longer than
   // |packet_length|.  Returns 0 if it fails to serialize.
@@ -665,13 +680,14 @@
 
   // Validates and updates |destination_connection_id_length| and
   // |source_connection_id_length|.
-  static bool ValidateIetfConnectionIdLength(
-      uint8_t connection_id_lengths_byte,
+  static bool ProcessAndValidateIetfConnectionIdLength(
+      QuicDataReader* reader,
       ParsedQuicVersion version,
       bool should_update_expected_connection_id_length,
       uint8_t* expected_connection_id_length,
       uint8_t* destination_connection_id_length,
-      uint8_t* source_connection_id_length);
+      uint8_t* source_connection_id_length,
+      std::string* detailed_error);
 
   bool ProcessIetfHeaderTypeByte(QuicDataReader* reader,
                                  QuicPacketHeader* header);
@@ -921,6 +937,8 @@
   // Updated by WritePacketHeader.
   QuicConnectionId last_serialized_connection_id_;
   // The last QUIC version label received.
+  // TODO(fayang): Remove this when deprecating
+  // quic_no_framer_object_in_dispatcher.
   QuicVersionLabel last_version_label_;
   // Version of the protocol being used.
   ParsedQuicVersion version_;
@@ -975,10 +993,14 @@
   // encode its length. This variable contains the length we expect to read.
   // This is also used to validate the long header connection ID lengths in
   // older versions of QUIC.
+  // TODO(fayang): Remove this when deprecating
+  // quic_no_framer_object_in_dispatcher.
   uint8_t expected_connection_id_length_;
 
   // When this is true, QuicFramer will change expected_connection_id_length_
   // to the received destination connection ID length of all IETF long headers.
+  // TODO(fayang): Remove this when deprecating
+  // quic_no_framer_object_in_dispatcher.
   bool should_update_expected_connection_id_length_;
 
   // Indicates whether this framer supports multiple packet number spaces.
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 4af5b3a..96f335c 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -913,6 +913,22 @@
   EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
 
   CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER);
+
+  PacketHeaderFormat format;
+  bool version_flag;
+  uint8_t destination_connection_id_length;
+  QuicConnectionId destination_connection_id;
+  QuicVersionLabel version_label;
+  std::string detailed_error;
+  EXPECT_EQ(QUIC_NO_ERROR, QuicFramer::ProcessPacketDispatcher(
+                               *encrypted, kQuicDefaultConnectionIdLength,
+                               &format, &version_flag, &version_label,
+                               &destination_connection_id_length,
+                               &destination_connection_id, &detailed_error));
+  EXPECT_EQ(GOOGLE_QUIC_PACKET, format);
+  EXPECT_FALSE(version_flag);
+  EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id_length);
+  EXPECT_EQ(FramerTestConnectionId(), destination_connection_id);
 }
 
 TEST_P(QuicFramerTest, LongPacketHeader) {
@@ -975,6 +991,22 @@
   CheckFramingBoundaries(
       framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44,
       QUIC_INVALID_PACKET_HEADER);
+
+  PacketHeaderFormat format;
+  bool version_flag;
+  uint8_t destination_connection_id_length;
+  QuicConnectionId destination_connection_id;
+  QuicVersionLabel version_label;
+  std::string detailed_error;
+  EXPECT_EQ(QUIC_NO_ERROR, QuicFramer::ProcessPacketDispatcher(
+                               *encrypted, kQuicDefaultConnectionIdLength,
+                               &format, &version_flag, &version_label,
+                               &destination_connection_id_length,
+                               &destination_connection_id, &detailed_error));
+  EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+  EXPECT_TRUE(version_flag);
+  EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id_length);
+  EXPECT_EQ(FramerTestConnectionId(), destination_connection_id);
 }
 
 TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
@@ -13251,6 +13283,34 @@
             FramerTestConnectionIdNineBytes());
   EXPECT_EQ(visitor_.header_.get()->packet_number,
             QuicPacketNumber(UINT64_C(0x13374233)));
+
+  PacketHeaderFormat format;
+  bool version_flag;
+  uint8_t destination_connection_id_length;
+  QuicConnectionId destination_connection_id;
+  QuicVersionLabel version_label;
+  std::string detailed_error;
+  EXPECT_EQ(QUIC_NO_ERROR,
+            QuicFramer::ProcessPacketDispatcher(
+                QuicEncryptedPacket(AsChars(long_header_packet),
+                                    QUIC_ARRAYSIZE(long_header_packet)),
+                kQuicDefaultConnectionIdLength, &format, &version_flag,
+                &version_label, &destination_connection_id_length,
+                &destination_connection_id, &detailed_error));
+  EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format);
+  EXPECT_TRUE(version_flag);
+  EXPECT_EQ(9, destination_connection_id_length);
+  EXPECT_EQ(FramerTestConnectionIdNineBytes(), destination_connection_id);
+
+  EXPECT_EQ(QUIC_NO_ERROR,
+            QuicFramer::ProcessPacketDispatcher(
+                short_header_encrypted, 9, &format, &version_flag,
+                &version_label, &destination_connection_id_length,
+                &destination_connection_id, &detailed_error));
+  EXPECT_EQ(IETF_QUIC_SHORT_HEADER_PACKET, format);
+  EXPECT_FALSE(version_flag);
+  EXPECT_EQ(9, destination_connection_id_length);
+  EXPECT_EQ(FramerTestConnectionIdNineBytes(), destination_connection_id);
 }
 
 TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) {