forked from quic-go/quic-go
http3: allow concurrent calls to Body.Close (#4798)
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
)
|
)
|
||||||
@@ -96,7 +97,7 @@ type hijackableBody struct {
|
|||||||
// The channel is closed when the user is done with this response:
|
// The channel is closed when the user is done with this response:
|
||||||
// either when Read() errors, or when Close() is called.
|
// either when Read() errors, or when Close() is called.
|
||||||
reqDone chan<- struct{}
|
reqDone chan<- struct{}
|
||||||
reqDoneClosed bool
|
reqDoneOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ io.ReadCloser = &hijackableBody{}
|
var _ io.ReadCloser = &hijackableBody{}
|
||||||
@@ -117,13 +118,11 @@ func (r *hijackableBody) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *hijackableBody) requestDone() {
|
func (r *hijackableBody) requestDone() {
|
||||||
if r.reqDoneClosed || r.reqDone == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.reqDone != nil {
|
if r.reqDone != nil {
|
||||||
|
r.reqDoneOnce.Do(func() {
|
||||||
close(r.reqDone)
|
close(r.reqDone)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
r.reqDoneClosed = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *hijackableBody) Close() error {
|
func (r *hijackableBody) Close() error {
|
||||||
|
|||||||
@@ -54,6 +54,18 @@ var _ = Describe("Response Body", func() {
|
|||||||
Expect(rb.Close()).To(Succeed())
|
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() {
|
Context("length limiting", func() {
|
||||||
It("reads all frames", func() {
|
It("reads all frames", func() {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|||||||
Reference in New Issue
Block a user