Skip to content

Remove redundant CanonicalizeHeaderKey from addApplicationHeaders - #2444

Open
kshitijsuri90 wants to merge 2 commits into
yarpc:mainfrom
kshitijsuri90:kshitij/remove-canonicalize-addheaders
Open

Remove redundant CanonicalizeHeaderKey from addApplicationHeaders#2444
kshitijsuri90 wants to merge 2 commits into
yarpc:mainfrom
kshitijsuri90:kshitij/remove-canonicalize-addheaders

Conversation

@kshitijsuri90

@kshitijsuri90 kshitijsuri90 commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Remove redundant transport.CanonicalizeHeaderKey call from addApplicationHeaders in transport/grpc/headers.go. The keys from Headers.Items() are already guaranteed lowercase by the Headers API contract.

Safety

  • Items() returns keys stored via With(), which always lowercases on insertion (CanonicalizeHeaderKey(k))
  • The items field is unexported — no external code can bypass With()
  • Items() doc: "Keys in the map are normalized using CanonicalizeHeaderKey"

Benchmark

count=6, AMD EPYC 9B45:

Benchmark Before (main) After (this PR) Change
AddApplicationHeaders 454.8 ns/op 441.3 ns/op -2.96% (p=0.002)

Test plan

  • All gRPC header tests pass
  • BenchmarkAddApplicationHeaders added and run with count=6

RELEASE NOTES: N/a


Update (2026-07-26): rebased onto current main. One positional conflict in transport/grpc/headers_test.go: main's newly-added BenchmarkIsReserved and this PR's BenchmarkAddApplicationHeaders were both appended at the same location — resolved by keeping both functions.

@kshitijsuri90
kshitijsuri90 force-pushed the kshitij/remove-canonicalize-addheaders branch from 7a039d5 to 8c472a6 Compare April 8, 2026 12:31
Comment thread transport/grpc/headers.go
func addApplicationHeaders(md metadata.MD, headers transport.Headers) error {
for header, value := range headers.Items() {
header = transport.CanonicalizeHeaderKey(header)
// Items() keys are already canonical (lowercased on insertion via With).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: comment is a bit confusing for first time readers.

@kshitijsuri90
kshitijsuri90 force-pushed the kshitij/remove-canonicalize-addheaders branch from 8c472a6 to e07f876 Compare July 27, 2026 08:32
@bananacocodrilo bananacocodrilo added this to the v1.89.8 milestone Aug 14, 2026
Problem:
addApplicationHeaders calls transport.CanonicalizeHeaderKey
(strings.ToLower) on every key from headers.Items() while building
outbound gRPC metadata. These keys are already lowercase, making the
call redundant CPU work on every outbound RPC.

Fix:
Remove the CanonicalizeHeaderKey call from addApplicationHeaders.

Safety — Items() keys are guaranteed lowercase by the Headers API:

- Items() returns the unexported items map whose keys are stored
  via With(), which always lowercases on insertion:
    canonicalizedKey := CanonicalizeHeaderKey(k)
    h.items[canonicalizedKey] = v
  https://github.com/yarpc/yarpc-go/blob/main/api/transport/header.go#L84-L85

- The items field is unexported, so no external code can bypass
  With() to insert non-canonical keys.

- The Items() doc explicitly states:
  "Keys in the map are normalized using CanonicalizeHeaderKey."

Call sites:
- transportRequestToMetadata at headers.go:131 (client outbound path)
- response_writer.go:70 (server response path)

Impact:
Eliminates one strings.ToLower scan per application header on the
client outbound and server response paths.

Benchmark (count=6, AMD EPYC 9B45):
  AddApplicationHeaders: 454.8 ns/op → 441.3 ns/op (-2.96%, p=0.002)

Rebase note (2026-07-26): rebased onto current main; resolved a
positional conflict in transport/grpc/headers_test.go where main's
newly-added BenchmarkIsReserved and this PR's BenchmarkAddApplicationHeaders
were both appended at the same spot — kept both functions.

Made-with: Cursor
@kshitijsuri90
kshitijsuri90 force-pushed the kshitij/remove-canonicalize-addheaders branch from e07f876 to 15d7b57 Compare August 18, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants