Skip to content

Commit

Permalink
Use lowercase keys for gRPC-web trailers appended to the response body (
Browse files Browse the repository at this point in the history
#461)

As a partial solution to #453, lower-case keys when appending gRPC-Web
trailers to the response body. This is uncontroversial, since it only
affects a portion of the wire format specific to gRPC-Web.

This does _not_ address trailers-only responses or standard response
headers, which the gRPC-Web specification seems to also demand in
lowercase.

---------

Co-authored-by: Akshay Shah <[email protected]>
  • Loading branch information
timostamm and akshayjshah authored Feb 15, 2023
1 parent dfa669e commit 0b3c43c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
11 changes: 11 additions & 0 deletions protocol_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,17 @@ type grpcMarshaler struct {
func (m *grpcMarshaler) MarshalWebTrailers(trailer http.Header) *Error {
raw := m.envelopeWriter.bufferPool.Get()
defer m.envelopeWriter.bufferPool.Put(raw)
for key, values := range trailer {
// Per the Go specification, keys inserted during iteration may be produced
// later in the iteration or may be skipped. For safety, avoid mutating the
// map if the key is already lower-cased.
lower := strings.ToLower(key)
if key == lower {
continue
}
delete(trailer, key)
trailer[lower] = values
}
if err := trailer.Write(raw); err != nil {
return errorf(CodeInternal, "format trailers: %w", err)
}
Expand Down
20 changes: 20 additions & 0 deletions protocol_grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,23 @@ func TestGRPCPercentEncoding(t *testing.T) {
roundtrip(`foo%bar`)
roundtrip("fiancée")
}

func TestGRPCWebTrailerMarshalling(t *testing.T) {
t.Parallel()
responseWriter := httptest.NewRecorder()
marshaler := grpcMarshaler{
envelopeWriter: envelopeWriter{
writer: responseWriter,
bufferPool: newBufferPool(),
},
}
trailer := http.Header{}
trailer.Add("grpc-status", "0")
trailer.Add("Grpc-Message", "Foo")
trailer.Add("User-Provided", "bar")
err := marshaler.MarshalWebTrailers(trailer)
assert.Nil(t, err)
responseWriter.Body.Next(5) // skip flags and message length
marshalled := responseWriter.Body.String()
assert.Equal(t, marshalled, "grpc-message: Foo\r\ngrpc-status: 0\r\nuser-provided: bar\r\n")
}

0 comments on commit 0b3c43c

Please sign in to comment.