Have framer store frame type currently being processed

This CL has QuicFramer save the frame type for the frame that it currently
is extracting from the packet and processing. This is done so that the
IETF QUIC Transport Connection Close can get the type of frame that
precipitated the close. If the frame-type was not saved like this then
it would need to be passed around in the call stack -- one more parameter
threaded throughout many calls in QUIC.

This done only when IETF Framing (version 99) is enabled.

Tests in quic_framer_test.cc have been modified to check that the right
frame type has been saved (done in all of the On...Frame upcalls, so that
the testing is fairly complete). Also checks that the saved type is 0
when not processing a frame (eg, when doing header processing) OR when not
doing IETF QUIC Framing.

gfe-relnote: N/A is only for Version 99/IETF QUIC Framing.
PiperOrigin-RevId: 265888094
Change-Id: If068d49c9f72b4e3c0e8eb3e7ab7460abde85f8a
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index c3d645d..9aab379 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -4138,7 +4138,11 @@
       session, GetNthClientInitiatedBidirectionalId(max_number_of_streams + 1));
   client_->SendCustomSynchronousRequest(headers, body);
   EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
-  EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error());
+  EXPECT_EQ(QUIC_INVALID_STREAM_ID, GetClientSession()->error());
+  EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+            GetClientSession()->close_type());
+  EXPECT_TRUE(
+      IS_IETF_STREAM_FRAME(GetClientSession()->transport_close_frame_type()));
 }
 
 TEST_P(EndToEndTest, TestMaxPushId) {
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 3e8f834..cc99744 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2836,11 +2836,9 @@
     QuicErrorCodeToIetfMapping mapping =
         QuicErrorCodeToTransportErrorCode(error);
     if (mapping.is_transport_close_) {
-      // Maps to a transport close
-      // TODO(fkastenholz) need to change "0" to get the frame type currently
-      // being processed so that it can be inserted into the frame.
-      frame = new QuicConnectionCloseFrame(error, details,
-                                           mapping.transport_error_code_, 0);
+      frame = new QuicConnectionCloseFrame(
+          error, details, mapping.transport_error_code_,
+          framer_.current_received_frame_type());
     } else {
       // Maps to an application close.
       frame = new QuicConnectionCloseFrame(error, details,
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index dbf3860..9f8127d 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1466,8 +1466,7 @@
         // Maps to a transport close
         qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
         qccf.transport_error_code = mapping.transport_error_code_;
-        // TODO(fkastenholz) need to change "0" to get the frame type currently
-        // being processed so that it can be inserted into the frame.
+        // Frame type is not important for the tests that invoke this method.
         qccf.transport_close_frame_type = 0;
       } else {
         // Maps to an application close.
@@ -9131,6 +9130,32 @@
   }
 }
 
+TEST_P(QuicConnectionTest, ConnectionCloseFrameType) {
+  if (!VersionHasIetfQuicFrames(version().transport_version)) {
+    // Test relevent only for IETF QUIC.
+    return;
+  }
+  const QuicErrorCode kQuicErrorCode = IETF_QUIC_PROTOCOL_VIOLATION;
+  // Use the (unknown) frame type of 9999 to avoid triggering any logic
+  // which might be associated with the processing of a known frame type.
+  const uint64_t kTransportCloseFrameType = 9999u;
+  QuicFramerPeer::set_current_received_frame_type(
+      QuicConnectionPeer::GetFramer(&connection_), kTransportCloseFrameType);
+  // Do a transport connection close
+  EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+  connection_.CloseConnection(
+      kQuicErrorCode, "Some random error message",
+      ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+  const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
+      writer_->connection_close_frames();
+  ASSERT_EQ(1u, connection_close_frames.size());
+  EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+            connection_close_frames[0].close_type);
+  EXPECT_EQ(kQuicErrorCode, connection_close_frames[0].extracted_error_code);
+  EXPECT_EQ(kTransportCloseFrameType,
+            connection_close_frames[0].transport_close_frame_type);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index c667e9b..9890f36 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -426,7 +426,8 @@
       supports_multiple_packet_number_spaces_(false),
       last_written_packet_number_length_(0),
       peer_ack_delay_exponent_(kDefaultAckDelayExponent),
-      local_ack_delay_exponent_(kDefaultAckDelayExponent) {
+      local_ack_delay_exponent_(kDefaultAckDelayExponent),
+      current_received_frame_type_(0) {
   DCHECK(!supported_versions.empty());
   version_ = supported_versions_[0];
   decrypter_[ENCRYPTION_INITIAL] = QuicMakeUnique<NullDecrypter>(perspective);
@@ -1877,13 +1878,16 @@
 
   // Handle the payload.
   if (VersionHasIetfQuicFrames(version_.transport_version)) {
+    current_received_frame_type_ = 0;
     if (!ProcessIetfFrameData(&reader, *header)) {
+      current_received_frame_type_ = 0;
       DCHECK_NE(QUIC_NO_ERROR, error_);  // ProcessIetfFrameData sets the error.
       DCHECK_NE("", detailed_error_);
       QUIC_DLOG(WARNING) << ENDPOINT << "Unable to process frame data. Error: "
                          << detailed_error_;
       return false;
     }
+    current_received_frame_type_ = 0;
   } else {
     if (!ProcessFrameData(&reader, *header)) {
       DCHECK_NE(QUIC_NO_ERROR, error_);  // ProcessFrameData sets the error.
@@ -3045,6 +3049,7 @@
       set_detailed_error("Unable to read frame type.");
       return RaiseError(QUIC_INVALID_FRAME_DATA);
     }
+    current_received_frame_type_ = frame_type;
 
     // Is now the number of bytes into which the frame type was encoded.
     encoded_bytes -= reader->BytesRemaining();
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 5cfba86..f429a83 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -610,6 +610,10 @@
     return first_sending_packet_number_;
   }
 
+  uint64_t current_received_frame_type() const {
+    return current_received_frame_type_;
+  }
+
   // The connection ID length the framer expects on incoming IETF short headers
   // on the server.
   uint8_t GetExpectedServerConnectionIdLength() {
@@ -1098,6 +1102,12 @@
   // the peer in the transport parameter negotiation. IETF QUIC only.
   uint32_t peer_ack_delay_exponent_;
   uint32_t local_ack_delay_exponent_;
+
+  // The type of received IETF frame currently being processed.  0 when not
+  // processing a frame or when processing Google QUIC frames.  Used to populate
+  // the Transport Connection Close when there is an error during frame
+  // processing.
+  uint64_t current_received_frame_type_;
 };
 
 // Look for and parse the error code from the "<quic_error_code>:" text that
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 2c2e3fc..ce040f2 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -197,12 +197,14 @@
 
   void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
     public_reset_packet_ = QuicMakeUnique<QuicPublicResetPacket>((packet));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
   }
 
   void OnVersionNegotiationPacket(
       const QuicVersionNegotiationPacket& packet) override {
     version_negotiation_packet_ =
         QuicMakeUnique<QuicVersionNegotiationPacket>((packet));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
   }
 
   void OnRetryPacket(QuicConnectionId original_connection_id,
@@ -213,29 +215,36 @@
     retry_new_connection_id_ =
         QuicMakeUnique<QuicConnectionId>(new_connection_id);
     retry_token_ = QuicMakeUnique<std::string>(std::string(retry_token));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
   }
 
   bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override {
     QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: "
                     << received_version;
     ++version_mismatch_;
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return false;
   }
 
   bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override {
     header_ = QuicMakeUnique<QuicPacketHeader>((header));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return accept_public_header_;
   }
 
   bool OnUnauthenticatedHeader(const QuicPacketHeader& /*header*/) override {
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return true;
   }
 
-  void OnDecryptedPacket(EncryptionLevel /*level*/) override {}
+  void OnDecryptedPacket(EncryptionLevel /*level*/) override {
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
+  }
 
   bool OnPacketHeader(const QuicPacketHeader& header) override {
     ++packet_count_;
     header_ = QuicMakeUnique<QuicPacketHeader>((header));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return accept_packet_;
   }
 
@@ -259,6 +268,12 @@
     stream_data_.push_back(QuicWrapUnique(string_data));
     stream_frames_.push_back(QuicMakeUnique<QuicStreamFrame>(
         frame.stream_id, frame.fin, frame.offset, *string_data));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      // Low order bits of type encode flags, ignore them for this test.
+      EXPECT_TRUE(IS_IETF_STREAM_FRAME(framer_->current_received_frame_type()));
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
@@ -270,6 +285,11 @@
     crypto_data_.push_back(QuicWrapUnique(string_data));
     crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
         ENCRYPTION_INITIAL, frame.offset, *string_data));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_CRYPTO, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
@@ -280,12 +300,22 @@
     ack_frame.largest_acked = largest_acked;
     ack_frame.ack_delay_time = ack_delay_time;
     ack_frames_.push_back(QuicMakeUnique<QuicAckFrame>(ack_frame));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_ACK, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override {
     DCHECK(!ack_frames_.empty());
     ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end);
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_ACK, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
@@ -293,6 +323,7 @@
                       QuicTime timestamp) override {
     ack_frames_[ack_frames_.size() - 1]->received_packet_times.push_back(
         std::make_pair(packet_number, timestamp));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return true;
   }
 
@@ -301,17 +332,28 @@
   bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
     ++frame_count_;
     stop_waiting_frames_.push_back(QuicMakeUnique<QuicStopWaitingFrame>(frame));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return true;
   }
 
   bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
     padding_frames_.push_back(QuicMakeUnique<QuicPaddingFrame>(frame));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_PADDING, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnPingFrame(const QuicPingFrame& frame) override {
     ++frame_count_;
     ping_frames_.push_back(QuicMakeUnique<QuicPingFrame>(frame));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_PING, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
@@ -319,6 +361,14 @@
     ++frame_count_;
     message_frames_.push_back(
         QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length));
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_TRUE(IETF_EXTENSION_MESSAGE_NO_LENGTH ==
+                      framer_->current_received_frame_type() ||
+                  IETF_EXTENSION_MESSAGE ==
+                      framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
@@ -326,71 +376,128 @@
 
   bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
     rst_stream_frame_ = frame;
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_EQ(IETF_RST_STREAM, framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
     connection_close_frame_ = frame;
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_NE(GOOGLE_QUIC_CONNECTION_CLOSE, frame.close_type);
+      if (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
+        EXPECT_EQ(IETF_CONNECTION_CLOSE,
+                  framer_->current_received_frame_type());
+      } else {
+        EXPECT_EQ(IETF_APPLICATION_CLOSE,
+                  framer_->current_received_frame_type());
+      }
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override {
     stop_sending_frame_ = frame;
+    EXPECT_EQ(IETF_STOP_SENDING, framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     return true;
   }
 
   bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override {
     path_challenge_frame_ = frame;
+    EXPECT_EQ(IETF_PATH_CHALLENGE, framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     return true;
   }
 
   bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override {
     path_response_frame_ = frame;
+    EXPECT_EQ(IETF_PATH_RESPONSE, framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     return true;
   }
 
   bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
     goaway_frame_ = frame;
+    EXPECT_FALSE(VersionHasIetfQuicFrames(transport_version_));
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return true;
   }
 
   bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override {
     max_streams_frame_ = frame;
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
+    EXPECT_TRUE(IETF_MAX_STREAMS_UNIDIRECTIONAL ==
+                    framer_->current_received_frame_type() ||
+                IETF_MAX_STREAMS_BIDIRECTIONAL ==
+                    framer_->current_received_frame_type());
     return true;
   }
 
   bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override {
     streams_blocked_frame_ = frame;
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
+    EXPECT_TRUE(IETF_STREAMS_BLOCKED_UNIDIRECTIONAL ==
+                    framer_->current_received_frame_type() ||
+                IETF_STREAMS_BLOCKED_BIDIRECTIONAL ==
+                    framer_->current_received_frame_type());
     return true;
   }
 
   bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {
     window_update_frame_ = frame;
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_TRUE(IETF_MAX_DATA == framer_->current_received_frame_type() ||
+                  IETF_MAX_STREAM_DATA ==
+                      framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
     blocked_frame_ = frame;
+    if (VersionHasIetfQuicFrames(transport_version_)) {
+      EXPECT_TRUE(IETF_BLOCKED == framer_->current_received_frame_type() ||
+                  IETF_STREAM_BLOCKED ==
+                      framer_->current_received_frame_type());
+    } else {
+      EXPECT_EQ(0u, framer_->current_received_frame_type());
+    }
     return true;
   }
 
   bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override {
     new_connection_id_ = frame;
+    EXPECT_EQ(IETF_NEW_CONNECTION_ID, framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     return true;
   }
 
   bool OnRetireConnectionIdFrame(
       const QuicRetireConnectionIdFrame& frame) override {
+    EXPECT_EQ(IETF_RETIRE_CONNECTION_ID,
+              framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     retire_connection_id_ = frame;
     return true;
   }
 
   bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override {
     new_token_ = frame;
+    EXPECT_EQ(IETF_NEW_TOKEN, framer_->current_received_frame_type());
+    EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_));
     return true;
   }
 
   bool IsValidStatelessResetToken(QuicUint128 token) const override {
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
     return token == kTestStatelessResetToken;
   }
 
@@ -398,6 +505,12 @@
       const QuicIetfStatelessResetPacket& packet) override {
     stateless_reset_packet_ =
         QuicMakeUnique<QuicIetfStatelessResetPacket>(packet);
+    EXPECT_EQ(0u, framer_->current_received_frame_type());
+  }
+
+  void set_framer(QuicFramer* framer) {
+    framer_ = framer;
+    transport_version_ = framer->transport_version();
   }
 
   // Counters from the visitor_ callbacks.
@@ -442,6 +555,8 @@
   QuicNewTokenFrame new_token_;
   std::vector<std::unique_ptr<std::string>> stream_data_;
   std::vector<std::unique_ptr<std::string>> crypto_data_;
+  QuicTransportVersion transport_version_;
+  QuicFramer* framer_;
 };
 
 // Simple struct for defining a packet's content, and associated
@@ -478,6 +593,7 @@
 
     framer_.set_visitor(&visitor_);
     framer_.InferPacketHeaderTypeFromVersion();
+    visitor_.set_framer(&framer_);
   }
 
   void SetDecrypterLevel(EncryptionLevel level) {
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
index 8496718..24b8818 100644
--- a/quic/test_tools/quic_framer_peer.h
+++ b/quic/test_tools/quic_framer_peer.h
@@ -179,6 +179,12 @@
       uint8_t* destination_connection_id_length,
       uint8_t* source_connection_id_length,
       std::string* detailed_error);
+
+  static void set_current_received_frame_type(
+      QuicFramer* framer,
+      uint64_t current_received_frame_type) {
+    framer->current_received_frame_type_ = current_received_frame_type;
+  }
 };
 
 }  // namespace test