Skip to content

fix: deduplicate Allow header methods in 405 responses#1112

Open
LeSingh1 wants to merge 1 commit into
go-chi:masterfrom
LeSingh1:fix/deduplicate-allow-header
Open

fix: deduplicate Allow header methods in 405 responses#1112
LeSingh1 wants to merge 1 commit into
go-chi:masterfrom
LeSingh1:fix/deduplicate-allow-header

Conversation

@LeSingh1

Copy link
Copy Markdown

Problem

When multiple overlapping parameterized route patterns all register the same HTTP method, a request with an unregistered method produces duplicate entries in the Allow response header.

Minimal reproduction (from #996):

r.Post("/article/1-2-3", ...)
r.Post("/article/{a}", ...)
r.Post("/article/{b}-{c}", ...)
r.Post("/article/{b}-{c}-{d}", ...)

// GET /article/1-2-3 → 405 with Allow: POST, POST, POST, POST

Each parameterized node that matched during route traversal independently appended POST to rctx.methodsAllowed []methodTyp. The methodNotAllowedHandler then wrote one Allow header value per slice entry — one per matched node — instead of one per distinct method.

Fix

Replace methodsAllowed []methodTyp in Context with a methodTyp bitmask. Since methodTyp is already defined as a bitmask of power-of-two constants, each candidate node can OR its methods into the bitmask (rctx.methodsAllowed |= endpoints) rather than append to a slice. methodNotAllowedHandler then iterates reverseMethodMap and emits one Allow header entry for each bit that is set — guaranteeing uniqueness without any extra allocation.

Changes

  • context.go: methodsAllowed []methodTypmethodsAllowed methodTyp; Reset() zeroes with = 0
  • tree.go: two append(rctx.methodsAllowed, ...)rctx.methodsAllowed |= endpoints
  • mux.go: MethodNotAllowedHandler and methodNotAllowedHandler take a single methodTyp bitmask instead of ...methodTyp; handler iterates reverseMethodMap by bitmask
  • mux_test.go: TestMethodNotAllowedNoDuplicates — regression test from the exact scenario in Duplicate HTTP methods in 405 Allow header #996

Test plan

  • TestMethodNotAllowedNoDuplicates — asserts no duplicate values in Allow header and that POST is present
  • Existing TestMethodNotAllowed still passes (2 distinct methods, GET and HEAD, each appear once)
  • go test ./...

Fixes #996

When multiple overlapping parameterized route patterns all have the same
HTTP method registered (e.g. /{a}, /{b}-{c}, /{b}-{c}-{d}), a request
with an unregistered method would trigger methodNotAllowed on each
matching node, appending the allowed method to rctx.methodsAllowed
multiple times. The 405 handler then wrote one Allow header entry per
duplicate, producing responses like 'Allow: POST, POST, POST, POST'.

Fix: change rctx.methodsAllowed from []methodTyp to a methodTyp bitmask.
Each candidate node ORs its allowed methods into the bitmask instead of
appending to a slice, so each method appears at most once. The
methodNotAllowedHandler iterates reverseMethodMap and sets an Allow
header entry for each bit that is set.

Fixes go-chi#996
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate HTTP methods in 405 Allow header

1 participant