Skip to content

Commit

Permalink
quic: return error from Stream.Flush
Browse files Browse the repository at this point in the history
Report errors (stream closed, stream reset) when flushing.

Change-Id: I94b7a35fe874372eb7969aacebc861c5f2e29b3c
Reviewed-on: https://go-review.googlesource.com/c/net/+/640796
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
  • Loading branch information
neild committed Jan 7, 2025
1 parent 2e60102 commit dc3b8a8
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
12 changes: 11 additions & 1 deletion quic/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,20 @@ func (s *Stream) flushFastOutputBuffer() {
// Flush flushes data written to the stream.
// It does not wait for the peer to acknowledge receipt of the data.
// Use Close to wait for the peer's acknowledgement.
func (s *Stream) Flush() {
func (s *Stream) Flush() error {
if s.IsReadOnly() {
return errors.New("flush of read-only stream")
}
s.outgate.lock()
defer s.outUnlock()
if s.outreset.isSet() {
return errors.New("write to reset stream")
}
if s.outclosed.isSet() {
return errors.New("write to closed stream")
}
s.flushLocked()
return nil
}

func (s *Stream) flushLocked() {
Expand Down
48 changes: 48 additions & 0 deletions quic/stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,54 @@ func TestStreamFlushExplicit(t *testing.T) {
})
}

func TestStreamFlushClosedStream(t *testing.T) {
_, s := newTestConnAndLocalStream(t, clientSide, bidiStream,
permissiveTransportParameters)
s.Close()
if err := s.Flush(); err == nil {
t.Errorf("s.Flush of closed stream = nil, want error")
}
}

func TestStreamFlushResetStream(t *testing.T) {
_, s := newTestConnAndLocalStream(t, clientSide, bidiStream,
permissiveTransportParameters)
s.Reset(0)
if err := s.Flush(); err == nil {
t.Errorf("s.Flush of reset stream = nil, want error")
}
}

func TestStreamFlushStreamAfterPeerStopSending(t *testing.T) {
tc, s := newTestConnAndLocalStream(t, clientSide, bidiStream,
permissiveTransportParameters)
s.Flush() // create the stream
tc.wantFrame("stream created after flush",
packetType1RTT, debugFrameStream{
id: s.id,
data: []byte{},
})

// Peer sends a STOP_SENDING.
tc.writeFrames(packetType1RTT, debugFrameStopSending{
id: s.id,
})
if err := s.Flush(); err == nil {
t.Errorf("s.Flush of stream reset by peer = nil, want error")
}
}

func TestStreamFlushStreamAfterConnectionClosed(t *testing.T) {
tc, s := newTestConnAndLocalStream(t, clientSide, bidiStream,
permissiveTransportParameters)
tc.writeFrames(packetType1RTT, debugFrameConnectionCloseApplication{
code: 0,
})
if err := s.Flush(); err == nil {
t.Errorf("s.Flush of stream on closed connection = nil, want error")
}
}

func TestStreamFlushImplicitExact(t *testing.T) {
testStreamTypes(t, "", func(t *testing.T, styp streamType) {
const writeBufferSize = 4
Expand Down

0 comments on commit dc3b8a8

Please sign in to comment.