UNPKG

@cldn/web-ts

Version:
212 lines (211 loc) 8.9 kB
import { IP } from "@cldn/ip"; import { Multipart } from "multipart-ts"; import http from "node:http"; import stream from "node:stream"; import { Authorisation } from "./auth/Authorisation.js"; import { Permission } from "./auth/index.js"; import { Server } from "./Server.js"; /** * An incoming HTTP request from a connected client. */ export declare class Request<A> { /** * The request method. */ readonly method: Request.Method; /** * The original request address, as sent by the last peer. The {@link !URL} `protocol` is always set to `http:` and * the `host` (and related) are always taken from the `HOST` environment variable or defaulted to `localhost`. * * If basic authentication is available to this request via headers, the `username` and `password` fields are * available in the {@link URL} object. */ readonly originalUrl: Readonly<URL>; /** * The address requested by the client (first peer). If the request originated from a trusted proxy, this address * will be constructed based on protocol and host provided by the proxy. If the proxy does not specify protocol, * `http:` will be used as a default. If the proxy does not specify host (or the proxy is not trusted), will use the * `Host` request header. If that is not specified either, will use the `HOST` environment variable or default to * `localhost`. * * In short, this is, as closely as possible, the exact URL address the client requested. * * If basic authentication is available to this request via headers, the `username` and `password` fields are * available in the {@link URL} object. */ readonly url: Readonly<URL>; /** * The request headers. */ readonly headers: Readonly<Headers>; /** * Request body readable stream. */ readonly bodyStream: stream.Readable; /** * The IP address of the request sender (last peer). This might be a proxy. */ readonly originalIp: IP; /** * IP address of client (first peer). If the request originated from a trusted proxy, this will be the client IP * indicated by the proxy. Otherwise, if the proxy specifies no client IP, or the proxy is untrusted, this will be * the proxy IP and equivalent to {@link Request#originalIp}. */ readonly ip: IP; /** * The {@link Server} from which this request was received. */ readonly server: Server<A>; /** * The components of the request URL path name. */ readonly pathComponents: ReadonlyArray<string>; /** * The parsed request cookies from the {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cookie|Cookie} request header. */ readonly cookies: ReadonlyMap<string, string>; /** * Construct a new Request. * @param method See {@link Request#method}. * @param originalUrl See {@link Request#originalUrl}. * @param url See {@link Request#url}. * @param headers See {@link Request#headers}. * @param bodyStream See {@link Request#bodyStream}. * @param originalIp See {@link Request#originalIp}. * @param ip See {@link Request#ip}. * @param server See {@link Request#server}. * @throws {@link !URIError} If the request URL path name contains an invalid URI escape sequence. */ constructor(method: Request<A>["method"], originalUrl: Request<A>["originalUrl"], url: Request<A>["url"], headers: Request<A>["headers"], bodyStream: Request<A>["bodyStream"], originalIp: Request<A>["originalIp"], ip: Request<A>["ip"], server: Request<A>["server"]); /** * Create a new Request from a Node.js incoming HTTP request. * @throws {@link Request.BadUrlError} If the request URL is invalid. * @throws {@link Request.SocketClosedError} If the request socket was closed before the request could be handled. */ static incomingMessage<A>(incomingMessage: http.IncomingMessage, server: Server<A>): Request<A>; /** * Extract client IP, protocol, and host, from the information provided by a trusted proxy. * @param headers The HTTP headers sent by a trusted proxy. */ private static getClientInfoFromTrustedProxy; /** * Attempt to obtain authorisation for this request with one of the {@link Server}’s {@link Authenticator}s. * @returns `null` if the request lacks authorisation information. */ getAuthorisation(): Promise<Authorisation<A> | null>; /** * Returns a boolean value that declares whether the body has been read yet. */ bodyUsed(): boolean; /** * Returns a promise that resolves with an ArrayBuffer representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. */ arrayBuffer(): Promise<ArrayBuffer>; /** * Returns a promise that resolves with a Blob representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. */ blob(): Promise<Blob>; /** * Returns a promise that resolves with a Uint8Array representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. */ bytes(): Promise<Uint8Array>; /** * Returns a promise that resolves with a FormData representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. * @throws {@link !TypeError} If the request body cannot be parsed as multipart. */ formData(): Promise<FormData>; /** * Returns a promise that resolves with the result of parsing the request body as JSON. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. * @throws {@link !SyntaxError} If the request body cannot be parsed as JSON. */ json(): Promise<unknown>; /** * Returns a promise that resolves with a FormData representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. * @throws {@link !TypeError} If the request body cannot be parsed as multipart. */ multipart(): Promise<Multipart>; /** * Returns a promise that resolves with a text representation of the request body. * @throws {@link Request.BodyAlreadyConsumedError} If the request body has already been consumed. */ text(): Promise<string>; /** * Require that authorisation can be obtained from this request. * @throws {@link ThrowableResponse} of {@link ServerErrorRegistry.ErrorCodes.UNAUTHORISED} if authorisation cannot * be obtained. */ auth(): Promise<Authorisation<A>>; /** * Require that authorisation can be obtained from this request and that the given (requested) permission(s) are * ALL within the scope of the authorisation. * @param permissions The requested permissions. * @throws {@link ThrowableResponse} of {@link ServerErrorRegistry.ErrorCodes.UNAUTHORISED} if authorisation cannot * be obtained. * @throws {@link ThrowableResponse} of {@link ServerErrorRegistry.ErrorCodes.NO_PERMISSION} if the authorisation * lacks any of the requested permissions. */ auth(...permissions: [Permission, ...Permission[]]): Promise<Authorisation<A>>; } export declare namespace Request { class BadUrlError extends Error { readonly path: string | undefined; constructor(path: string | undefined); } /** * The request body has already been consumed. */ class BodyAlreadyConsumedError extends Error { constructor(); } /** * HTTP request methods. */ const enum Method { ACL = "ACL", BIND = "BIND", CHECKOUT = "CHECKOUT", CONNECT = "CONNECT", COPY = "COPY", DELETE = "DELETE", GET = "GET", HEAD = "HEAD", LINK = "LINK", LOCK = "LOCK", "M-SEARCH" = "M-SEARCH", MERGE = "MERGE", MKACTIVITY = "MKACTIVITY", MKCALENDAR = "MKCALENDAR", MKCOL = "MKCOL", MOVE = "MOVE", NOTIFY = "NOTIFY", OPTIONS = "OPTIONS", PATCH = "PATCH", POST = "POST", PROPFIND = "PROPFIND", PROPPATCH = "PROPPATCH", PURGE = "PURGE", PUT = "PUT", REBIND = "REBIND", REPORT = "REPORT", SEARCH = "SEARCH", SOURCE = "SOURCE", SUBSCRIBE = "SUBSCRIBE", TRACE = "TRACE", UNBIND = "UNBIND", UNLINK = "UNLINK", UNLOCK = "UNLOCK", UNSUBSCRIBE = "UNSUBSCRIBE" } /** * Socket closed by peer. */ class SocketClosedError extends Error { constructor(); } }