Skip to content

Instantly share code, notes, and snippets.

@stif
Last active April 1, 2024 04:10
Show Gist options
  • Save stif/f063d2807556d18a786369425758cbc4 to your computer and use it in GitHub Desktop.
Save stif/f063d2807556d18a786369425758cbc4 to your computer and use it in GitHub Desktop.
node.js HTTP Server
import * as http from 'http'
import { URL } from 'url'
import { stat, readFile } from 'fs/promises';
import { join, extname } from 'path';
// you can pass the parameter in the command line. e.g. node http_server.js 3000
const port = process.argv[2] || 9000;
// maps file extention to MIME types
// full list can be found here: https://www.freeformatter.com/mime-types-list.html
const mimeType = {
'.ico': 'image/x-icon',
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.wav': 'audio/wav',
'.mp3': 'audio/mpeg',
'.svg': 'image/svg+xml',
'.pdf': 'application/pdf',
'.zip': 'application/zip',
'.doc': 'application/msword',
'.eot': 'application/vnd.ms-fontobject',
'.ttf': 'application/x-font-ttf',
};
let webserver = http.createServer( async (req, res) => {
console.log(`${req.method} ${req.url}`);
//console.log("Request Headers: " + JSON.stringify(req.headers, null, '\t'));
// parse URL
const baseURL = 'http://' + req.headers.host + '/';
const parsedUrl = new URL(req.url, baseURL);
let pathname = decodeURIComponent(join('../frontend/dist', parsedUrl.pathname));
try {
let stats = await stat(pathname)
if(stats.isDirectory()) {
pathname += '/index.html';
}
// if the file is found, read it and its extension
const data = await readFile(pathname)
const ext = extname(pathname)
// set Content-type and send data
res.setHeader('Content-type', mimeType[ext] || 'text/plain' );
res.end(data);
}
catch (err) {
// if the file is not found, return 404
if(err.code == 'ENOENT') {
console.error(`file ${pathname} does not exist / stats undefined`)
res.statusCode = 404;
res.end(`File ${pathname} not found!`);
}
else {
console.error("Error: " + err.message)
res.statusCode = 500;
res.end(`Error getting the file: ${err}.`);
}
}
})
webserver.listen(port);
console.log(`Server listening on port ${port}`);
//export { webserver };
@trpapp
Copy link

trpapp commented Sep 28, 2022

Hi there! I've modified this gist to use https and it works pretty much the same way. One thing to note is that the gist (as well as my https version of the gist) will fail and crash a running website if req.headers.host contains unsafe characters (which I found happens to me because CloudFlare was injecting its own req.headers.host requests; more specifically the string- {ip}:{host}). I've replaced req.headers.host with image to fix the error instead of catching it and handling it. Essentially, the (potentially malformed/injected) host header string is regex parsed against all unsafe characters and replaces it with '.' to force it to validate and then the rest of your code takes care of the possible file-not-found condition. This is what I used to resolve the issue but may not be the correct remedy. Either way, I hope this is useful to you or others looking at the gist and was the reason for my comment. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment