Skip to content

fix: preserve a req.url rewritten inside a mounted layer - #206

Open
bilashcse wants to merge 3 commits into
pillarjs:masterfrom
bilashcse:fix/preserve-rewritten-req-url
Open

fix: preserve a req.url rewritten inside a mounted layer#206
bilashcse wants to merge 3 commits into
pillarjs:masterfrom
bilashcse:fix/preserve-rewritten-req-url

Conversation

@bilashcse

Copy link
Copy Markdown

Fixes the req.url rewriting bug reported in expressjs/express#4059.

Problem

When a layer mounted with a path is entered and there is nothing left of the path, the router injects a leading slash so that req.url is never an empty string. On the way back out that slash was removed unconditionally, even when the layer had replaced req.url in the meantime, so the mount path was restored without a separator:

const router = new Router()

router.use('/foo', function (req, res, next) {
  req.url = '/bar'
  next()
})

router.use(function (req, res) {
  res.end(req.url) // => '/foobar', expected '/foo/bar'
})

GET /foo (no trailing slash) is the trigger; with GET /foo/ there is nothing to strip and the rewrite works as expected. This is what breaks rewriting middleware such as connect-history-api-fallback when it is mounted on a path.

Fix

Remember the exact url the injected slash produced and only strip it again when the layer left req.url untouched. Comparing against the stored value rather than against '/' also keeps it correct when a query string is present, since the injected value is then '/?...' rather than '/'.

Tests

Two regression tests under .use(path, ...fn) > req.url, one plain and one where the original url carried a query string. The existing strip/restore tests are untouched.

Docs

Added a note to the router.use([path], ...middleware) section: the stripped path is added back when the middleware calls next(), and a rewritten req.url is treated as relative to the mount path.

When a layer mounted with a path is entered and nothing is left of the path, the router injects a leading slash into req.url. That slash used to be removed unconditionally on the way out, so when the layer rewrote req.url the real leading slash was stripped and the mount path was restored without a separator (/app + /index.html became /appindex.html).

Remember the exact URL the injected slash produced and only strip it again when the layer left req.url untouched.

Ref: expressjs/express#4059
Regression tests for the mount path being restored without a separator when a layer rewrote req.url, including the case where the original url carried a query string.
The stripped mount path is only mentioned as being removed, not as being added back, which makes the behavior of rewriting req.url inside a mounted middleware unclear.
@bilashcse

Copy link
Copy Markdown
Author

CI here is waiting on maintainer approval, so I ran the ci workflow on my fork against this branch: all 7 Test - Node.js 18..24 jobs are green. The only red job is coverage, which fails on forks because the Coveralls repo token is not available, and is unrelated to this change.

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.

1 participant