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:
Kiko Beats 2021-11-19 22:24:22 +01:00 committed by GitHub
parent 9652bdd653
commit f52211bad3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 6 deletions

View file

@ -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('/')
}

View file

@ -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)
})