@@ -9,6 +9,7 @@ import type {
9
9
RouteHas ,
10
10
} from "types/next-types" ;
11
11
import type { InternalEvent , InternalResult } from "types/open-next" ;
12
+ import { normalizeRepeatedSlashes } from "utils/normalize-path" ;
12
13
import { emptyReadableStream , toReadableStream } from "utils/stream" ;
13
14
14
15
import { debug } from "../../adapters/logger" ;
@@ -262,6 +263,29 @@ export function handleRewrites<T extends RewriteDefinition>(
262
263
} ;
263
264
}
264
265
266
+ // Normalizes repeated slashes in the path e.g. hello//world -> hello/world
267
+ // or backslashes to forward slashes. This prevents requests such as //domain
268
+ // from invoking the middleware with `request.url === "domain"`.
269
+ // See: https://github.com/vercel/next.js/blob/3ecf087f10fdfba4426daa02b459387bc9c3c54f/packages/next/src/server/base-server.ts#L1016-L1020
270
+ function handleRepeatedSlashRedirect (
271
+ event : InternalEvent ,
272
+ ) : false | InternalResult {
273
+ // Redirect `https://example.com//foo` to `https://example.com/foo`.
274
+ if ( event . rawPath . match ( / ( \\ | \/ \/ ) / ) ) {
275
+ return {
276
+ type : event . type ,
277
+ statusCode : 308 ,
278
+ headers : {
279
+ Location : normalizeRepeatedSlashes ( new URL ( event . url ) ) ,
280
+ } ,
281
+ body : emptyReadableStream ( ) ,
282
+ isBase64Encoded : false ,
283
+ } ;
284
+ }
285
+
286
+ return false ;
287
+ }
288
+
265
289
function handleTrailingSlashRedirect (
266
290
event : InternalEvent ,
267
291
) : false | InternalResult {
@@ -326,6 +350,9 @@ export function handleRedirects(
326
350
event : InternalEvent ,
327
351
redirects : RedirectDefinition [ ] ,
328
352
) : InternalResult | undefined {
353
+ const repeatedSlashRedirect = handleRepeatedSlashRedirect ( event ) ;
354
+ if ( repeatedSlashRedirect ) return repeatedSlashRedirect ;
355
+
329
356
const trailingSlashRedirect = handleTrailingSlashRedirect ( event ) ;
330
357
if ( trailingSlashRedirect ) return trailingSlashRedirect ;
331
358
0 commit comments