forked from quic-go/quic-go
wire: add support for the reset_stream_at transport parameter (#5158)
This commit is contained in:
@@ -48,8 +48,9 @@ func TestTransportParametersStringRepresentation(t *testing.T) {
|
||||
StatelessResetToken: &protocol.StatelessResetToken{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00},
|
||||
ActiveConnectionIDLimit: 123,
|
||||
MaxDatagramFrameSize: 876,
|
||||
EnableResetStreamAt: true,
|
||||
}
|
||||
expected := "&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: decafbad, RetrySourceConnectionID: deadc0de, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00, MaxDatagramFrameSize: 876}"
|
||||
expected := "&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: decafbad, RetrySourceConnectionID: deadc0de, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00, MaxDatagramFrameSize: 876, EnableResetStreamAt: true}"
|
||||
require.Equal(t, expected, p.String())
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ func TestTransportParametersStringRepresentationWithoutOptionalFields(t *testing
|
||||
ActiveConnectionIDLimit: 89,
|
||||
MaxDatagramFrameSize: protocol.InvalidByteCount,
|
||||
}
|
||||
expected := "&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: (empty), InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}"
|
||||
expected := "&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: (empty), InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89, EnableResetStreamAt: false}"
|
||||
require.Equal(t, expected, p.String())
|
||||
}
|
||||
|
||||
@@ -95,6 +96,7 @@ func TestMarshalAndUnmarshalTransportParameters(t *testing.T) {
|
||||
ActiveConnectionIDLimit: 2 + getRandomValueUpTo(quicvarint.Max-2),
|
||||
MaxUDPPayloadSize: 1200 + protocol.ByteCount(getRandomValueUpTo(quicvarint.Max-1200)),
|
||||
MaxDatagramFrameSize: protocol.ByteCount(getRandomValue()),
|
||||
EnableResetStreamAt: getRandomValue()%2 == 0,
|
||||
}
|
||||
data := params.Marshal(protocol.PerspectiveServer)
|
||||
|
||||
@@ -117,6 +119,7 @@ func TestMarshalAndUnmarshalTransportParameters(t *testing.T) {
|
||||
require.Equal(t, params.ActiveConnectionIDLimit, p.ActiveConnectionIDLimit)
|
||||
require.Equal(t, params.MaxUDPPayloadSize, p.MaxUDPPayloadSize)
|
||||
require.Equal(t, params.MaxDatagramFrameSize, p.MaxDatagramFrameSize)
|
||||
require.Equal(t, params.EnableResetStreamAt, p.EnableResetStreamAt)
|
||||
}
|
||||
|
||||
func TestMarshalAdditionalTransportParameters(t *testing.T) {
|
||||
@@ -369,6 +372,17 @@ func TestTransportParameterErrors(t *testing.T) {
|
||||
perspective: protocol.PerspectiveClient,
|
||||
expectedErrMsg: "invalid value for max_ack_delay: 3689348814741910323ms (maximum 16383ms)",
|
||||
},
|
||||
{
|
||||
name: "invalid value for reset_stream_at",
|
||||
data: func() []byte {
|
||||
b := quicvarint.Append(nil, uint64(resetStreamAtParameterID))
|
||||
b = quicvarint.Append(b, 1)
|
||||
b = quicvarint.Append(b, 1)
|
||||
return appendInitialSourceConnectionID(b)
|
||||
}(),
|
||||
perspective: protocol.PerspectiveClient,
|
||||
expectedErrMsg: "wrong length for reset_stream_at: 1 (expected empty)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -550,6 +564,7 @@ func TestTransportParametersFromSessionTicket(t *testing.T) {
|
||||
MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(uint64(protocol.MaxStreamCount))),
|
||||
ActiveConnectionIDLimit: 2 + getRandomValueUpTo(quicvarint.Max-2),
|
||||
MaxDatagramFrameSize: protocol.ByteCount(getRandomValueUpTo(uint64(MaxDatagramSize))),
|
||||
EnableResetStreamAt: getRandomValue()%2 == 0,
|
||||
}
|
||||
require.True(t, params.ValidFor0RTT(params))
|
||||
b := params.MarshalForSessionTicket(nil)
|
||||
@@ -563,6 +578,7 @@ func TestTransportParametersFromSessionTicket(t *testing.T) {
|
||||
require.Equal(t, params.MaxUniStreamNum, tp.MaxUniStreamNum)
|
||||
require.Equal(t, params.ActiveConnectionIDLimit, tp.ActiveConnectionIDLimit)
|
||||
require.Equal(t, params.MaxDatagramFrameSize, tp.MaxDatagramFrameSize)
|
||||
require.Equal(t, params.EnableResetStreamAt, tp.EnableResetStreamAt)
|
||||
}
|
||||
|
||||
func TestSessionTicketInvalidTransportParameters(t *testing.T) {
|
||||
|
||||
@@ -45,6 +45,8 @@ const (
|
||||
retrySourceConnectionIDParameterID transportParameterID = 0x10
|
||||
// RFC 9221
|
||||
maxDatagramFrameSizeParameterID transportParameterID = 0x20
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/
|
||||
resetStreamAtParameterID transportParameterID = 0x17f7586d2cb571
|
||||
)
|
||||
|
||||
// PreferredAddress is the value encoding in the preferred_address transport parameter
|
||||
@@ -82,7 +84,8 @@ type TransportParameters struct {
|
||||
StatelessResetToken *protocol.StatelessResetToken
|
||||
ActiveConnectionIDLimit uint64
|
||||
|
||||
MaxDatagramFrameSize protocol.ByteCount
|
||||
MaxDatagramFrameSize protocol.ByteCount // RFC 9221
|
||||
EnableResetStreamAt bool // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/
|
||||
}
|
||||
|
||||
// Unmarshal the transport parameters
|
||||
@@ -199,6 +202,11 @@ func (p *TransportParameters) unmarshal(b []byte, sentBy protocol.Perspective, f
|
||||
connID := protocol.ParseConnectionID(b[:paramLen])
|
||||
b = b[paramLen:]
|
||||
p.RetrySourceConnectionID = &connID
|
||||
case resetStreamAtParameterID:
|
||||
if paramLen != 0 {
|
||||
return fmt.Errorf("wrong length for reset_stream_at: %d (expected empty)", paramLen)
|
||||
}
|
||||
p.EnableResetStreamAt = true
|
||||
default:
|
||||
b = b[paramLen:]
|
||||
}
|
||||
@@ -428,9 +436,15 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
|
||||
b = quicvarint.Append(b, uint64(p.RetrySourceConnectionID.Len()))
|
||||
b = append(b, p.RetrySourceConnectionID.Bytes()...)
|
||||
}
|
||||
// QUIC datagrams
|
||||
if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
||||
b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
}
|
||||
// QUIC Stream Resets with Partial Delivery
|
||||
if p.EnableResetStreamAt {
|
||||
b = quicvarint.Append(b, uint64(resetStreamAtParameterID))
|
||||
b = quicvarint.Append(b, 0)
|
||||
}
|
||||
|
||||
if pers == protocol.PerspectiveClient && len(AdditionalTransportParametersClient) > 0 {
|
||||
for k, v := range AdditionalTransportParametersClient {
|
||||
@@ -472,12 +486,18 @@ func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
// initial_max_uni_streams
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
// active_connection_id_limit
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
// max_datagram_frame_size
|
||||
if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
||||
b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
}
|
||||
// active_connection_id_limit
|
||||
return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
// reset_stream_at
|
||||
if p.EnableResetStreamAt {
|
||||
b = quicvarint.Append(b, uint64(resetStreamAtParameterID))
|
||||
b = quicvarint.Append(b, 0)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket.
|
||||
@@ -524,13 +544,13 @@ func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool {
|
||||
// String returns a string representation, intended for logging.
|
||||
func (p *TransportParameters) String() string {
|
||||
logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, "
|
||||
logParams := []interface{}{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID}
|
||||
logParams := []any{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID}
|
||||
if p.RetrySourceConnectionID != nil {
|
||||
logString += "RetrySourceConnectionID: %s, "
|
||||
logParams = append(logParams, p.RetrySourceConnectionID)
|
||||
}
|
||||
logString += "InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d"
|
||||
logParams = append(logParams, []interface{}{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...)
|
||||
logParams = append(logParams, []any{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...)
|
||||
if p.StatelessResetToken != nil { // the client never sends a stateless reset token
|
||||
logString += ", StatelessResetToken: %#x"
|
||||
logParams = append(logParams, *p.StatelessResetToken)
|
||||
@@ -539,6 +559,8 @@ func (p *TransportParameters) String() string {
|
||||
logString += ", MaxDatagramFrameSize: %d"
|
||||
logParams = append(logParams, p.MaxDatagramFrameSize)
|
||||
}
|
||||
logString += ", EnableResetStreamAt: %t"
|
||||
logParams = append(logParams, p.EnableResetStreamAt)
|
||||
logString += "}"
|
||||
return fmt.Sprintf(logString, logParams...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user