Skip to content

Commit

Permalink
don't require the presense of the Capsule protocol header (#78)
Browse files Browse the repository at this point in the history
The header is optional. We only need to verify the value if the header
is present.
  • Loading branch information
marten-seemann authored Nov 15, 2024
1 parent 7499833 commit b312bc5
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 33 deletions.
40 changes: 19 additions & 21 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,27 @@ func ParseRequest(r *http.Request, template *uritemplate.Template) (*Request, er
Err: fmt.Errorf("host in :authority (%s) does not match template host (%s)", r.Host, u.Host),
}
}
// The capsule protocol header is optional, but if it's present,
// we need to validate its value.
capsuleHeaderValues, ok := r.Header[http3.CapsuleProtocolHeader]
if !ok {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("missing Capsule-Protocol header"),
}
}
item, err := httpsfv.UnmarshalItem(capsuleHeaderValues)
if err != nil {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("invalid capsule header value: %s", capsuleHeaderValues),
if ok {
item, err := httpsfv.UnmarshalItem(capsuleHeaderValues)
if err != nil {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("invalid capsule header value: %s", capsuleHeaderValues),
}
}
}
if v, ok := item.Value.(bool); !ok {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("incorrect capsule header value type: %s", reflect.TypeOf(item.Value)),
}
} else if !v {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("incorrect capsule header value: %t", item.Value),
if v, ok := item.Value.(bool); !ok {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("incorrect capsule header value type: %s", reflect.TypeOf(item.Value)),
}
} else if !v {
return nil, &RequestParseError{
HTTPStatus: http.StatusBadRequest,
Err: fmt.Errorf("incorrect capsule header value: %t", item.Value),
}
}
}

Expand Down
25 changes: 13 additions & 12 deletions request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"testing"

"github.com/dunglas/httpsfv"
"github.com/stretchr/testify/require"
"github.com/quic-go/quic-go/http3"
"github.com/yosida95/uritemplate/v3"

"github.com/stretchr/testify/require"
)

func TestRequestParsing(t *testing.T) {
Expand All @@ -34,6 +36,13 @@ func TestRequestParsing(t *testing.T) {
require.Equal(t, r.Target, "[::1]:1234")
})

t.Run("valid request, without the Capsule-Protocol header", func(t *testing.T) {
req := newRequest("https://localhost:1234/masque?h=localhost&p=1337")
req.Header.Del(http3.CapsuleProtocolHeader)
_, err := ParseRequest(req, template)
require.NoError(t, err)
})

t.Run("wrong request method", func(t *testing.T) {
req := newRequest("https://localhost:1234/masque")
req.Method = http.MethodHead
Expand All @@ -57,25 +66,17 @@ func TestRequestParsing(t *testing.T) {
require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus)
})

t.Run("missing Capsule-Protocol header", func(t *testing.T) {
req := newRequest("https://localhost:1234/masque")
req.Header.Del("Capsule-Protocol")
_, err := ParseRequest(req, template)
require.EqualError(t, err, "missing Capsule-Protocol header")
require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus)
})

t.Run("invalid Capsule-Protocol header", func(t *testing.T) {
req := newRequest("https://localhost:1234/masque")
req.Header.Set("Capsule-Protocol", "🤡")
req.Header.Set(http3.CapsuleProtocolHeader, "🤡")
_, err := ParseRequest(req, template)
require.EqualError(t, err, "invalid capsule header value: [🤡]")
require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus)
})

t.Run("invalid Capsule-Protocol header value type", func(t *testing.T) {
req := newRequest("https://localhost:1234/masque")
req.Header.Set("Capsule-Protocol", "1")
req.Header.Set(http3.CapsuleProtocolHeader, "1")
_, err := ParseRequest(req, template)
require.EqualError(t, err, "incorrect capsule header value type: int64")
require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus)
Expand All @@ -85,7 +86,7 @@ func TestRequestParsing(t *testing.T) {
req := newRequest("https://localhost:1234/masque")
v, err := httpsfv.Marshal(httpsfv.NewItem(false))
require.NoError(t, err)
req.Header.Set("Capsule-Protocol", v)
req.Header.Set(http3.CapsuleProtocolHeader, v)
_, err = ParseRequest(req, template)
require.EqualError(t, err, "incorrect capsule header value: false")
require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus)
Expand Down

0 comments on commit b312bc5

Please sign in to comment.