diff --git a/docs/api-reference/next.config.js/redirects.md b/docs/api-reference/next.config.js/redirects.md index 7dd369881fee5..c02aacc229ee2 100644 --- a/docs/api-reference/next.config.js/redirects.md +++ b/docs/api-reference/next.config.js/redirects.md @@ -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-(?.*)` 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 = { @@ -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', + }, ] }, } diff --git a/docs/api-reference/next.config.js/rewrites.md b/docs/api-reference/next.config.js/rewrites.md index 1b557175db052..c6043cb84e304 100644 --- a/docs/api-reference/next.config.js/rewrites.md +++ b/docs/api-reference/next.config.js/rewrites.md @@ -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-(?.*)` 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 = { @@ -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', + }, ] }, } diff --git a/packages/next/lib/load-custom-routes.ts b/packages/next/lib/load-custom-routes.ts index 57e7290142484..4af1eeff6911c 100644 --- a/packages/next/lib/load-custom-routes.ts +++ b/packages/next/lib/load-custom-routes.ts @@ -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' @@ -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 = { diff --git a/packages/next/shared/lib/router/utils/prepare-destination.ts b/packages/next/shared/lib/router/utils/prepare-destination.ts index 79de9ee20bdcc..78a54ecb536fc 100644 --- a/packages/next/shared/lib/router/utils/prepare-destination.ts +++ b/packages/next/shared/lib/router/utils/prepare-destination.ts @@ -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 }