Skip to content

Commit bb5c41a

Browse files
committed
Remove redundant CanonicalizeHeaderKey from metadata iteration paths
Problem: metadataToTransportRequest and getApplicationHeaders both call transport.CanonicalizeHeaderKey (strings.ToLower) on every key while iterating gRPC metadata.MD. These keys are already guaranteed to be lowercase, making the calls redundant CPU work on every inbound and response path. Fix: Remove the CanonicalizeHeaderKey call from both functions. Also normalize a test case in TestGetApplicationHeaders that used a mixed-case metadata key via a raw metadata.MD literal, which no longer reflects a realistic scenario. Safety — three independent guarantees that metadata keys are lowercase: 1. HTTP/2 spec (RFC 7540 s8.1.2): header field names MUST be converted to lowercase prior to their encoding in HTTP/2. The requirement is on the sender; receivers are guaranteed to see lowercase keys on the wire. https://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2 2. grpc-go PR #4416 (merged v1.39, June 2021): FromIncomingContext now explicitly lowercases all keys, including those injected by interceptors. grpc/grpc-go#4416 3. yarpc-go uses grpc-go v1.67.3 (go.mod), well past v1.39. Call sites: - metadataToTransportRequest: called from handler.go via metadata.FromIncomingContext (server inbound path) - getApplicationHeaders: called from outbound.go with response trailer metadata (client response path) Impact: Eliminates one strings.ToLower scan per metadata entry on both the server inbound and client response paths. Made-with: Cursor
1 parent cccfbde commit bb5c41a

2 files changed

Lines changed: 3 additions & 4 deletions

File tree

transport/grpc/headers.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ func metadataToTransportRequest(md metadata.MD) (*transport.Request, error) {
147147
default:
148148
return nil, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values)
149149
}
150-
header = transport.CanonicalizeHeaderKey(header)
151-
// skip routing header
150+
// gRPC metadata keys are already lowercase.
152151
if routingHeaders[header] {
153152
continue
154153
}
@@ -223,7 +222,7 @@ func getApplicationHeaders(md metadata.MD) (transport.Headers, error) {
223222
}
224223
headers := transport.NewHeadersWithCapacity(md.Len())
225224
for header, values := range md {
226-
header = transport.CanonicalizeHeaderKey(header)
225+
// gRPC metadata keys are already lowercase.
227226
if isReserved(header) {
228227
continue
229228
}

transport/grpc/headers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ func TestGetApplicationHeaders(t *testing.T) {
253253
"rpc-service": []string{"foo"}, // reserved header
254254
"test-header-empty": []string{}, // no value
255255
"test-header-valid-1": []string{"test-value-1"},
256-
"test-Header-Valid-2": []string{"test-value-2"},
256+
"test-header-valid-2": []string{"test-value-2"},
257257
},
258258
wantHeaders: map[string]string{
259259
"test-header-valid-1": "test-value-1",

0 commit comments

Comments
 (0)