netlify/next-runtime

[Bug]: Middleware rewrites cause infinite redirect loop when pointing to a directory in `public`

cprussin opened this issue · 2 comments

Summary

Given the following middleware:

export default (request) => NextResponse.rewrite(new URL('/foo', request.url));

If there's a folder /foo in /public, requests enter an infinite redirect loop.

Note this is almost certainly related to #2331 , and I'd bet it's cause by the same underlying root issue. The difference between this ticket and that one is that here we use NextResponse.rewrite instead of MiddlewareRequest.rewrite, and instead of an error we get an infinite redirect loop.

A link to a reproduction repository

https://github.com/cprussin/netlify-issue-repro-2

Expected Result

Render the file /public/foo/index.html if it exists, and 404 if it does not.

Actual Result

Infinite redirect loop

Steps to reproduce

  1. Deploy repo
  2. Navigate to site

Next Runtime version

4.40.2

Is your issue related to the app directory?

  • Yes, I am using the app directory

More information about your build

  • I am building using the CLI
  • I am building using file-based configuration (netlify.toml)

What OS are you using?

None

Your netlify.toml file

No response

Your public/_redirects file

No response

Your next.config.js file

`next.config.js`
module.exports = {
  reactStrictMode: true
};

Builds logs (or link to your logs)

Build logs
6:27:29 AM: build-image version: 2a79f2b6b97edab3f858983ec4cea00280a2836a (focal)
6:27:29 AM: buildbot version: c7db8131ac2d97256c1f537cc5bbdf08464b8daa
6:27:29 AM: Fetching cached dependencies
6:27:29 AM: Starting to download cache of 201.6MB
6:27:30 AM: Finished downloading cache in 544ms
6:27:30 AM: Starting to extract cache
6:27:32 AM: Finished extracting cache in 2.525s
6:27:32 AM: Finished fetching cache in 3.127s
6:27:32 AM: Starting to prepare the repo for build
6:27:32 AM: Preparing Git Reference refs/heads/master
6:27:34 AM: Starting to install dependencies
6:27:34 AM: Python version set to 3.8
6:27:34 AM: Attempting Ruby version 2.7.2, read from environment
6:27:35 AM: Using Ruby version 2.7.2
6:27:35 AM: Started restoring cached go cache
6:27:35 AM: Finished restoring cached go cache
6:27:35 AM: go version go1.19.13 linux/amd64
6:27:36 AM: Using PHP version 8.0
6:27:37 AM: Started restoring cached Node.js version
6:27:38 AM: Finished restoring cached Node.js version
6:27:39 AM: v18.18.2 is already installed.
6:27:39 AM: Now using node v18.18.2 (npm v9.8.1)
6:27:39 AM: Enabling Node.js Corepack
6:27:39 AM: Started restoring cached build plugins
6:27:39 AM: Finished restoring cached build plugins
6:27:39 AM: Started restoring cached corepack dependencies
6:27:39 AM: Finished restoring cached corepack dependencies
6:27:39 AM: No pnpm workspaces detected
6:27:39 AM: Started restoring cached node modules
6:27:39 AM: Finished restoring cached node modules
6:27:40 AM: Installing npm packages using pnpm version 8.7.6
6:27:40 AM: Lockfile is up to date, resolution step is skipped
6:27:40 AM: Already up to date
6:27:40 AM: Done in 467ms
6:27:40 AM: npm packages installed using pnpm
6:27:41 AM: Install dependencies script success
6:27:41 AM: Starting build script
6:27:42 AM: Detected 1 framework(s)
6:27:42 AM: "next" at version "13.5.4"
6:27:42 AM: Section completed: initializing
6:27:44 AM: ​
6:27:44 AM: Netlify Build                                                 
6:27:44 AM: ────────────────────────────────────────────────────────────────
6:27:44 AM: ​
6:27:44 AM: ❯ Version
6:27:44 AM:   @netlify/build 29.22.5
6:27:44 AM: ​
6:27:44 AM: ❯ Flags
6:27:44 AM:   baseRelDir: true
6:27:44 AM:   buildId: 652a973f3a0d00000817e314
6:27:44 AM:   deployId: 652a973f3a0d00000817e316
6:27:44 AM: ​
6:27:44 AM: ❯ Current directory
6:27:44 AM:   /opt/build/repo
6:27:44 AM: ​
6:27:44 AM: ❯ Config file
6:27:44 AM:   No config file was defined: using default values.
6:27:44 AM: ​
6:27:44 AM: ❯ Context
6:27:44 AM:   production
6:27:44 AM: ​
6:27:44 AM: ❯ Using Next.js Runtime - v4.40.2
6:27:45 AM: ​
6:27:45 AM: @netlify/plugin-nextjs (onPreBuild event)                     
6:27:45 AM: ────────────────────────────────────────────────────────────────
6:27:45 AM: ​
6:27:45 AM: Next.js cache restored.
6:27:45 AM: Netlify configuration property "build.environment.NEXT_PRIVATE_TARGET" value changed.
6:27:45 AM: ​
6:27:45 AM: (@netlify/plugin-nextjs onPreBuild completed in 111ms)
6:27:45 AM: ​
6:27:45 AM: Build command from Netlify app                                
6:27:45 AM: ────────────────────────────────────────────────────────────────
6:27:45 AM: ​
6:27:45 AM: $ pnpm run build
6:27:45 AM: > next-test@1.0.0 build /opt/build/repo
6:27:45 AM: > next build
6:27:46 AM:    Creating an optimized production build ...
6:27:48 AM:  ✓ Compiled successfully
6:27:48 AM:    Linting and checking validity of types ...
6:27:48 AM:    Collecting page data ...
6:27:50 AM:    Generating static pages (0/4) ...
6:27:51 AM:    Generating static pages (1/4)
6:27:51 AM:    Generating static pages (2/4)
6:27:51 AM:    Generating static pages (3/4)
6:27:51 AM:  ✓ Generating static pages (4/4)
6:27:53 AM:    Finalizing page optimization ...
6:27:53 AM:    Collecting build traces ...
6:27:54 AM: Route (app)                              Size     First Load JS
6:27:54 AM: ┌ ○ /                                    140 B          80.5 kB
6:27:54 AM: └ ○ /_not-found                          883 B          81.2 kB
6:27:54 AM: + First Load JS shared by all            80.3 kB
6:27:54 AM:   ├ chunks/95-667055ea6e31680b.js        27.5 kB
6:27:54 AM:   ├ chunks/b97a3a71-357a375a396d8622.js  51 kB
6:27:54 AM:   ├ chunks/main-app-968e29e1596532ac.js  229 B
6:27:54 AM:   └ chunks/webpack-bf1a64d1eafd2816.js   1.66 kB
6:27:54 AM: ƒ Middleware                             25 kB
6:27:54 AM: ○  (Static)  automatically rendered as static HTML (uses no initial props)
6:27:55 AM: ​
6:27:55 AM: (build.command completed in 9.5s)
6:27:55 AM: ​
6:27:55 AM: @netlify/plugin-nextjs (onBuild event)                        
6:27:55 AM: ────────────────────────────────────────────────────────────────
6:27:55 AM: ​
6:27:55 AM: Moving static page files to serve from CDN...
6:27:55 AM: Moved 6 files
6:27:55 AM: You are not using Netlify Edge Functions for image format detection. Set env var "NEXT_FORCE_EDGE_IMAGES=true" to enable.
6:27:55 AM: ✨ Deploying middleware and functions to Netlify Edge Functions ✨
6:27:55 AM: Netlify configuration property "redirects" value changed to [
6:27:55 AM:   { from: "/_next/static/*", to: "/static/:splat", status: 200 },
6:27:55 AM:   {
6:27:55 AM:     from: "/_next/image*",
6:27:55 AM:     query: { url: ":url", w: ":width", q: ":quality" },
6:27:55 AM:     to: "/_ipx/w_:width,q_:quality/:url",
6:27:55 AM:     status: 301
6:27:55 AM:   },
6:27:55 AM:   { from: "/_ipx/*", to: "/.netlify/builders/_ipx", status: 200 },
6:27:55 AM:   {
6:27:55 AM:     from: "/api/*",
6:27:55 AM:     to: "/.netlify/functions/___netlify-handler",
6:27:55 AM:     status: 200
6:27:55 AM:   },
6:27:55 AM:   {
6:27:55 AM:     from: "/foo/index.html",
6:27:55 AM:     to: "/foo/index.html",
6:27:55 AM:     conditions: { Cookie: [Array] },
6:27:55 AM:     status: 200
6:27:55 AM:   },
6:27:55 AM:   {
6:27:55 AM:     from: "/*",
6:27:55 AM:     to: "/.netlify/functions/___netlify-handler",
6:27:55 AM:     status: 200,
6:27:55 AM:     conditions: { Cookie: [Array] },
6:27:55 AM:     force: true
6:27:55 AM:   },
6:27:55 AM:   {
6:27:55 AM:     from: "/_next/data/HIbEp6Vx_qa969jm4QjQU/_not-found.json",
6:27:55 AM:     to: "/.netlify/functions/___netlify-handler",
6:27:55 AM:     status: 200,
6:27:55 AM:     force: false
6:27:55 AM:   },
6:27:55 AM:   {
6:27:55 AM:     from: "/_not-found",
6:27:55 AM:     to: "/.netlify/functions/___netlify-handler",
6:27:55 AM:     status: 200,
6:27:55 AM:     force: false
6:27:55 AM:   },
6:27:55 AM:   {
6:27:55 AM:     from: "/*",
6:27:55 AM:     to: "/.netlify/functions/___netlify-handler",
6:27:55 AM:     status: 200
6:27:55 AM:   }
6:27:55 AM: ].
6:27:55 AM: ​
6:27:55 AM: (@netlify/plugin-nextjs onBuild completed in 190ms)
6:27:55 AM: ​
6:27:55 AM: Functions bundling                                            
6:27:55 AM: ────────────────────────────────────────────────────────────────
6:27:55 AM: ​
6:27:55 AM: Packaging Functions from .netlify/functions-internal directory:
6:27:55 AM:  - ___netlify-handler/___netlify-handler.js
6:27:55 AM:  - ___netlify-odb-handler/___netlify-odb-handler.js
6:27:55 AM:  - _ipx/_ipx.js
6:27:55 AM: ​
6:28:30 AM: ​
6:28:30 AM: (Functions bundling completed in 35.4s)
6:28:30 AM: ​
6:28:30 AM: Edge Functions bundling                                       
6:28:30 AM: ────────────────────────────────────────────────────────────────
6:28:30 AM: ​
6:28:30 AM: Packaging Edge Functions from .netlify/edge-functions directory:
6:28:30 AM:  - next_src_middleware
6:28:30 AM:  - rsc-data
6:28:32 AM: ​
6:28:32 AM: (Edge Functions bundling completed in 1.6s)
6:28:32 AM: ​
6:28:32 AM: @netlify/plugin-nextjs (onPostBuild event)                    
6:28:32 AM: ────────────────────────────────────────────────────────────────
6:28:32 AM: ​
6:28:32 AM: Next.js cache saved.
6:28:32 AM: ​
6:28:32 AM: (@netlify/plugin-nextjs onPostBuild completed in 66ms)
6:28:32 AM: ​
6:28:32 AM: Deploy site                                                   
6:28:32 AM: ────────────────────────────────────────────────────────────────
6:28:32 AM: ​
6:28:32 AM: Starting to deploy site from ".next"
6:28:32 AM: Calculating files to upload
6:28:32 AM: 8 new files to upload
6:28:32 AM: 2 new functions to upload
6:28:41 AM: Skipping HTML post processing
6:28:41 AM: Post processing - header rules
6:28:41 AM: Starting post processing
6:28:41 AM: Section completed: deploying
6:28:41 AM: Site deploy was successfully initiated
6:28:41 AM: ​
6:28:41 AM: (Deploy site completed in 8.7s)
6:28:41 AM: ​
6:28:41 AM: Netlify Build Complete                                        
6:28:41 AM: ────────────────────────────────────────────────────────────────
6:28:41 AM: ​
6:28:41 AM: (Netlify Build completed in 57.2s)
6:28:41 AM: Caching artifacts
6:28:41 AM: Started saving node modules
6:28:41 AM: Finished saving node modules
6:28:41 AM: Started saving build plugins
6:28:41 AM: Finished saving build plugins
6:28:41 AM: Started saving corepack cache
6:28:41 AM: Finished saving corepack cache
6:28:41 AM: Started saving pip cache
6:28:41 AM: Finished saving pip cache
6:28:41 AM: Started saving emacs cask dependencies
6:28:41 AM: Finished saving emacs cask dependencies
6:28:41 AM: Started saving maven dependencies
6:28:41 AM: Finished saving maven dependencies
6:28:41 AM: Started saving boot dependencies
6:28:41 AM: Finished saving boot dependencies
6:28:41 AM: Started saving rust rustup cache
6:28:41 AM: Finished saving rust rustup cache
6:28:41 AM: Started saving go dependencies
6:28:41 AM: Finished saving go dependencies
6:28:41 AM: Build script success
6:28:41 AM: Section completed: building
6:28:43 AM: Uploading Cache of size 201.6MB
6:28:44 AM: Section completed: cleanup
6:28:44 AM: Finished processing build request in 1m15.444s
6:28:41 AM: Post processing - redirect rules
6:28:41 AM: Post processing done
6:28:41 AM: Section completed: postprocessing
6:28:42 AM: Site is live ✨

Function logs

N/A -- logs are empty

.next JSON files

No response

This appears to be related to Pretty URLs -- disabling Pretty URLs causes the infinite redirect to go away. However, strangely, when using this middleware with pretty URLs disabled, I'm still getting behavior that matches pretty URLs, i.e. a rewrite to /foo is actually pointing to /foo/index.html.

So it appears that there's some issue with how pretty URLs interacts with next apps. I'm not sure if what I'm seeing is intended functionality or a bug, but it works for my use case -- I'll leave this ticket open in case it's considered unexpected functionality.