-
Notifications
You must be signed in to change notification settings - Fork 11
/
static-development-server.js
76 lines (72 loc) · 5.43 KB
/
static-development-server.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
// This is a static http server script
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { join, resolve } from 'path';
import { createServer } from 'http';
import { stat, readFile } from 'fs';
/**
* @param {string} parameter
* @param {string} fallback
*/
function getArgumentOrDefault(parameter, fallback) {
const before = process.argv.slice(2).map((arg, index) => ({ arg, index })).filter(({ arg }) => arg === parameter).pop();
return before ? process.argv[2 + before.index + 1] || fallback : fallback;
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const config = { host: getArgumentOrDefault('--host', 'localhost'), port: getArgumentOrDefault('--port', '8080'), path: getArgumentOrDefault('--path', __dirname) };
const mimeLookup = { 'aac': 'audio/aac', 'abw': 'application/x-abiword', 'arc': 'application/x-freearc', 'avi': 'video/x-msvideo', 'azw': 'application/vnd.amazon.ebook', 'bin': 'application/octet-stream', 'bmp': 'image/bmp', 'bz': 'application/x-bzip', 'bz2': 'application/x-bzip2', 'csh': 'application/x-csh', 'css': 'text/css', 'csv': 'text/csv', 'doc': 'application/msword', 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'eot': 'application/vnd.ms-fontobject', 'epub': 'application/epub+zip', 'gz': 'application/gzip', 'gif': 'image/gif', 'htm': 'text/html', 'html': 'text/html', 'ico': 'image/vnd.microsoft.icon', 'ics': 'text/calendar', 'jar': 'application/java-archive', 'jpeg': 'image/jpeg', 'jpg': 'image/jpeg', 'js': 'text/javascript', 'json': 'application/json', 'jsonld': 'application/ld+json', 'mid': 'audio/midi', 'midi': 'audio/midi', 'mjs': 'text/javascript', 'mp3': 'audio/mpeg', 'mpeg': 'video/mpeg', 'mpkg': 'application/vnd.apple.installer+xml', 'odp': 'application/vnd.oasis.opendocument.presentation', 'ods': 'application/vnd.oasis.opendocument.spreadsheet', 'odt': 'application/vnd.oasis.opendocument.text', 'oga': 'audio/ogg', 'ogv': 'video/ogg', 'ogx': 'application/ogg', 'opus': 'audio/opus', 'otf': 'font/otf', 'png': 'image/png', 'pdf': 'application/pdf', 'php': 'application/x-httpd-php', 'ppt': 'application/vnd.ms-powerpoint', 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'rar': 'application/vnd.rar', 'rtf': 'application/rtf', 'sh': 'application/x-sh', 'svg': 'image/svg+xml', 'swf': 'application/x-shockwave-flash', 'tar': 'application/x-tar', 'tif': 'image/tiff', 'tiff': 'image/tiff', 'ts': 'video/mp2t', 'ttf': 'font/ttf', 'txt': 'text/plain', 'vsd': 'application/vnd.visio', 'wav': 'audio/wav', 'weba': 'audio/webm', 'webm': 'video/webm', 'webp': 'image/webp', 'woff': 'font/woff', 'woff2': 'font/woff2', 'xhtml': 'application/xhtml+xml', 'xls': 'application/vnd.ms-excel', 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xml': 'application/xml ', 'xul': 'application/vnd.mozilla.xul+xml', 'zip': 'application/zip', '3gp': 'video/3gpp', '3g2': 'video/3gpp2', '7z': 'application/x-7z-compressed' };
createServer(function (request, response) {
const url = new URL(request.url, `http://${request.headers.host}`);
const uri = url.pathname;
if (uri.includes("..")) {
console.log(`[${(new Date()).toISOString()}] 404 ${uri} (unsafe request blocked)`);
response.writeHead(404, { 'Content-Type': 'text/plain' });
response.write('404 Not Found\n');
response.end();
return;
}
let filename = join(config.path, decodeURIComponent(uri));
stat(filename, function (err, stats) {
if (err) {
if (err.code === "ENOENT") {
console.log(`[${(new Date()).toISOString()}] 404 ${uri} Not found: "${resolve(filename)}"`);
response.writeHead(404, { 'Content-Type': 'text/plain' });
response.write('404 Not Found\n');
} else {
console.log(`[${(new Date()).toISOString()}] 500 ${uri} ${err.toString()}`);
response.writeHead(500, { 'Content-Type': 'text/plain' });
response.write(err + '\n');
}
response.end();
return;
}
if (stats.isDirectory()) {
filename += '/index.html';
}
readFile(filename, 'binary', function (err, file) {
if (err) {
if (err.code === "ENOENT") {
console.log(`[${(new Date()).toISOString()}] 404 ${uri} Not found: "${resolve(filename)}"`);
response.writeHead(404, { 'Content-Type': 'text/plain' });
response.write('404 Not Found\n');
} else {
console.log(`[${(new Date()).toISOString()}] 500 ${uri} ${err.toString()}`);
response.writeHead(500, { 'Content-Type': 'text/plain' });
response.write(err + '\n');
}
response.end();
return;
}
const type = mimeLookup[filename.substring(filename.lastIndexOf(".") + 1)];
response.writeHead(200, { 'Content-Type': type || "text/plain" });
response.write(file, 'binary');
response.end();
console.log(`[${(new Date()).toISOString()}] 200 ${uri}`);
});
});
}).listen(
parseInt(config.port.toString(), 10),
config.host,
() => console.log(`[${(new Date()).toISOString()}] Listening at 'http://${config.host}${config.port.toString() !== '80' ? ':' + config.port : ''}/' and serving '${resolve(config.path)}'`)
);