Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: return plain text 404 for invalid static asset paths #75111

Open
wants to merge 2 commits into
base: canary
Choose a base branch
from

Conversation

devjiwonchoi
Copy link
Member

@devjiwonchoi devjiwonchoi commented Jan 20, 2025

Why?

When bots like Googlebot crawl a site, it gets the asset paths /_next/static/... from the <link> and <script> tags.
As those asset paths may change over time, when Googlebot tries to sync the resources, it reaches a 404 page.

The problem is that Next.js returns an HTML 404 page, which lets bots consider that they've found an invalid 404 page.

How?

On the base-server, if it is 404 page and includes /_next/static/ in the path, return plain text 'Not Found' without HTML.

Closes NDX-697

@ijjk ijjk added created-by: Next.js team PRs by the Next.js team. tests labels Jan 20, 2025
Copy link
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@devjiwonchoi devjiwonchoi force-pushed the 01-21-fix_return_plain_text_404_for_invalid_asset_path branch from 5efa140 to a9e40de Compare January 20, 2025 17:12
@devjiwonchoi devjiwonchoi marked this pull request as ready for review January 20, 2025 17:13
@ijjk
Copy link
Member

ijjk commented Jan 20, 2025

Failing test suites

Commit: a9e40de

pnpm test test/integration/file-serving/test/index.test.js (turbopack)

  • File Serving > development mode > should prevent traversing with /../test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e/test-file.txt
  • File Serving > development mode > should prevent traversing with /..\test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e\test-file.txt
  • File Serving > development mode > should prevent traversing with /../test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e/test-file.txt
  • File Serving > development mode > should prevent traversing with /..\test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e\test-file.txt
  • File Serving > development mode > should prevent traversing with /../test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e/test-file.txt
  • File Serving > development mode > should prevent traversing with /..\test-file.txt
  • File Serving > development mode > should prevent traversing with /%2e%2e\test-file.txt
  • File Serving > development mode > should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/../../test-file.txt
  • File Serving > development mode > should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....\test-file.txt
  • File Serving > development mode > should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/../../test-file.txt
  • File Serving > development mode > should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....\test-file.txt
  • File Serving > development mode > should prevent traversing with /........................................................................../../../test-file.txt
  • File Serving > development mode > should prevent traversing with /..............................................................................\test-file.txt
  • File Serving > development mode > should prevent traversing with /././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././../test-file.txt
  • File Serving > development mode > should prevent traversing with /........................................................................................................................................................\test-file.txt
  • File Serving > development mode > should prevent traversing with /./../test-file.txt
  • File Serving > development mode > should prevent traversing with /...\test-file.txt
  • File Serving > development mode > should prevent traversing with /../test-file.txt
  • File Serving > development mode > should prevent traversing with /..\test-file.txt
Expand output

● File Serving › development mode › should prevent traversing with /../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:90:5)

● File Serving › development mode › should prevent traversing with /%2e%2e/test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:154:5)

● File Serving › development mode › should prevent traversing with /..\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:356:5)

● File Serving › development mode › should prevent traversing with /%2e%2e\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:454:5)

● File Serving › development mode › should prevent traversing with /../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1396:5)

● File Serving › development mode › should prevent traversing with /%2e%2e/test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1460:5)

● File Serving › development mode › should prevent traversing with /..\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1662:5)

● File Serving › development mode › should prevent traversing with /%2e%2e\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1726:5)

● File Serving › development mode › should prevent traversing with /../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1928:5)

● File Serving › development mode › should prevent traversing with /%2e%2e/test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:1992:5)

● File Serving › development mode › should prevent traversing with /..\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2194:5)

● File Serving › development mode › should prevent traversing with /%2e%2e\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2258:5)

● File Serving › development mode › should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/../../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2530:5)

● File Serving › development mode › should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2578:5)

● File Serving › development mode › should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/../../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2626:5)

● File Serving › development mode › should prevent traversing with /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2674:5)

● File Serving › development mode › should prevent traversing with /........................................................................../../../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2860:5)

● File Serving › development mode › should prevent traversing with /..............................................................................\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:2908:5)

● File Serving › development mode › should prevent traversing with /././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4054:5)

● File Serving › development mode › should prevent traversing with /........................................................................................................................................................\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4102:5)

● File Serving › development mode › should prevent traversing with /./../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4150:5)

● File Serving › development mode › should prevent traversing with /...\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4182:5)

● File Serving › development mode › should prevent traversing with /../test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4300:5)

● File Serving › development mode › should prevent traversing with /..\test-file.txt

expect(received).toMatch(expected)

Expected pattern: /(This page could not be found|Bad Request)/
Received string:  ""

  33 |         throw err
  34 |       }
> 35 |       expect(await res.text()).toMatch(containRegex)
     |                                ^
  36 |     }
  37 |   }
  38 |   const res = await fetchViaHTTP(appPort, path, undefined, {

  at toMatch (integration/file-serving/test/index.test.js:35:32)
  at expectStatus (integration/file-serving/test/index.test.js:47:3)
  at Object.<anonymous> (integration/file-serving/test/index.test.js:4332:5)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Jan 20, 2025

Failing test suites

Commit: c8dc992

pnpm test test/integration/required-server-files-ssr-404/test/index.test.js

  • Required Server Files > production mode > should handle 404s properly
Expand output

● Required Server Files › production mode › should handle 404s properly

expect(received).toContain(expected) // indexOf

Expected substring: "custom 404"
Received string:    "Not Found"

  428 |           })
  429 |
> 430 |           expect(res.status).toBe(200)
      |                                       ^
  431 |         }
  432 |       })
  433 |

  at Object.<anonymous> (integration/required-server-files-ssr-404/test/index.test.js:430:42)

Read more about building and testing Next.js in contributing.md.

pnpm test test/integration/i18n-support/test/index.test.js (turbopack)

  • i18n Support > production mode > should 404 for locale prefixed static assets correctly
Expand output

● i18n Support › production mode › should 404 for locale prefixed static assets correctly

expect(received).toContain(expected) // indexOf

Expected substring: "could not be found"
Received string:    "Not Found"

  79 |         if (!defaultLocales.includes(locale)) {
  80 |           expect(res.status).toBe(404)
> 81 |           expect(await res.text()).toContain('could not be found')
     |                                    ^
  82 |         } else {
  83 |           // We only 404 for non-default locale
  84 |           expect(res.status).toBe(200)

  at Object.toContain (integration/i18n-support/test/shared.js:81:36)

Read more about building and testing Next.js in contributing.md.

pnpm test test/integration/i18n-support-base-path/test/index.test.js (turbopack)

  • i18n Support basePath > development mode > should 404 for locale prefixed static assets correctly
Expand output

● i18n Support basePath › development mode › should 404 for locale prefixed static assets correctly

expect(received).toContain(expected) // indexOf

Expected substring: "could not be found"
Received string:    "Not Found"

  79 |         if (!defaultLocales.includes(locale)) {
  80 |           expect(res.status).toBe(404)
> 81 |           expect(await res.text()).toContain('could not be found')
     |                                    ^
  82 |         } else {
  83 |           // We only 404 for non-default locale
  84 |           expect(res.status).toBe(200)

  at Object.toContain (integration/i18n-support/test/shared.js:81:36)

Read more about building and testing Next.js in contributing.md.

pnpm test-deploy test/e2e/invalid-asset-path-req-404/app-dir/asset-prefix.test.ts

  • app-dir - invalid-asset-path-req-404 - asset-prefix > should return 404 with plain text when fetching invalid asset path
Expand output

● app-dir - invalid-asset-path-req-404 - asset-prefix › should return 404 with plain text when fetching invalid asset path

expect(received).toBe(expected) // Object.is equality

Expected: "Not Found"
Received: "<!DOCTYPE html><html><head><meta charSet=\"utf-8\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><link rel=\"preload\" as=\"script\" fetchPriority=\"low\" href=\"/_assets/_next/static/chunks/webpack-db5504f5cb6a0bc5.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\"/><script src=\"/_assets/_next/static/chunks/4bd1b696-3d6c1b6f416b43cf.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\" async=\"\"></script><script src=\"/_assets/_next/static/chunks/587-91a1f6e45d267279.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\" async=\"\"></script><script src=\"/_assets/_next/static/chunks/main-app-154b0864d9a8bda1.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\" async=\"\"></script><meta name=\"robots\" content=\"noindex\"/><script src=\"/_assets/_next/static/chunks/polyfills-42372ed130431b0a.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\" noModule=\"\"></script></head><body><p>Custom Not Found</p><script src=\"/_assets/_next/static/chunks/webpack-db5504f5cb6a0bc5.js?dpl=dpl_HAEGNiWUYgLuJ7TWgk8iPccSUHG7\" async=\"\"></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,\"1:\\\"$Sreact.fragment\\\"\\n2:I[5244,[],\\\"\\\"]\\n3:I[3866,[],\\\"\\\"]\\n4:I[6213,[],\\\"MetadataBoundary\\\"]\\n7:I[6213,[],\\\"OutletBoundary\\\"]\\na:I[6213,[],\\\"ViewportBoundary\\\"]\\nc:I[4835,[],\\\"\\\"]\\n0:{\\\"P\\\":null,\\\"b\\\":\\\"IvC6to6h1iHt6U2GaGQE8\\\",\\\"p\\\":\\\"/_assets\\\",\\\"c\\\":[\\\"\\\",\\\"_not-found\\\"],\\\"i\\\":false,\\\"f\\\":[[[\\\"\\\",{\\\"children\\\":[\\\"/_not-found\\\",{\\\"children\\\":[\\\"__PAGE__\\\",{}]}]},\\\"$undefined\\\",\\\"$undefined\\\",true],[\\\"\\\",[\\\"$\\\",\\\"$1\\\",\\\"c\\\",{\\\"children\\\":[null,[\\\"$\\\",\\\"html\\\",null,{\\\"children\\\":[\\\"$\\\",\\\"body\\\",null,{\\\"children\\\":[\\\"$\\\",\\\"$L2\\\",null,{\\\"parallelRouterKey\\\":\\\"children\\\",\\\"error\\\":\\\"$undefined\\\",\\\"errorStyles\\\":\\\"$undefined\\\",\\\"errorScripts\\\":\\\"$undefined\\\",\\\"template\\\":[\\\"$\\\",\\\"$L3\\\",null,{}],\\\"templateStyles\\\":\\\"$undefined\\\",\\\"templateScripts\\\":\\\"$undefined\\\",\\\"notFound\\\":[[\\\"$\\\",\\\"p\\\",null,{\\\"children\\\":\\\"Custom Not Found\\\"}],[[\\\"$\\\",\\\"$1\\\",\\\"h\\\",{\\\"children\\\":[\\\"$\\\",\\\"$L4\\\",null,{\\\"children\\\":\\\"$L5\\\"}]}]],[]],\\\"forbidden\\\":\\\"$undefined\\\",\\\"unauthorized\\\":\\\"$undefined\\\"}]}]}]]}],{\\\"children\\\":[\\\"/_not-found\\\",[\\\"$\\\",\\\"$1\\\",\\\"c\\\",{\\\"children\\\":[null,[\\\"$\\\",\\\"$L2\\\",null,{\\\"parallelRouterKey\\\":\\\"children\\\",\\\"error\\\":\\\"$undefined\\\",\\\"errorStyles\\\":\\\"$undefined\\\",\\\"errorScripts\\\":\\\"$undefined\\\",\\\"template\\\":[\\\"$\\\",\\\"$L3\\\",null,{}],\\\"templateStyles\\\":\\\"$undefined\\\",\\\"templateScripts\\\":\\\"$undefined\\\",\\\"notFound\\\":\\\"$undefined\\\",\\\"forbidden\\\":\\\"$undefined\\\",\\\"unauthorized\\\":\\\"$undefined\\\"}]]}],{\\\"children\\\":[\\\"__PAGE__\\\",[\\\"$\\\",\\\"$1\\\",\\\"c\\\",{\\\"children\\\":[[\\\"$\\\",\\\"p\\\",null,{\\\"children\\\":\\\"Custom Not Found\\\"}],[[\\\"$\\\",\\\"$1\\\",\\\"h\\\",{\\\"children\\\":[\\\"$\\\",\\\"$L4\\\",null,{\\\"children\\\":\\\"$L6\\\"}]}]],null,[\\\"$\\\",\\\"$L7\\\",null,{\\\"children\\\":[\\\"$L8\\\",\\\"$L9\\\"]}]]}],{},null,false]},null,false]},null,false],[[\\\"$\\\",\\\"$1\\\",\\\"v\\\",{\\\"children\\\":[[\\\"$\\\",\\\"meta\\\",null,{\\\"name\\\":\\\"robots\\\",\\\"content\\\":\\\"noindex\\\"}],[\\\"$\\\",\\\"$1\\\",\\\"FwPveyIQfe83N9NGWMGmD\\\",{\\\"children\\\":[[\\\"$\\\",\\\"$La\\\",null,{\\\"children\\\":\\\"$Lb\\\"}],null]}]]}],null],false]],\\\"m\\\":\\\"$undefined\\\",\\\"G\\\":[\\\"$c\\\",\\\"$undefined\\\"],\\\"s\\\":false,\\\"S\\\":true}\\n\"])</script><script>self.__next_f.push([1,\"b:[[\\\"$\\\",\\\"meta\\\",\\\"0\\\",{\\\"charSet\\\":\\\"utf-8\\\"}],[\\\"$\\\",\\\"meta\\\",\\\"1\\\",{\\\"name\\\":\\\"viewport\\\",\\\"content\\\":\\\"width=device-width, initial-scale=1\\\"}]]\\n5:[]\\n6:\\\"$5\\\"\\n9:null\\n8:null\\n\"])</script></body></html>"

  35 |     expect(res.status).toBe(404)
  36 |     const text = await res.text()
> 37 |     expect(text).toBe('Not Found')
     |                  ^
  38 |   })
  39 | })
  40 |

  at Object.toBe (e2e/invalid-asset-path-req-404/app-dir/asset-prefix.test.ts:37:18)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Jan 20, 2025

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
buildDuration 18.3s 15.1s N/A
buildDurationCached 14.4s 12.3s N/A
nodeModulesSize 418 MB 418 MB ⚠️ +4.77 kB
nextStartRea..uration (ms) 418ms 420ms N/A
Client Bundles (main, webpack)
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
5306-HASH.js gzip 54 kB 54 kB N/A
8276.HASH.js gzip 169 B 168 B N/A
8377-HASH.js gzip 5.44 kB 5.44 kB N/A
bccd1874-HASH.js gzip 52.9 kB 52.9 kB
framework-HASH.js gzip 57.5 kB 57.5 kB N/A
main-app-HASH.js gzip 240 B 242 B N/A
main-HASH.js gzip 34.4 kB 34.4 kB N/A
webpack-HASH.js gzip 1.71 kB 1.71 kB N/A
Overall change 52.9 kB 52.9 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 193 B 193 B
amp-HASH.js gzip 512 B 510 B N/A
css-HASH.js gzip 343 B 342 B N/A
dynamic-HASH.js gzip 1.84 kB 1.84 kB
edge-ssr-HASH.js gzip 265 B 265 B
head-HASH.js gzip 363 B 362 B N/A
hooks-HASH.js gzip 393 B 392 B N/A
image-HASH.js gzip 4.57 kB 4.57 kB N/A
index-HASH.js gzip 268 B 268 B
link-HASH.js gzip 2.35 kB 2.34 kB N/A
routerDirect..HASH.js gzip 328 B 328 B
script-HASH.js gzip 397 B 397 B
withRouter-HASH.js gzip 323 B 326 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 3.59 kB 3.59 kB
Client Build Manifests
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
_buildManifest.js gzip 749 B 747 B N/A
Overall change 0 B 0 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
index.html gzip 523 B 523 B
link.html gzip 538 B 537 B N/A
withRouter.html gzip 519 B 520 B N/A
Overall change 523 B 523 B
Edge SSR bundle Size
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
edge-ssr.js gzip 129 kB 129 kB N/A
page.js gzip 208 kB 208 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
middleware-b..fest.js gzip 669 B 667 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 31.3 kB 31.3 kB N/A
edge-runtime..pack.js gzip 844 B 844 B
Overall change 844 B 844 B
Next Runtimes
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
274-experime...dev.js gzip 322 B 322 B
274.runtime.dev.js gzip 314 B 314 B
app-page-exp...dev.js gzip 374 kB 374 kB
app-page-exp..prod.js gzip 130 kB 130 kB
app-page-tur..prod.js gzip 143 kB 143 kB
app-page-tur..prod.js gzip 139 kB 139 kB
app-page.run...dev.js gzip 362 kB 362 kB
app-page.run..prod.js gzip 126 kB 126 kB
app-route-ex...dev.js gzip 37.6 kB 37.6 kB
app-route-ex..prod.js gzip 25.6 kB 25.6 kB
app-route-tu..prod.js gzip 25.6 kB 25.6 kB
app-route-tu..prod.js gzip 25.4 kB 25.4 kB
app-route.ru...dev.js gzip 39.2 kB 39.2 kB
app-route.ru..prod.js gzip 25.4 kB 25.4 kB
pages-api-tu..prod.js gzip 9.69 kB 9.69 kB
pages-api.ru...dev.js gzip 11.6 kB 11.6 kB
pages-api.ru..prod.js gzip 9.68 kB 9.68 kB
pages-turbo...prod.js gzip 21.9 kB 21.9 kB
pages.runtim...dev.js gzip 27.7 kB 27.7 kB
pages.runtim..prod.js gzip 21.9 kB 21.9 kB
server.runti..prod.js gzip 916 kB 916 kB N/A
Overall change 1.56 MB 1.56 MB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js 01-21-fix_return_plain_text_404_for_invalid_asset_path Change
0.pack gzip 2.09 MB 2.1 MB ⚠️ +3.04 kB
index.pack gzip 74.6 kB 74.2 kB N/A
Overall change 2.09 MB 2.1 MB ⚠️ +3.04 kB
Diff details
Diff for edge-ssr.js

Diff too large to display

Diff for main-HASH.js

Diff too large to display

Diff for server.runtime.prod.js

Diff too large to display

Commit: c8dc992

@devjiwonchoi devjiwonchoi force-pushed the 01-21-fix_return_plain_text_404_for_invalid_asset_path branch 4 times, most recently from 1c1789b to 5f568dd Compare January 21, 2025 03:35
@devjiwonchoi devjiwonchoi force-pushed the 01-21-fix_return_plain_text_404_for_invalid_asset_path branch 2 times, most recently from 98166cb to 41d009c Compare January 21, 2025 04:10
@devjiwonchoi devjiwonchoi force-pushed the 01-21-fix_return_plain_text_404_for_invalid_asset_path branch from 2dee8e8 to c8dc992 Compare January 21, 2025 04:49
@devjiwonchoi devjiwonchoi changed the title fix: return plain text 404 for invalid asset path fix: return plain text 404 for invalid static asset paths Jan 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants