fix(router): deduplicate Vary response header during subgraph propagation#2723
fix(router): deduplicate Vary response header during subgraph propagation#2723vickyshaw29 wants to merge 2 commits intowundergraph:mainfrom
Conversation
…tion The gzhttp compression middleware unconditionally adds Vary: Accept-Encoding to every response. When subgraphs also return Vary: Accept-Encoding, the headerPropagationWriter.Write() method blindly appends it via wh.Add(), resulting in duplicate Vary: Accept-Encoding headers in the client response. This change adds value-level deduplication for the Vary header during subgraph response header propagation. Existing Vary values on the response are checked (case-insensitively) before adding new ones, preventing duplicates while still allowing novel Vary directives to be propagated. Fixes wundergraph#2614
Add TestHeaderPropagationWriterDeduplicatesVary with 5 subtests covering: - Exact duplicate prevention (gzhttp + subgraph both set Accept-Encoding) - New Vary value propagation (Origin added alongside existing Accept-Encoding) - Comma-separated Vary value handling from subgraphs - Case-insensitive deduplication - Non-Vary headers still propagated normally
WalkthroughModified the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
router/core/header_rule_engine_test.go (1)
446-454: Consider simplifying the assertion for clarity.The assertion on line 453 is convoluted:
assert.False(t, found["Accept-Encoding"] && len(varyValues) > 2)Since you're already asserting that
Accept-EncodingandOriginare both found, a direct length check would be clearer:♻️ Suggested simplification
varyValues := rec.Header().Values("Vary") found := make(map[string]bool) for _, v := range varyValues { found[http.CanonicalHeaderKey(v)] = true } assert.True(t, found["Accept-Encoding"]) assert.True(t, found["Origin"]) -assert.False(t, found["Accept-Encoding"] && len(varyValues) > 2) +assert.Len(t, varyValues, 2, "should have exactly 2 Vary values after deduplication")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@router/core/header_rule_engine_test.go` around lines 446 - 454, The final assertion is convoluted: instead of assert.False(t, found["Accept-Encoding"] && len(varyValues) > 2), replace it with a direct length check on varyValues (or use assert.Len) to ensure there are exactly two Vary entries since you already assert Accept-Encoding and Origin exist; update the test around the variables varyValues and found (populated from rec.Header().Values("Vary")) to assert len(varyValues) == 2 (or assert.Len(t, varyValues, 2) / assert.Equal(t, 2, len(varyValues))) for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@router/core/header_rule_engine_test.go`:
- Around line 446-454: The final assertion is convoluted: instead of
assert.False(t, found["Accept-Encoding"] && len(varyValues) > 2), replace it
with a direct length check on varyValues (or use assert.Len) to ensure there are
exactly two Vary entries since you already assert Accept-Encoding and Origin
exist; update the test around the variables varyValues and found (populated from
rec.Header().Values("Vary")) to assert len(varyValues) == 2 (or assert.Len(t,
varyValues, 2) / assert.Equal(t, 2, len(varyValues))) for clarity.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3afeced0-62fc-47ed-a793-ac71e0ad4924
📒 Files selected for processing (2)
router/core/header_rule_engine.gorouter/core/header_rule_engine_test.go
|
Hi @vickyshaw29, is there an accompanying issue for this PR? It seems like Claude has done most of the work here, and while the solution may function I'd suggest just adding We normally ask that there be an issue in advance to discuss what the best solution would be. I'd also encourage you to read our guidance on using AI in contributions: https://human-oss.dev |
|
Hey, thanks for the feedback. The accompanying issue is #2614. You are right, adding Vary to SkippedHeaders is the cleaner approach. Propagating it from subgraphs doesn't really serve a purpose since gzhttp already sets it on every compressed response. I overcomplicated this. I'll close this PR and open a fresh one with the simpler fix. Thanks for pointing me to the human-oss guidelines too, noted for future contributions. |
|
Hi @vickyshaw29, sounds good, remember to link the new PR to the issue in the description. |
Summary
The
gzhttpcompression middleware (klauspost/compress) unconditionally addsVary: Accept-Encodingto every response. When subgraphs also returnVary: Accept-Encoding, theheaderPropagationWriter.Write()method inheader_rule_engine.goblindly appends it viawh.Add(), resulting in duplicateVary: Accept-Encodingheaders in the client response.Root Cause
gzhttp.NewWrapper()ingraph_server.gowraps the handler and addsVary: Accept-Encodingviaw.Header().Add(vary, acceptEncoding)for every compressed responseheaderPropagationWriter.Write()inheader_rule_engine.gopropagates all collected subgraph response headers usingwh.Add(k, el)Varyis not in theSkippedHeadersmap ininternal/headers/headers.go, so subgraphVaryvalues get blindly appendedVary: Accept-Encoding, Vary: Accept-Encodingin the final responseChanges
router/core/header_rule_engine.go: ModifiedheaderPropagationWriter.Write()to deduplicateVaryheader values before propagating. Builds a set of existingVarydirectives (handling comma-separated values and case-insensitive comparison), then only adds new directives that aren't already present.router/core/header_rule_engine_test.go: AddedTestHeaderPropagationWriterDeduplicatesVarywith 5 subtests covering exact duplicate prevention, new value propagation, comma-separated value handling, case-insensitive deduplication, and non-Vary header passthrough.Checklist
Fixes #2614
Summary by CodeRabbit