Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@
to = "/.netlify/functions/qa-301"
status = 200

# QA-only: expose the qa-403 function at the clean path /qa-403. Same
# rewrite-proxy mechanism as the QA endpoints above (status = 200 is
# the rewrite TYPE, not a forced response code) — it preserves the
# function's actual 403 status and its text/html Content-Type. Must
# remain BEFORE the SPA catch-all below.
[[redirects]]
from = "/qa-403"
to = "/.netlify/functions/qa-403"
status = 200

# Redirect all requests to /index.html for SPA routing
[[redirects]]
from = "/*"
Expand Down
28 changes: 28 additions & 0 deletions netlify/functions/qa-403.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// QA-only Netlify Function that always returns a real HTTP 403
// Forbidden with a minimal HTML body. Used to test Prerender's
// handling of 4xx responses on a clean, page-looking URL. Reached
// publicly via /qa-403 (see redirect in netlify.toml).
//
// The 403 status code and Content-Type are set by THIS function and
// passed through unchanged by Netlify's status=200 rewrite proxy —
// the client sees a real 403, not a 200 carrying error text.

export default async (_req: Request): Promise<Response> => {
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>403 - QA</title>
</head>
<body>
<h1>Forbidden</h1>
</body>
</html>
`;

return new Response(html, {
status: 403,
headers: { "Content-Type": "text/html; charset=utf-8" },
});
};
Loading