-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathExpressRequest.js
More file actions
207 lines (169 loc) · 6.05 KB
/
ExpressRequest.js
File metadata and controls
207 lines (169 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
'use strict';
const Negotiator = require('negotiator');
const parse_range = require('range-parser');
const type_is = require('type-is');
const is_ip = require('net').isIP;
class ExpressRequest {
#negotiator;
ExpressRequest() {
this.#negotiator = new Negotiator(this);
}
/* Methods */
get(name) {
let lowercase = name.toLowerCase();
switch (lowercase) {
case 'referer':
// Continue execution to below case for catching of both spelling variations
case 'referrer':
return this.headers['referer'] || this.headers['referrer'];
default:
return this.headers[lowercase];
}
}
header(name) {
return this.get(name);
}
acceptsCharsets() {
charsets = flattened(charsets, arguments);
// no charsets, return all requested charsets
if (!charsets || charsets.length === 0) {
return this.#negotiator.charsets();
}
return this.#negotiator.charsets(charsets)[0] || false;
}
acceptsEncodings() {
encodings = flattened(encodings, arguments);
// no encodings, return all requested encodings
if (!encodings || encodings.length === 0) {
return this.#negotiator.encodings();
}
return this.#negotiator.encodings(encodings)[0] || false;
}
acceptsLanguages() {
languages = flattened(languages, arguments);
// no languages, return all requested languages
if (!languages || languages.length === 0) {
return this.#negotiator.languages();
}
return this.#negotiator.languages(languages)[0] || false;
}
range(size, options) {
let range = this.get('Range');
if (!range) return;
return parse_range(size, range, options);
}
param(name, default_value) {
// Parse three dataset candidates
let body = this.body;
let path_parameters = this.path_parameters;
let query_parameters = this.query_parameters;
// First check path parameters, body, and finally query_parameters
if (null != path_parameters[name] && path_parameters.hasOwnProperty(name)) return path_parameters[name];
if (null != body[name]) return body[name];
if (null != query_parameters[name]) return query_parameters[name];
return default_value;
}
is(types) {
// support flattened arguments
let arr = types;
if (!Array.isArray(types)) {
arr = new Array(arguments.length);
for (let i = 0; i < arr.length; i++) arr[i] = arguments[i];
}
return type_is(this, arr);
}
/* Properties */
get baseUrl() {
return this.path;
}
get originalUrl() {
return this.url;
}
set originalUrl(url) {
this.url = url;
}
get fresh() {
this._throw_unsupported('fresh');
}
get params() {
return this.path_parameters;
}
get hostname() {
// Retrieve the host header and determine if we can trust intermediary proxy servers
let host = this.get('X-Forwarded-Host');
const trust_proxy = this.route.app._options.trust_proxy;
if (!host || !trust_proxy) {
// Use the 'Host' header as fallback
host = this.get('Host');
} else {
// Note: X-Forwarded-Host is normally only ever a single value, but this is to be safe.
host = host.split(',')[0];
}
// If we don't have a host, return undefined
if (!host) return;
// IPv6 literal support
let offset = host[0] === '[' ? host.indexOf(']') + 1 : 0;
let index = host.indexOf(':', offset);
return index !== -1 ? host.substring(0, index) : host;
}
get ips() {
// Retrieve the client and proxy IP addresses
const client_ip = this.ip;
const proxy_ip = this.proxy_ip;
// Determine if we can trust intermediary proxy servers and have a x-forwarded-for header
const trust_proxy = this.route.app._options.trust_proxy;
const x_forwarded_for = this.get('X-Forwarded-For');
if (trust_proxy && x_forwarded_for) {
// Will split and return all possible IP addresses in the x-forwarded-for header (e.g. "client, proxy1, proxy2")
return x_forwarded_for.split(',');
} else {
// Returns all valid IP addresses available from uWS
return [client_ip, proxy_ip].filter((ip) => ip);
}
}
get protocol() {
// Resolves x-forwarded-proto header if trust proxy is enabled
const trust_proxy = this.route.app._options.trust_proxy;
const x_forwarded_proto = this.get('X-Forwarded-Proto');
if (trust_proxy && x_forwarded_proto) {
// Return the first protocol in the x-forwarded-proto header
// If the header contains a single value, the split will contain that value in the first index element anyways
return x_forwarded_proto.split(',')[0];
} else {
// Use HyperExpress/uWS initially defined protocol as fallback
return this.route.app.is_ssl ? 'https' : 'http';
}
}
get query() {
return this.query_parameters;
}
get secure() {
return this.protocol === 'https';
}
get signedCookies() {
this._throw_unsupported('signedCookies');
}
get stale() {
this._throw_unsupported('stale');
}
get subdomains() {
let hostname = this.hostname;
if (!hostname) return [];
let offset = 2;
let subdomains = !is_ip(hostname) ? hostname.split('.').reverse() : [hostname];
return subdomains.slice(offset);
}
get xhr() {
return (this.get('X-Requested-With') || '').toLowerCase() === 'xmlhttprequest';
}
}
const flattened = function (arr, args) {
if (arr && !Array.isArray(arr)) {
arr = new Array(args.length);
for (var i = 0; i < arr.length; i++) {
arr[i] = args[i];
}
}
return arr;
};
module.exports = ExpressRequest;