Skip to content

Commit 47d5e3f

Browse files
committed
flag to disable encoding of regex matches in 'rewrites' and 'redirects'
primary use case: * regex pattern matches a subset of the URL pathname example (configs): - source: '/foo/:bar*' - destination: '/:bar' - purpose: * 'rewrites' rule would be used to silently ignore the leading 'foo/' directory in path * 'redirects' rule would be used to trigger a 301 redirect to a new URL that removes the leading 'foo/' directory in path example (behavior): - request URL path: '/foo/a/b/c/d/e/f.txt' - :bar interpolates to value (before encoding): 'a/b/c/d/e/f.txt' - :bar interpolates to value (after default encoding): encodeURIComponent('a/b/c/d/e/f.txt') === 'a%2Fb%2Fc%2Fd%2Fe%2Ff.txt' * if the corresponding 'rewrites' or 'redirects' rule includes the flag: {"raw": true} then the raw value will be returned without any encoding based on: * upstream PR 85 vercel/serve-handler#85 references: * pathToRegExp.compile(data, options) https://github.com/pillarjs/path-to-regexp#compile-reverse-path-to-regexp road blocks: * pathToRegExp bug pillarjs/path-to-regexp#260 pillarjs/path-to-regexp#261 status: - the desired behavior will remain broken until this PR is merged - 'source' patterns that match one or more '/' characters cause the library to throw an Error for a failed assertion
1 parent 897b9e6 commit 47d5e3f

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

lib/serve-handler/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ You can also use so-called "routing segments" as follows:
130130
```json
131131
{
132132
"rewrites": [
133-
{ "source": "/projects/:id/edit", "destination": "/edit-project-:id.html" },
133+
{ "source": "/projects/:id/edit", "destination": "/edit-project-:id.html" }
134134
]
135135
}
136136
```
@@ -139,6 +139,16 @@ Now, if a visitor accesses `/projects/123/edit`, it will respond with the file `
139139

140140
**NOTE:** The paths can contain globs (matched using [minimatch](https://github.com/isaacs/minimatch)) or regular expressions (match using [path-to-regexp](https://github.com/pillarjs/path-to-regexp)).
141141

142+
By default, values matched by a regular expression are encoded by `encodeURIComponent` before being included in the rewritten URL. This encoding can be disabled with the flag:
143+
144+
```json
145+
{
146+
"rewrites": [
147+
{ "source": "/foo/:bar*", "destination": "/:bar", "raw": true }
148+
]
149+
}
150+
```
151+
142152
### redirects (Array)
143153

144154
In order to redirect visits to a certain path to a different one (or even an external URL), you can use this option:
@@ -167,7 +177,7 @@ Just like with [rewrites](#rewrites-array), you can also use routing segments:
167177

168178
In the example above, `/old-docs/12` would be forwarded to `/new-docs/12` with status code [301](https://en.wikipedia.org/wiki/HTTP_301). In addition `/old` would be forwarded to `/new` with status code [302](https://en.wikipedia.org/wiki/HTTP_302).
169179

170-
**NOTE:** The paths can contain globs (matched using [minimatch](https://github.com/isaacs/minimatch)) or regular expressions (match using [path-to-regexp](https://github.com/pillarjs/path-to-regexp)).
180+
**NOTE:** The paths can contain globs (matched using [minimatch](https://github.com/isaacs/minimatch)) or regular expressions (match using [path-to-regexp](https://github.com/pillarjs/path-to-regexp)). Just like with [rewrites](#rewrites-array), you can also disable the encoding of regular expression matches by adding `{raw: true}`.
171181

172182
By default, the querystring and hash are not preserved by the redirect. The following boolean attributes enable this behavior:
173183

lib/serve-handler/src/index.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const sourceMatches = (source, requestPath, allowSegments) => {
6868
return null
6969
}
7070

71-
const toTarget = (source, destination, previousPath) => {
71+
const toTarget = (source, destination, previousPath, raw) => {
7272
const matches = sourceMatches(source, previousPath, true)
7373

7474
if (!matches) {
@@ -87,7 +87,9 @@ const toTarget = (source, destination, previousPath) => {
8787
props[name] = results[index + 1]
8888
}
8989

90-
return toPath(props)
90+
const options = raw ? {encode: value => value} : {}
91+
92+
return toPath(props, options)
9193
}
9294

9395
const applyRewrites = (requestPath, rewrites = [], repetitive) => {
@@ -103,8 +105,8 @@ const applyRewrites = (requestPath, rewrites = [], repetitive) => {
103105
}
104106

105107
for (let index = 0; index < rewritesCopy.length; index++) {
106-
const {source, destination} = rewrites[index]
107-
const target = toTarget(source, destination, requestPath)
108+
const {source, destination, raw} = rewrites[index]
109+
const target = toTarget(source, destination, requestPath, raw)
108110

109111
if (target) {
110112
// Remove rules that were already applied
@@ -177,8 +179,8 @@ const shouldRedirect = (decodedPath, {redirects = [], trailingSlash}, cleanUrl)
177179
// This is currently the fastest way to
178180
// iterate over an array
179181
for (let index = 0; index < redirects.length; index++) {
180-
const {source, destination, type, preserveQuery, preserveHash} = redirects[index]
181-
const target = toTarget(source, destination, decodedPath)
182+
const {source, destination, type, preserveQuery, preserveHash, raw} = redirects[index]
183+
const target = toTarget(source, destination, decodedPath, raw)
182184

183185
if (target) {
184186
return {

0 commit comments

Comments
 (0)