gfe-relnote: Use encryption level instead of looking for the string "CHLO" to identify the QUIC ClientHello.  Client side change only, not flag protected.

PiperOrigin-RevId: 241995962
Change-Id: I840eb7531ef55f32c7bb06bc08bcdb947459e732
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index d1200a9..27ff2b8 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -163,7 +163,7 @@
       if (!QuicVersionUsesCryptoFrames(framer_->transport_version())) {
         if (!creator_.ConsumeData(
                 QuicUtils::GetCryptoStreamId(framer_->transport_version()),
-                reject.length(), offset, offset,
+                reject.length() - offset, offset,
                 /*fin=*/false,
                 /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) {
           QUIC_BUG << "Unable to consume data into an empty packet.";
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index a3542d3..ca53ca4 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -5176,25 +5176,6 @@
   return header.long_packet_type == VERSION_NEGOTIATION;
 }
 
-bool QuicFramer::StartsWithChlo(QuicStreamId id,
-                                QuicStreamOffset offset) const {
-  if (data_producer_ == nullptr) {
-    QUIC_BUG << "Does not have data producer.";
-    return false;
-  }
-  char buf[sizeof(kCHLO)];
-  QuicDataWriter writer(sizeof(kCHLO), buf);
-  if (data_producer_->WriteStreamData(id, offset, sizeof(kCHLO), &writer) !=
-      WRITE_SUCCESS) {
-    QUIC_BUG << "Failed to write data for stream " << id << " with offset "
-             << offset << " data_length = " << sizeof(kCHLO);
-    return false;
-  }
-
-  return strncmp(buf, reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) ==
-         0;
-}
-
 bool QuicFramer::AppendIetfConnectionCloseFrame(
     const QuicConnectionCloseFrame& frame,
     QuicDataWriter* writer) {
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index d8c135a..b431f14 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -523,9 +523,6 @@
   // Tell framer to infer packet header type from version_.
   void InferPacketHeaderTypeFromVersion();
 
-  // Returns true if data with |offset| of stream |id| starts with 'CHLO'.
-  bool StartsWithChlo(QuicStreamId id, QuicStreamOffset offset) const;
-
   // Returns true if |header| is considered as an stateless reset packet.
   bool IsIetfStatelessResetPacket(const QuicPacketHeader& header) const;
 
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 9f0e700..e627579 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -9854,30 +9854,6 @@
                      framer_.version());
 }
 
-TEST_P(QuicFramerTest, StartsWithChlo) {
-  if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
-    // When client hellos are sent in crypto frames, this test doesn't make
-    // sense.
-    return;
-  }
-  SimpleDataProducer producer;
-  framer_.set_data_producer(&producer);
-  QuicStringPiece data("CHLOCHLO");
-  struct iovec iovec;
-  iovec.iov_base = const_cast<char*>(data.data());
-  iovec.iov_len = data.length();
-  QuicStreamId stream_id =
-      QuicUtils::GetCryptoStreamId(framer_.transport_version());
-  producer.SaveStreamData(stream_id, &iovec, 1, 0, data.length());
-  for (size_t offset = 0; offset < 5; ++offset) {
-    if (offset == 0 || offset == 4) {
-      EXPECT_TRUE(framer_.StartsWithChlo(stream_id, offset));
-    } else {
-      EXPECT_FALSE(framer_.StartsWithChlo(stream_id, offset));
-    }
-  }
-}
-
 TEST_P(QuicFramerTest, IetfBlockedFrame) {
   // This test only for version 99.
   if (framer_.transport_version() != QUIC_VERSION_99) {
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 951fb81..224aadf 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -174,30 +174,25 @@
 }
 
 bool QuicPacketCreator::ConsumeData(QuicStreamId id,
-                                    size_t write_length,
-                                    size_t iov_offset,
+                                    size_t data_size,
                                     QuicStreamOffset offset,
                                     bool fin,
                                     bool needs_full_padding,
                                     TransmissionType transmission_type,
                                     QuicFrame* frame) {
-  // TODO(ianswett): Remove write_length once the multi-packet CHLO check is
-  // done higher in the stack.
-  DCHECK_GE(write_length, iov_offset);
-  const size_t data_size = write_length - iov_offset;
   if (!HasRoomForStreamFrame(id, offset, data_size)) {
     return false;
   }
   CreateStreamFrame(id, data_size, offset, fin, frame);
   // Explicitly disallow multi-packet CHLOs.
   if (FLAGS_quic_enforce_single_packet_chlo &&
-      StreamFrameStartsWithChlo(frame->stream_frame) &&
-      frame->stream_frame.data_length < write_length) {
+      StreamFrameIsClientHello(frame->stream_frame) &&
+      frame->stream_frame.data_length < data_size) {
     const std::string error_details =
         "Client hello won't fit in a single packet.";
     QUIC_BUG << error_details << " Constructed stream frame length: "
              << frame->stream_frame.data_length
-             << " CHLO length: " << write_length;
+             << " CHLO length: " << data_size;
     delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
                                     ConnectionCloseSource::FROM_SELF);
     return false;
@@ -953,15 +948,15 @@
   pending_padding_bytes_ += size;
 }
 
-bool QuicPacketCreator::StreamFrameStartsWithChlo(
+bool QuicPacketCreator::StreamFrameIsClientHello(
     const QuicStreamFrame& frame) const {
   if (framer_->perspective() == Perspective::IS_SERVER ||
       frame.stream_id !=
-          QuicUtils::GetCryptoStreamId(framer_->transport_version()) ||
-      frame.data_length < sizeof(kCHLO)) {
+          QuicUtils::GetCryptoStreamId(framer_->transport_version())) {
     return false;
   }
-  return framer_->StartsWithChlo(frame.stream_id, frame.offset);
+  // The ClientHello is always sent with INITIAL encryption.
+  return packet_.encryption_level == ENCRYPTION_INITIAL;
 }
 
 void QuicPacketCreator::SetConnectionIdIncluded(
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h
index 150cb9c..7c8f496 100644
--- a/quic/core/quic_packet_creator.h
+++ b/quic/core/quic_packet_creator.h
@@ -96,8 +96,7 @@
   // If current packet is not full, creates a stream frame that fits into the
   // open packet and adds it to the packet.
   bool ConsumeData(QuicStreamId id,
-                   size_t write_length,
-                   size_t iov_offset,
+                   size_t data_length,
                    QuicStreamOffset offset,
                    bool fin,
                    bool needs_full_padding,
@@ -352,8 +351,8 @@
   // wire. Is non-zero for v99 IETF Initial, 0-RTT or Handshake packets.
   QuicVariableLengthIntegerLength GetLengthLength() const;
 
-  // Returns true if |frame| starts with CHLO.
-  bool StreamFrameStartsWithChlo(const QuicStreamFrame& frame) const;
+  // Returns true if |frame| is a ClientHello.
+  bool StreamFrameIsClientHello(const QuicStreamFrame& frame) const;
 
   // Returns true if packet under construction has IETF long header.
   bool HasIetfLongHeader() const;
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 1cdc3e4..aea0540 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -97,7 +97,7 @@
     if (data_length > 0) {
       producer_->SaveStreamData(id, iov, iov_count, iov_offset, data_length);
     }
-    return QuicPacketCreator::ConsumeData(id, data_length, iov_offset, offset,
+    return QuicPacketCreator::ConsumeData(id, data_length - iov_offset, offset,
                                           fin, needs_full_padding,
                                           transmission_type, frame);
   }
@@ -693,6 +693,9 @@
 }
 
 TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
+  // This test serializes crypto payloads slightly larger than a packet, which
+  // Causes the multi-packet ClientHello check to fail.
+  FLAGS_quic_enforce_single_packet_chlo = false;
   // Compute the total overhead for a single frame in packet.
   size_t overhead =
       GetPacketHeaderOverhead(client_framer_.transport_version()) +
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc
index 257ca9b..8267ade 100644
--- a/quic/core/quic_packet_generator.cc
+++ b/quic/core/quic_packet_generator.cc
@@ -148,7 +148,7 @@
     bool needs_full_padding =
         has_handshake && fully_pad_crypto_handshake_packets_;
 
-    if (!packet_creator_.ConsumeData(id, write_length, total_bytes_consumed,
+    if (!packet_creator_.ConsumeData(id, write_length - total_bytes_consumed,
                                      offset + total_bytes_consumed, fin,
                                      needs_full_padding,
                                      next_transmission_type_, &frame)) {