fix(middleware): consider localhost variations (#31603)
Since `localhost` is actually an alias for `127.0.0.1` that points to loopback, we should take that into consideration at `NextURL` when we handle local URLs. The implementation is based on [is-localhost-url](https://github.com/Kikobeats/is-localhost-url); I added some tests over local URLs variations present at the library to ensure other variations are working fine. Additionally, I refactor some things over the code to avoid doing the same twice and added some legibility that is always welcome when you are working with URLs stuff. closes https://github.com/vercel/next.js/issues/31533
This commit is contained in:
parent
9652bdd653
commit
f52211bad3
2 changed files with 27 additions and 6 deletions
|
@ -20,6 +20,9 @@ interface Options {
|
|||
trailingSlash?: boolean
|
||||
}
|
||||
|
||||
const REGEX_LOCALHOST_HOSTNAME =
|
||||
/(?!^https?:\/\/)(127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|::1)/
|
||||
|
||||
export class NextURL extends URL {
|
||||
private _basePath: string
|
||||
private _locale?: {
|
||||
|
@ -33,11 +36,12 @@ export class NextURL extends URL {
|
|||
private _options: Options
|
||||
private _url: URL
|
||||
|
||||
constructor(url: string, options: Options = {}) {
|
||||
super(formatRelative(url))
|
||||
constructor(input: string, options: Options = {}) {
|
||||
const url = createWHATWGURL(input)
|
||||
super(url)
|
||||
this._options = options
|
||||
this._basePath = ''
|
||||
this._url = formatRelative(url)
|
||||
this._url = url
|
||||
this.analyzeUrl()
|
||||
}
|
||||
|
||||
|
@ -163,7 +167,7 @@ export class NextURL extends URL {
|
|||
}
|
||||
|
||||
set href(url: string) {
|
||||
this._url = formatRelative(url)
|
||||
this._url = createWHATWGURL(url)
|
||||
this.analyzeUrl()
|
||||
}
|
||||
|
||||
|
@ -228,8 +232,13 @@ export class NextURL extends URL {
|
|||
}
|
||||
}
|
||||
|
||||
function formatRelative(url: string) {
|
||||
return url.startsWith('/')
|
||||
function createWHATWGURL(url: string) {
|
||||
url = url.replace(REGEX_LOCALHOST_HOSTNAME, 'localhost')
|
||||
return isRelativeURL(url)
|
||||
? new URL(url.replace(/^\/+/, '/'), new URL('https://localhost'))
|
||||
: new URL(url)
|
||||
}
|
||||
|
||||
function isRelativeURL(url: string) {
|
||||
return url.startsWith('/')
|
||||
}
|
||||
|
|
|
@ -119,3 +119,15 @@ it('parses and formats the default locale', () => {
|
|||
expect(url.locale).toEqual('fr')
|
||||
expect(url.toString()).toEqual('/root/fr/bar')
|
||||
})
|
||||
|
||||
it('consider 127.0.0.1 and variations as localhost', () => {
|
||||
const httpUrl = new NextURL('http://localhost:3000/hello')
|
||||
expect(new NextURL('http://127.0.0.1:3000/hello')).toStrictEqual(httpUrl)
|
||||
expect(new NextURL('http://127.0.1.0:3000/hello')).toStrictEqual(httpUrl)
|
||||
expect(new NextURL('http://::1:3000/hello')).toStrictEqual(httpUrl)
|
||||
|
||||
const httpsUrl = new NextURL('https://localhost:3000/hello')
|
||||
expect(new NextURL('https://127.0.0.1:3000/hello')).toStrictEqual(httpsUrl)
|
||||
expect(new NextURL('https://127.0.1.0:3000/hello')).toStrictEqual(httpsUrl)
|
||||
expect(new NextURL('https://::1:3000/hello')).toStrictEqual(httpsUrl)
|
||||
})
|
Loading…
Reference in a new issue