Repository navigation
http: percent-decode path segments for literal route matching - #37615
Nic-Polumeyv wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. WalkthroughChangesEncoded route matching
Suggested reviewers: Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to This PR fixes a real bug where percent-encoded literal route segments (e.g. '/robots.tx%74') failed to match their decoded route ('/robots.txt'), bringing literal route matching in line with existing parameter decoding. The change is narrowly scoped to route matching, includes a fast path to avoid decoding overhead on typical requests, and is covered by a comprehensive new test suite exercising the relevant edge cases (malformed escapes, encoded slashes, UTF-8, precedence, HEAD). No material risk was identified in this review. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/bun-uws/src/HttpRouter.h`:
- Around line 99-110: Update normalizePatternSegment and the route-node
representation in packages/bun-uws/src/HttpRouter.h (lines 99-110) to store node
kind separately from segment text, then decode every valid literal segment,
including values beginning with ':' or '*'; preserve parameter and wildcard
classification based on the original route syntax. In
test/js/bun/http/bun-serve-routes.test.ts (lines 343-350), add literal routes
for /api/%3Aname and /api/%2Aname and verify encoded and raw request spellings
reach the same handlers, covering both reserved-marker representations at the
route boundary.
In `@test/js/bun/http/bun-serve-routes.test.ts`:
- Around line 330-334: In the regression test near the issue reference, remove
the explanatory comment lines and retain only the single issue URL comment.
Leave the test name and assertions unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5a2ed9c5-2521-401f-a61f-da920a669581
📒 Files selected for processing (2)
packages/bun-uws/src/HttpRouter.htest/js/bun/http/bun-serve-routes.test.ts
| // https://github.com/oven-sh/bun/issues/37603 | ||
| // Literal route segments must match percent-encoded request spellings the same | ||
| // way :param segments already do: the path is split on raw "/" first, then | ||
| // each segment is percent-decoded, so %2F never creates a new separator and | ||
| // "/robots.tx%74" hits "/robots.txt". |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Keep the regression comment to the issue URL.
Remove the explanatory lines. The test name and assertions describe the covered behavior.
As per coding guidelines, “regression tests use one issue-URL comment.”
Proposed fix
// https://github.com/oven-sh/bun/issues/37603
-//
-// Literal route segments must match percent-encoded request spellings the same
-// way :param segments already do: the path is split on raw "/" first, then
-// each segment is percent-decoded, so %2F never creates a new separator and
-// "/robots.tx%74" hits "/robots.txt".📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // https://github.com/oven-sh/bun/issues/37603 | |
| // Literal route segments must match percent-encoded request spellings the same | |
| // way :param segments already do: the path is split on raw "/" first, then | |
| // each segment is percent-decoded, so %2F never creates a new separator and | |
| // "/robots.tx%74" hits "/robots.txt". | |
| // https://github.com/oven-sh/bun/issues/37603 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/js/bun/http/bun-serve-routes.test.ts` around lines 330 - 334, In the
regression test near the issue reference, remove the explanatory comment lines
and retain only the single issue URL comment. Leave the test name and assertions
unchanged.
Source: Coding guidelines
9cd17c9 to
fc849e0
Compare
Bun.serve routes matched literal segments against the raw request bytes while :param segments captured raw and percent-decoded afterwards, so '/robots.tx%74' missed the literal '/robots.txt' route (and fell through to fetch) while '/user/a%20b' matched '/user/:id' with id 'a b'. Decode per segment, matching what params already do: the path is still split on raw '/' first, then each segment is percent-decoded for literal comparison, so %2F never creates a new separator. Route pattern segments are normalized the same way at registration, so a route key spelled '/caf%C3%A9' matches both request spellings. A segment with no '%' costs one memchr; a segment with any malformed escape falls back to raw-byte comparison instead of erroring. Param capture still pushes the raw bytes so the params consumer's decode is not applied twice, and pattern segments whose decoded form would look like a param or wildcard keep their raw spelling (the raw request spelling still matches them). This lives in HttpRouter so every consumer - static Response routes, function routes, HTML bundle routes, negative routes, and the HTTP/3 router - matches identically. Requests that previously fell through to a :param, wildcard, or the fetch handler now hit the literal route when an encoded spelling decodes to it; that precedence shift is the fix. Fixes oven-sh#37603
fc849e0 to
2eeba97
Compare
What does this PR do?
Fixes #37603. uWS's
HttpRoutercompares literal segments against raw request bytes, while:paramvalues are percent-decoded after matching inServerRouteList, so/robots.tx%74misses a literal/robots.txtroute. This decodes per segment before literal comparison, inHttpRouteritself, so static, function, HTML, negative and HTTP/3 routes become consistent together. The path splits on raw/first, so%2Fnever creates a separator; route keys normalize the same way at registration; malformed escapes fall back to raw comparison; segments without%cost onememchr. Param capture still pushes raw bytes, decoded once as before.Observable change: requests whose encoded spelling decodes to a literal route now hit that route instead of falling through to a
:param, wildcard,fetch, or 404.How did you verify your code works?
10 new tests in bun-serve-routes: encoded spellings on static and function routes, encoded route keys against both wire spellings, hex case, malformed-escape raw fallback,
%2Fnon-separation, literal-over-param precedence, HEAD on an encoded literal. bun-serve-routes 65/0; serve-directory-routes, bun-serve-static, bun-serve-file, bun-serve-html, filesystem_router, serve-http3 and bun-server suites pass (the one bun-server failure reproduces on unpatched main). No existing test needed changes.