-
Notifications
You must be signed in to change notification settings - Fork 7
/
index.js
125 lines (104 loc) · 3.65 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
import parser from 'accept-language-parser'
/**
* The DEBUG flag will do two things that help during development:
* 1. we will skip caching on the edge, which makes it easier to
* debug.
* 2. we will return an error message on exception in your Response rather
* than the default 404.html page.
*/
const DEBUG = false
const LANGUAGES = ['en', 'es', 'zh']
const DEFAULT_LANGUAGE = 'en'
const languageRegex = new RegExp(`^/(${LANGUAGES.join('|')})(/|$)`)
addEventListener('fetch', (event) => {
try {
event.respondWith(handleEvent(event))
} catch (e) {
if (DEBUG) {
return event.respondWith(
new Response(e.message || e.toString(), {
status: 500
})
)
}
event.respondWith(new Response('Internal Error', { status: 500 }))
}
})
async function handleEvent(event) {
let options = {}
const languageHeader = event.request.headers.get('Accept-Language')
const headerLanguage =
parser.pick(LANGUAGES, languageHeader) || DEFAULT_LANGUAGE
const getUrl = (requestUrl) => {
const url = new URL(requestUrl)
// If requesting a file, don't alter the path
if (url.pathname.includes('.')) {
return url
}
// Check if the language is specified in the path
const languageMatch = url.pathname.match(languageRegex)
const language = languageMatch ? languageMatch[1] : headerLanguage
// Remove the language from the path if necessary
const unlocalizedPathname = language
? url.pathname.replace(`/${language}`, '')
: url.pathname
const isIndex = !unlocalizedPathname.length || unlocalizedPathname === '/'
const path = isIndex ? '/home' : unlocalizedPathname.replace(/\/$/, '')
url.pathname = `/${language}${path}.html`
return url
}
options.mapRequestToAsset = (request) => {
return mapRequestToAsset(new Request(getUrl(request.url), request))
}
try {
if (DEBUG) {
// customize caching
options.cacheControl = {
bypassCache: true
}
}
const page = await getAssetFromKV(event, options)
// allow headers to be altered
const response = new Response(page.body, page)
response.headers.set('X-XSS-Protection', '1; mode=block')
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('Referrer-Policy', 'unsafe-url')
response.headers.set('Feature-Policy', 'none')
return response
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: (req) =>
new Request(`${new URL(req.url).origin}/404.html`, req)
})
return new Response(notFoundResponse.body, {
...notFoundResponse,
status: 404
})
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
}
/**
* Here's one example of how to modify a request to
* remove a specific prefix, in this case `/docs` from
* the url. This can be useful if you are deploying to a
* route on a zone, or if you only want your static content
* to exist at a specific path.
*/
function handlePrefix(prefix) {
return (request) => {
// compute the default (e.g. / -> index.html)
let defaultAssetKey = mapRequestToAsset(request)
let url = new URL(defaultAssetKey.url)
// strip the prefix from the path for lookup
url.pathname = url.pathname.replace(prefix, '/')
// inherit all other props from the default request
return new Request(url.toString(), defaultAssetKey)
}
}