Skip to content

Commit 268e692

Browse files
authored
Min html 404 (#49954)
1 parent a123b01 commit 268e692

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

src/frame/lib/constants.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,20 @@ export const MAX_REQUEST_TIMEOUT = process.env.REQUEST_TIMEOUT
1717
? parseInt(process.env.REQUEST_TIMEOUT, 10)
1818
: DEFAULT_MAX_REQUEST_TIMEOUT
1919
export const TRANSLATIONS_FIXTURE_ROOT = process.env.TRANSLATIONS_FIXTURE_ROOT
20+
21+
// Minimum required HTML for 404: W3C valid, no external, legal.
22+
export const minimumNotFoundHtml = `
23+
<!doctype html>
24+
<html lang=en>
25+
<meta charset=utf-8>
26+
<title>404 - GitHub Docs</title>
27+
<style>body{font-family:system-ui,sans-serif;margin:3rem}a{color:#0969DA}</style>
28+
<p style=font-weight:500>GitHub Docs</p>
29+
<p>Page not found.</p>
30+
<p><a href=/>Return to home.</a></p>
31+
<small>
32+
&copy; ${new Date().getFullYear()} GitHub, Inc.
33+
&bull; <a href=https://docs.github.com/site-policy/github-terms/github-terms-of-service>Terms</a>
34+
&bull; <a href=https://docs.github.com/site-policy/privacy-policies/github-privacy-statement>Privacy</a>
35+
</small>
36+
`.replace(/\n/g, '')

src/frame/middleware/render-page.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { allVersions } from '#src/versions/lib/all-versions.js'
1111
import { isConnectionDropped } from './halt-on-dropped-connection.js'
1212
import { nextHandleRequest } from './next.js'
1313
import { defaultCacheControl } from './cache-control.js'
14+
import { minimumNotFoundHtml } from '../lib/constants.js'
1415

1516
const STATSD_KEY_RENDER = 'middleware.render_page'
1617
const STATSD_KEY_404 = 'middleware.render_404'
@@ -59,7 +60,7 @@ export default async function renderPage(req, res) {
5960

6061
if (!pathLanguagePrefixed(req.path)) {
6162
defaultCacheControl(res)
62-
return res.status(404).type('text').send('Not found')
63+
return res.status(404).type('html').send(minimumNotFoundHtml)
6364
}
6465

6566
// The rest is "unhandled" requests where we don't have the page

src/shielding/tests/shielding.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,28 @@ describe('rate limiting', () => {
126126
})
127127

128128
describe('404 pages and their content-type', () => {
129+
const exampleNonLanguage404plain = ['/_next/image/foo']
130+
test.each(exampleNonLanguage404plain)(
131+
'non-language 404 response is plain text and cacheable: %s',
132+
async (pathname) => {
133+
const res = await get(pathname)
134+
expect(res.statusCode).toBe(404)
135+
expect(res.headers['content-type']).toMatch('text/plain')
136+
expect(res.headers['cache-control']).toMatch('public')
137+
},
138+
)
139+
129140
const exampleNonLanguage404s = [
130-
'/_next/image/foo',
131141
'/wp-content/themes/seotheme/db.php?u',
132142
'/enterprise/3.1/_next/static/chunks/616-910d0397bafa52e0.js',
133143
'/~root',
134144
]
135145
test.each(exampleNonLanguage404s)(
136-
'non-language 404 response is plain text and cacheable: %s',
146+
'non-language 404 response is html text and cacheable: %s',
137147
async (pathname) => {
138148
const res = await get(pathname)
139149
expect(res.statusCode).toBe(404)
140-
expect(res.headers['content-type']).toMatch('text/plain')
150+
expect(res.headers['content-type']).toMatch('text/html; charset=utf-8')
141151
expect(res.headers['cache-control']).toMatch('public')
142152
},
143153
)

0 commit comments

Comments
 (0)