Add transport parameter 'discard' to QUIC and switch connection option `CHP1` and `CHP2` to use it.
This parameter is meant to be discarded by the receiver. It is mainly used to make the ClientHello larger for testing.
PiperOrigin-RevId: 691180591
diff --git a/quiche/quic/core/crypto/transport_parameters.cc b/quiche/quic/core/crypto/transport_parameters.cc
index 0456134..f03e67e 100644
--- a/quiche/quic/core/crypto/transport_parameters.cc
+++ b/quiche/quic/core/crypto/transport_parameters.cc
@@ -57,6 +57,9 @@
kMaxDatagramFrameSize = 0x20,
+ // https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test
+ kDiscard = 0x173E,
+
kGoogleHandshakeMessage = 0x26ab,
kInitialRoundTripTime = 0x3127,
@@ -71,8 +74,9 @@
kMinAckDelay = 0xDE1A, // draft-iyengar-quic-delayed-ack.
kVersionInformation = 0xFF73DB, // draft-ietf-quic-version-negotiation.
- kReliableStreamReset = 0x17F7586D2CB571,
+
// draft-ietf-quic-reliable-stream-reset.
+ kReliableStreamReset = 0x17F7586D2CB571,
};
namespace {
@@ -130,6 +134,8 @@
return "retry_source_connection_id";
case TransportParameters::kMaxDatagramFrameSize:
return "max_datagram_frame_size";
+ case TransportParameters::kDiscard:
+ return "discard";
case TransportParameters::kGoogleHandshakeMessage:
return "google_handshake_message";
case TransportParameters::kInitialRoundTripTime:
@@ -169,6 +175,7 @@
case TransportParameters::kInitialSourceConnectionId:
case TransportParameters::kRetrySourceConnectionId:
case TransportParameters::kMaxDatagramFrameSize:
+ case TransportParameters::kDiscard:
case TransportParameters::kGoogleHandshakeMessage:
case TransportParameters::kInitialRoundTripTime:
case TransportParameters::kGoogleConnectionOptions:
@@ -439,6 +446,10 @@
retry_source_connection_id->ToString();
}
rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
+ if (discard_length >= 0) {
+ absl::StrAppend(&rv, " ", TransportParameterIdToString(kDiscard),
+ " length: ", discard_length);
+ }
if (google_handshake_message.has_value()) {
absl::StrAppend(&rv, " ",
TransportParameterIdToString(kGoogleHandshakeMessage),
@@ -532,6 +543,7 @@
max_datagram_frame_size(other.max_datagram_frame_size),
reliable_stream_reset(other.reliable_stream_reset),
initial_round_trip_time_us(other.initial_round_trip_time_us),
+ discard_length(other.discard_length),
google_handshake_message(other.google_handshake_message),
google_connection_options(other.google_connection_options),
custom_parameters(other.custom_parameters) {
@@ -574,6 +586,7 @@
reliable_stream_reset == rhs.reliable_stream_reset &&
initial_round_trip_time_us.value() ==
rhs.initial_round_trip_time_us.value() &&
+ discard_length == rhs.discard_length &&
google_handshake_message == rhs.google_handshake_message &&
google_connection_options == rhs.google_connection_options &&
custom_parameters == rhs.custom_parameters)) {
@@ -762,6 +775,7 @@
kIntegerParameterLength + // max_datagram_frame_size
kTypeAndValueLength + // reliable_stream_reset
kIntegerParameterLength + // initial_round_trip_time_us
+ kTypeAndValueLength + // discard
kTypeAndValueLength + // google_handshake_message
kTypeAndValueLength + // google_connection_options
kTypeAndValueLength; // google-version
@@ -783,6 +797,7 @@
TransportParameters::kActiveConnectionIdLimit,
TransportParameters::kMaxDatagramFrameSize,
TransportParameters::kReliableStreamReset,
+ TransportParameters::kDiscard,
TransportParameters::kGoogleHandshakeMessage,
TransportParameters::kInitialRoundTripTime,
TransportParameters::kDisableActiveMigration,
@@ -816,6 +831,10 @@
(in.version_information->other_versions.size() + 1) *
sizeof(QuicVersionLabel);
}
+ // discard.
+ if (in.discard_length >= 0) {
+ max_transport_param_length += in.discard_length;
+ }
// google_handshake_message.
if (in.google_handshake_message.has_value()) {
max_transport_param_length += in.google_handshake_message->length();
@@ -1001,6 +1020,19 @@
return false;
}
} break;
+ // discard
+ case TransportParameters::kDiscard: {
+ if (in.discard_length >= 0) {
+ std::string discard_data(in.discard_length, '\0');
+ if (!writer.WriteVarInt62(TransportParameters::kDiscard) ||
+ !writer.WriteStringPieceVarInt62(discard_data)) {
+ QUIC_BUG(Failed to write discard_data)
+ << "Failed to write discard data of length: "
+ << in.discard_length << " for " << in;
+ return false;
+ }
+ }
+ } break;
// google_handshake_message
case TransportParameters::kGoogleHandshakeMessage: {
if (in.google_handshake_message.has_value()) {
@@ -1250,7 +1282,7 @@
<< " bytes";
return true;
-}
+} // NOLINT(readability/fn_size)
bool ParseTransportParameters(ParsedQuicVersion version,
Perspective perspective, const uint8_t* in,
@@ -1451,6 +1483,9 @@
parse_success =
out->max_datagram_frame_size.Read(&value_reader, error_details);
break;
+ case TransportParameters::kDiscard:
+ out->discard_length = value_reader.ReadRemainingPayload().length();
+ break;
case TransportParameters::kGoogleHandshakeMessage:
if (out->google_handshake_message.has_value()) {
*error_details = "Received a second google_handshake_message";
diff --git a/quiche/quic/core/crypto/transport_parameters.h b/quiche/quic/core/crypto/transport_parameters.h
index 9255793..5efba82 100644
--- a/quiche/quic/core/crypto/transport_parameters.h
+++ b/quiche/quic/core/crypto/transport_parameters.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_
#define QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_
+#include <cstdint>
#include <memory>
#include <optional>
#include <vector>
@@ -255,6 +256,10 @@
// initial round-trip time in microseconds.
IntegerParameter initial_round_trip_time_us;
+ // Data length for TransportParameterId::kDiscard. Negative values means the
+ // parameter is not set.
+ int32_t discard_length = -1;
+
// Google internal handshake message.
std::optional<std::string> google_handshake_message;
diff --git a/quiche/quic/core/crypto/transport_parameters_test.cc b/quiche/quic/core/crypto/transport_parameters_test.cc
index 4fb1fed..8f3c6c9 100644
--- a/quiche/quic/core/crypto/transport_parameters_test.cc
+++ b/quiche/quic/core/crypto/transport_parameters_test.cc
@@ -296,6 +296,7 @@
CreateFakeInitialSourceConnectionId();
orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+ orig_params.discard_length = 2000;
std::string google_handshake_message;
ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
&google_handshake_message));
@@ -335,6 +336,7 @@
orig_params.initial_source_connection_id =
CreateFakeInitialSourceConnectionId();
orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+ orig_params.discard_length = 2000;
std::string google_handshake_message;
ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
&google_handshake_message));
@@ -573,6 +575,11 @@
0x0f, // parameter id
0x08, // length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+ // discard
+ 0x57, 0x3e, // parameter id
+ 0x10, // length
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// google_handshake_message
0x66, 0xab, // parameter id
0x24, // length
@@ -652,6 +659,7 @@
ASSERT_TRUE(new_params.google_connection_options.has_value());
EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
new_params.google_connection_options.value());
+ EXPECT_EQ(16, new_params.discard_length);
std::string expected_google_handshake_message;
ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
&expected_google_handshake_message));
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 6e3f8d4..308d2d9 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -501,6 +501,10 @@
return received_google_handshake_message_;
}
+void QuicConfig::SetDiscardLengthToSend(int32_t discard_length) {
+ discard_length_to_send_ = discard_length;
+}
+
bool QuicConfig::HasReceivedConnectionOptions() const {
return connection_options_.HasReceivedValues();
}
@@ -1279,6 +1283,8 @@
params->google_handshake_message = google_handshake_message_to_send_;
}
+ params->discard_length = discard_length_to_send_;
+
params->reliable_stream_reset = reliable_stream_reset_;
params->custom_parameters = custom_transport_parameters_to_send_;
@@ -1416,6 +1422,8 @@
received_custom_transport_parameters_ = params.custom_parameters;
+ discard_length_received_ = params.discard_length;
+
if (reliable_stream_reset_) {
reliable_stream_reset_ = params.reliable_stream_reset;
}
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index dd72974..cfa3628 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -250,6 +250,13 @@
bool HasReceivedConnectionOptions() const;
+ // Sets the data length to be sent for transport parameter 'discard'. The data
+ // to send in the transport parameter will be all zeros. Negative values means
+ // do not send.
+ void SetDiscardLengthToSend(int32_t discard_length);
+
+ int32_t GetDiscardLengthReceived() const { return discard_length_received_; }
+
void SetGoogleHandshakeMessageToSend(std::string message);
const std::optional<std::string>& GetReceivedGoogleHandshakeMessage() const;
@@ -707,6 +714,14 @@
TransportParameters::ParameterMap custom_transport_parameters_to_send_;
TransportParameters::ParameterMap received_custom_transport_parameters_;
+ // Length of the data to send in the 'discard' transport parameter. Negative
+ // values means do not send.
+ int32_t discard_length_to_send_ = -1;
+
+ // Length of the receive data in the 'discard' transport parameter. Negative
+ // values means 'discard' data not received.
+ int32_t discard_length_received_ = -1;
+
// Google internal handshake message.
std::optional<std::string> google_handshake_message_to_send_;
std::optional<std::string> received_google_handshake_message_;
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc
index ea311e9..24a2ec1 100644
--- a/quiche/quic/core/quic_config_test.cc
+++ b/quiche/quic/core/quic_config_test.cc
@@ -4,6 +4,7 @@
#include "quiche/quic/core/quic_config.h"
+#include <cstdint>
#include <memory>
#include <string>
#include <utility>
@@ -467,6 +468,7 @@
return;
}
const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
+ const int32_t kDiscardLength = 2000;
config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
2 * kMinimumFlowControlSendWindow);
config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
@@ -481,6 +483,7 @@
config_.SetInitialSourceConnectionIdToSend(TestConnectionId(0x2222));
config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333));
config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
+ config_.SetDiscardLengthToSend(kDiscardLength);
config_.SetGoogleHandshakeMessageToSend(kFakeGoogleHandshakeMessage);
config_.SetReliableStreamReset(true);
@@ -542,6 +545,7 @@
EXPECT_EQ(*reinterpret_cast<StatelessResetToken*>(
¶ms.preferred_address->stateless_reset_token.front()),
new_stateless_reset_token);
+ EXPECT_EQ(kDiscardLength, params.discard_length);
EXPECT_EQ(kFakeGoogleHandshakeMessage, params.google_handshake_message);
EXPECT_TRUE(params.reliable_stream_reset);
@@ -655,6 +659,7 @@
return;
}
const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
+ const int32_t kDiscardLength = 2000;
TransportParameters params;
params.initial_max_stream_data_bidi_local.set_value(
@@ -674,6 +679,7 @@
params.original_destination_connection_id = TestConnectionId(0x1111);
params.initial_source_connection_id = TestConnectionId(0x2222);
params.retry_source_connection_id = TestConnectionId(0x3333);
+ params.discard_length = kDiscardLength;
params.google_handshake_message = kFakeGoogleHandshakeMessage;
std::string error_details;
@@ -795,6 +801,7 @@
TestConnectionId(0x3333));
EXPECT_EQ(kFakeGoogleHandshakeMessage,
config_.GetReceivedGoogleHandshakeMessage());
+ EXPECT_EQ(kDiscardLength, config_.GetDiscardLengthReceived());
}
TEST_P(QuicConfigTest, DisableMigrationTransportParameter) {
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index b83d773..829d7f1 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -174,11 +174,9 @@
connection_->SetUnackedMapInitialCapacity();
if (perspective_ == Perspective::IS_CLIENT) {
if (config_.HasClientSentConnectionOption(kCHP1, perspective_)) {
- config_.SetGoogleHandshakeMessageToSend(
- std::string(kDefaultMaxPacketSize, '0'));
+ config_.SetDiscardLengthToSend(kDefaultMaxPacketSize);
} else if (config_.HasClientSentConnectionOption(kCHP2, perspective_)) {
- config_.SetGoogleHandshakeMessageToSend(
- std::string(kDefaultMaxPacketSize * 2, '0'));
+ config_.SetDiscardLengthToSend(kDefaultMaxPacketSize * 2);
}
}
connection_->SetFromConfig(config_);
@@ -1873,11 +1871,6 @@
MaybeSendAddressToken();
}
}
- if (perspective_ == Perspective::IS_CLIENT &&
- (config_.HasClientSentConnectionOption(kCHP1, perspective_) ||
- config_.HasClientSentConnectionOption(kCHP2, perspective_))) {
- config_.ClearGoogleHandshakeMessage();
- }
}
bool QuicSession::MaybeSendAddressToken() {
diff --git a/quiche/quic/tools/quic_client_interop_test_bin.cc b/quiche/quic/tools/quic_client_interop_test_bin.cc
index 0df5e68..71ee23f 100644
--- a/quiche/quic/tools/quic_client_interop_test_bin.cc
+++ b/quiche/quic/tools/quic_client_interop_test_bin.cc
@@ -213,11 +213,7 @@
if (attempt_multi_packet_chlo) {
// Make the ClientHello span multiple packets by adding a custom transport
// parameter.
- constexpr auto kCustomParameter =
- static_cast<TransportParameters::TransportParameterId>(0x173E);
- std::string custom_value(2000, '?');
- config.custom_transport_parameters_to_send()[kCustomParameter] =
- custom_value;
+ config.SetDiscardLengthToSend(2000);
}
std::unique_ptr<QuicEventLoop> event_loop =
GetDefaultEventLoop()->Create(QuicDefaultClock::Get());
diff --git a/quiche/quic/tools/quic_toy_client.cc b/quiche/quic/tools/quic_toy_client.cc
index 79aafb7..1857025 100644
--- a/quiche/quic/tools/quic_toy_client.cc
+++ b/quiche/quic/tools/quic_toy_client.cc
@@ -312,13 +312,9 @@
ParseQuicTagVector(client_connection_options_string));
}
if (quiche::GetQuicheCommandLineFlag(FLAGS_multi_packet_chlo)) {
- // Make the ClientHello span multiple packets by adding a custom transport
- // parameter.
- constexpr auto kCustomParameter =
- static_cast<TransportParameters::TransportParameterId>(0x173E);
- std::string custom_value(2000, '?');
- config.custom_transport_parameters_to_send()[kCustomParameter] =
- custom_value;
+ // Make the ClientHello span multiple packets by adding a large 'discard'
+ // transport parameter.
+ config.SetDiscardLengthToSend(2000);
}
config.set_max_time_before_crypto_handshake(
QuicTime::Delta::FromMilliseconds(quiche::GetQuicheCommandLineFlag(