@@ -311,182 +311,192 @@ export default class Server {
311
311
res : ServerResponse ,
312
312
parsedUrl ?: UrlWithParsedQuery
313
313
) : Promise < void > {
314
- const urlParts = ( req . url || '' ) . split ( '?' )
315
- const urlNoQuery = urlParts [ 0 ]
316
-
317
- if ( urlNoQuery ?. match ( / ( \\ | \/ \/ ) / ) ) {
318
- const cleanUrl = normalizeRepeatedSlashes ( req . url ! )
319
- res . setHeader ( 'Location' , cleanUrl )
320
- res . setHeader ( 'Refresh' , `0;url=${ cleanUrl } ` )
321
- res . statusCode = 308
322
- res . end ( cleanUrl )
323
- return
324
- }
314
+ try {
315
+ const urlParts = ( req . url || '' ) . split ( '?' )
316
+ const urlNoQuery = urlParts [ 0 ]
317
+
318
+ if ( urlNoQuery ?. match ( / ( \\ | \/ \/ ) / ) ) {
319
+ const cleanUrl = normalizeRepeatedSlashes ( req . url ! )
320
+ res . setHeader ( 'Location' , cleanUrl )
321
+ res . setHeader ( 'Refresh' , `0;url=${ cleanUrl } ` )
322
+ res . statusCode = 308
323
+ res . end ( cleanUrl )
324
+ return
325
+ }
325
326
326
- setLazyProp ( { req : req as any } , 'cookies' , getCookieParser ( req . headers ) )
327
+ setLazyProp ( { req : req as any } , 'cookies' , getCookieParser ( req . headers ) )
327
328
328
- // Parse url if parsedUrl not provided
329
- if ( ! parsedUrl || typeof parsedUrl !== 'object' ) {
330
- const url : any = req . url
331
- parsedUrl = parseUrl ( url , true )
332
- }
333
- const { basePath, i18n } = this . nextConfig
329
+ // Parse url if parsedUrl not provided
330
+ if ( ! parsedUrl || typeof parsedUrl !== 'object' ) {
331
+ const url : any = req . url
332
+ parsedUrl = parseUrl ( url , true )
333
+ }
334
+ const { basePath, i18n } = this . nextConfig
334
335
335
- // Parse the querystring ourselves if the user doesn't handle querystring parsing
336
- if ( typeof parsedUrl . query === 'string' ) {
337
- parsedUrl . query = parseQs ( parsedUrl . query )
338
- }
339
- ; ( req as any ) . __NEXT_INIT_QUERY = Object . assign ( { } , parsedUrl . query )
336
+ // Parse the querystring ourselves if the user doesn't handle querystring parsing
337
+ if ( typeof parsedUrl . query === 'string' ) {
338
+ parsedUrl . query = parseQs ( parsedUrl . query )
339
+ }
340
+ ; ( req as any ) . __NEXT_INIT_QUERY = Object . assign ( { } , parsedUrl . query )
340
341
341
- const url = parseNextUrl ( {
342
- headers : req . headers ,
343
- nextConfig : this . nextConfig ,
344
- url : req . url ?. replace ( / ^ \/ + / , '/' ) ,
345
- } )
342
+ const url = parseNextUrl ( {
343
+ headers : req . headers ,
344
+ nextConfig : this . nextConfig ,
345
+ url : req . url ?. replace ( / ^ \/ + / , '/' ) ,
346
+ } )
346
347
347
- if ( url . basePath ) {
348
- ; ( req as any ) . _nextHadBasePath = true
349
- req . url = req . url ! . replace ( basePath , '' ) || '/'
350
- }
348
+ if ( url . basePath ) {
349
+ ; ( req as any ) . _nextHadBasePath = true
350
+ req . url = req . url ! . replace ( basePath , '' ) || '/'
351
+ }
351
352
352
- if (
353
- this . minimalMode &&
354
- req . headers [ 'x-matched-path' ] &&
355
- typeof req . headers [ 'x-matched-path' ] === 'string'
356
- ) {
357
- const reqUrlIsDataUrl = req . url ?. includes ( '/_next/data' )
358
- const matchedPathIsDataUrl =
359
- req . headers [ 'x-matched-path' ] ?. includes ( '/_next/data' )
360
- const isDataUrl = reqUrlIsDataUrl || matchedPathIsDataUrl
361
-
362
- let parsedPath = parseUrl (
363
- isDataUrl ? req . url ! : ( req . headers [ 'x-matched-path' ] as string ) ,
364
- true
365
- )
366
- const { pathname, query } = parsedPath
367
- let matchedPathname = pathname as string
353
+ if (
354
+ this . minimalMode &&
355
+ req . headers [ 'x-matched-path' ] &&
356
+ typeof req . headers [ 'x-matched-path' ] === 'string'
357
+ ) {
358
+ const reqUrlIsDataUrl = req . url ?. includes ( '/_next/data' )
359
+ const matchedPathIsDataUrl =
360
+ req . headers [ 'x-matched-path' ] ?. includes ( '/_next/data' )
361
+ const isDataUrl = reqUrlIsDataUrl || matchedPathIsDataUrl
362
+
363
+ let parsedPath = parseUrl (
364
+ isDataUrl ? req . url ! : ( req . headers [ 'x-matched-path' ] as string ) ,
365
+ true
366
+ )
367
+ const { pathname, query } = parsedPath
368
+ let matchedPathname = pathname as string
368
369
369
- let matchedPathnameNoExt = isDataUrl
370
- ? matchedPathname . replace ( / \. j s o n $ / , '' )
371
- : matchedPathname
370
+ let matchedPathnameNoExt = isDataUrl
371
+ ? matchedPathname . replace ( / \. j s o n $ / , '' )
372
+ : matchedPathname
372
373
373
- if ( i18n ) {
374
- const localePathResult = normalizeLocalePath (
375
- matchedPathname || '/' ,
376
- i18n . locales
377
- )
374
+ if ( i18n ) {
375
+ const localePathResult = normalizeLocalePath (
376
+ matchedPathname || '/' ,
377
+ i18n . locales
378
+ )
378
379
379
- if ( localePathResult . detectedLocale ) {
380
- parsedUrl . query . __nextLocale = localePathResult . detectedLocale
380
+ if ( localePathResult . detectedLocale ) {
381
+ parsedUrl . query . __nextLocale = localePathResult . detectedLocale
382
+ }
381
383
}
382
- }
383
384
384
- if ( isDataUrl ) {
385
- matchedPathname = denormalizePagePath ( matchedPathname )
386
- matchedPathnameNoExt = denormalizePagePath ( matchedPathnameNoExt )
387
- }
388
-
389
- const pageIsDynamic = isDynamicRoute ( matchedPathnameNoExt )
390
- const combinedRewrites : Rewrite [ ] = [ ]
385
+ if ( isDataUrl ) {
386
+ matchedPathname = denormalizePagePath ( matchedPathname )
387
+ matchedPathnameNoExt = denormalizePagePath ( matchedPathnameNoExt )
388
+ }
391
389
392
- combinedRewrites . push ( ...this . customRoutes . rewrites . beforeFiles )
393
- combinedRewrites . push ( ...this . customRoutes . rewrites . afterFiles )
394
- combinedRewrites . push ( ...this . customRoutes . rewrites . fallback )
390
+ const pageIsDynamic = isDynamicRoute ( matchedPathnameNoExt )
391
+ const combinedRewrites : Rewrite [ ] = [ ]
395
392
396
- const utils = getUtils ( {
397
- pageIsDynamic,
398
- page : matchedPathnameNoExt ,
399
- i18n : this . nextConfig . i18n ,
400
- basePath : this . nextConfig . basePath ,
401
- rewrites : combinedRewrites ,
402
- } )
393
+ combinedRewrites . push ( ...this . customRoutes . rewrites . beforeFiles )
394
+ combinedRewrites . push ( ...this . customRoutes . rewrites . afterFiles )
395
+ combinedRewrites . push ( ...this . customRoutes . rewrites . fallback )
403
396
404
- utils . handleRewrites ( req , parsedUrl )
397
+ const utils = getUtils ( {
398
+ pageIsDynamic,
399
+ page : matchedPathnameNoExt ,
400
+ i18n : this . nextConfig . i18n ,
401
+ basePath : this . nextConfig . basePath ,
402
+ rewrites : combinedRewrites ,
403
+ } )
405
404
406
- // interpolate dynamic params and normalize URL if needed
407
- if ( pageIsDynamic ) {
408
- let params : ParsedUrlQuery | false = { }
405
+ utils . handleRewrites ( req , parsedUrl )
409
406
410
- Object . assign ( parsedUrl . query , query )
411
- const paramsResult = utils . normalizeDynamicRouteParams ( parsedUrl . query )
407
+ // interpolate dynamic params and normalize URL if needed
408
+ if ( pageIsDynamic ) {
409
+ let params : ParsedUrlQuery | false = { }
412
410
413
- if ( paramsResult . hasValidParams ) {
414
- params = paramsResult . params
415
- } else if ( req . headers [ 'x-now-route-matches' ] ) {
416
- const opts : Record < string , string > = { }
417
- params = utils . getParamsFromRouteMatches (
418
- req ,
419
- opts ,
420
- ( parsedUrl . query . __nextLocale as string | undefined ) || ''
411
+ Object . assign ( parsedUrl . query , query )
412
+ const paramsResult = utils . normalizeDynamicRouteParams (
413
+ parsedUrl . query
421
414
)
422
415
423
- if ( opts . locale ) {
424
- parsedUrl . query . __nextLocale = opts . locale
416
+ if ( paramsResult . hasValidParams ) {
417
+ params = paramsResult . params
418
+ } else if ( req . headers [ 'x-now-route-matches' ] ) {
419
+ const opts : Record < string , string > = { }
420
+ params = utils . getParamsFromRouteMatches (
421
+ req ,
422
+ opts ,
423
+ ( parsedUrl . query . __nextLocale as string | undefined ) || ''
424
+ )
425
+
426
+ if ( opts . locale ) {
427
+ parsedUrl . query . __nextLocale = opts . locale
428
+ }
429
+ } else {
430
+ params = utils . dynamicRouteMatcher ! ( matchedPathnameNoExt )
425
431
}
426
- } else {
427
- params = utils . dynamicRouteMatcher ! ( matchedPathnameNoExt )
428
- }
429
432
430
- if ( params ) {
431
- params = utils . normalizeDynamicRouteParams ( params ) . params
433
+ if ( params ) {
434
+ params = utils . normalizeDynamicRouteParams ( params ) . params
432
435
433
- matchedPathname = utils . interpolateDynamicPath (
434
- matchedPathname ,
435
- params
436
- )
437
- req . url = utils . interpolateDynamicPath ( req . url ! , params )
438
- }
436
+ matchedPathname = utils . interpolateDynamicPath (
437
+ matchedPathname ,
438
+ params
439
+ )
440
+ req . url = utils . interpolateDynamicPath ( req . url ! , params )
441
+ }
439
442
440
- if ( reqUrlIsDataUrl && matchedPathIsDataUrl ) {
441
- req . url = formatUrl ( {
442
- ...parsedPath ,
443
- pathname : matchedPathname ,
444
- } )
443
+ if ( reqUrlIsDataUrl && matchedPathIsDataUrl ) {
444
+ req . url = formatUrl ( {
445
+ ...parsedPath ,
446
+ pathname : matchedPathname ,
447
+ } )
448
+ }
449
+
450
+ Object . assign ( parsedUrl . query , params )
451
+ utils . normalizeVercelUrl ( req , true )
445
452
}
446
453
447
- Object . assign ( parsedUrl . query , params )
448
- utils . normalizeVercelUrl ( req , true )
454
+ parsedUrl . pathname = `${ basePath || '' } ${
455
+ matchedPathname === '/' && basePath ? '' : matchedPathname
456
+ } `
449
457
}
450
458
451
- parsedUrl . pathname = `${ basePath || '' } ${
452
- matchedPathname === '/' && basePath ? '' : matchedPathname
453
- } `
454
- }
455
-
456
- ; ( req as any ) . __nextHadTrailingSlash = url . locale ?. trailingSlash
457
- if ( url . locale ?. domain ) {
458
- ; ( req as any ) . __nextIsLocaleDomain = true
459
- }
459
+ ; ( req as any ) . __nextHadTrailingSlash = url . locale ?. trailingSlash
460
+ if ( url . locale ?. domain ) {
461
+ ; ( req as any ) . __nextIsLocaleDomain = true
462
+ }
460
463
461
- if ( url . locale ?. path . detectedLocale ) {
462
- req . url = formatUrl ( url )
463
- ; ( req as any ) . __nextStrippedLocale = true
464
- if ( url . pathname === '/api' || url . pathname . startsWith ( '/api/' ) ) {
465
- return this . render404 ( req , res , parsedUrl )
464
+ if ( url . locale ?. path . detectedLocale ) {
465
+ req . url = formatUrl ( url )
466
+ ; ( req as any ) . __nextStrippedLocale = true
467
+ if ( url . pathname === '/api' || url . pathname . startsWith ( '/api/' ) ) {
468
+ return this . render404 ( req , res , parsedUrl )
469
+ }
466
470
}
467
- }
468
471
469
- if ( ! this . minimalMode || ! parsedUrl . query . __nextLocale ) {
470
- if ( url ?. locale ?. locale ) {
471
- parsedUrl . query . __nextLocale = url . locale . locale
472
+ if ( ! this . minimalMode || ! parsedUrl . query . __nextLocale ) {
473
+ if ( url ?. locale ?. locale ) {
474
+ parsedUrl . query . __nextLocale = url . locale . locale
475
+ }
472
476
}
473
- }
474
477
475
- if ( url ?. locale ?. defaultLocale ) {
476
- parsedUrl . query . __nextDefaultLocale = url . locale . defaultLocale
477
- }
478
+ if ( url ?. locale ?. defaultLocale ) {
479
+ parsedUrl . query . __nextDefaultLocale = url . locale . defaultLocale
480
+ }
478
481
479
- if ( url . locale ?. redirect ) {
480
- res . setHeader ( 'Location' , url . locale . redirect )
481
- res . statusCode = TEMPORARY_REDIRECT_STATUS
482
- res . end ( )
483
- return
484
- }
482
+ if ( url . locale ?. redirect ) {
483
+ res . setHeader ( 'Location' , url . locale . redirect )
484
+ res . statusCode = TEMPORARY_REDIRECT_STATUS
485
+ res . end ( )
486
+ return
487
+ }
485
488
486
- res . statusCode = 200
487
- try {
489
+ res . statusCode = 200
488
490
return await this . run ( req , res , parsedUrl )
489
491
} catch ( err ) {
492
+ if (
493
+ ( err && typeof err === 'object' && err . code === 'ERR_INVALID_URL' ) ||
494
+ err instanceof DecodeError
495
+ ) {
496
+ res . statusCode = 400
497
+ return this . renderError ( null , req , res , '/_error' , { } )
498
+ }
499
+
490
500
if ( this . minimalMode || this . renderOpts . dev ) {
491
501
throw err
492
502
}
0 commit comments