UNPKG

@ozmap/logger

Version:
150 lines (149 loc) 5.23 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkRequestHeader = exports.setupLogServer = void 0; const cluster_1 = __importDefault(require("cluster")); const http_1 = __importDefault(require("http")); const errors_1 = require("./errors"); const routes_1 = __importDefault(require("./routes")); /** * Function to create HTTP server on the primary process. * * @param port The interface port for the server to listen on. * @param address The interface address for the server to listen on. * @param logger The logger instance. * @returns The HTTP server that was setup. */ function setupLogServer(port, address, logger) { var _a; if (cluster_1.default.isWorker) return; if ((_a = process.env.OZLOGGER_HTTP) === null || _a === void 0 ? void 0 : _a.match(/false/i)) return; process.env.OZLOGGER_HTTP = 'false'; return http_1.default .createServer(handleRequest(logger)) .listen(port, address, () => { logger.info(`Log server started listening at ${address}:${port}`); }); } exports.setupLogServer = setupLogServer; /** * Closure for handling incoming HTTP requests. * * @param logger The logger client. * @returns The HTTP request handler. */ function handleRequest(logger) { return async (req, res) => { const reqIsJson = isContentTypeJson(req.headers); const resIsJson = isAcceptTypeJson(req.headers); Object.assign(req, { reqIsJson, resIsJson }); if (req.method !== 'GET') { try { await parseBody(req, reqIsJson ? 'json' : 'text'); } catch (e) { if (e instanceof errors_1.HttpError) return e.respond(res, resIsJson); logger.error(e); return new errors_1.HttpError(`Something went wrong while processing your request content.`, 500).respond(res, resIsJson); } } return router(req, res).catch((e) => { if (e instanceof errors_1.HttpError) return e.respond(res, resIsJson); logger.error(e); return new errors_1.HttpError(`Something went wrong while handling your request.`, 500).respond(res, resIsJson); }); }; } /** * Method for processing request contents. * * @param req The incoming HTTP request. * @param type The content type. */ async function parseBody(req, type) { const data = []; for await (const chunk of req) { data.push(chunk); if (limit(Buffer.concat(data), 5)) { req.socket.destroy(); throw new errors_1.HttpError('Content too large', 413); } } try { Object.assign(req, { body: type === 'json' ? JSON.parse(Buffer.concat(data).toString()) : Buffer.concat(data).toString() }); } catch (e) { throw new errors_1.HttpError('Unprocessable content', 422); } } /** * Function for checking if HTTP header * is present and has the given value. * * @param headers The HTTP request headers. * @param header The HTTP header being checked. * @param value The HTTP header value being verified. * @returns If the header is present and has the given value. */ function checkRequestHeader(headers, header, value) { var _a, _b, _c; if (!(header in headers)) return false; return Array.isArray(headers[header]) ? (_a = headers[header].some((h) => h.trim() === value)) !== null && _a !== void 0 ? _a : false : (_c = (_b = headers[header]) === null || _b === void 0 ? void 0 : _b.split(',').some((h) => h.trim() === value)) !== null && _c !== void 0 ? _c : false; } exports.checkRequestHeader = checkRequestHeader; /** * Validation method for Content-Type HTTP * header having the application/json type. * * @param headers The HTTP request headers. * @returns If the request content is JSON. */ function isContentTypeJson(headers) { return checkRequestHeader(headers, 'content-type', 'application/json'); } /** * Validation method for Accept HTTP header * having the application/json type. * * @param headers The HTTP request headers. * @returns If JSON is accepted as response. */ function isAcceptTypeJson(headers) { return checkRequestHeader(headers, 'accept', 'application/json'); } /** * Function for checking if data reached the allowed limit. * * @param data The current data being checked. * @param mb The limit data size. * @returns Whether or not the limit has been reached. */ function limit(data, mb) { return data.length > mb * 1000000; } /** * Router function to handle actions for different routes. * * @param req Incoming HTTP request. * @param res Outgoing HTTP response. */ async function router(req, res) { const route = `${req.method} ${req.url}`; if (!(route in routes_1.default)) throw new errors_1.HttpError('Not found', 404); await routes_1.default[route](req, res); return res.writeHead(200).end(); }