Skip to content

Instantly share code, notes, and snippets.

@intrnl
Last active August 18, 2022 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save intrnl/7458c09d4d2433d59d19994b5f273486 to your computer and use it in GitHub Desktop.
Save intrnl/7458c09d4d2433d59d19994b5f273486 to your computer and use it in GitHub Desktop.
import http from 'node:http';
export function createRunner (middlewares) {
/**
* @param {http.IncomingMessage} request
* @param {http.ServerResponse} response
* @param {(error?: any) => void} done
*/
return function runner (request, response, done = createFinalHandler(request, response)) {
let idx = 0;
function next (error) {
if (idx >= middlewares.length) {
setImmediate(done, error);
return
}
const handle = middlewares[idx++];
const arity = handle.length;
try {
if (error && arity === 4) {
handle(error, request, response, next);
return;
}
else if (!error && arity < 4) {
handle(request, response, next);
return;
}
}
catch (e) {
// replace the error
error = e;
}
next(error);
}
attachParsedUrl(request);
next(null);
}
}
/**
* @param {http.IncomingMessage} request
* @param {http.ServerResponse} response
*/
export function createFinalHandler (request, response) {
return function handler (error) {
let status;
let headers;
let message;
if (response.headersSent) {
return;
}
if (error) {
if ('status' in error && typeof error.status === 'number') {
status = error.status;
if ('headers' in error && typeof error.headers === 'object') {
headers = Object.assign(Object.create(null), error.headers);
}
}
else {
status = res.statusCode;
}
if (status < 400 || status > 599) {
status = 500;
}
message = http.STATUS_CODES[status];
}
else {
status = 404;
message = `Cannot ${request.method} ${encodeURIComponent(request.pathname)}`;
}
const body = (
'<!doctype html>' +
'<html lang="en">' +
'<head>' +
'<meta charset="utf-8">' +
'<title>Error</title>' +
'</head>' +
'<body>' +
'<pre>' + message + '</pre>' +
'</body>' +
'</html>'
);
response.statusCode = status;
response.statusMessage = http.STATUS_CODES[status];
response.removeHeader('Content-Encoding');
response.removeHeader('Content-Language');
response.removeHeader('Content-Range');
if (headers) {
const keys = Object.keys(headers);
const length = keys.length;
for (let idx = 0; idx < length; idx++) {
const header = keys[idx];
const value = headers[header];
response.setHeader(header, value);
}
}
response.setHeader('Content-Type', 'text/html; charset=utf-8');
response.setHeader('Content-Length', Buffer.byteLength(body, 'utf-8'));
response.setHeader('Content-Security-Policy', 'default-src "none"');
response.setHeader('X-Content-Type-Options', 'nosniff');
if (request.method === 'HEAD') {
response.end();
return;
}
response.end(body, 'utf-8');
}
}
/**
* @param {http.IncomingMessage} request
*/
function attachParsedUrl (request) {
let raw = request.url;
if (raw == null) {
return;
}
let pathname = raw;
let search = '';
let searchIdx = raw.indexOf('?', 1);
if (searchIdx !== -1) {
search = raw.substring(idx);
pathname = raw.substring(0, idx);
}
request.pathname = pathname;
request.search = search;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment