-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
121 lines (95 loc) · 3.32 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
'use strict';
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
///// Cluster Code /////
const PORT = 8000;
if (cluster.isMaster) {
console.log(`Master here (pid: ${process.pid}):`);
console.log(`Based on your current hardware, ${numCPUs} workers will be started...`);
console.log(`Listening on 0.0.0.0:${PORT}`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster
.on('SIGTERM', () => cluster.off('exit'))
.on('exit', (deadWorker) => {
console.warn(`${deadWorker.process.pid} died, forking new process...`);
cluster.fork();
});
return;
}
///// Worker Code /////
const pjson = require('./package.json');
const path = require('path');
const fs = require('fs');
const http = require('http');
const zlib = require('zlib');
const mime = require('mime');
const Throttle = require('stream-throttle').Throttle;
const rateLimit = 0; //3 * 1024 * 1024; // bps == 3 MB/s
const baseUrl = './www';
function handleRequest(request, response) {
const url = path.join(baseUrl, path.normalize(decodeURIComponent(request.url)));
console.log(`#${cluster.worker.id}: HTTP/${request.httpVersion} ${request.method} ${request.url}`);
response.setHeader('Server', `${pjson.name}/${pjson.version}`);
fs.stat(url, (error, stat) => {
if (error || stat.isDirectory()) {
response.writeHead(404);
return response.end('Not found');
}
const acceptEncoding = (request.headers['accept-encoding'] || '').split(',').map(s => s.trim());
const contentType = mime.lookup(url);
const isBinary = ['application/javascript', 'text/'].every(s => !contentType.startsWith(s));
response.setHeader('Content-Type', contentType);
let compressionStream;
if (!isBinary) {
['deflate', 'gzip'].some((encoding) => {
if (acceptEncoding.includes(encoding)) {
response.setHeader('Content-Encoding', encoding);
const method = 'create' + encoding.replace(/^./, c => c.toUpperCase());
compressionStream = zlib[method]({
flush: zlib.Z_PARTIAL_FLUSH,
level: zlib.Z_BEST_COMPRESSION,
});
return true;
}
});
}
let data;
let partial;
if (request.headers.range) {
const {range} = request.headers;
const [partialStart, partialEnd] = range.replace(/bytes=/, '').split('-');
const start = parseInt(partialStart, 10);
const end = partialEnd ? parseInt(partialEnd, 10) : stat.size - 1;
partial = {
start,
end,
chunkSize: (end - start) + 1,
};
data = fs.createReadStream(url, partial);
} else {
data = fs.createReadStream(url);
}
if (compressionStream) {
data = data.pipe(compressionStream);
} else {
response.setHeader('Content-Length', partial ? partial.chunkSize : stat.size);
}
if (rateLimit > 0) {
data = data.pipe(new Throttle({rate: rateLimit}));
}
if (!partial) {
response.writeHead(200);
} else {
response.writeHead(206, {
'Content-Range': `bytes ${partial.start}-${partial.end}/${stat.size}`,
'Accept-Ranges': 'bytes',
});
}
data.pipe(response);
});
}
http
.createServer(handleRequest)
.listen(PORT, () => console.log(`${cluster.worker.id} is ready (pid: ${process.pid})`));