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 {