egg
Version:
A web application framework for Node.js
225 lines (224 loc) • 5.57 kB
JavaScript
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 };