Skip to content

Commit a51e1d5

Browse files
tmcyugui
authored andcommitted
Pass permanent HTTP request headers (#252)
* Pass Permanent Request Headers * Fix tests and update pr213
1 parent 2dbcd36 commit a51e1d5

File tree

4 files changed

+61
-13
lines changed

4 files changed

+61
-13
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ To use the same port for custom HTTP handlers (e.g. serving `swagger.json`), gRP
206206
* Method parameters in query string
207207
* Enum fields in path parameter (including repeated enum fields).
208208
* Mapping streaming APIs to newline-delimited JSON streams
209-
* Mapping HTTP headers with `Grpc-Metadata-` prefix to gRPC metadata
209+
* Mapping HTTP headers with `Grpc-Metadata-` prefix to gRPC metadata (prefixed with `grpcgateway-`)
210210
* Optionally emitting API definition for [Swagger](http://swagger.io).
211211
* Setting [gRPC timeouts](http://www.grpc.io/docs/guides/wire.html) through inbound HTTP `Grpc-Timeout` header.
212212
@@ -229,7 +229,8 @@ But patch is welcome.
229229
* HTTP request source IP is added as `X-Forwarded-For` gRPC request header
230230
* HTTP request host is added as `X-Forwarded-Host` gRPC request header
231231
* HTTP `Authorization` header is added as `authorization` gRPC request header
232-
* Remaining HTTP header keys are prefixed with `Grpc-Metadata-` and added with their values to gRPC request header
232+
* Remaining Permanent HTTP header keys (as specified by the IANA [here](http://www.iana.org/assignments/message-headers/message-headers.xhtml) are prefixed with `grpcgateway-` and added with their values to gRPC request header
233+
* HTTP headers that start with 'Grpc-Metadata-' are mapped to gRPC metadata (prefixed with `grpcgateway-`)
233234
* While configurable, the default {un,}marshaling uses [jsonpb](https://godoc.org/github.com/golang/protobuf/jsonpb) with `OrigName: true`.
234235
235236
# Contribution

examples/integration_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ func testEchoBody(t *testing.T) {
128128
}
129129

130130
if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want {
131-
t.Errorf("Grpc-Header-Foo was %q, wanted %q", got, want)
131+
t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want)
132132
}
133133
if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want {
134-
t.Errorf("Grpc-Header-Bar was %q, wanted %q", got, want)
134+
t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want)
135135
}
136136

137137
if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want {
@@ -369,7 +369,7 @@ func testABEBulkCreate(t *testing.T) {
369369
}
370370

371371
if got, want := resp.Header.Get("Grpc-Metadata-Count"), fmt.Sprintf("%d", count); got != want {
372-
t.Errorf("Grpc-Header-Count was %q, wanted %q", got, want)
372+
t.Errorf("Grpc-Metadata-Count was %q, wanted %q", got, want)
373373
}
374374

375375
if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want {
@@ -518,7 +518,7 @@ func testABEList(t *testing.T) {
518518

519519
value := resp.Header.Get("Grpc-Metadata-Count")
520520
if value == "" {
521-
t.Errorf("Grpc-Header-Count should not be empty")
521+
t.Errorf("Grpc-Metadata-Count should not be empty")
522522
}
523523

524524
count, err := strconv.Atoi(value)

runtime/context.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ import (
1515
"google.golang.org/grpc/metadata"
1616
)
1717

18-
// MetadataHeaderPrefix is prepended to HTTP headers in order to convert them to
19-
// gRPC metadata for incoming requests processed by grpc-gateway
18+
// MetadataHeaderPrefix is the http prefix that represents custom metadata
19+
// parameters to or from a gRPC call.
2020
const MetadataHeaderPrefix = "Grpc-Metadata-"
21+
22+
// MetadataPrefix is the prefix for grpc-gateway supplied custom metadata fields.
23+
const MetadataPrefix = "grpcgateway-"
24+
2125
// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
2226
// HTTP headers in a response handled by grpc-gateway
2327
const MetadataTrailerPrefix = "Grpc-Trailer-"
28+
2429
const metadataGrpcTimeout = "Grpc-Timeout"
2530

2631
const xForwardedFor = "X-Forwarded-For"
@@ -52,8 +57,12 @@ func AnnotateContext(ctx context.Context, req *http.Request) (context.Context, e
5257

5358
for key, vals := range req.Header {
5459
for _, val := range vals {
55-
if key == "Authorization" {
60+
// For backwards-compatibility, pass through 'authorization' header with no prefix.
61+
if strings.ToLower(key) == "authorization" {
5662
pairs = append(pairs, "authorization", val)
63+
}
64+
if isPermanentHTTPHeader(key) {
65+
pairs = append(pairs, strings.ToLower(fmt.Sprintf("%s%s", MetadataPrefix, key)), val)
5766
continue
5867
}
5968
if strings.HasPrefix(key, MetadataHeaderPrefix) {
@@ -141,3 +150,38 @@ func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) {
141150
}
142151
return
143152
}
153+
154+
// isPermanentHTTPHeader checks whether hdr belongs to the list of
155+
// permenant request headers maintained by IANA.
156+
// http://www.iana.org/assignments/message-headers/message-headers.xml
157+
func isPermanentHTTPHeader(hdr string) bool {
158+
switch hdr {
159+
case
160+
"Accept",
161+
"Accept-Charset",
162+
"Accept-Language",
163+
"Accept-Ranges",
164+
"Authorization",
165+
"Cache-Control",
166+
"Content-Type",
167+
"Cookie",
168+
"Date",
169+
"Expect",
170+
"From",
171+
"Host",
172+
"If-Match",
173+
"If-Modified-Since",
174+
"If-None-Match",
175+
"If-Schedule-Tag-Match",
176+
"If-Unmodified-Since",
177+
"Max-Forwards",
178+
"Origin",
179+
"Pragma",
180+
"Referer",
181+
"User-Agent",
182+
"Via",
183+
"Warning":
184+
return true
185+
}
186+
return false
187+
}

runtime/context_test.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,17 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) {
5151
return
5252
}
5353
md, ok := metadata.FromContext(annotated)
54-
if got, want := len(md), emptyForwardMetaCount+3; !ok || got != want {
55-
t.Errorf("Expected %d metadata items in context; got %d", got, want)
54+
if got, want := len(md), emptyForwardMetaCount+4; !ok || got != want {
55+
t.Errorf("metadata items in context = %d want %d: %v", got, want, md)
5656
}
5757
if got, want := md["foobar"], []string{"Value1"}; !reflect.DeepEqual(got, want) {
58-
t.Errorf(`md["foobar"] = %q; want %q`, got, want)
58+
t.Errorf(`md["grpcgateway-foobar"] = %q; want %q`, got, want)
5959
}
6060
if got, want := md["foo-baz"], []string{"Value2", "Value3"}; !reflect.DeepEqual(got, want) {
61-
t.Errorf(`md["foo-baz"] = %q want %q`, got, want)
61+
t.Errorf(`md["grpcgateway-foo-baz"] = %q want %q`, got, want)
62+
}
63+
if got, want := md["grpcgateway-authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) {
64+
t.Errorf(`md["grpcgateway-authorization"] = %q want %q`, got, want)
6265
}
6366
if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) {
6467
t.Errorf(`md["authorization"] = %q want %q`, got, want)

0 commit comments

Comments
 (0)