import { ServerRequest } from '../external/http.ts' import { HTTPProtocol, HTTPRequest, RemoteHost } from './type/HTTPRequest.ts' import { Response } from './Response.ts' import { HTTPResponse } from './type/HTTPResponse.ts' import Utility from '../service/utility/Utility.ts' import { Injectable } from '../../../di/src/decorator/Injection.ts' import SessionInterface from './session/SessionInterface.ts' import ActivatedRoute from './routing/ActivatedRoute.ts' /** * Base class for Daton-managed HTTP requests. * @implements HTTPRequest */ @Injectable() export class Request implements HTTPRequest { /** * The associated response object. * @type HTTPResponse */ public readonly response: HTTPResponse /** * The base raw Deno request. * @type ServerRequest */ private readonly _deno_req: ServerRequest /** * The parsed body. */ private _body: any /** * The parsed query params. * @type object */ private _query: { [key: string]: any } = {} /** * The associated session. * @type SessionInterface */ private _session!: SessionInterface /** * The matched, mounted route. * @type ActivatedRoute */ private _activated_route!: ActivatedRoute /** * The incoming URL. * @type string */ public readonly url: string /** * The incoming request method. * @type string */ public readonly method: string /** * The incoming HTTP protocol. * @type HTTPProtocol */ public readonly protocol: HTTPProtocol /** * The underlying Deno connection. * @type Deno.Conn */ public readonly connection: Deno.Conn /** * True if the request used HTTPS. * @type boolean */ public readonly secure: boolean = false /** * The incoming headers. */ public get headers() { return this._deno_req.headers } /** * Get the underlying Deno request. * @type ServerRequest */ get to_native(): ServerRequest { return this._deno_req } /** * Get the cookies for the response. * @type CookieJar */ get cookies() { return this.response.cookies } /** * Get the associated session. * @type SessionInterface */ get session(): SessionInterface { return this._session } /** * Set the associated session. * @param {SessionInterface} session */ set session(session: SessionInterface) { if ( !this._session ) this._session = session } /** * Get the activated route mounted to this request. * @type ActivatedRoute */ get route(): ActivatedRoute { return this._activated_route } /** * Mount the given route to the request. * @param {ActivatedRoute} route */ set route(route: ActivatedRoute) { if ( !this._activated_route ) this._activated_route = route } constructor( protected utility: Utility, /** * The raw Deno request. */ from: ServerRequest ) { this._deno_req = from this.url = this._deno_req.url this.method = this._deno_req.method.toLowerCase() this.protocol = { string: this._deno_req.proto, major: this._deno_req.protoMajor, minor: this._deno_req.protoMinor, } this.connection = this._deno_req.conn this.response = new Response(this) } /** * Prepare the request for the Daton framework. * @return Promise */ public async prepare() { this._body = await Deno.readAll(this._deno_req.body) const url_params = new URLSearchParams(this.url.substr(1)) const param_obj = Object.fromEntries(url_params) const params: any = {} for ( const key in param_obj ) { if ( !param_obj.hasOwnProperty(key) ) continue if ( param_obj[key] === '' ) params[key] = true else params[key] = this.utility.infer(param_obj[key]) } this._query = params } /** * Send the given response. * @param res */ respond(res: any) { return this._deno_req.respond(res) } // public body: RequestBody = {} // public original_body: RequestBody = {} /** * Get the remote host information. * @type RemoteHost */ get remote() { return this.connection.remoteAddr as RemoteHost } /** * Get the raw body from the request. * @type string */ get body() { return this._body } /** * Get the query params. * @type object */ get query() { return this._query } /** * Get the incoming host name. * @type string */ get hostname() { return this.headers.get('host')?.split(':')[0] } /** * Get the incoming path of the route. * @type string */ get path() { return this.url.split('?')[0].split('#')[0] } /** * True if the request is an XHR incoming. * @type boolean */ get xhr() { return this.headers.get('x-requested-with')?.toLowerCase() === 'xmlhttprequest' } /* body fresh/stale - cache remote ips (proxy) params route? signedCookies */ /* accepts content type accepts charsets accepts encodings accepts languages get header is content type get param with default value get input with default value range header parser */ }