@webda/core
Version:
Expose API with Lambda
313 lines • 8 kB
JavaScript
import { parse as cookieParse } from "cookie";
import { Readable } from "stream";
/**
* All methods supported by Webda
*/
export const HttpMethodTypeAny = ["GET", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"];
/**
* The HttpContext
*
* It has similar properties than URL
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/URL_API
*
* @category CoreFeatures
*/
export class HttpContext {
constructor(hostname, method, uri, protocol = "http", port = "80", headers = {}) {
/**
* URI prefix in case it is exposed through something that prefix the uri
*/
this.prefix = "";
this.hostname = hostname;
this.method = method;
this.uri = uri;
[this.path, this.search] = uri.split("?");
if (this.search) {
this.search = "?" + this.search;
}
else {
this.search = "";
}
// @ts-ignore
this.protocol = protocol + ":";
this.port = port.toString();
this.headers = {};
for (let i in headers) {
if (i.toLowerCase() === "cookie") {
this.cookies = Array.isArray(headers[i])
? headers[i].map(c => cookieParse(c))
: cookieParse(headers[i]);
}
this.headers[i.toLowerCase()] = headers[i];
}
let portUrl = "";
if (port !== undefined &&
((this.port !== "80" && protocol === "http") || (this.port !== "443" && protocol === "https"))) {
portUrl = ":" + port;
}
else {
this.port = "";
}
this.origin = this.protocol + "//" + this.hostname + portUrl;
this.host = this.hostname + portUrl;
}
/**
* Set the client ip
*/
setClientIp(ip) {
this.clientIp = ip;
return this;
}
/**
* Get the client ip
*/
getClientIp() {
return this.clientIp;
}
/**
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/URL/href
* @returns
*/
getHref() {
return this.getAbsoluteUrl();
}
/**
*
* @param prefix uri to not consider
*/
setPrefix(prefix) {
if (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length - 1);
}
this.prefix = prefix;
}
/**
* Return Uri without prefix
*/
getRelativeUri() {
return this.uri.substring(this.prefix.length);
}
/**
* Get full URI
* @returns
*/
getUrl() {
return this.uri;
}
/**
* Get cookies
* @returns
*/
getCookies() {
return this.cookies;
}
/**
* Get port number as string
*
* If http on port 80, or https on port 443 will return ""
*/
getPort() {
return this.port;
}
/**
* Get the port number
*/
getPortNumber() {
if (this.port) {
return Number.parseInt(this.port);
}
if (this.protocol === "https:") {
return 443;
}
else {
return 80;
}
}
/**
* Return hostname and port
* @returns
*/
getHost() {
return this.host;
}
/**
* Return protocol, hostname and port
* @returns
*/
getOrigin() {
return this.origin;
}
/**
* Get the hostname
* @returns
*/
getHostName() {
return this.hostname;
}
/**
* Get HTTP Method used
* @returns
*/
getMethod() {
return this.method;
}
/**
* Get protocol used
* @returns
*/
getProtocol() {
return this.protocol;
}
/**
* Get the raw body as string
*
* @param limit the size of readable request
* @param timeout the time to read the request
* @param encoding to analyze
* @returns
*/
async getRawBodyAsString(limit = 1024 * 1024 * 10, timeout = 60000, encoding) {
// Get charset from header
if (!encoding) {
let match = this.getUniqueHeader("content-type", "charset=utf-8").match(/charset=([^;\s]+)/);
if (match) {
encoding = match[1].trim();
}
else {
encoding = "utf-8";
}
}
if (encoding !== "utf-8") {
throw new Error("Only UTF-8 is currently managed: https://github.com/loopingz/webda.io/issues/221");
}
return ((await this.getRawBody(limit, timeout)) || Buffer.from("")).toString(encoding);
}
/**
* Get request body
*
* @param limit the size of readable request
* @param timeout the time to read the request
* @returns
*/
async getRawBody(limit = 1024 * 1024 * 10, timeout = 60000) {
if (this.body instanceof Readable) {
return new Promise((resolve, reject) => {
let req = this.body;
let body = [];
let timeoutId = setTimeout(() => {
reject("Request timeout");
}, timeout);
req.on("readable", () => {
let chunk = req.read();
if (chunk !== null) {
if (chunk.length + body.length > limit) {
clearTimeout(timeoutId);
reject("Request oversized");
}
body.push(chunk);
}
});
req.on("end", () => {
clearTimeout(timeoutId);
// Cache body as stream won't be able to be read twice
this.body = Buffer.concat(body);
resolve(this.body);
});
});
}
else {
return this.body;
}
}
/**
* Get the body as stream
*/
getRawStream() {
if (this.body instanceof Readable) {
return this.body;
}
return Readable.from(this.body || Buffer.from(""));
}
/**
* Get HTTP Headers
* @returns
*/
getHeaders() {
return this.headers;
}
/**
* Get header value
* @param name
* @param def
* @returns
*/
getHeader(name, def) {
return this.headers[name.toLowerCase()] || def;
}
/**
* Return the last header found with that name
*/
getUniqueHeader(name, def) {
let header = this.getHeader(name, def);
if (Array.isArray(header)) {
return header.pop() || def;
}
return header || def;
}
/**
* Used for test
* @param body
*/
setBody(body) {
if (body instanceof Readable || body instanceof Buffer) {
this.body = body;
}
else if (typeof body === "string") {
this.body = Buffer.from(body);
}
else if (body === undefined) {
this.body = undefined;
}
else {
this.body = Buffer.from(JSON.stringify(body));
}
return this;
}
/**
* Get request path name
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname
* @returns
*/
getPathName() {
return this.path;
}
/**
* Get search section
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/URL/search
* @returns
*/
getSearch() {
return this.search;
}
/**
*
* @param uri to return absolute url from
*/
getAbsoluteUrl(uri = this.uri) {
if (uri.match(/^\w{1,10}:\/\//)) {
return uri;
}
if (!uri.startsWith("/")) {
uri = "/" + uri;
}
if (this.port) {
return `${this.protocol}//${this.hostname}:${this.port}${uri}`;
}
return `${this.protocol}//${this.hostname}${uri}`;
}
}
//# sourceMappingURL=httpcontext.js.map