-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
106 lines (93 loc) · 2.26 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
const DEFAULT_DISABLE_LIST = [
'setHeaders',
'write',
'send',
'json',
'status',
'end',
'writeHead',
'addTrailers',
'writeContinue',
'append',
'attachment',
'download',
'format',
'jsonp',
'location',
'redirect',
'render',
'sendFile',
'sendStatus',
'set',
'type',
'vary'
];
module.exports = {
set: set,
handler
};
function set(timeout) {
validateTimeout(timeout);
return function(req, res, next) {
req.connection.setTimeout(timeout);
next();
};
}
function handler(opts) {
if (opts && typeof opts.timeout !== 'undefined') {
validateTimeout(opts.timeout);
}
opts = opts || {};
if (opts.onTimeout && typeof opts.onTimeout !== 'function') {
throw new Error('onTimeout option must be a function');
}
if (opts.onDelayedResponse && typeof opts.onDelayedResponse !== 'function') {
throw new Error('onDelayedResponse option must be a function');
}
if (opts.disable && !Array.isArray(opts.disable)) {
throw new Error('disable option must be an array');
}
const disableList = opts.disable || DEFAULT_DISABLE_LIST;
return function(req, res, next) {
const start = Date.now();
let timeoutSocket = null;
opts.timeout && req.connection.setTimeout(opts.timeout);
res.on('timeout', socket => {
res.globalTimeout = true;
timeoutSocket = socket;
if (!res.headersSent) {
if (opts.onTimeout) {
opts.onTimeout(req, res, next);
} else {
res.status(503).send('Service unavailable');
}
disableList.forEach( method => {
res[method] = accessAttempt.bind(res, method);
});
}
});
res.on('finish', () => {
timeoutSocket && timeoutSocket.destroy();
});
function accessAttempt() {
if (opts.onDelayedResponse) {
const requestTime = Date.now() - start;
const method = `res.${arguments[0]}`;
delete arguments[0];
const args = Object.keys(arguments).reduce((memo, key, index) => {
memo[index] = arguments[key];
return memo;
}, {});
opts.onDelayedResponse(req, method, args, requestTime);
opts.onDelayedResponse = null; //only call onDelayedResponse once
}
return this;
}
next();
};
}
function validateTimeout(timeout) {
if (typeof timeout !== 'number' || timeout % 1 !== 0 || timeout <= 0) {
throw new Error('timeout must be a whole number bigger than zero');
}
}