import type { Body, BodyBytes, BodyForm, BodyFormData, BodyJson, BodyOptions, BodyReader, BodyStream, BodyText,} from "./body.ts";import { RequestBody } from "./body.ts";import { NativeRequest } from "./http_server_native.ts";import type { ServerRequest } from "./http_server_std.ts";import type { HTTPMethods } from "./types.d.ts";import { preferredCharsets } from "./negotiation/charset.ts";import { preferredEncodings } from "./negotiation/encoding.ts";import { preferredLanguages } from "./negotiation/language.ts";import { preferredMediaTypes } from "./negotiation/mediaType.ts";
export class Request { #body: RequestBody; #proxy: boolean; #secure: boolean; #serverRequest: ServerRequest | NativeRequest; #url?: URL;
#getRemoteAddr(): string { return this.#serverRequest instanceof NativeRequest ? this.#serverRequest.remoteAddr ?? "" : (this.#serverRequest?.conn?.remoteAddr as Deno.NetAddr)?.hostname ?? ""; }
get hasBody(): boolean { return this.#body.has(); }
get headers(): Headers { return this.#serverRequest.headers; }
get ip(): string { return (this.#proxy ? this.ips[0] : this.#getRemoteAddr()) ?? ""; }
get ips(): string[] { return this.#proxy ? (this.#serverRequest.headers.get("x-forwarded-for") ?? this.#getRemoteAddr()).split(/\s*,\s*/) : []; }
get method(): HTTPMethods { return this.#serverRequest.method as HTTPMethods; }
get secure(): boolean { return this.#secure; }
get originalRequest(): ServerRequest | NativeRequest { return this.#serverRequest; }
get url(): URL { if (!this.#url) { const serverRequest = this.#serverRequest; if (serverRequest instanceof NativeRequest && !this.#proxy) { try { this.#url = new URL(serverRequest.rawUrl); return this.#url; } catch { } } let proto: string; let host: string; if (this.#proxy) { proto = serverRequest .headers.get("x-forwarded-proto")?.split(/\s*,\s*/, 1)[0] ?? "http"; host = serverRequest.headers.get("x-forwarded-host") ?? serverRequest.headers.get("host") ?? ""; } else { proto = this.#secure ? "https" : "http"; host = serverRequest.headers.get("host") ?? ""; } try { this.#url = new URL(`${proto}://${host}${serverRequest.url}`); } catch { throw new TypeError( `The server request URL of "${proto}://${host}${serverRequest.url}" is invalid.`, ); } } return this.#url; }
constructor( serverRequest: ServerRequest | NativeRequest, proxy = false, secure = false, ) { this.#proxy = proxy; this.#secure = secure; this.#serverRequest = serverRequest; this.#body = new RequestBody( serverRequest instanceof NativeRequest ? serverRequest.request : serverRequest, ); }
accepts(): string[] | undefined; accepts(...types: string[]): string | undefined; accepts(...types: string[]): string | string[] | undefined { const acceptValue = this.#serverRequest.headers.get("Accept"); if (!acceptValue) { return; } if (types.length) { return preferredMediaTypes(acceptValue, types)[0]; } return preferredMediaTypes(acceptValue); }
acceptsCharsets(): string[] | undefined; acceptsCharsets(...charsets: string[]): string | undefined; acceptsCharsets(...charsets: string[]): string[] | string | undefined { const acceptCharsetValue = this.#serverRequest.headers.get( "Accept-Charset", ); if (!acceptCharsetValue) { return; } if (charsets.length) { return preferredCharsets(acceptCharsetValue, charsets)[0]; } return preferredCharsets(acceptCharsetValue); }
acceptsEncodings(): string[] | undefined; acceptsEncodings(...encodings: string[]): string | undefined; acceptsEncodings(...encodings: string[]): string[] | string | undefined { const acceptEncodingValue = this.#serverRequest.headers.get( "Accept-Encoding", ); if (!acceptEncodingValue) { return; } if (encodings.length) { return preferredEncodings(acceptEncodingValue, encodings)[0]; } return preferredEncodings(acceptEncodingValue); }
acceptsLanguages(): string[] | undefined; acceptsLanguages(...langs: string[]): string | undefined; acceptsLanguages(...langs: string[]): string[] | string | undefined { const acceptLanguageValue = this.#serverRequest.headers.get( "Accept-Language", ); if (!acceptLanguageValue) { return; } if (langs.length) { return preferredLanguages(acceptLanguageValue, langs)[0]; } return preferredLanguages(acceptLanguageValue); }
body(options: BodyOptions<"bytes">): BodyBytes; body(options: BodyOptions<"form">): BodyForm; body(options: BodyOptions<"form-data">): BodyFormData; body(options: BodyOptions<"json">): BodyJson; body(options: BodyOptions<"reader">): BodyReader; body(options: BodyOptions<"stream">): BodyStream; body(options: BodyOptions<"text">): BodyText; body(options?: BodyOptions): Body; body(options: BodyOptions = {}): Body | BodyReader | BodyStream { return this.#body.get(options); }
[Symbol.for("Deno.customInspect")](inspect: (value: unknown) => string) { const { hasBody, headers, ip, ips, method, secure, url } = this; return `Request ${ inspect({ hasBody, headers, ip, ips, method, secure, url: url.toString(), }) }`; }}