25 lines
2.6 KiB
JavaScript
25 lines
2.6 KiB
JavaScript
import http from 'node:http';
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { pathToFileURL } from 'node:url';
|
|
import { root, blockedPath } from './lib.mjs';
|
|
import { sites } from './sites.mjs';
|
|
|
|
const types={'.html':'text/html; charset=utf-8','.css':'text/css; charset=utf-8','.js':'text/javascript; charset=utf-8','.json':'application/json; charset=utf-8','.png':'image/png','.jpg':'image/jpeg','.jpeg':'image/jpeg','.webp':'image/webp','.gif':'image/gif','.svg':'image/svg+xml','.ico':'image/x-icon','.woff':'font/woff','.woff2':'font/woff2','.ttf':'font/ttf','.eot':'application/vnd.ms-fontobject','.mp4':'video/mp4','.pdf':'application/pdf'};
|
|
export function createStaticServer({site:singleSite}={}){
|
|
return http.createServer(async(req,res)=>{
|
|
let pathname;try{pathname=decodeURIComponent(new URL(req.url,'http://localhost').pathname);}catch{res.writeHead(400);res.end();return;}
|
|
if(!['GET','HEAD'].includes(req.method)){res.writeHead(405,{'allow':'GET, HEAD'});res.end();return;}
|
|
let site=singleSite;let within=pathname;
|
|
if(!site){const match=pathname.match(/^\/(jskcloud|scck)(\/.*)?$/);if(!match){if(pathname==='/'){res.writeHead(302,{'location':'/jskcloud/'});res.end();}else{res.writeHead(404);res.end('404');}return;}site=match[1];within=match[2]||'/';if(!match[2]){res.writeHead(301,{'location':pathname+'/'});res.end();return;}}
|
|
const base=path.join(root,site);let status=200;let file=path.resolve(base,'.'+within);
|
|
if(!file.startsWith(base+path.sep)&&file!==base||blockedPath(within)||/\.(?:php|conf|md)(?:$|\.)/i.test(within)||/(?:^|\/)\./.test(within)){status=404;file=path.join(base,'404.html');}
|
|
try{let stat=await fs.stat(file);if(stat.isDirectory()){if(!pathname.endsWith('/')){res.writeHead(301,{'location':pathname+'/'});res.end();return;}file=path.join(file,'index.html');}const body=await fs.readFile(file);res.writeHead(status,{'content-type':types[path.extname(file)]||'application/octet-stream','content-length':body.length,'cache-control':'no-cache'});res.end(req.method==='HEAD'?undefined:body);}
|
|
catch{const body=await fs.readFile(path.join(base,'404.html'));res.writeHead(404,{'content-type':types['.html']});res.end(req.method==='HEAD'?undefined:body);}
|
|
});
|
|
}
|
|
if(process.argv[1]&&import.meta.url===pathToFileURL(process.argv[1]).href){
|
|
const args=process.argv.slice(2);const chosen=args.find(x=>sites.some(s=>s.id===x));const port=Number(args.find(x=>/^\d+$/.test(x))||4173);
|
|
createStaticServer({site:chosen}).listen(port,'0.0.0.0',()=>console.log(chosen?`Preview: http://localhost:${port}/ (${chosen})`:`Preview: http://localhost:${port}/jskcloud/ and http://localhost:${port}/scck/`));
|
|
}
|