Allow minimum size QUIC packets.
Protected by FLAGS_quic_restart_flag_quic_allow_smaller_packets.
PiperOrigin-RevId: 496688436
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 653029c..2b404a7 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -63,6 +63,8 @@
QUIC_FLAG(quic_reloadable_flag_quic_remove_connection_migration_connection_option_v2, false)
// If true, include stream information in idle timeout connection close detail.
QUIC_FLAG(quic_reloadable_flag_quic_add_stream_info_to_idle_close_detail, true)
+// If true, lowers the minimum packet size to that in the spec.
+QUIC_FLAG(quic_restart_flag_quic_allow_smaller_packets, false)
// If true, quic server will send ENABLE_CONNECT_PROTOCOL setting and and endpoint will validate required request/response headers and extended CONNECT mechanism and update code counts of valid/invalid headers.
QUIC_FLAG(quic_reloadable_flag_quic_verify_request_headers_2, true)
// If true, reject or send error response code upon receiving invalid request or response headers. This flag depends on --gfe2_reloadable_flag_quic_verify_request_headers_2.
diff --git a/quiche/quic/core/quic_packet_creator.cc b/quiche/quic/core/quic_packet_creator.cc
index ad4e785..cfcd3e2 100644
--- a/quiche/quic/core/quic_packet_creator.cc
+++ b/quiche/quic/core/quic_packet_creator.cc
@@ -19,6 +19,7 @@
#include "absl/types/optional.h"
#include "quiche/quic/core/crypto/crypto_protocol.h"
#include "quiche/quic/core/frames/quic_frame.h"
+#include "quiche/quic/core/frames/quic_padding_frame.h"
#include "quiche/quic/core/frames/quic_path_challenge_frame.h"
#include "quiche/quic/core/frames/quic_stream_frame.h"
#include "quiche/quic/core/quic_chaos_protector.h"
@@ -167,8 +168,10 @@
max_packet_length_ = length;
max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
- QUIC_BUG_IF(quic_bug_12398_2, max_plaintext_size_ - PacketHeaderSize() <
- MinPlaintextPacketSize(framer_->version()))
+ QUIC_BUG_IF(
+ quic_bug_12398_2,
+ max_plaintext_size_ - PacketHeaderSize() <
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength()))
<< ENDPOINT << "Attempted to set max packet length too small";
}
@@ -197,7 +200,8 @@
return;
}
if (framer_->GetMaxPlaintextSize(length) <
- PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) {
+ PacketHeaderSize() +
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength())) {
// Please note: this would not guarantee to fit next packet if the size of
// packet header increases (e.g., encryption level changes).
QUIC_DLOG(INFO) << ENDPOINT << length
@@ -611,16 +615,20 @@
size_t bytes_consumed = std::min<size_t>(available_size, remaining_data_size);
size_t plaintext_bytes_written = min_frame_size + bytes_consumed;
bool needs_padding = false;
- if (plaintext_bytes_written < MinPlaintextPacketSize(framer_->version())) {
+ const size_t min_plaintext_size =
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength());
+ if (plaintext_bytes_written < min_plaintext_size) {
needs_padding = true;
- // Recalculate sizes with the stream frame not being marked as the last
- // frame in the packet.
- min_frame_size = QuicFramer::GetMinStreamFrameSize(
- framer_->transport_version(), id, stream_offset,
- /* last_frame_in_packet= */ false, remaining_data_size);
- available_size = max_plaintext_size_ - writer.length() - min_frame_size;
- bytes_consumed = std::min<size_t>(available_size, remaining_data_size);
- plaintext_bytes_written = min_frame_size + bytes_consumed;
+ if (!GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ // Recalculate sizes with the stream frame not being marked as the last
+ // frame in the packet.
+ min_frame_size = QuicFramer::GetMinStreamFrameSize(
+ framer_->transport_version(), id, stream_offset,
+ /* last_frame_in_packet= */ false, remaining_data_size);
+ available_size = max_plaintext_size_ - writer.length() - min_frame_size;
+ bytes_consumed = std::min<size_t>(available_size, remaining_data_size);
+ plaintext_bytes_written = min_frame_size + bytes_consumed;
+ }
}
const bool set_fin = fin && (bytes_consumed == remaining_data_size);
@@ -634,6 +642,15 @@
// TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized
// into one method that takes a QuicStreamFrame, if warranted.
+ if (needs_padding && GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_allow_smaller_packets, 2, 5);
+ if (!writer.WritePaddingBytes(min_plaintext_size -
+ plaintext_bytes_written)) {
+ QUIC_BUG(quic_bug_10752_12) << ENDPOINT << "Unable to add padding bytes";
+ return;
+ }
+ needs_padding = false;
+ }
bool omit_frame_length = !needs_padding;
if (!framer_->AppendTypeByte(QuicFrame(frame), omit_frame_length, &writer)) {
QUIC_BUG(quic_bug_10752_10) << ENDPOINT << "AppendTypeByte failed";
@@ -643,10 +660,8 @@
QUIC_BUG(quic_bug_10752_11) << ENDPOINT << "AppendStreamFrame failed";
return;
}
- if (needs_padding &&
- plaintext_bytes_written < MinPlaintextPacketSize(framer_->version()) &&
- !writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) -
- plaintext_bytes_written)) {
+ if (needs_padding && plaintext_bytes_written < min_plaintext_size &&
+ !writer.WritePaddingBytes(min_plaintext_size - plaintext_bytes_written)) {
QUIC_BUG(quic_bug_10752_12) << ENDPOINT << "Unable to add padding bytes";
return;
}
@@ -737,6 +752,18 @@
std::min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame());
}
+size_t QuicPacketCreator::BytesFreeForPadding() const {
+ size_t consumed = PacketSize();
+
+ if (!GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ consumed += ExpansionOnNewFrame();
+ } else {
+ // The next frame (which is PADDING) will be prepended to the packet.
+ QUIC_RESTART_FLAG_COUNT_N(quic_allow_smaller_packets, 5, 5);
+ }
+ return max_plaintext_size_ - std::min(max_plaintext_size_, consumed);
+}
+
size_t QuicPacketCreator::PacketSize() const {
return queued_frames_.empty() ? PacketHeaderSize() : packet_size_;
}
@@ -1680,7 +1707,8 @@
// Calculate frame bytes and bytes free with this frame added.
const size_t frame_bytes = PacketSize() - PacketHeaderSize() +
ExpansionOnNewFrame() + serialized_frame_length;
- if (frame_bytes >= MinPlaintextPacketSize(framer_->version())) {
+ if (frame_bytes >=
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength())) {
// No extra bytes is needed.
return serialized_frame_length;
}
@@ -1694,7 +1722,8 @@
// padding + expansion.
const size_t extra_bytes_needed = std::max(
1 + ExpansionOnNewFrameWithLastFrame(frame, framer_->transport_version()),
- MinPlaintextPacketSize(framer_->version()) - frame_bytes);
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength()) -
+ frame_bytes);
if (bytes_free < extra_bytes_needed) {
// This frame does not fit.
return 0;
@@ -1814,13 +1843,24 @@
return;
}
const size_t frame_bytes = PacketSize() - PacketHeaderSize();
- if (frame_bytes >= MinPlaintextPacketSize(framer_->version())) {
+ if (frame_bytes >=
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength())) {
return;
}
- const QuicByteCount min_header_protection_padding =
- std::max(1 + ExpansionOnNewFrame(),
- MinPlaintextPacketSize(framer_->version()) - frame_bytes) -
- ExpansionOnNewFrame();
+ QuicByteCount min_header_protection_padding;
+ if (GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_allow_smaller_packets, 4, 5);
+ min_header_protection_padding =
+ MinPlaintextPacketSize(framer_->version(), GetPacketNumberLength()) -
+ frame_bytes;
+ } else {
+ min_header_protection_padding =
+ std::max(1 + ExpansionOnNewFrame(),
+ MinPlaintextPacketSize(framer_->version(),
+ GetPacketNumberLength()) -
+ frame_bytes) -
+ ExpansionOnNewFrame();
+ }
// Update pending_padding_bytes_.
pending_padding_bytes_ =
std::max(pending_padding_bytes_, min_header_protection_padding);
@@ -1876,7 +1916,7 @@
void QuicPacketCreator::MaybeAddPadding() {
// The current packet should have no padding bytes because padding is only
// added when this method is called just before the packet is serialized.
- if (BytesFree() == 0) {
+ if (BytesFreeForPadding() == 0) {
// Don't pad full packets.
return;
}
@@ -1903,15 +1943,36 @@
int padding_bytes = -1;
if (!needs_full_padding_) {
- padding_bytes = std::min<int16_t>(pending_padding_bytes_, BytesFree());
+ padding_bytes =
+ std::min<int16_t>(pending_padding_bytes_, BytesFreeForPadding());
pending_padding_bytes_ -= padding_bytes;
}
- bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)),
- packet_.transmission_type);
- QUIC_BUG_IF(quic_bug_10752_36, !success)
- << ENDPOINT << "Failed to add padding_bytes: " << padding_bytes
- << " transmission_type: " << packet_.transmission_type;
+ if (!queued_frames_.empty() &&
+ GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ // Insert PADDING before the other frames to avoid adding a length field
+ // to any trailing STREAM frame.
+ QUIC_RESTART_FLAG_COUNT_N(quic_allow_smaller_packets, 3, 5);
+ if (needs_full_padding_) {
+ padding_bytes = BytesFreeForPadding();
+ }
+ // AddFrame cannot be used here because it adds the frame to the end of the
+ // packet.
+ QuicFrame frame{QuicPaddingFrame(padding_bytes)};
+ queued_frames_.insert(queued_frames_.begin(), frame);
+ packet_size_ += padding_bytes;
+ packet_.nonretransmittable_frames.push_back(frame);
+ if (packet_.transmission_type == NOT_RETRANSMISSION) {
+ packet_.bytes_not_retransmitted.emplace(
+ packet_.bytes_not_retransmitted.value_or(0) + padding_bytes);
+ }
+ } else {
+ bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)),
+ packet_.transmission_type);
+ QUIC_BUG_IF(quic_bug_10752_36, !success)
+ << ENDPOINT << "Failed to add padding_bytes: " << padding_bytes
+ << " transmission_type: " << packet_.transmission_type;
+ }
}
bool QuicPacketCreator::IncludeNonceInPublicHeader() const {
@@ -2055,7 +2116,8 @@
// static
size_t QuicPacketCreator::MinPlaintextPacketSize(
- const ParsedQuicVersion& version) {
+ const ParsedQuicVersion& version,
+ QuicPacketNumberLength packet_number_length) {
if (!version.HasHeaderProtection()) {
return 0;
}
@@ -2077,7 +2139,10 @@
// 1.3 is used, unittests still use NullEncrypter/NullDecrypter (and other
// test crypters) which also only use 12 byte tags.
//
- // TODO(b/234061734): Set this based on the handshake protocol in use.
+ if (GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ QUIC_RESTART_FLAG_COUNT_N(quic_allow_smaller_packets, 1, 5);
+ return (version.UsesTls() ? 4 : 8) - packet_number_length;
+ }
return 7;
}
diff --git a/quiche/quic/core/quic_packet_creator.h b/quiche/quic/core/quic_packet_creator.h
index 0bcd745..785efb1 100644
--- a/quiche/quic/core/quic_packet_creator.h
+++ b/quiche/quic/core/quic_packet_creator.h
@@ -212,6 +212,10 @@
// value than max_packet_size - PacketSize(), in this case.
size_t BytesFree() const;
+ // Since PADDING frames are always prepended, a separate function computes
+ // available space without considering STREAM frame expansion.
+ size_t BytesFreeForPadding() const;
+
// Returns the number of bytes that the packet will expand by if a new frame
// is added to the packet. If the last frame was a stream frame, it will
// expand slightly when a new frame is added, and this method returns the
@@ -428,7 +432,9 @@
}
// Returns the minimum size that the plaintext of a packet must be.
- static size_t MinPlaintextPacketSize(const ParsedQuicVersion& version);
+ static size_t MinPlaintextPacketSize(
+ const ParsedQuicVersion& version,
+ QuicPacketNumberLength packet_number_length);
// Indicates whether packet flusher is currently attached.
bool PacketFlusherAttached() const;
diff --git a/quiche/quic/core/quic_packet_creator_test.cc b/quiche/quic/core/quic_packet_creator_test.cc
index f71d9e4..6dcd4a5 100644
--- a/quiche/quic/core/quic_packet_creator_test.cc
+++ b/quiche/quic/core/quic_packet_creator_test.cc
@@ -279,17 +279,24 @@
::testing::PrintToStringParamName());
TEST_P(QuicPacketCreatorTest, SerializeFrames) {
+ ParsedQuicVersion version = client_framer_.version();
for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) {
EncryptionLevel level = static_cast<EncryptionLevel>(i);
+ bool has_ack = false, has_stream = false;
creator_.set_encryption_level(level);
+ size_t payload_len = 0;
if (level != ENCRYPTION_ZERO_RTT) {
frames_.push_back(QuicFrame(new QuicAckFrame(InitAckFrame(1))));
+ has_ack = true;
+ payload_len += version.UsesTls() ? 12 : 6;
}
- QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
- client_framer_.transport_version(), Perspective::IS_CLIENT);
if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) {
+ QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
+ client_framer_.transport_version(), Perspective::IS_CLIENT);
frames_.push_back(QuicFrame(
QuicStreamFrame(stream_id, false, 0u, absl::string_view())));
+ has_stream = true;
+ payload_len += 2;
}
SerializedPacket serialized = SerializeAllFrames(frames_);
EXPECT_EQ(level, serialized.encryption_level);
@@ -297,7 +304,13 @@
delete frames_[0].ack_frame;
}
frames_.clear();
-
+ ASSERT_GT(payload_len, 0); // Must have a frame!
+ size_t min_payload =
+ (version.UsesTls() && GetQuicRestartFlag(quic_allow_smaller_packets))
+ ? 3
+ : 7;
+ bool need_padding =
+ (version.HasHeaderProtection() && (payload_len < min_payload));
{
InSequence s;
EXPECT_CALL(framer_visitor_, OnPacket());
@@ -305,7 +318,10 @@
EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- if (level != ENCRYPTION_ZERO_RTT) {
+ if (need_padding && GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ }
+ if (has_ack) {
EXPECT_CALL(framer_visitor_, OnAckFrameStart(_, _))
.WillOnce(Return(true));
EXPECT_CALL(framer_visitor_,
@@ -314,12 +330,11 @@
EXPECT_CALL(framer_visitor_, OnAckFrameEnd(QuicPacketNumber(1)))
.WillOnce(Return(true));
}
- if (level != ENCRYPTION_INITIAL && level != ENCRYPTION_HANDSHAKE) {
+ if (has_stream) {
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
}
- if (client_framer_.version().HasHeaderProtection()) {
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_))
- .Times(testing::AnyNumber());
+ if (need_padding && !GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
@@ -409,8 +424,10 @@
const size_t overhead =
GetPacketHeaderOverhead(client_framer_.transport_version()) +
GetEncryptionOverhead();
- for (size_t i = overhead + QuicPacketCreator::MinPlaintextPacketSize(
- client_framer_.version());
+ for (size_t i = overhead +
+ QuicPacketCreator::MinPlaintextPacketSize(
+ client_framer_.version(),
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
i < overhead + 100; ++i) {
SCOPED_TRACE(i);
creator_.SetMaxPacketLength(i);
@@ -478,7 +495,12 @@
overhead +=
QuicFramer::GetMinCryptoFrameSize(kOffset, kMaxOutgoingPacketSize);
} else {
- overhead += GetStreamFrameOverhead(client_framer_.transport_version());
+ overhead +=
+ GetQuicRestartFlag(quic_allow_smaller_packets)
+ ? QuicFramer::GetMinStreamFrameSize(
+ client_framer_.transport_version(),
+ GetNthClientInitiatedStreamId(1), kOffset, false, 0)
+ : GetStreamFrameOverhead(client_framer_.transport_version());
}
ASSERT_GT(kMaxOutgoingPacketSize, overhead);
size_t capacity = kDefaultMaxPacketSize - overhead;
@@ -516,7 +538,7 @@
// (1 byte) and to expand the stream frame (another 2 bytes) the packet
// will not be padded.
// Padding is skipped when we try to send coalesced packets.
- if ((bytes_free < 3 &&
+ if ((!GetQuicRestartFlag(quic_allow_smaller_packets) && bytes_free < 3 &&
!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) ||
client_framer_.version().CanSendCoalescedPackets()) {
EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
@@ -1495,20 +1517,20 @@
}
EXPECT_FALSE(creator_.HasPendingFrames());
- // Send one byte of stream data.
- const std::string data("a");
- producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), data);
+ // Send zero bytes of stream data. This requires padding.
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
size_t num_bytes_consumed;
- creator_.CreateAndSerializeStreamFrame(
- GetNthClientInitiatedStreamId(0), data.length(), 0, 0, true,
- NOT_RETRANSMISSION, &num_bytes_consumed);
- EXPECT_EQ(1u, num_bytes_consumed);
+ creator_.CreateAndSerializeStreamFrame(GetNthClientInitiatedStreamId(0), 0, 0,
+ 0, true, NOT_RETRANSMISSION,
+ &num_bytes_consumed);
+ EXPECT_EQ(0u, num_bytes_consumed);
// Check that a packet is created.
ASSERT_TRUE(serialized_packet_->encrypted_buffer);
ASSERT_FALSE(serialized_packet_->retransmittable_frames.empty());
+ ASSERT_EQ(serialized_packet_->packet_number_length,
+ PACKET_1BYTE_PACKET_NUMBER);
{
InSequence s;
EXPECT_CALL(framer_visitor_, OnPacket());
@@ -1516,9 +1538,16 @@
EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
if (client_framer_.version().HasHeaderProtection()) {
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ if (GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ } else {
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ }
+ } else {
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
}
EXPECT_CALL(framer_visitor_, OnPacketComplete());
}
@@ -1639,13 +1668,14 @@
// 1.
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- size_t length =
- GetPacketHeaderOverhead(client_framer_.transport_version()) +
- GetEncryptionOverhead() +
- QuicFramer::GetMinStreamFrameSize(
- client_framer_.transport_version(), stream_id, 0,
- /*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) +
- kStreamFramePayloadSize + 1;
+ size_t length = GetPacketHeaderOverhead(client_framer_.transport_version()) +
+ GetEncryptionOverhead() +
+ QuicFramer::GetMinStreamFrameSize(
+ client_framer_.transport_version(), stream_id, 0,
+ /*last_frame_in_packet=*/
+ GetQuicRestartFlag(quic_allow_smaller_packets),
+ kStreamFramePayloadSize + 1) +
+ kStreamFramePayloadSize + 1;
creator_.SetMaxPacketLength(length);
creator_.AddPendingPadding(kMaxNumRandomPaddingBytes);
QuicByteCount pending_padding_bytes = creator_.pending_padding_bytes();
@@ -2098,8 +2128,13 @@
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
.WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
+ if (client_framer_.version().HasHeaderProtection() &&
+ GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ }
EXPECT_CALL(framer_visitor_, OnPingFrame(_));
- if (client_framer_.version().HasHeaderProtection()) {
+ if (client_framer_.version().HasHeaderProtection() &&
+ !GetQuicRestartFlag(quic_allow_smaller_packets)) {
EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
EXPECT_CALL(framer_visitor_, OnPacketComplete());
@@ -2277,27 +2312,38 @@
EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_, _));
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
if (i != ENCRYPTION_ZERO_RTT) {
+ if (GetQuicRestartFlag(quic_allow_smaller_packets) &&
+ i != ENCRYPTION_INITIAL) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_))
+ .Times(testing::AtMost(1));
+ }
EXPECT_CALL(framer_visitor_, OnAckFrameStart(_, _))
.WillOnce(Return(true));
EXPECT_CALL(framer_visitor_,
OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)))
.WillOnce(Return(true));
EXPECT_CALL(framer_visitor_, OnAckFrameEnd(_)).WillOnce(Return(true));
+ if (!GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_))
+ .Times(testing::AtMost(1));
+ }
}
if (i == ENCRYPTION_INITIAL) {
// Verify padding is added.
EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- } else if (i != ENCRYPTION_ZERO_RTT) {
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)).Times(testing::AtMost(1));
+ }
+ if (GetQuicRestartFlag(quic_allow_smaller_packets) &&
+ i == ENCRYPTION_ZERO_RTT) {
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
if (i != ENCRYPTION_INITIAL && i != ENCRYPTION_HANDSHAKE) {
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
}
- if (i == ENCRYPTION_ZERO_RTT) {
+ if (!GetQuicRestartFlag(quic_allow_smaller_packets) &&
+ i == ENCRYPTION_ZERO_RTT) {
EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
}
EXPECT_CALL(framer_visitor_, OnPacketComplete());
-
server_framer_.ProcessPacket(*packets[i]);
}
}
@@ -2307,7 +2353,9 @@
QuicByteCount previous_max_packet_length = creator_.max_packet_length();
const size_t overhead =
GetPacketHeaderOverhead(client_framer_.transport_version()) +
- QuicPacketCreator::MinPlaintextPacketSize(client_framer_.version()) +
+ QuicPacketCreator::MinPlaintextPacketSize(
+ client_framer_.version(),
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)) +
GetEncryptionOverhead();
// Make sure a length which cannot accommodate header (includes header
// protection minimal length) gets rejected.
@@ -2382,7 +2430,9 @@
const QuicByteCount previous_max_packet_length = creator_.max_packet_length();
const size_t min_acceptable_packet_size =
GetPacketHeaderOverhead(client_framer_.transport_version()) +
- QuicPacketCreator::MinPlaintextPacketSize(client_framer_.version()) +
+ QuicPacketCreator::MinPlaintextPacketSize(
+ client_framer_.version(),
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)) +
GetEncryptionOverhead();
// Then set the soft max packet length to the lowest allowed value.
creator_.SetSoftMaxPacketLength(min_acceptable_packet_size);
@@ -2398,6 +2448,88 @@
EXPECT_EQ(creator_.max_packet_length(), previous_max_packet_length);
}
+TEST_P(QuicPacketCreatorTest, MinPayloadLength) {
+ ParsedQuicVersion version = client_framer_.version();
+ for (QuicPacketNumberLength pn_length :
+ {PACKET_1BYTE_PACKET_NUMBER, PACKET_2BYTE_PACKET_NUMBER,
+ PACKET_3BYTE_PACKET_NUMBER, PACKET_4BYTE_PACKET_NUMBER}) {
+ if (!version.HasHeaderProtection()) {
+ EXPECT_EQ(creator_.MinPlaintextPacketSize(version, pn_length), 0);
+ } else if (!GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_EQ(creator_.MinPlaintextPacketSize(version, pn_length), 7);
+ } else {
+ EXPECT_EQ(creator_.MinPlaintextPacketSize(version, pn_length),
+ (version.UsesTls() ? 4 : 8) - pn_length);
+ }
+ }
+}
+
+// A variant of StreamFrameConsumption that tests when expansion of the stream
+// frame puts it at or over the max length, but the packet is supposed to be
+// padded to max length.
+TEST_P(QuicPacketCreatorTest, PadWhenAlmostMaxLength) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Compute the total overhead for a single frame in packet.
+ const size_t overhead =
+ GetPacketHeaderOverhead(client_framer_.transport_version()) +
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.transport_version());
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ for (size_t bytes_free = 1; bytes_free <= 2; bytes_free++) {
+ std::string data(capacity - bytes_free, 'A');
+
+ QuicFrame frame;
+ ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
+ GetNthClientInitiatedStreamId(1), data, kOffset, false,
+ /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
+
+ // BytesFree() returns bytes available for the next frame, which will
+ // be two bytes smaller since the stream frame would need to be grown.
+ EXPECT_EQ(2u, creator_.ExpansionOnNewFrame());
+ EXPECT_EQ(0u, creator_.BytesFree());
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.FlushCurrentPacket();
+ /* Without the fix, the packet is not full-length. */
+ if (GetQuicRestartFlag(quic_allow_smaller_packets)) {
+ EXPECT_EQ(serialized_packet_->encrypted_length, kDefaultMaxPacketSize);
+ } else {
+ EXPECT_EQ(serialized_packet_->encrypted_length,
+ kDefaultMaxPacketSize - bytes_free);
+ }
+ DeleteSerializedPacket();
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, MorePendingPaddingThanBytesFree) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Compute the total overhead for a single frame in packet.
+ const size_t overhead =
+ GetPacketHeaderOverhead(client_framer_.transport_version()) +
+ GetEncryptionOverhead() +
+ GetStreamFrameOverhead(client_framer_.transport_version());
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ const size_t pending_padding = 10;
+ std::string data(capacity - pending_padding, 'A');
+ QuicFrame frame;
+ // The stream frame means that BytesFree() will be less than the
+ // available space, because of the frame length field.
+ ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
+ GetNthClientInitiatedStreamId(1), data, kOffset, false,
+ /*needs_full_padding=*/false, NOT_RETRANSMISSION, &frame));
+ creator_.AddPendingPadding(pending_padding);
+ EXPECT_EQ(2u, creator_.ExpansionOnNewFrame());
+ // BytesFree() does not know about pending_padding because that's added
+ // when flushed.
+ EXPECT_EQ(pending_padding - 2u, creator_.BytesFree());
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.FlushCurrentPacket();
+ /* Without the fix, the packet is not full-length. */
+ EXPECT_EQ(serialized_packet_->encrypted_length, kDefaultMaxPacketSize);
+ DeleteSerializedPacket();
+}
+
class MockDelegate : public QuicPacketCreator::DelegateInterface {
public:
MockDelegate() {}
@@ -2603,7 +2735,6 @@
if (num_retransmittable_frames == 0) {
ASSERT_TRUE(packet.retransmittable_frames.empty());
} else {
- ASSERT_FALSE(packet.retransmittable_frames.empty());
EXPECT_EQ(num_retransmittable_frames,
packet.retransmittable_frames.size());
}
@@ -2926,7 +3057,8 @@
// frames, so the expected packet length differs slightly.
expected_packet_length = 32;
}
- if (framer_.version().HasHeaderProtection()) {
+ if (framer_.version().HasHeaderProtection() &&
+ !GetQuicRestartFlag(quic_allow_smaller_packets)) {
expected_packet_length = 33;
}
EXPECT_EQ(expected_packet_length, packets_[0].encrypted_length);
@@ -3872,18 +4004,22 @@
return;
}
delegate_.SetCanWriteAnything();
-
+ // If the packet number length > 1, we won't get padding.
+ EXPECT_EQ(QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ PACKET_1BYTE_PACKET_NUMBER);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ // with no data and no offset, this is a 2B STREAM frame.
creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- "a", 0, FIN);
+ "", 0, FIN);
creator_.Flush();
ASSERT_FALSE(packets_[0].nonretransmittable_frames.empty());
QuicFrame padding = packets_[0].nonretransmittable_frames[0];
// Verify stream frame expansion is excluded.
- EXPECT_EQ(3, padding.padding_frame.num_padding_bytes);
+ EXPECT_EQ(padding.padding_frame.num_padding_bytes,
+ GetQuicRestartFlag(quic_allow_smaller_packets) ? 1 : 4);
}
TEST_F(QuicPacketCreatorMultiplePacketsTest,
diff --git a/quiche/quic/test_tools/quic_test_utils.cc b/quiche/quic/test_tools/quic_test_utils.cc
index 8063aa2..62c8f69 100644
--- a/quiche/quic/test_tools/quic_test_utils.cc
+++ b/quiche/quic/test_tools/quic_test_utils.cc
@@ -939,8 +939,8 @@
// We need a minimum number of bytes of encrypted payload. This will
// guarantee that we have at least that much. (It ignores the overhead of
// the stream/crypto framing, so it overpads slightly.)
- size_t min_plaintext_size =
- QuicPacketCreator::MinPlaintextPacketSize(version);
+ size_t min_plaintext_size = QuicPacketCreator::MinPlaintextPacketSize(
+ version, packet_number_length);
if (data.length() < min_plaintext_size) {
size_t padding_length = min_plaintext_size - data.length();
frames.push_back(QuicFrame(QuicPaddingFrame(padding_length)));