fix HTTP request writing if the Request.Body reads data and returns EOF

This commit is contained in:
Marten Seemann 2020-07-01 15:31:24 +07:00
parent 5eb2bb8b4c
commit b8f36f35d5
2 changed files with 38 additions and 8 deletions

View file

@ -57,14 +57,13 @@ func (w *requestWriter) WriteRequest(str quic.Stream, req *http.Request, gzip bo
defer req.Body.Close()
b := make([]byte, bodyCopyBufferSize)
for {
n, err := req.Body.Read(b)
if err == io.EOF {
break
}
if err != nil {
str.CancelWrite(quic.ErrorCode(errorRequestCanceled))
w.logger.Errorf("Error writing request: %s", err)
return
n, rerr := req.Body.Read(b)
if n == 0 {
if rerr == nil {
continue
} else if rerr == io.EOF {
break
}
}
buf := &bytes.Buffer{}
(&dataFrame{Length: uint64(n)}).Write(buf)
@ -76,6 +75,14 @@ func (w *requestWriter) WriteRequest(str quic.Stream, req *http.Request, gzip bo
w.logger.Errorf("Error writing request: %s", err)
return
}
if rerr != nil {
if rerr == io.EOF {
break
}
str.CancelWrite(quic.ErrorCode(errorRequestCanceled))
w.logger.Errorf("Error writing request: %s", rerr)
return
}
}
str.Close()
}()

View file

@ -16,6 +16,12 @@ import (
. "github.com/onsi/gomega"
)
type foobarReader struct{}
func (r *foobarReader) Read(b []byte) (int, error) {
return copy(b, []byte("foobar")), io.EOF
}
var _ = Describe("Request Writer", func() {
var (
rw *requestWriter
@ -85,6 +91,23 @@ var _ = Describe("Request Writer", func() {
Expect(frame.(*dataFrame).Length).To(BeEquivalentTo(6))
})
It("writes a POST request, if the Body returns an EOF immediately", func() {
closed := make(chan struct{})
str.EXPECT().Close().Do(func() { close(closed) })
req, err := http.NewRequest("POST", "https://quic.clemente.io/upload.html", &foobarReader{})
Expect(err).ToNot(HaveOccurred())
Expect(rw.WriteRequest(str, req, false)).To(Succeed())
Eventually(closed).Should(BeClosed())
headerFields := decode(strBuf)
Expect(headerFields).To(HaveKeyWithValue(":method", "POST"))
frame, err := parseNextFrame(strBuf)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(BeAssignableToTypeOf(&dataFrame{}))
Expect(frame.(*dataFrame).Length).To(BeEquivalentTo(6))
})
It("sends cookies", func() {
str.EXPECT().Close()
req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil)