mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
Change-Id: I7e2c867efcc960553da77e395b0069ab6776cd9f
GitHub-Last-Rev: eaa122d1b6
GitHub-Pull-Request: golang/net#205
Reviewed-on: https://go-review.googlesource.com/c/net/+/572995
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
265 lines
8.0 KiB
Go
265 lines
8.0 KiB
Go
// Copyright 2023 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build go1.21
|
|
|
|
package quic
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"testing"
|
|
)
|
|
|
|
func TestStreamLimitNewStreamBlocked(t *testing.T) {
|
|
// "An endpoint that receives a frame with a stream ID exceeding the limit
|
|
// it has sent MUST treat this as a connection error of type STREAM_LIMIT_ERROR [...]"
|
|
// https://www.rfc-editor.org/rfc/rfc9000#section-4.6-3
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
ctx := canceledContext()
|
|
tc := newTestConn(t, clientSide,
|
|
permissiveTransportParameters,
|
|
func(p *transportParameters) {
|
|
p.initialMaxStreamsBidi = 0
|
|
p.initialMaxStreamsUni = 0
|
|
})
|
|
tc.handshake()
|
|
tc.ignoreFrame(frameTypeAck)
|
|
opening := runAsync(tc, func(ctx context.Context) (*Stream, error) {
|
|
return tc.conn.newLocalStream(ctx, styp)
|
|
})
|
|
if _, err := opening.result(); err != errNotDone {
|
|
t.Fatalf("new stream blocked by limit: %v, want errNotDone", err)
|
|
}
|
|
tc.writeFrames(packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 1,
|
|
})
|
|
if _, err := opening.result(); err != nil {
|
|
t.Fatalf("new stream not created after limit raised: %v", err)
|
|
}
|
|
if _, err := tc.conn.newLocalStream(ctx, styp); err == nil {
|
|
t.Fatalf("new stream blocked by raised limit: %v, want error", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitMaxStreamsDecreases(t *testing.T) {
|
|
// "MAX_STREAMS frames that do not increase the stream limit MUST be ignored."
|
|
// https://www.rfc-editor.org/rfc/rfc9000#section-4.6-4
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
ctx := canceledContext()
|
|
tc := newTestConn(t, clientSide,
|
|
permissiveTransportParameters,
|
|
func(p *transportParameters) {
|
|
p.initialMaxStreamsBidi = 0
|
|
p.initialMaxStreamsUni = 0
|
|
})
|
|
tc.handshake()
|
|
tc.ignoreFrame(frameTypeAck)
|
|
tc.writeFrames(packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 2,
|
|
})
|
|
tc.writeFrames(packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 1,
|
|
})
|
|
if _, err := tc.conn.newLocalStream(ctx, styp); err != nil {
|
|
t.Fatalf("open stream 1, limit 2, got error: %v", err)
|
|
}
|
|
if _, err := tc.conn.newLocalStream(ctx, styp); err != nil {
|
|
t.Fatalf("open stream 2, limit 2, got error: %v", err)
|
|
}
|
|
if _, err := tc.conn.newLocalStream(ctx, styp); err == nil {
|
|
t.Fatalf("open stream 3, limit 2, got error: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitViolated(t *testing.T) {
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
tc := newTestConn(t, serverSide,
|
|
func(c *Config) {
|
|
if styp == bidiStream {
|
|
c.MaxBidiRemoteStreams = 10
|
|
} else {
|
|
c.MaxUniRemoteStreams = 10
|
|
}
|
|
})
|
|
tc.handshake()
|
|
tc.ignoreFrame(frameTypeAck)
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, 9),
|
|
})
|
|
tc.wantIdle("stream number 9 is within the limit")
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, 10),
|
|
})
|
|
tc.wantFrame("stream number 10 is beyond the limit",
|
|
packetType1RTT, debugFrameConnectionCloseTransport{
|
|
code: errStreamLimit,
|
|
},
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitImplicitStreams(t *testing.T) {
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
tc := newTestConn(t, serverSide,
|
|
func(c *Config) {
|
|
c.MaxBidiRemoteStreams = 1 << 60
|
|
c.MaxUniRemoteStreams = 1 << 60
|
|
})
|
|
tc.handshake()
|
|
tc.ignoreFrame(frameTypeAck)
|
|
if got, want := tc.sentTransportParameters.initialMaxStreamsBidi, int64(implicitStreamLimit); got != want {
|
|
t.Errorf("sent initial_max_streams_bidi = %v, want %v", got, want)
|
|
}
|
|
if got, want := tc.sentTransportParameters.initialMaxStreamsUni, int64(implicitStreamLimit); got != want {
|
|
t.Errorf("sent initial_max_streams_uni = %v, want %v", got, want)
|
|
}
|
|
|
|
// Create stream 0.
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, 0),
|
|
})
|
|
tc.wantIdle("max streams not increased enough to send a new frame")
|
|
|
|
// Create streams [0, implicitStreamLimit).
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, implicitStreamLimit-1),
|
|
})
|
|
tc.wantFrame("max streams increases to implicit stream limit",
|
|
packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 2 * implicitStreamLimit,
|
|
})
|
|
|
|
// Create a stream past the limit.
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, 2*implicitStreamLimit),
|
|
})
|
|
tc.wantFrame("stream is past the limit",
|
|
packetType1RTT, debugFrameConnectionCloseTransport{
|
|
code: errStreamLimit,
|
|
},
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitMaxStreamsTransportParameterTooLarge(t *testing.T) {
|
|
// "If a max_streams transport parameter [...] is received with
|
|
// a value greater than 2^60 [...] the connection MUST be closed
|
|
// immediately with a connection error of type TRANSPORT_PARAMETER_ERROR [...]"
|
|
// https://www.rfc-editor.org/rfc/rfc9000#section-4.6-2
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
tc := newTestConn(t, serverSide,
|
|
func(p *transportParameters) {
|
|
if styp == bidiStream {
|
|
p.initialMaxStreamsBidi = 1<<60 + 1
|
|
} else {
|
|
p.initialMaxStreamsUni = 1<<60 + 1
|
|
}
|
|
})
|
|
tc.writeFrames(packetTypeInitial, debugFrameCrypto{
|
|
data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial],
|
|
})
|
|
tc.wantFrame("max streams transport parameter is too large",
|
|
packetTypeInitial, debugFrameConnectionCloseTransport{
|
|
code: errTransportParameter,
|
|
},
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitMaxStreamsFrameTooLarge(t *testing.T) {
|
|
// "If [...] a MAX_STREAMS frame is received with a value
|
|
// greater than 2^60 [...] the connection MUST be closed immediately
|
|
// with a connection error [...] of type FRAME_ENCODING_ERROR [...]"
|
|
// https://www.rfc-editor.org/rfc/rfc9000#section-4.6-2
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
tc := newTestConn(t, serverSide)
|
|
tc.handshake()
|
|
tc.writeFrames(packetTypeInitial,
|
|
debugFrameCrypto{
|
|
data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial],
|
|
})
|
|
tc.writeFrames(packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 1<<60 + 1,
|
|
})
|
|
tc.wantFrame("MAX_STREAMS value is too large",
|
|
packetType1RTT, debugFrameConnectionCloseTransport{
|
|
code: errFrameEncoding,
|
|
},
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitSendUpdatesMaxStreams(t *testing.T) {
|
|
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
|
|
tc := newTestConn(t, serverSide, func(c *Config) {
|
|
if styp == uniStream {
|
|
c.MaxUniRemoteStreams = 4
|
|
c.MaxBidiRemoteStreams = 0
|
|
} else {
|
|
c.MaxUniRemoteStreams = 0
|
|
c.MaxBidiRemoteStreams = 4
|
|
}
|
|
})
|
|
tc.handshake()
|
|
tc.ignoreFrame(frameTypeAck)
|
|
var streams []*Stream
|
|
for i := 0; i < 4; i++ {
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: newStreamID(clientSide, styp, int64(i)),
|
|
fin: true,
|
|
})
|
|
streams = append(streams, tc.acceptStream())
|
|
}
|
|
streams[3].Close()
|
|
if styp == bidiStream {
|
|
tc.wantFrame("stream is closed",
|
|
packetType1RTT, debugFrameStream{
|
|
id: streams[3].id,
|
|
fin: true,
|
|
data: []byte{},
|
|
})
|
|
tc.writeAckForAll()
|
|
}
|
|
tc.wantFrame("closing a stream when peer is at limit immediately extends the limit",
|
|
packetType1RTT, debugFrameMaxStreams{
|
|
streamType: styp,
|
|
max: 5,
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestStreamLimitStopSendingDoesNotUpdateMaxStreams(t *testing.T) {
|
|
tc, s := newTestConnAndRemoteStream(t, serverSide, bidiStream, func(c *Config) {
|
|
c.MaxBidiRemoteStreams = 1
|
|
})
|
|
tc.writeFrames(packetType1RTT, debugFrameStream{
|
|
id: s.id,
|
|
fin: true,
|
|
})
|
|
s.CloseRead()
|
|
tc.writeFrames(packetType1RTT, debugFrameStopSending{
|
|
id: s.id,
|
|
})
|
|
tc.wantFrame("received STOP_SENDING, send RESET_STREAM",
|
|
packetType1RTT, debugFrameResetStream{
|
|
id: s.id,
|
|
})
|
|
tc.writeAckForAll()
|
|
tc.wantIdle("MAX_STREAMS is not extended until the user fully closes the stream")
|
|
s.CloseWrite()
|
|
tc.wantFrame("user closing the stream triggers MAX_STREAMS update",
|
|
packetType1RTT, debugFrameMaxStreams{
|
|
streamType: bidiStream,
|
|
max: 2,
|
|
})
|
|
}
|