http3: add client-side HTTP Trailer support (#4581)

* http3: add HTTP Trailer support for clients

This change only adds support to read HTTP trailers sent to clients.

* chore: add protection against some out-of-spec behavior + tests

* chore: re-add test accidentally overwtitten

* chore: empty commit to re-trigger ci

* fix: address some review notes (wip)

* fix: simplify code in stream.Read by using a callback from requestStream.ReadResponse

* restructure where trailers are read and parsed

* WIP simplify trailer parsing design

* chore: refactor to use simpler trailer parsing strategy

* make gofumpt happy

* Update http3/headers.go

Co-authored-by: Marten Seemann <martenseemann@gmail.com>

* remove stray TODO

---------

Co-authored-by: Marten Seemann <martenseemann@gmail.com>
This commit is contained in:
Kevin McDonald
2024-08-23 07:25:58 +02:00
committed by GitHub
parent d067fe4156
commit 17fb3b96ba
8 changed files with 221 additions and 51 deletions

View File

@@ -178,25 +178,28 @@ func hostnameFromURL(url *url.URL) string {
return ""
}
func responseFromHeaders(headerFields []qpack.HeaderField) (*http.Response, error) {
// updateResponseFromHeaders sets up http.Response as an HTTP/3 response,
// using the decoded qpack header filed.
// It is only called for the HTTP header (and not the HTTP trailer).
// It takes an http.Response as an argument to allow the caller to set the trailer later on.
func updateResponseFromHeaders(rsp *http.Response, headerFields []qpack.HeaderField) error {
hdr, err := parseHeaders(headerFields, false)
if err != nil {
return nil, err
return err
}
if hdr.Status == "" {
return nil, errors.New("missing status field")
}
rsp := &http.Response{
Proto: "HTTP/3.0",
ProtoMajor: 3,
Header: hdr.Headers,
ContentLength: hdr.ContentLength,
return errors.New("missing status field")
}
rsp.Proto = "HTTP/3.0"
rsp.ProtoMajor = 3
rsp.Header = hdr.Headers
rsp.ContentLength = hdr.ContentLength
status, err := strconv.Atoi(hdr.Status)
if err != nil {
return nil, fmt.Errorf("invalid status code: %w", err)
return fmt.Errorf("invalid status code: %w", err)
}
rsp.StatusCode = status
rsp.Status = hdr.Status + " " + http.StatusText(status)
return rsp, nil
return nil
}