Last active
June 26, 2023 22:35
-
-
Save GuilhermeRossato/ec540453a3dd0813aba2f4ada813c84b to your computer and use it in GitHub Desktop.
Single file static http server with nodejs (without any dependency)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/node | |
const config = {host: '127.0.0.1', port: 8080, path: process.argv[2] || '.'}; | |
const path = require('path'); | |
const http = require('http'); | |
const fs = require('fs'); | |
const url = require('url'); | |
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'}; | |
http.createServer(function (request, response) { | |
const uri = url.parse(request.url).pathname; | |
if (uri.includes("..") || uri.endsWith('/.env')) { | |
console.log(`${(new Date()).toISOString()} - 404 ${uri} (unsafe request blocked)`); | |
response.writeHead(404, {'Content-Type': 'text/plain'}); | |
response.end(); | |
return; | |
} | |
let filePath = path.resolve(config.path, decodeURIComponent(uri.substring(1))); | |
fs.stat(filePath, function (err, stats) { | |
if (err) { | |
if (err.code === "ENOENT") { | |
console.log(`${(new Date()).toISOString()} - 404 ${uri} Not found: "${filePath}"`); | |
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()) { | |
filePath += filePath[filePath.length - 1] === '/' ? 'index.html' : '/index.html'; | |
} | |
fs.readFile(filePath, 'binary', function (err, file) { | |
if (err) { | |
if (err.code === "ENOENT") { | |
console.log(`${(new Date()).toISOString()} - 404 ${uri} Not found: "${filePath}"`); | |
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.message}\n`); | |
} | |
response.end(); | |
return; | |
} | |
const type = mimeLookup[filePath.substring(filePath.lastIndexOf(".")+1)]; | |
response.writeHead(200, {'Content-Type': type ? type : 'text/plain'}); | |
response.write(file, 'binary'); | |
response.end(); | |
console.log(`${(new Date()).toISOString()} - 200 ${uri}`); | |
}); | |
}); | |
}).listen(config.port, config.host, () => console.log(`${(new Date()).toISOString()} - Serving "${config.path}" - Listening at http://${config.host}${config.port != 80 ? ":" + config.port : ""}/`)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const config={host:"127.0.0.1",port:8080,path:process.argv[2]||"."},i=require("path"),o=require("http"),e=require("fs"),a=require("url"),n={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"};o.createServer((function(o,p){const l=a.parse(o.url).pathname;if(l.includes("..")||l.endsWith("/.env"))return console.log(`${(new Date).toISOString()} - 404 ${l} (unsafe request blocked)`),p.writeHead(404,{"Content-Type":"text/plain"}),void p.end();let c=i.resolve(config.path,decodeURIComponent(l.substring(1)));e.stat(c,(function(t,i){if(t)return"ENOENT"===t.code?(console.log(`${(new Date).toISOString()} - 404 ${l} Not found: "${c}"`),p.writeHead(404,{"Content-Type":"text/plain"}),p.write("404 Not Found\n")):(console.log(`${(new Date).toISOString()} - 500 ${l} ${t.toString()}`),p.writeHead(500,{"Content-Type":"text/plain"}),p.write(t+"\n")),void p.end();i.isDirectory()&&(c+="/"===c[c.length-1]?"index.html":"/index.html"),e.readFile(c,"binary",(function(t,i){if(t)return"ENOENT"===t.code?(console.log(`${(new Date).toISOString()} - 404 ${l} Not found: "${c}"`),p.writeHead(404,{"Content-Type":"text/plain"}),p.write("404 Not Found\n")):(console.log(`${(new Date).toISOString()} - 500 ${l} ${t.toString()}`),p.writeHead(500,{"Content-Type":"text/plain"}),p.write(`${t.message}\n`)),void p.end();const o=n[c.substring(c.lastIndexOf(".")+1)];p.writeHead(200,{"Content-Type":o||"text/plain"}),p.write(i,"binary"),p.end(),console.log(`${(new Date).toISOString()} - 200 ${l}`)}))}))})).listen(config.port,config.host,(()=>console.log(`${(new Date).toISOString()} - Serving "${config.path}" - Listening at http://${config.host}${80!=config.port?":"+config.port:""}/`))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment