http3: set ContentLength to -1 if no Content-Length header is set (#4645)

This applies to both the http.Response and the http.Request.
This commit is contained in:
Marten Seemann
2024-08-30 20:28:06 +08:00
committed by GitHub
parent 229937c503
commit 7c3544ca34
4 changed files with 15 additions and 7 deletions

View File

@@ -22,7 +22,7 @@ type header struct {
Status string
// for Extended connect
Protocol string
// parsed and deduplicated
// parsed and deduplicated. -1 if no Content-Length header is sent
ContentLength int64
// all non-pseudo headers
Headers http.Header
@@ -91,6 +91,7 @@ func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) {
}
}
}
hdr.ContentLength = -1
if len(contentLengthStr) > 0 {
// use ParseUint instead of ParseInt, so that parsing fails on negative values
cl, err := strconv.ParseUint(contentLengthStr, 10, 63)

View File

@@ -33,6 +33,17 @@ var _ = Describe("Request", func() {
Expect(req.RequestURI).To(Equal("/foo"))
})
It("sets the ContentLength to -1", func() {
headers := []qpack.HeaderField{
{Name: ":path", Value: "/foo"},
{Name: ":authority", Value: "quic.clemente.io"},
{Name: ":method", Value: "GET"},
}
req, err := requestFromHeaders(headers)
Expect(err).ToNot(HaveOccurred())
Expect(req.ContentLength).To(BeEquivalentTo(-1))
})
It("rejects upper-case fields", func() {
headers := []qpack.HeaderField{
{Name: ":path", Value: "/foo"},
@@ -343,7 +354,6 @@ var _ = Describe("Response", func() {
It("rejects invalid status codes", func() {
headers := []qpack.HeaderField{
{Name: ":status", Value: "foobar"},
{Name: "content-length", Value: "42"},
}
err := updateResponseFromHeaders(&http.Response{}, headers)
Expect(err).To(HaveOccurred())

View File

@@ -238,11 +238,7 @@ func (s *requestStream) ReadResponse() (*http.Response, error) {
// Check that the server doesn't send more data in DATA frames than indicated by the Content-Length header (if set).
// See section 4.1.2 of RFC 9114.
contentLength := int64(-1)
if _, ok := res.Header["Content-Length"]; ok && res.ContentLength >= 0 {
contentLength = res.ContentLength
}
respBody := newResponseBody(s.stream, contentLength, s.reqDone)
respBody := newResponseBody(s.stream, res.ContentLength, s.reqDone)
// Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2.
isInformational := res.StatusCode >= 100 && res.StatusCode < 200

View File

@@ -289,6 +289,7 @@ var _ = Describe("HTTP tests", func() {
Expect(resp.StatusCode).To(Equal(200))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 20*time.Second))
Expect(err).ToNot(HaveOccurred())
Expect(resp.ContentLength).To(BeEquivalentTo(-1))
Expect(body).To(Equal(PRDataLong))
})