forked from quic-go/quic-go
http3: reject connection-specific header fields, check value of TE (#4655)
This commit is contained in:
@@ -28,6 +28,15 @@ type header struct {
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
// connection-specific header fields must not be sent on HTTP/3
|
||||
var invalidHeaderFields = [...]string{
|
||||
"connection",
|
||||
"keep-alive",
|
||||
"proxy-connection",
|
||||
"transfer-encoding",
|
||||
"upgrade",
|
||||
}
|
||||
|
||||
func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) {
|
||||
hdr := header{Headers: make(http.Header, len(headers))}
|
||||
var readFirstRegularHeader, readContentLength bool
|
||||
@@ -73,10 +82,16 @@ func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) {
|
||||
if !httpguts.ValidHeaderFieldName(h.Name) {
|
||||
return header{}, fmt.Errorf("invalid header field name: %q", h.Name)
|
||||
}
|
||||
for _, invalidField := range invalidHeaderFields {
|
||||
if h.Name == invalidField {
|
||||
return header{}, fmt.Errorf("invalid header field name: %q", h.Name)
|
||||
}
|
||||
}
|
||||
if h.Name == "te" && h.Value != "trailers" {
|
||||
return header{}, fmt.Errorf("invalid TE header field value: %q", h.Value)
|
||||
}
|
||||
readFirstRegularHeader = true
|
||||
switch h.Name {
|
||||
case "transfer-encoding":
|
||||
return header{}, errors.New("invalid header field: Transfer-Encoding")
|
||||
case "content-length":
|
||||
// Ignore duplicate Content-Length headers.
|
||||
// Fail if the duplicates differ.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package http3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@@ -369,13 +370,33 @@ var _ = Describe("Response", func() {
|
||||
Expect(err).To(MatchError("invalid response pseudo header: :method"))
|
||||
})
|
||||
|
||||
It("rejects the Transfer-Encoding header field", func() {
|
||||
DescribeTable("rejecting invalid header fields",
|
||||
func(invalidField string) {
|
||||
headers := []qpack.HeaderField{
|
||||
{Name: ":status", Value: "404"},
|
||||
{Name: "transfer-encoding", Value: "chunked"},
|
||||
{Name: invalidField, Value: "some-value"},
|
||||
}
|
||||
err := updateResponseFromHeaders(&http.Response{}, headers)
|
||||
Expect(err).To(MatchError("invalid header field: Transfer-Encoding"))
|
||||
Expect(err).To(MatchError(fmt.Sprintf("invalid header field name: %q", invalidField)))
|
||||
},
|
||||
Entry("connection", "connection"),
|
||||
Entry("keep-alive", "keep-alive"),
|
||||
Entry("proxy-connection", "proxy-connection"),
|
||||
Entry("transfer-encoding", "transfer-encoding"),
|
||||
Entry("upgrade", "upgrade"),
|
||||
)
|
||||
|
||||
It("rejects the TE header field, unless it is set to trailers", func() {
|
||||
headers := []qpack.HeaderField{
|
||||
{Name: ":status", Value: "404"},
|
||||
{Name: "te", Value: "trailers"},
|
||||
}
|
||||
Expect(updateResponseFromHeaders(&http.Response{}, headers)).To(Succeed())
|
||||
headers = []qpack.HeaderField{
|
||||
{Name: ":status", Value: "404"},
|
||||
{Name: "te", Value: "not-trailers"},
|
||||
}
|
||||
Expect(updateResponseFromHeaders(&http.Response{}, headers)).To(MatchError("invalid TE header field value: \"not-trailers\""))
|
||||
})
|
||||
|
||||
It("parses trailers", func() {
|
||||
|
||||
@@ -765,8 +765,7 @@ var _ = Describe("HTTP tests", func() {
|
||||
It("processes 1xx terminal response", func() {
|
||||
mux.HandleFunc("/101-switch-protocols", func(w http.ResponseWriter, r *http.Request) {
|
||||
defer GinkgoRecover()
|
||||
w.Header().Add("Connection", "upgrade")
|
||||
w.Header().Add("Upgrade", "proto")
|
||||
w.Header().Add("foo", "bar")
|
||||
w.WriteHeader(http.StatusSwitchingProtocols)
|
||||
})
|
||||
|
||||
@@ -787,8 +786,7 @@ var _ = Describe("HTTP tests", func() {
|
||||
resp, err := client.Do(req)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusSwitchingProtocols))
|
||||
Expect(resp.Header).To(HaveKeyWithValue("Connection", []string{"upgrade"}))
|
||||
Expect(resp.Header).To(HaveKeyWithValue("Upgrade", []string{"proto"}))
|
||||
Expect(resp.Header).To(HaveKeyWithValue("Foo", []string{"bar"}))
|
||||
Expect(status).To(Equal(0))
|
||||
Expect(cnt).To(Equal(0))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user