UNPKG

rjweb-server

Version:

Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS

191 lines (190 loc) 6.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const Middleware_1 = __importDefault(require("../../../classes/Middleware")); const RuntimeError_1 = __importDefault(require("../../../classes/RuntimeError")); const URLObject_1 = __importDefault(require("../../../classes/URLObject")); const ValueCollection_1 = __importDefault(require("../../../classes/ValueCollection")); class RequestContext { constructor(context, middlewares, server, global) { this.context = context; this.middlewares = middlewares; this.server = server; this.executeSelf = () => true; this.middlewareData = {}; this.started = performance.now(); this.aborted = false; /** * The Params of the URL Path * @since 9.0.0 */ this.params = new ValueCollection_1.default(); /** * The Cookies of the Request * @since 9.0.0 */ this.cookies = null; /** * The Queries of the Request * @since 9.0.0 */ this.queries = null; /** * The Fragments of the Request * @since 9.0.0 */ this.fragments = null; /** * The Error this request encountered * @since 9.0.0 */ this.error = null; /** * Whether the EndFn was called * @since 9.0.0 */ this.endFn = false; /** * Whether the Request is chunked * @since 9.0.0 */ this.chunked = false; /** * The File to print at the end of the request * @warn Only used in static routes, do not use in other routes * @since 9.0.0 */ this.file = null; /** * Body / Ws Message Data * @since 9.0.0 */ this.body = { chunks: [], callbacks: [], raw: null, parsed: '', awaiting: false, type: 'raw' }; /** * The Route, if found * @since 9.0.0 */ this.route = null; /** * The Response Data * @since 9.0.0 */ this.response = { status: 200, statusText: null, headers: new ValueCollection_1.default(), cookies: new ValueCollection_1.default(), content: Buffer.allocUnsafe(0), prettify: false }; this.url = new URLObject_1.default(context.path(), context.method()); this.type = context.type(); this.global = global; this.headers = context.getHeaders(); this.ip = { isProxied: false, value: context.clientIP(), port: context.clientPort() }; } /** * Set Code to execute at the end end of the request, * return a boolean describing if you want the normal request end to proceed too * @since 9.0.0 */ setExecuteSelf(callback) { const old = this.executeSelf; this.executeSelf = async () => { const result = await Promise.resolve(old()); if (!result) return false; return await Promise.resolve(callback()); }; return this; } /** * Handle an Error, automatically sets status and calls callback * @since 9.0.0 */ handleError(error, cause) { this.error = new RuntimeError_1.default(cause, error); return this.error; } /** * Initiate Request Abortion * @since 9.0.0 */ async abort(ctr) { if (this.aborted) return true; if (!ctr) this.global.logger.debug(`Aborted Request on ${this.url.method} ${this.url.href}`); if (ctr) { for (let i = 0; i < this.middlewares.length; i++) { const middleware = this.middlewares[i]; if (middleware.finishCallbacks.httpRequest) try { await Promise.resolve(middleware.finishCallbacks.httpRequest(middleware.config, this.server, this, ctr, this.elapsed())); } catch { } } if (this.global.finishHandlers.httpRequest) try { await Promise.resolve(this.global.finishHandlers.httpRequest(ctr, this.elapsed())); } catch { } } this.aborted = !ctr; return false; } /** * Retrieve Middleware Data * @since 9.0.0 */ data(middleware) { const key = middleware instanceof Middleware_1.default ? middleware['name'] : 'use' in middleware ? middleware.use().infos.name : middleware.infos.name; if (!this.middlewareData[key]) this.middlewareData[key] = {}; return this.middlewareData[key]; } /** * Await the Body * @since 9.0.0 */ async awaitBody(ctr, concat = true) { if (this.url.method === 'GET') return Buffer.allocUnsafe(0); if (this.body.awaiting) return new Promise((resolve) => this.body.callbacks.push(resolve)); if (this.body.raw) return this.body.raw; this.body.awaiting = true; await this.context.onBodyChunk(async (chunk, isLast) => { const buffer = Buffer.from(chunk); if (this.context.aborted().aborted) return this.abort(); if (this.route?.type === 'http' && !this.route.data.onRawBody && concat) this.body.chunks.push(buffer); else if (this.route?.type === 'http') try { if (!this.endFn) await Promise.resolve(this.route.data.onRawBody?.(ctr, () => this.endFn = true, buffer, isLast)); } catch (err) { this.handleError(err, 'http.handle.onRawBody'); } if (isLast && concat) { this.body.raw = Buffer.concat(this.body.chunks); this.body.chunks.length = 0; for (const callback of this.body.callbacks) { callback(this.body.raw); } this.body.callbacks.length = 0; } }); return this.body.raw; } /** * Get the ms elapsed since the request started * @since 9.0.0 */ elapsed(reset = false) { const ms = performance.now() - this.started; if (reset) this.started = performance.now(); return ms; } } exports.default = RequestContext;