fix(http): normalize trailing slash in static file endpoints (#3827) - #4149
ogMaverick12 wants to merge 3 commits into
Conversation
|
Hi @aryanmehrotra — when you get a moment, would you mind taking a look? This fixes #3827, which you had flagged during the review of #3820. It's a one-line normalization change (TrimPrefix → Trim) plus a regression test covering all four endpoint forms. Thanks! |
|
Thanks for picking this up, and for the write-up — the diagnosis is exactly right, and I reproduced it both ways locally: with One thing I'd like sorted before merge, and it's about where the fix sits rather than whether it works.
Worth noting that your own test calls it directly, which is a good sign that it's a real entry point. We already have the precedent for this one function down: func (rou *Router) AddStaticFiles(logger logging.Logger, endpoint, dirName string) {
// The route patterns below are built from endpoint verbatim, and ServeHTTP normalizes
// incoming paths with path.Clean — so an endpoint carrying a leading or trailing slash
// registers a pattern no request can ever match. Normalize here, where the patterns are
// built, so a direct caller cannot register a dead route either.
endpoint = "/" + strings.Trim(endpoint, "/")
absDir, err := filepath.Abs(dirName)
...Keep your Two practical notes for the next push, neither of them a problem with the change itself:
On process: the issue had no maintainer comment agreeing the approach, and someone else had asked for it a month earlier without a PR. The fix here matches what the issue itself suggested so I'm not asking you to unwind anything — just flagging that for the next one, a quick check on the issue before opening the PR saves everyone the rework risk. |
a287638 to
3538ad9
Compare
|
Done — thanks for the thorough check. Normalization now also lives in Router.AddStaticFiles (kept the gofr.go line for the log consistency), with Test_StaticFileServing_EndpointForms next to DirectoryNameForms and a shared const for the goconst nit. Rebased onto development so the full suite can run. Both new tests were verified to fail pre-fix (404s) and pass post-fix. And noted on the process point — I'll check for maintainer agreement on the issue before opening the next PR. |
|
@aryanmehrotra — flagging that the requested changes are pushed and ready for another look when you have a moment. Thanks! |
|
This is exactly it — thanks for turning it around so quickly. I re-verified rather than taking the description on trust, and everything holds up. I mutation-tested the two tests separately: reverting only the I also ran it as a real app rather than only through Checked the cases the normalization could have broken, since it now runs before the Lint is clean too: with the const in place the finding count is identical to the base, so nothing new surfaced. One thing outstanding on my side rather than yours — the Actions workflows haven't run on this branch yet, only Snyk. I'll get those triggered so we can see the full matrix before merging. |
|
Thank you for the thorough verification — the separate mutation testing of both layers is especially reassuring. CI is fully green on my side, so please let me know if anything else is needed before merge. @aryanmehrotra |
Umang01-hash
left a comment
There was a problem hiding this comment.
APPROVE — verified at head 3538ad9.
The bug is real and I reproduced it: with the old leading-only TrimPrefix, a trailing-slash endpoint registers Path("/static/") + PathPrefix("/static//"), the server logs 'registered static files at endpoint /static//' (success), yet every request 404s because ServeHTTP path.Clean's them to /static and /static/x which match neither pattern. Normalizing with strings.Trim at both entry points (gofr.go App + router.go direct caller) fixes it.
Verified:
- Revert-red: restoring TrimPrefix turns the trailing_slash and leading_and_trailing_slash subtests RED; restored -> green. The tests drive the real router.ServeHTTP asserting 200 + body, across all four endpoint forms.
- Live E2E: AddStaticFiles("static/", ...) now serves /static/hello.txt=200, /static/index.html=200, /static=200. DELETE -> 405 with Allow: GET, HEAD (method guard intact). /static/../main.go and %2e%2e -> 404, no traversal leak.
- No breaking change (signature unchanged; only previously-dead routes start working). No security impact — the endpoint normalization doesn't touch the containment guard.
- gofmt/vet/build clean; full static-file regression suites pass; golangci-lint --new-from-rev = 0 issues.
Nit: the branch (fix/cron-docs-3876) and title (#3827) are mismatched leftover naming — cosmetic.
Umang01-hash
left a comment
There was a problem hiding this comment.
Verified against head 76c8fb5. Real dead-route bug: a trailing-slash endpoint registered Path("/static/")+PathPrefix("/static//"), but ServeHTTP's path.Clean turns an incoming /static/ into /static so it matched nothing and 404'd. strings.Trim(endpoint, "/") at both registration sites fixes it. Ran locally: full pkg/gofr/http suite -race and pkg/gofr -short both green; both changed lines are mutation-pinned (reverting router.go OR gofr.go reddens a test); golangci-lint --new-from-rev clean. No exported-API break, no regression to correct /static usage.
Nit (non-code): branch is fix/cron-docs-3876 but the PR is the static-file fix #3827 — reused branch, cosmetic.
Description:
Fixes #3827.
App.AddStaticFilesnormalized the endpoint withstrings.TrimPrefix(endpoint, "/"), which strips only a leading slash. A trailing slash survived into the stored endpoint, causingAddStaticFiles("static/", dir)to register a dead route and return 404s despite logging success.Replace
strings.TrimPrefixwithstrings.Trimsostatic,/static,static/, and/static/all normalize to/static.Verified with a new table-driven regression test covering all four endpoint forms. The test reproduces the failure on the original implementation and passes with the fix. The relevant
pkg/gofrandpkg/gofr/httptest suites pass, andgo vet ./pkg/gofr/is clean.Breaking Changes (if applicable):
None. This only changes previously-dead trailing-slash inputs from returning 404 to serving the intended static files.
Additional Information:
No new dependencies. The regression test exercises the stored endpoint through the real router and verifies both
/staticand/static/index.html.Checklist: