Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

type custom, for redirect and rewrite has #27431

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/api-reference/next.config.js/redirects.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ To only match a redirect when header, cookie, or query values also match the `ha

`has` items have the following fields:

- `type`: `String` - must be either `header`, `cookie`, `host`, or `query`.
- `type`: `String` - must be either `header`, `cookie`, `host`, `query`, or `custom`.
- `key`: `String` - the key from the selected type to match against.
- `value`: `String` or `undefined` - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value `first-(?<paramName>.*)` is used for `first-second` then `second` will be usable in the destination with `:paramName`.
- `check`: `Function` - when the `type` is `custom`, `check` is a function that accepts `req` and returns `false` when it should not redirect, `true` when it should redirect, or a parameters object, with parameters to be used in the redirection.

```js
module.exports = {
Expand Down Expand Up @@ -198,6 +199,18 @@ module.exports = {
],
destination: '/another-page',
},
// if a custom check matches (the cookie foo should be equal to the query parameter foo),
// this redirect will be applied
{
source: '/some-page',
has: [
{
type: 'custom',
check: req => req.cookies.foo === req.query.foo
},
],
destination: '/another-page',
},
]
},
}
Expand Down
15 changes: 14 additions & 1 deletion docs/api-reference/next.config.js/rewrites.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,10 @@ To only match a rewrite when header, cookie, or query values also match the `has

`has` items have the following fields:

- `type`: `String` - must be either `header`, `cookie`, `host`, or `query`.
- `type`: `String` - must be either `header`, `cookie`, `host`, `query`, or `custom`.
- `key`: `String` - the key from the selected type to match against.
- `value`: `String` or `undefined` - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value `first-(?<paramName>.*)` is used for `first-second` then `second` will be usable in the destination with `:paramName`.
- `check`: `Function` - when the `type` is `custom`, `check` is a function that accepts `req` and returns `false` when it should not rewrite, `true` when it should redirect, or a parameters object, with parameters to be used in the redirection.

```js
module.exports = {
Expand Down Expand Up @@ -288,6 +289,18 @@ module.exports = {
],
destination: '/another-page',
},
// if a custom check matches (the cookie foo should be equal to the query parameter foo),
// this redirect will be applied
{
source: '/some-page',
has: [
{
type: 'custom',
check: (req) => req.cookies.foo === req.query.foo,
},
],
destination: '/another-page',
},
]
},
}
Expand Down
9 changes: 9 additions & 0 deletions packages/next/lib/load-custom-routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import chalk from 'chalk'
import { IncomingMessage } from 'http'
import { parse as parseUrl } from 'url'
import { NextConfig } from '../server/config'
import * as pathToRegexp from 'next/dist/compiled/path-to-regexp'
Expand All @@ -13,11 +14,19 @@ export type RouteHas =
type: 'header' | 'query' | 'cookie'
key: string
value?: string
check?: undefined
}
| {
type: 'host'
key?: undefined
value: string
check?: undefined
}
| {
type: 'custom'
key?: undefined
value?: undefined
check: (req: IncomingMessage) => boolean | { [param: string]: any }
}

export type Rewrite = {
Expand Down
18 changes: 18 additions & 0 deletions packages/next/shared/lib/router/utils/prepare-destination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,24 @@ export function matchHas(
value = hostname
break
}
case 'custom': {
if (typeof hasItem.check !== 'function') {
return false
}
try {
const result = hasItem.check(req)
if (!result) {
return false
}
if (typeof result === 'object') {
Object.assign(params, result)
}
return true
} catch (e) {
console.error(e)
return false
}
}
default: {
break
}
Expand Down