/
Common.js
75 lines (63 loc) · 2.79 KB
/
Common.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
import { clock } from 'source/common/time'
// TODO: add responderEndRandomErrorStatus?
const responderEnd = (store) => {
if (store.response.writableEnded) return // NOTE: normally this should be it, the request is handled and response ended
const { error } = store.getState()
!store.response.headersSent && store.response.writeHead(error ? 500 : 400)
store.response.end() // force end the response to prevent pending
}
const responderEndWithStatusCode = (store, { statusCode = 500, headerMap }) => {
if (store.response.finished) return
!store.response.headersSent && store.response.writeHead(statusCode, headerMap)
store.response.end()
}
const responderEndWithRedirect = (store, { statusCode = 302, redirectUrl }) => {
if (store.response.finished) return
!store.response.headersSent && store.response.writeHead(statusCode, { 'location': redirectUrl })
store.response.end()
}
const responderSetHeaderCacheControlImmutable = (store) => { store.response.setHeader('cache-control', 'max-age=315360000, public, immutable') }
const DEFAULT_DESCRIBE_REQUEST = ({
url, method, headers: { host }, socket: { remoteAddress, remotePort }
}) => `[${method}] ${host || ''}${url} (${remoteAddress}:${remotePort})`
const createResponderLog = ({ log, describeRequest = DEFAULT_DESCRIBE_REQUEST }) => (store) => {
const userAgentString = store.request.headers[ 'user-agent' ] || 'none'
log(
describeRequest(store.request),
'[UA]', userAgentString
)
}
const createResponderLogEnd = ({ log, describeRequest = DEFAULT_DESCRIBE_REQUEST }) => (store) => {
const { statusCode } = store.response
const { time, error } = store.getState()
const timeString = `${Math.round(clock() - time)}ms`
log(
describeRequest(store.request),
error
? `[ERROR|${statusCode}|${timeString}] ${error.stack || error}`
: `[END|${statusCode}|${timeString}]`
)
}
const createResponderSetHeaderHSTS = ({ protocol }) => protocol !== 'https:'
? () => {}
: (store) => { store.response.setHeader('strict-transport-security', 'max-age=31536000; includeSubDomains; preload') }
// TODO: this just solves HTTP host map problem or HTTPS port map, for multi HTTPS host server, check `SNICallback`:
// https://en.wikipedia.org/wiki/Server_Name_Indication
// https://github.com/nodejs/node/issues/17567
const createResponderHostMapper = ({
hostResponderMap, // { [host]: responder }
responderDefault // for last fallback
}) => (store) => {
const responder = hostResponderMap[ (store.request.headers[ 'host' ] || '').toLowerCase() ] || responderDefault
return responder && responder(store)
}
export {
responderEnd,
responderEndWithStatusCode,
responderEndWithRedirect,
responderSetHeaderCacheControlImmutable,
createResponderLog,
createResponderLogEnd,
createResponderSetHeaderHSTS,
createResponderHostMapper
}