quic: don't block when closing read-only streams
Stream.Close blocks until all data sent on a stream has been
acked by the peer. Don't block indefinitely when closing
a read-only stream, waiting for an ack of data we never sent.
For golang/go#58547
Change-Id: I4087666f739d7388e460b613d211c043626f1c87
Reviewed-on: https://go-review.googlesource.com/c/net/+/524038
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/quic/stream.go b/internal/quic/stream.go
index 12117db..1033cbb 100644
--- a/internal/quic/stream.go
+++ b/internal/quic/stream.go
@@ -66,7 +66,9 @@
inresetcode: -1, // -1 indicates no RESET_STREAM received
ingate: newLockedGate(),
outgate: newLockedGate(),
- outdone: make(chan struct{}),
+ }
+ if !s.IsReadOnly() {
+ s.outdone = make(chan struct{})
}
return s
}
@@ -237,6 +239,9 @@
// CloseContext discards the buffer and returns the context error.
func (s *Stream) CloseContext(ctx context.Context) error {
s.CloseRead()
+ if s.IsReadOnly() {
+ return nil
+ }
s.CloseWrite()
// TODO: Return code from peer's RESET_STREAM frame?
return s.conn.waitOnDone(ctx, s.outdone)
diff --git a/internal/quic/stream_test.go b/internal/quic/stream_test.go
index 7b8ba2c..79377c6 100644
--- a/internal/quic/stream_test.go
+++ b/internal/quic/stream_test.go
@@ -972,6 +972,17 @@
}
}
+func TestStreamCloseReadOnly(t *testing.T) {
+ tc, s := newTestConnAndRemoteStream(t, serverSide, uniStream, permissiveTransportParameters)
+ if err := s.CloseContext(canceledContext()); err != nil {
+ t.Errorf("s.CloseContext() = %v, want nil", err)
+ }
+ tc.wantFrame("closed stream sends STOP_SENDING",
+ packetType1RTT, debugFrameStopSending{
+ id: s.id,
+ })
+}
+
func TestStreamCloseUnblocked(t *testing.T) {
for _, test := range []struct {
name string