Skip to content

Commit

Permalink
http3: allow concurrent calls to Body.Close (quic-go#4798)
Browse files Browse the repository at this point in the history
  • Loading branch information
RPRX committed Jan 1, 2025
1 parent bee89bb commit 652c146
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 7 deletions.
13 changes: 6 additions & 7 deletions http3/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"io"
"sync"

"github.com/xtls/quic-go"
)
Expand Down Expand Up @@ -95,8 +96,8 @@ type hijackableBody struct {
// only set for the http.Response
// The channel is closed when the user is done with this response:
// either when Read() errors, or when Close() is called.
reqDone chan<- struct{}
reqDoneClosed bool
reqDone chan<- struct{}
reqDoneOnce sync.Once
}

var _ io.ReadCloser = &hijackableBody{}
Expand All @@ -117,13 +118,11 @@ func (r *hijackableBody) Read(b []byte) (int, error) {
}

func (r *hijackableBody) requestDone() {
if r.reqDoneClosed || r.reqDone == nil {
return
}
if r.reqDone != nil {
close(r.reqDone)
r.reqDoneOnce.Do(func() {
close(r.reqDone)
})
}
r.reqDoneClosed = true
}

func (r *hijackableBody) Close() error {
Expand Down
12 changes: 12 additions & 0 deletions http3/body_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ var _ = Describe("Response Body", func() {
Expect(rb.Close()).To(Succeed())
})

It("allows concurrent calls to Close", func() {
str := mockquic.NewMockStream(mockCtrl)
rb := newResponseBody(&stream{Stream: str}, -1, reqDone)
str.EXPECT().CancelRead(quic.StreamErrorCode(ErrCodeRequestCanceled)).MaxTimes(2)
go func() {
defer GinkgoRecover()
Expect(rb.Close()).To(Succeed())
}()
Expect(rb.Close()).To(Succeed())
Expect(reqDone).To(BeClosed())
})

Context("length limiting", func() {
It("reads all frames", func() {
var buf bytes.Buffer
Expand Down

0 comments on commit 652c146

Please sign in to comment.