@@ -151,6 +151,29 @@ const encodeOverlaySettings = (
151151
152152const DEFAULT_ALLOWED_PROTOCOLS = / ^ ( f i l e | .+ - e x t e n s i o n ) : / i;
153153
154+ /**
155+ * Extracts and normalizes the hostname from a header, removing brackets for IPv6.
156+ */
157+ function parseHostnameFromHeader ( header : string ) : string | null {
158+ try {
159+ const parsedUrl = new URL (
160+ // if header doesn't have scheme, add // for parsing.
161+ / ^ ( .+ : ) ? \/ \/ / . test ( header ) ? header : `//${ header } ` ,
162+ 'http://localhost/' ,
163+ ) ;
164+ let { hostname } = parsedUrl ;
165+
166+ // `URL#hostname` keeps IPv6 brackets, but our validation expects bare IPv6.
167+ if ( hostname . startsWith ( '[' ) && hostname . endsWith ( ']' ) ) {
168+ hostname = hostname . slice ( 1 , - 1 ) ;
169+ }
170+
171+ return hostname ;
172+ } catch {
173+ return null ;
174+ }
175+ }
176+
154177function isMultiCompiler (
155178 compiler : Compiler | MultiCompiler ,
156179) : compiler is MultiCompiler {
@@ -2484,15 +2507,7 @@ class Server<
24842507 return true ;
24852508 }
24862509
2487- // use the node url-parser to retrieve the hostname from the host-header.
2488- // TODO resolve me in the next major release
2489- // eslint-disable-next-line n/no-deprecated-api
2490- const { hostname } = url . parse (
2491- // if header doesn't have scheme, add // for parsing.
2492- / ^ ( .+ : ) ? \/ \/ / . test ( header ) ? header : `//${ header } ` ,
2493- false ,
2494- true ,
2495- ) ;
2510+ const hostname = parseHostnameFromHeader ( header ) ;
24962511
24972512 if ( hostname === null ) {
24982513 return false ;
@@ -2506,8 +2521,8 @@ class Server<
25062521 // A note on IPv6 addresses:
25072522 // header will always contain the brackets denoting
25082523 // an IPv6-address in URLs,
2509- // these are removed from the hostname in url.parse() ,
2510- // so we have the pure IPv6-address in hostname .
2524+ // these are not removed from `URL# hostname` ,
2525+ // so we normalize to a pure IPv6-address when parsing .
25112526 // For convenience, always allow localhost (hostname === 'localhost')
25122527 // and its subdomains (hostname.endsWith(".localhost")).
25132528 // allow hostname of listening address (hostname === this.options.host)
@@ -2537,9 +2552,7 @@ class Server<
25372552 return true ;
25382553 }
25392554
2540- // TODO resolve me in the next major release
2541- // eslint-disable-next-line n/no-deprecated-api
2542- const origin = url . parse ( originHeader , false , true ) . hostname ;
2555+ const origin = parseHostnameFromHeader ( originHeader ) ;
25432556
25442557 if ( origin === null ) {
25452558 return false ;
@@ -2559,13 +2572,7 @@ class Server<
25592572 return true ;
25602573 }
25612574
2562- // eslint-disable-next-line n/no-deprecated-api
2563- const host = url . parse (
2564- // if hostHeader doesn't have scheme, add // for parsing.
2565- / ^ ( .+ : ) ? \/ \/ / . test ( hostHeader ) ? hostHeader : `//${ hostHeader } ` ,
2566- false ,
2567- true ,
2568- ) . hostname ;
2575+ const host = parseHostnameFromHeader ( hostHeader ) ;
25692576
25702577 if ( host === null ) {
25712578 return false ;
0 commit comments