UNPKG

egg

Version:

A web application framework for Node.js

225 lines (224 loc) • 5.57 kB
import "./response.js"; import { Request as Request$1 } from "@eggjs/core"; import querystring from "node:querystring"; //#region src/app/extend/request.ts const QUERY_CACHE = Symbol("request query cache"); const QUERIES_CACHE = Symbol("request queries cache"); const PROTOCOL = Symbol("request protocol"); const HOST = Symbol("request host"); const IPS = Symbol("request ips"); const RE_ARRAY_KEY = /[^[\]]+\[\]$/; var Request = class extends Request$1 { /** * Parse the "Host" header field host * and support X-Forwarded-Host when a * proxy is enabled. * @member {String} Request#host * @example * ip + port * ```js * this.request.host * => '127.0.0.1:7001' * ``` * or domain * ```js * this.request.host * => 'demo.eggjs.org' * ``` */ get host() { let host = this[HOST]; if (host) return host; if (this.app.config.proxy) host = getFromHeaders(this, this.app.config.hostHeaders); host = host || this.get("host") || ""; this[HOST] = host = host.split(",")[0].trim(); return host; } /** * @member {String} Request#protocol * @example * ```js * this.request.protocol * => 'https' * ``` */ get protocol() { let protocol = this[PROTOCOL]; if (protocol) return protocol; if (this.socket?.encrypted) { this[PROTOCOL] = protocol = "https"; return protocol; } if (this.app.config.proxy) { const proto = getFromHeaders(this, this.app.config.protocolHeaders); if (proto) { this[PROTOCOL] = protocol = proto.split(/\s*,\s*/)[0]; return protocol; } } this[PROTOCOL] = protocol = this.app.config.protocol || "http"; return protocol; } /** * Get all pass through ip addresses from the request. * Enable only on `app.config.proxy = true` * * @member {Array} Request#ips * @example * ```js * this.request.ips * => ['100.23.1.2', '201.10.10.2'] * ``` */ get ips() { let ips = this[IPS]; if (ips) return ips; if (!this.app.config.proxy) { this[IPS] = ips = []; return ips; } const val = getFromHeaders(this, this.app.config.ipHeaders); this[IPS] = ips = val ? val.split(/\s*,\s*/) : []; let maxIpsCount = this.app.config.maxIpsCount; if (!maxIpsCount && this.app.config.maxProxyCount) maxIpsCount = this.app.config.maxProxyCount + 1; if (maxIpsCount > 0) this[IPS] = ips = ips.slice(-maxIpsCount); return ips; } /** * Get the request remote IPv4 address * @member {String} Request#ip * @return {String} IPv4 address * @example * ```js * this.request.ip * => '127.0.0.1' * => '111.10.2.1' * ``` */ get ip() { if (this._ip) return this._ip; const ip = this.ips[0] ?? this.socket.remoteAddress; this._ip = ip && ip.startsWith("::ffff:") ? ip.substring(7) : ip; return this._ip; } /** * Set the request remote IPv4 address * @member {String} Request#ip * @param {String} ip - IPv4 address * @example * ```js * this.request.ip * => '127.0.0.1' * => '111.10.2.1' * ``` */ set ip(ip) { this._ip = ip; } /** * detect if response should be json * 1. url path ends with `.json` * 2. response type is set to json * 3. detect by request accept header * * @member {Boolean} Request#acceptJSON * @since 1.0.0 */ get acceptJSON() { if (this.path.endsWith(".json")) return true; if (this.response.type && this.response.type.indexOf("json") >= 0) return true; if (this.accepts("html", "text", "json") === "json") return true; return false; } _customQuery(cacheName, filter) { const str = this.querystring || ""; let c = this[cacheName]; if (!c) c = this[cacheName] = {}; let cacheQuery = c[str]; if (!cacheQuery) { cacheQuery = c[str] = {}; const isQueries = cacheName === QUERIES_CACHE; const query = str ? querystring.parse(str) : {}; for (const key in query) { if (!key) continue; const value = filter(query[key]); cacheQuery[key] = value; if (isQueries && RE_ARRAY_KEY.test(key)) { const subKey = key.substring(0, key.length - 2); if (!cacheQuery[subKey]) cacheQuery[subKey] = value; } } } return cacheQuery; } /** * get params pass by querystring, all values are of string type. * @member {Object} Request#query * @example * ```js * GET http://127.0.0.1:7001?name=Foo&age=20&age=21 * this.query * => { 'name': 'Foo', 'age': '20' } * * GET http://127.0.0.1:7001?a=b&a=c&o[foo]=bar&b[]=1&b[]=2&e=val * this.query * => * { * "a": "b", * "o[foo]": "bar", * "b[]": "1", * "e": "val" * } * ``` */ get query() { return this._customQuery(QUERY_CACHE, firstValue); } /** * get params pass by querystring, all value are Array type. {@link Request#query} * @member {Array} Request#queries * @example * ```js * GET http://127.0.0.1:7001?a=b&a=c&o[foo]=bar&b[]=1&b[]=2&e=val * this.queries * => * { * "a": ["b", "c"], * "o[foo]": ["bar"], * "b[]": ["1", "2"], * "e": ["val"] * } * ``` */ get queries() { return this._customQuery(QUERIES_CACHE, arrayValue); } /** * Set query-string as an object. * * @function Request#query * @param {Object} obj set querystring and query object for request. */ set query(obj) { this.querystring = querystring.stringify(obj); } }; function firstValue(value) { if (Array.isArray(value)) value = value[0]; return value; } function arrayValue(value) { if (!Array.isArray(value)) value = [value]; return value; } function getFromHeaders(request, names) { if (!names) return ""; const fields = names.split(/\s*,\s*/); for (const name of fields) { const value = request.get(name); if (value) return value; } return ""; } //#endregion export { Request as default };