gfe-relnote: In QUIC v48, support partial write of CRYPTO frames. Protected by existing gfe2_reloadable_flag_quic_enable_version_48.

PiperOrigin-RevId: 264373472
Change-Id: I285900280e459bbd70e519ec1e78dc2fa518e4c4
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 395b490..9d70139 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -154,6 +154,7 @@
     QUIC_BUG << "Empty crypto data being written";
     return;
   }
+  const bool had_buffered_data = HasBufferedCryptoFrames();
   // Append |data| to the send buffer for this encryption level.
   struct iovec iov(QuicUtils::MakeIovec(data));
   QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
@@ -167,16 +168,16 @@
     CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW,
                                "Writing too much crypto handshake data");
   }
+  if (had_buffered_data) {
+    // Do not try to write if there is buffered data.
+    return;
+  }
 
   EncryptionLevel current_level = session()->connection()->encryption_level();
   session()->connection()->SetDefaultEncryptionLevel(level);
   size_t bytes_consumed =
       session()->connection()->SendCryptoData(level, data.length(), offset);
   session()->connection()->SetDefaultEncryptionLevel(current_level);
-  // Since CRYPTO frames aren't flow controlled, SendCryptoData should have sent
-  // all data we asked it to send.
-  DCHECK_EQ(bytes_consumed, data.length());
-
   send_buffer->OnStreamDataConsumed(bytes_consumed);
 }
 
@@ -412,6 +413,48 @@
   session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
 }
 
+void QuicCryptoStream::WriteBufferedCryptoFrames() {
+  QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(
+      session()->connection()->transport_version()))
+      << "Versions less than 47 don't use CRYPTO frames";
+  EncryptionLevel current_encryption_level =
+      session()->connection()->encryption_level();
+  for (EncryptionLevel level :
+       {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+    QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
+    const size_t data_length =
+        send_buffer->stream_offset() - send_buffer->stream_bytes_written();
+    if (data_length == 0) {
+      // No buffered data for this encryption level.
+      continue;
+    }
+    session()->connection()->SetDefaultEncryptionLevel(level);
+    size_t bytes_consumed = session()->connection()->SendCryptoData(
+        level, data_length, send_buffer->stream_bytes_written());
+    send_buffer->OnStreamDataConsumed(bytes_consumed);
+    if (bytes_consumed < data_length) {
+      // Connection is write blocked.
+      break;
+    }
+  }
+  session()->connection()->SetDefaultEncryptionLevel(current_encryption_level);
+}
+
+bool QuicCryptoStream::HasBufferedCryptoFrames() const {
+  QUIC_BUG_IF(!QuicVersionUsesCryptoFrames(
+      session()->connection()->transport_version()))
+      << "Versions less than 47 don't use CRYPTO frames";
+  for (EncryptionLevel level :
+       {ENCRYPTION_INITIAL, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+    const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer;
+    DCHECK_GE(send_buffer.stream_offset(), send_buffer.stream_bytes_written());
+    if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level,
                                           size_t offset,
                                           size_t length) const {