@adonisjs/http-server 6.8.2-3 → 6.8.2-5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/build/factories/http_context.d.ts +1 -0
- package/build/factories/http_context.d.ts.map +1 -0
- package/build/factories/main.d.ts +1 -0
- package/build/factories/main.d.ts.map +1 -0
- package/build/factories/qs_parser_factory.d.ts +1 -0
- package/build/factories/qs_parser_factory.d.ts.map +1 -0
- package/build/factories/request.d.ts +1 -0
- package/build/factories/request.d.ts.map +1 -0
- package/build/factories/response.d.ts +1 -0
- package/build/factories/response.d.ts.map +1 -0
- package/build/factories/router.d.ts +1 -0
- package/build/factories/router.d.ts.map +1 -0
- package/build/factories/server_factory.d.ts +1 -0
- package/build/factories/server_factory.d.ts.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -0
- package/build/src/cookies/client.d.ts +1 -0
- package/build/src/cookies/client.d.ts.map +1 -0
- package/build/src/cookies/drivers/encrypted.d.ts +1 -0
- package/build/src/cookies/drivers/encrypted.d.ts.map +1 -0
- package/build/src/cookies/drivers/plain.d.ts +1 -0
- package/build/src/cookies/drivers/plain.d.ts.map +1 -0
- package/build/src/cookies/drivers/signed.d.ts +1 -0
- package/build/src/cookies/drivers/signed.d.ts.map +1 -0
- package/build/src/cookies/parser.d.ts +1 -0
- package/build/src/cookies/parser.d.ts.map +1 -0
- package/build/src/cookies/serializer.d.ts +1 -0
- package/build/src/cookies/serializer.d.ts.map +1 -0
- package/build/src/debug.d.ts +1 -0
- package/build/src/debug.d.ts.map +1 -0
- package/build/src/define_config.d.ts +1 -0
- package/build/src/define_config.d.ts.map +1 -0
- package/build/src/define_middleware.d.ts +1 -0
- package/build/src/define_middleware.d.ts.map +1 -0
- package/build/src/exception_handler.d.ts +1 -0
- package/build/src/exception_handler.d.ts.map +1 -0
- package/build/src/exceptions.d.ts +1 -0
- package/build/src/exceptions.d.ts.map +1 -0
- package/build/src/helpers.d.ts +1 -0
- package/build/src/helpers.d.ts.map +1 -0
- package/build/src/http_context/local_storage.d.ts +1 -0
- package/build/src/http_context/local_storage.d.ts.map +1 -0
- package/build/src/http_context/main.d.ts +1 -0
- package/build/src/http_context/main.d.ts.map +1 -0
- package/build/src/qs.d.ts +1 -0
- package/build/src/qs.d.ts.map +1 -0
- package/build/src/redirect.d.ts +1 -0
- package/build/src/redirect.d.ts.map +1 -0
- package/build/src/request.d.ts +1 -0
- package/build/src/request.d.ts.map +1 -0
- package/build/src/response.d.ts +1 -0
- package/build/src/response.d.ts.map +1 -0
- package/build/src/router/brisk.d.ts +1 -0
- package/build/src/router/brisk.d.ts.map +1 -0
- package/build/src/router/executor.d.ts +1 -0
- package/build/src/router/executor.d.ts.map +1 -0
- package/build/src/router/factories/use_return_value.d.ts +1 -0
- package/build/src/router/factories/use_return_value.d.ts.map +1 -0
- package/build/src/router/group.d.ts +1 -0
- package/build/src/router/group.d.ts.map +1 -0
- package/build/src/router/lookup_store/main.d.ts +1 -0
- package/build/src/router/lookup_store/main.d.ts.map +1 -0
- package/build/src/router/lookup_store/route_finder.d.ts +1 -0
- package/build/src/router/lookup_store/route_finder.d.ts.map +1 -0
- package/build/src/router/lookup_store/url_builder.d.ts +1 -0
- package/build/src/router/lookup_store/url_builder.d.ts.map +1 -0
- package/build/src/router/lookup_store/url_builder.js +2 -2
- package/build/src/router/main.d.ts +4 -2
- package/build/src/router/main.d.ts.map +1 -0
- package/build/src/router/main.js +4 -0
- package/build/src/router/matchers.d.ts +1 -0
- package/build/src/router/matchers.d.ts.map +1 -0
- package/build/src/router/parser.d.ts +3 -0
- package/build/src/router/parser.d.ts.map +1 -0
- package/build/src/router/parser.js +5 -0
- package/build/src/router/resource.d.ts +1 -0
- package/build/src/router/resource.d.ts.map +1 -0
- package/build/src/router/route.d.ts +1 -0
- package/build/src/router/route.d.ts.map +1 -0
- package/build/src/router/store.d.ts +1 -0
- package/build/src/router/store.d.ts.map +1 -0
- package/build/src/router/store.js +3 -2
- package/build/src/server/factories/final_handler.d.ts +1 -0
- package/build/src/server/factories/final_handler.d.ts.map +1 -0
- package/build/src/server/factories/middleware_handler.d.ts +1 -0
- package/build/src/server/factories/middleware_handler.d.ts.map +1 -0
- package/build/src/server/factories/write_response.d.ts +1 -0
- package/build/src/server/factories/write_response.d.ts.map +1 -0
- package/build/src/server/main.d.ts +1 -0
- package/build/src/server/main.d.ts.map +1 -0
- package/build/src/types/base.d.ts +1 -0
- package/build/src/types/base.d.ts.map +1 -0
- package/build/src/types/main.d.ts +1 -0
- package/build/src/types/main.d.ts.map +1 -0
- package/build/src/types/middleware.d.ts +1 -0
- package/build/src/types/middleware.d.ts.map +1 -0
- package/build/src/types/qs.d.ts +1 -0
- package/build/src/types/qs.d.ts.map +1 -0
- package/build/src/types/request.d.ts +1 -0
- package/build/src/types/request.d.ts.map +1 -0
- package/build/src/types/response.d.ts +1 -0
- package/build/src/types/response.d.ts.map +1 -0
- package/build/src/types/route.d.ts +1 -0
- package/build/src/types/route.d.ts.map +1 -0
- package/build/src/types/server.d.ts +1 -0
- package/build/src/types/server.d.ts.map +1 -0
- package/factories/http_context.ts +73 -0
- package/factories/main.ts +15 -0
- package/factories/qs_parser_factory.ts +54 -0
- package/factories/request.ts +101 -0
- package/factories/response.ts +106 -0
- package/factories/router.ts +61 -0
- package/factories/server_factory.ts +94 -0
- package/index.ts +23 -0
- package/package.json +27 -23
- package/src/cookies/client.ts +98 -0
- package/src/cookies/drivers/encrypted.ts +42 -0
- package/src/cookies/drivers/plain.ts +37 -0
- package/src/cookies/drivers/signed.ts +42 -0
- package/src/cookies/parser.ts +196 -0
- package/src/cookies/serializer.ts +98 -0
- package/src/debug.ts +11 -0
- package/src/define_config.ts +56 -0
- package/src/define_middleware.ts +61 -0
- package/src/exception_handler.ts +290 -0
- package/src/exceptions.ts +55 -0
- package/src/helpers.ts +108 -0
- package/src/http_context/local_storage.ts +50 -0
- package/src/http_context/main.ts +126 -0
- package/src/qs.ts +31 -0
- package/src/redirect.ts +181 -0
- package/src/request.ts +982 -0
- package/src/response.ts +1421 -0
- package/src/router/brisk.ts +113 -0
- package/src/router/executor.ts +36 -0
- package/src/router/factories/use_return_value.ts +26 -0
- package/src/router/group.ts +243 -0
- package/src/router/lookup_store/main.ts +102 -0
- package/src/router/lookup_store/route_finder.ts +60 -0
- package/src/router/lookup_store/url_builder.ts +250 -0
- package/src/router/main.ts +431 -0
- package/src/router/matchers.ts +40 -0
- package/src/router/parser.ts +20 -0
- package/src/router/resource.ts +277 -0
- package/src/router/route.ts +363 -0
- package/src/router/store.ts +239 -0
- package/src/server/factories/final_handler.ts +38 -0
- package/src/server/factories/middleware_handler.ts +23 -0
- package/src/server/factories/write_response.ts +26 -0
- package/src/server/main.ts +356 -0
- package/src/types/base.ts +30 -0
- package/src/types/main.ts +16 -0
- package/src/types/middleware.ts +59 -0
- package/src/types/qs.ts +85 -0
- package/src/types/request.ts +52 -0
- package/src/types/response.ts +57 -0
- package/src/types/route.ts +217 -0
- package/src/types/server.ts +92 -0
package/src/request.ts
ADDED
|
@@ -0,0 +1,982 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/http-server
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fresh from 'fresh'
|
|
11
|
+
import typeIs from 'type-is'
|
|
12
|
+
import accepts from 'accepts'
|
|
13
|
+
import { isIP } from 'node:net'
|
|
14
|
+
import is from '@sindresorhus/is'
|
|
15
|
+
import proxyaddr from 'proxy-addr'
|
|
16
|
+
import { safeEqual } from '@poppinss/utils'
|
|
17
|
+
import Macroable from '@poppinss/macroable'
|
|
18
|
+
import lodash from '@poppinss/utils/lodash'
|
|
19
|
+
import { createId } from '@paralleldrive/cuid2'
|
|
20
|
+
import { parse, UrlWithStringQuery } from 'node:url'
|
|
21
|
+
import type { Encryption } from '@adonisjs/encryption'
|
|
22
|
+
import { ServerResponse, IncomingMessage, IncomingHttpHeaders } from 'node:http'
|
|
23
|
+
|
|
24
|
+
import type { Qs } from './qs.js'
|
|
25
|
+
import { trustProxy } from './helpers.js'
|
|
26
|
+
import { CookieParser } from './cookies/parser.js'
|
|
27
|
+
import { RequestConfig } from './types/request.js'
|
|
28
|
+
import type { HttpContext } from './http_context/main.js'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* HTTP Request class exposes the interface to consistently read values
|
|
32
|
+
* related to a given HTTP request. The class is wrapper over
|
|
33
|
+
* [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
|
|
34
|
+
* and has extended API.
|
|
35
|
+
*
|
|
36
|
+
* You can access the original [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
|
|
37
|
+
* using `request.request` property.
|
|
38
|
+
*/
|
|
39
|
+
export class Request extends Macroable {
|
|
40
|
+
/**
|
|
41
|
+
* Query string parser
|
|
42
|
+
*/
|
|
43
|
+
#qsParser: Qs
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Encryption module to verify signed URLs and unsign/decrypt
|
|
47
|
+
* cookies
|
|
48
|
+
*/
|
|
49
|
+
#encryption: Encryption
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Request config
|
|
53
|
+
*/
|
|
54
|
+
#config: RequestConfig
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Request body set using `setBody` method
|
|
58
|
+
*/
|
|
59
|
+
#requestBody: Record<string, any> = {}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A merged copy of `request body` and `querystring`
|
|
63
|
+
*/
|
|
64
|
+
#requestData: Record<string, any> = {}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Original merged copy of `request body` and `querystring`.
|
|
68
|
+
* Further mutation to this object are not allowed
|
|
69
|
+
*/
|
|
70
|
+
#originalRequestData: Record<string, any> = {}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parsed query string
|
|
74
|
+
*/
|
|
75
|
+
#requestQs: Record<string, any> = {}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Raw request body as text
|
|
79
|
+
*/
|
|
80
|
+
#rawRequestBody?: string
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Cached copy of `accepts` fn to do content
|
|
84
|
+
* negotiation.
|
|
85
|
+
*/
|
|
86
|
+
#lazyAccepts?: any
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Copy of lazily parsed signed and plain cookies.
|
|
90
|
+
*/
|
|
91
|
+
#cookieParser?: CookieParser
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parses copy of the URL with query string as a string and not
|
|
95
|
+
* object. This is done to build URL's with query string without
|
|
96
|
+
* stringifying the object
|
|
97
|
+
*/
|
|
98
|
+
parsedUrl: UrlWithStringQuery
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The ctx will be set by the context itself. It creates a circular
|
|
102
|
+
* reference
|
|
103
|
+
*/
|
|
104
|
+
ctx?: HttpContext
|
|
105
|
+
|
|
106
|
+
constructor(
|
|
107
|
+
public request: IncomingMessage,
|
|
108
|
+
public response: ServerResponse,
|
|
109
|
+
encryption: Encryption,
|
|
110
|
+
config: RequestConfig,
|
|
111
|
+
qsParser: Qs
|
|
112
|
+
) {
|
|
113
|
+
super()
|
|
114
|
+
|
|
115
|
+
this.#qsParser = qsParser
|
|
116
|
+
this.#config = config
|
|
117
|
+
this.#encryption = encryption
|
|
118
|
+
this.parsedUrl = parse(this.request.url!, false)
|
|
119
|
+
this.#parseQueryString()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Parses the query string
|
|
124
|
+
*/
|
|
125
|
+
#parseQueryString() {
|
|
126
|
+
if (this.parsedUrl.query) {
|
|
127
|
+
this.updateQs(this.#qsParser.parse(this.parsedUrl.query))
|
|
128
|
+
this.#originalRequestData = { ...this.#requestData }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initiates the cookie parser lazily
|
|
134
|
+
*/
|
|
135
|
+
#initiateCookieParser() {
|
|
136
|
+
if (!this.#cookieParser) {
|
|
137
|
+
this.#cookieParser = new CookieParser(this.header('cookie')!, this.#encryption)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Lazily initiates the `accepts` module to make sure to parse
|
|
143
|
+
* the request headers only when one of the content-negotiation
|
|
144
|
+
* methods are used.
|
|
145
|
+
*/
|
|
146
|
+
#initiateAccepts() {
|
|
147
|
+
this.#lazyAccepts = this.#lazyAccepts || accepts(this.request)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Returns the request id from the `x-request-id` header. The
|
|
152
|
+
* header is untouched, if it already exists.
|
|
153
|
+
*/
|
|
154
|
+
id(): string | undefined {
|
|
155
|
+
let requestId = this.header('x-request-id')
|
|
156
|
+
if (!requestId && this.#config.generateRequestId) {
|
|
157
|
+
requestId = createId()
|
|
158
|
+
this.request.headers['x-request-id'] = requestId
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return requestId
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Set initial request body. A copy of the input will be maintained as the original
|
|
166
|
+
* request body. Since the request body and query string is subject to mutations, we
|
|
167
|
+
* keep one original reference to flash old data (whenever required).
|
|
168
|
+
*
|
|
169
|
+
* This method is supposed to be invoked by the body parser and must be called only
|
|
170
|
+
* once. For further mutations make use of `updateBody` method.
|
|
171
|
+
*/
|
|
172
|
+
setInitialBody(body: Record<string, any>) {
|
|
173
|
+
if (this.#originalRequestData && Object.isFrozen(this.#originalRequestData)) {
|
|
174
|
+
throw new Error('Cannot re-set initial body. Use "request.updateBody" instead')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.updateBody(body)
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Freeze the original object
|
|
181
|
+
*/
|
|
182
|
+
this.#originalRequestData = Object.freeze(lodash.cloneDeep(this.#requestData))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Update the request body with new data object. The `all` property
|
|
187
|
+
* will be re-computed by merging the query string and request
|
|
188
|
+
* body.
|
|
189
|
+
*/
|
|
190
|
+
updateBody(body: Record<string, any>) {
|
|
191
|
+
this.#requestBody = body
|
|
192
|
+
this.#requestData = { ...this.#requestBody, ...this.#requestQs }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Update the request raw body. Bodyparser sets this when unable to parse
|
|
197
|
+
* the request body or when request is multipart/form-data.
|
|
198
|
+
*/
|
|
199
|
+
updateRawBody(rawBody: string) {
|
|
200
|
+
this.#rawRequestBody = rawBody
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Update the query string with the new data object. The `all` property
|
|
205
|
+
* will be re-computed by merging the query and the request body.
|
|
206
|
+
*/
|
|
207
|
+
updateQs(data: Record<string, any>) {
|
|
208
|
+
this.#requestQs = data
|
|
209
|
+
this.#requestData = { ...this.#requestBody, ...this.#requestQs }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Returns route params
|
|
214
|
+
*/
|
|
215
|
+
params(): Record<string, any> {
|
|
216
|
+
return this.ctx?.params || {}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Returns the query string object by reference
|
|
221
|
+
*/
|
|
222
|
+
qs(): Record<string, any> {
|
|
223
|
+
return this.#requestQs
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Returns reference to the request body
|
|
228
|
+
*/
|
|
229
|
+
body(): Record<string, any> {
|
|
230
|
+
return this.#requestBody
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Returns reference to the merged copy of request body
|
|
235
|
+
* and query string
|
|
236
|
+
*/
|
|
237
|
+
all(): Record<string, any> {
|
|
238
|
+
return this.#requestData
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Returns reference to the merged copy of original request
|
|
243
|
+
* query string and body
|
|
244
|
+
*/
|
|
245
|
+
original(): Record<string, any> {
|
|
246
|
+
return this.#originalRequestData
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Returns the request raw body (if exists), or returns `null`.
|
|
251
|
+
*
|
|
252
|
+
* Ideally you must be dealing with the parsed body accessed using [[input]], [[all]] or
|
|
253
|
+
* [[post]] methods. The `raw` body is always a string.
|
|
254
|
+
*/
|
|
255
|
+
raw(): string | null {
|
|
256
|
+
return this.#rawRequestBody || null
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Returns value for a given key from the request body or query string.
|
|
261
|
+
* The `defaultValue` is used when original value is `undefined`.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```js
|
|
265
|
+
* request.input('username')
|
|
266
|
+
*
|
|
267
|
+
* // with default value
|
|
268
|
+
* request.input('username', 'virk')
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
input(key: string, defaultValue?: any): any {
|
|
272
|
+
return lodash.get(this.#requestData, key, defaultValue)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Returns value for a given key from route params
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```js
|
|
280
|
+
* request.param('id')
|
|
281
|
+
*
|
|
282
|
+
* // with default value
|
|
283
|
+
* request.param('id', 1)
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
param(key: string, defaultValue?: any): any {
|
|
287
|
+
return lodash.get(this.params(), key, defaultValue)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Get everything from the request body except the given keys.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```js
|
|
295
|
+
* request.except(['_csrf'])
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
except(keys: string[]): Record<string, any> {
|
|
299
|
+
return lodash.omit(this.#requestData, keys)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get value for specified keys.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```js
|
|
307
|
+
* request.only(['username', 'age'])
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
only<T extends string>(keys: T[]): { [K in T]: any } {
|
|
311
|
+
return lodash.pick(this.#requestData, keys) as { [K in T]: any }
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Returns the HTTP request method. This is the original
|
|
316
|
+
* request method. For spoofed request method, make
|
|
317
|
+
* use of [[method]].
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```js
|
|
321
|
+
* request.intended()
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
intended(): string {
|
|
325
|
+
return this.request.method!
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Returns the request HTTP method by taking method spoofing into account.
|
|
330
|
+
*
|
|
331
|
+
* Method spoofing works when all of the following are true.
|
|
332
|
+
*
|
|
333
|
+
* 1. `app.http.allowMethodSpoofing` config value is true.
|
|
334
|
+
* 2. request query string has `_method`.
|
|
335
|
+
* 3. The [[intended]] request method is `POST`.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```js
|
|
339
|
+
* request.method()
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
method(): string {
|
|
343
|
+
if (this.#config.allowMethodSpoofing && this.intended() === 'POST') {
|
|
344
|
+
return this.input('_method', this.intended()).toUpperCase()
|
|
345
|
+
}
|
|
346
|
+
return this.intended()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Returns a copy of headers as an object
|
|
351
|
+
*/
|
|
352
|
+
headers(): IncomingHttpHeaders {
|
|
353
|
+
return this.request.headers
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Returns value for a given header key. The default value is
|
|
358
|
+
* used when original value is `undefined`.
|
|
359
|
+
*/
|
|
360
|
+
header(key: string, defaultValue?: any): string | undefined {
|
|
361
|
+
key = key.toLowerCase()
|
|
362
|
+
const headers = this.headers()
|
|
363
|
+
|
|
364
|
+
switch (key) {
|
|
365
|
+
case 'referer':
|
|
366
|
+
case 'referrer':
|
|
367
|
+
return headers.referrer || headers.referer || defaultValue
|
|
368
|
+
default:
|
|
369
|
+
return headers[key] || defaultValue
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Returns the ip address of the user. This method is optimize to fetch
|
|
375
|
+
* ip address even when running your AdonisJs app behind a proxy.
|
|
376
|
+
*
|
|
377
|
+
* You can also define your own custom function to compute the ip address by
|
|
378
|
+
* defining `app.http.getIp` as a function inside the config file.
|
|
379
|
+
*
|
|
380
|
+
* ```js
|
|
381
|
+
* {
|
|
382
|
+
* http: {
|
|
383
|
+
* getIp (request) {
|
|
384
|
+
* // I am using nginx as a proxy server and want to trust 'x-real-ip'
|
|
385
|
+
* return request.header('x-real-ip')
|
|
386
|
+
* }
|
|
387
|
+
* }
|
|
388
|
+
* }
|
|
389
|
+
* ```
|
|
390
|
+
*
|
|
391
|
+
* You can control the behavior of trusting the proxy values by defining it
|
|
392
|
+
* inside the `config/app.js` file.
|
|
393
|
+
*
|
|
394
|
+
* ```js
|
|
395
|
+
* {
|
|
396
|
+
* http: {
|
|
397
|
+
* trustProxy: '127.0.0.1'
|
|
398
|
+
* }
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
|
|
403
|
+
*/
|
|
404
|
+
ip(): string {
|
|
405
|
+
const ipFn = this.#config.getIp
|
|
406
|
+
if (typeof ipFn === 'function') {
|
|
407
|
+
return ipFn(this)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return proxyaddr(this.request, this.#config.trustProxy)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Returns an array of ip addresses from most to least trusted one.
|
|
415
|
+
* This method is optimize to fetch ip address even when running
|
|
416
|
+
* your AdonisJs app behind a proxy.
|
|
417
|
+
*
|
|
418
|
+
* You can control the behavior of trusting the proxy values by defining it
|
|
419
|
+
* inside the `config/app.js` file.
|
|
420
|
+
*
|
|
421
|
+
* ```js
|
|
422
|
+
* {
|
|
423
|
+
* http: {
|
|
424
|
+
* trustProxy: '127.0.0.1'
|
|
425
|
+
* }
|
|
426
|
+
* }
|
|
427
|
+
* ```
|
|
428
|
+
*
|
|
429
|
+
* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
|
|
430
|
+
*/
|
|
431
|
+
ips(): string[] {
|
|
432
|
+
return proxyaddr.all(this.request, this.#config.trustProxy)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Returns the request protocol by checking for the URL protocol or
|
|
437
|
+
* `X-Forwarded-Proto` header.
|
|
438
|
+
*
|
|
439
|
+
* If the `trust` is evaluated to `false`, then URL protocol is returned,
|
|
440
|
+
* otherwise `X-Forwarded-Proto` header is used (if exists).
|
|
441
|
+
*
|
|
442
|
+
* You can control the behavior of trusting the proxy values by defining it
|
|
443
|
+
* inside the `config/app.js` file.
|
|
444
|
+
*
|
|
445
|
+
* ```js
|
|
446
|
+
* {
|
|
447
|
+
* http: {
|
|
448
|
+
* trustProxy: '127.0.0.1'
|
|
449
|
+
* }
|
|
450
|
+
* }
|
|
451
|
+
* ```
|
|
452
|
+
*
|
|
453
|
+
* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
|
|
454
|
+
*/
|
|
455
|
+
protocol(): string {
|
|
456
|
+
if ('encrypted' in this.request.socket) {
|
|
457
|
+
return 'https'
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!trustProxy(this.request.socket.remoteAddress!, this.#config.trustProxy)) {
|
|
461
|
+
return this.parsedUrl.protocol || 'http'
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const forwardedProtocol = this.header('X-Forwarded-Proto')
|
|
465
|
+
return forwardedProtocol ? forwardedProtocol.split(/\s*,\s*/)[0] : 'http'
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Returns a boolean telling if request is served over `https`
|
|
470
|
+
* or not. Check [[protocol]] method to know how protocol is
|
|
471
|
+
* fetched.
|
|
472
|
+
*/
|
|
473
|
+
secure(): boolean {
|
|
474
|
+
return this.protocol() === 'https'
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Returns the request host. If proxy headers are trusted, then
|
|
479
|
+
* `X-Forwarded-Host` is given priority over the `Host` header.
|
|
480
|
+
*
|
|
481
|
+
* You can control the behavior of trusting the proxy values by defining it
|
|
482
|
+
* inside the `config/app.js` file.
|
|
483
|
+
*
|
|
484
|
+
* ```js
|
|
485
|
+
* {
|
|
486
|
+
* http: {
|
|
487
|
+
* trustProxy: '127.0.0.1'
|
|
488
|
+
* }
|
|
489
|
+
* }
|
|
490
|
+
* ```
|
|
491
|
+
*
|
|
492
|
+
* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
|
|
493
|
+
*/
|
|
494
|
+
host(): string | null {
|
|
495
|
+
let host = this.header('host')
|
|
496
|
+
|
|
497
|
+
/*
|
|
498
|
+
* Use X-Fowarded-Host when we trust the proxy header and it
|
|
499
|
+
* exists
|
|
500
|
+
*/
|
|
501
|
+
if (trustProxy(this.request.socket.remoteAddress!, this.#config.trustProxy)) {
|
|
502
|
+
host = this.header('X-Forwarded-Host') || host
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!host) {
|
|
506
|
+
return null
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return host
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Returns the request hostname. If proxy headers are trusted, then
|
|
514
|
+
* `X-Forwarded-Host` is given priority over the `Host` header.
|
|
515
|
+
*
|
|
516
|
+
* You can control the behavior of trusting the proxy values by defining it
|
|
517
|
+
* inside the `config/app.js` file.
|
|
518
|
+
*
|
|
519
|
+
* ```js
|
|
520
|
+
* {
|
|
521
|
+
* http: {
|
|
522
|
+
* trustProxy: '127.0.0.1'
|
|
523
|
+
* }
|
|
524
|
+
* }
|
|
525
|
+
* ```
|
|
526
|
+
*
|
|
527
|
+
* The value of trustProxy is passed directly to [proxy-addr](https://www.npmjs.com/package/proxy-addr)
|
|
528
|
+
*/
|
|
529
|
+
hostname(): string | null {
|
|
530
|
+
const host = this.host()
|
|
531
|
+
|
|
532
|
+
if (!host) {
|
|
533
|
+
return null
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/*
|
|
537
|
+
* Support for IPv6
|
|
538
|
+
* https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2
|
|
539
|
+
* https://github.com/nodejs/node/pull/5314
|
|
540
|
+
*/
|
|
541
|
+
const offset = host[0] === '[' ? host.indexOf(']') + 1 : 0
|
|
542
|
+
const index = host.indexOf(':', offset)
|
|
543
|
+
return index !== -1 ? host.substring(0, index) : host
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Returns an array of subdomains for the given host. An empty array is
|
|
548
|
+
* returned if [[hostname]] is `null` or is an IP address.
|
|
549
|
+
*
|
|
550
|
+
* Also `www` is not considered as a subdomain
|
|
551
|
+
*/
|
|
552
|
+
subdomains(): string[] {
|
|
553
|
+
const hostname = this.hostname()
|
|
554
|
+
|
|
555
|
+
/*
|
|
556
|
+
* Return empty array when hostname is missing or it's
|
|
557
|
+
* an IP address
|
|
558
|
+
*/
|
|
559
|
+
if (!hostname || isIP(hostname)) {
|
|
560
|
+
return []
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const offset = this.#config.subdomainOffset
|
|
564
|
+
const subdomains = hostname.split('.').reverse().slice(offset)
|
|
565
|
+
|
|
566
|
+
/*
|
|
567
|
+
* Remove www from the subdomains list
|
|
568
|
+
*/
|
|
569
|
+
if (subdomains[subdomains.length - 1] === 'www') {
|
|
570
|
+
subdomains.splice(subdomains.length - 1, 1)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return subdomains
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Returns a boolean telling, if request `X-Requested-With === 'xmlhttprequest'`
|
|
578
|
+
* or not.
|
|
579
|
+
*/
|
|
580
|
+
ajax(): boolean {
|
|
581
|
+
const xRequestedWith = this.header('X-Requested-With', '')
|
|
582
|
+
return xRequestedWith!.toLowerCase() === 'xmlhttprequest'
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Returns a boolean telling, if request has `X-Pjax` header
|
|
587
|
+
* set or not
|
|
588
|
+
*/
|
|
589
|
+
pjax(): boolean {
|
|
590
|
+
return !!this.header('X-Pjax')
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Returns the request relative URL.
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```js
|
|
598
|
+
* request.url()
|
|
599
|
+
*
|
|
600
|
+
* // include query string
|
|
601
|
+
* request.url(true)
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
url(includeQueryString?: boolean): string {
|
|
605
|
+
const pathname = this.parsedUrl.pathname!
|
|
606
|
+
return includeQueryString && this.parsedUrl.query
|
|
607
|
+
? `${pathname}?${this.parsedUrl.query}`
|
|
608
|
+
: pathname
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Returns the complete HTTP url by combining
|
|
613
|
+
* [[protocol]]://[[hostname]]/[[url]]
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```js
|
|
617
|
+
* request.completeUrl()
|
|
618
|
+
*
|
|
619
|
+
* // include query string
|
|
620
|
+
* request.completeUrl(true)
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
623
|
+
completeUrl(includeQueryString?: boolean): string {
|
|
624
|
+
const protocol = this.protocol()
|
|
625
|
+
const hostname = this.host()
|
|
626
|
+
return `${protocol}://${hostname}${this.url(includeQueryString)}`
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Find if the current HTTP request is for the given route or the routes
|
|
631
|
+
*/
|
|
632
|
+
matchesRoute(routeIdentifier: string | string[]): boolean {
|
|
633
|
+
/**
|
|
634
|
+
* The context is missing inside the HTTP server hooks.
|
|
635
|
+
*/
|
|
636
|
+
if (!this.ctx || !this.ctx.route) {
|
|
637
|
+
return false
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const route = this.ctx.route
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Search the identifier(s) against the route "pattern", "name" and the route handler
|
|
644
|
+
*/
|
|
645
|
+
return !!(Array.isArray(routeIdentifier) ? routeIdentifier : [routeIdentifier]).find(
|
|
646
|
+
(identifier) => {
|
|
647
|
+
if (route.pattern === identifier || route.name === identifier) {
|
|
648
|
+
return true
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (typeof route.handler === 'function') {
|
|
652
|
+
return false
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return route.handler.reference === identifier
|
|
656
|
+
}
|
|
657
|
+
)
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Returns the best matching content type of the request by
|
|
662
|
+
* matching against the given types.
|
|
663
|
+
*
|
|
664
|
+
* The content type is picked from the `content-type` header and request
|
|
665
|
+
* must have body.
|
|
666
|
+
*
|
|
667
|
+
* The method response highly depends upon the types array values. Described below:
|
|
668
|
+
*
|
|
669
|
+
* | Type(s) | Return value |
|
|
670
|
+
* |----------|---------------|
|
|
671
|
+
* | ['json'] | json |
|
|
672
|
+
* | ['application/*'] | application/json |
|
|
673
|
+
* | ['vnd+json'] | application/json |
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* ```js
|
|
677
|
+
* const bodyType = request.is(['json', 'xml'])
|
|
678
|
+
*
|
|
679
|
+
* if (bodyType === 'json') {
|
|
680
|
+
* // process JSON
|
|
681
|
+
* }
|
|
682
|
+
*
|
|
683
|
+
* if (bodyType === 'xml') {
|
|
684
|
+
* // process XML
|
|
685
|
+
* }
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
is(types: string[]): string | null {
|
|
689
|
+
return typeIs(this.request, types) || null
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Returns the best type using `Accept` header and
|
|
694
|
+
* by matching it against the given types.
|
|
695
|
+
*
|
|
696
|
+
* If nothing is matched, then `null` will be returned
|
|
697
|
+
*
|
|
698
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
699
|
+
* docs too.
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* ```js
|
|
703
|
+
* switch (request.accepts(['json', 'html'])) {
|
|
704
|
+
* case 'json':
|
|
705
|
+
* return response.json(user)
|
|
706
|
+
* case 'html':
|
|
707
|
+
* return view.render('user', { user })
|
|
708
|
+
* default:
|
|
709
|
+
* // decide yourself
|
|
710
|
+
* }
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
accepts<T extends string>(types: T[]): T | null {
|
|
714
|
+
this.#initiateAccepts()
|
|
715
|
+
return this.#lazyAccepts.type(types) || null
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Return the types that the request accepts, in the order of the
|
|
720
|
+
* client's preference (most preferred first).
|
|
721
|
+
*
|
|
722
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
723
|
+
* docs too.
|
|
724
|
+
*/
|
|
725
|
+
types(): string[] {
|
|
726
|
+
this.#initiateAccepts()
|
|
727
|
+
return this.#lazyAccepts.types()
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Returns the best language using `Accept-language` header
|
|
732
|
+
* and by matching it against the given languages.
|
|
733
|
+
*
|
|
734
|
+
* If nothing is matched, then `null` will be returned
|
|
735
|
+
*
|
|
736
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
737
|
+
* docs too.
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```js
|
|
741
|
+
* switch (request.language(['fr', 'de'])) {
|
|
742
|
+
* case 'fr':
|
|
743
|
+
* return view.render('about', { lang: 'fr' })
|
|
744
|
+
* case 'de':
|
|
745
|
+
* return view.render('about', { lang: 'de' })
|
|
746
|
+
* default:
|
|
747
|
+
* return view.render('about', { lang: 'en' })
|
|
748
|
+
* }
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
language<T extends string>(languages: T[]): T | null {
|
|
752
|
+
this.#initiateAccepts()
|
|
753
|
+
return this.#lazyAccepts.language(languages) || null
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Return the languages that the request accepts, in the order of the
|
|
758
|
+
* client's preference (most preferred first).
|
|
759
|
+
*
|
|
760
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
761
|
+
* docs too.
|
|
762
|
+
*/
|
|
763
|
+
languages(): string[] {
|
|
764
|
+
this.#initiateAccepts()
|
|
765
|
+
return this.#lazyAccepts.languages()
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Returns the best charset using `Accept-charset` header
|
|
770
|
+
* and by matching it against the given charsets.
|
|
771
|
+
*
|
|
772
|
+
* If nothing is matched, then `null` will be returned
|
|
773
|
+
*
|
|
774
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
775
|
+
* docs too.
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```js
|
|
779
|
+
* switch (request.charset(['utf-8', 'ISO-8859-1'])) {
|
|
780
|
+
* case 'utf-8':
|
|
781
|
+
* // make utf-8 friendly response
|
|
782
|
+
* case 'ISO-8859-1':
|
|
783
|
+
* // make ISO-8859-1 friendly response
|
|
784
|
+
* }
|
|
785
|
+
* ```
|
|
786
|
+
*/
|
|
787
|
+
charset<T extends string>(charsets: T[]): T | null {
|
|
788
|
+
this.#initiateAccepts()
|
|
789
|
+
return this.#lazyAccepts.charset(charsets) || null
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Return the charsets that the request accepts, in the order of the
|
|
794
|
+
* client's preference (most preferred first).
|
|
795
|
+
*
|
|
796
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
797
|
+
* docs too.
|
|
798
|
+
*/
|
|
799
|
+
charsets(): string[] {
|
|
800
|
+
this.#initiateAccepts()
|
|
801
|
+
return this.#lazyAccepts.charsets()
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Returns the best encoding using `Accept-encoding` header
|
|
806
|
+
* and by matching it against the given encodings.
|
|
807
|
+
*
|
|
808
|
+
* If nothing is matched, then `null` will be returned
|
|
809
|
+
*
|
|
810
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
811
|
+
* docs too.
|
|
812
|
+
*/
|
|
813
|
+
encoding<T extends string>(encodings: T[]): T | null {
|
|
814
|
+
this.#initiateAccepts()
|
|
815
|
+
return this.#lazyAccepts.encoding(encodings) || null
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Return the charsets that the request accepts, in the order of the
|
|
820
|
+
* client's preference (most preferred first).
|
|
821
|
+
*
|
|
822
|
+
* Make sure to check [accepts](https://www.npmjs.com/package/accepts) package
|
|
823
|
+
* docs too.
|
|
824
|
+
*/
|
|
825
|
+
encodings(): string[] {
|
|
826
|
+
this.#initiateAccepts()
|
|
827
|
+
return this.#lazyAccepts.encodings()
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Returns a boolean telling if request has body
|
|
832
|
+
*/
|
|
833
|
+
hasBody(): boolean {
|
|
834
|
+
return typeIs.hasBody(this.request)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Returns a boolean telling if the new response etag evaluates same
|
|
839
|
+
* as the request header `if-none-match`. In case of `true`, the
|
|
840
|
+
* server must return `304` response, telling the browser to
|
|
841
|
+
* use the client cache.
|
|
842
|
+
*
|
|
843
|
+
* You won't have to deal with this method directly, since AdonisJs will
|
|
844
|
+
* handle this for you when `http.etag = true` inside `config/app.js` file.
|
|
845
|
+
*
|
|
846
|
+
* However, this is how you can use it manually.
|
|
847
|
+
*
|
|
848
|
+
* ```js
|
|
849
|
+
* const responseBody = view.render('some-view')
|
|
850
|
+
*
|
|
851
|
+
* // sets the HTTP etag header for response
|
|
852
|
+
* response.setEtag(responseBody)
|
|
853
|
+
*
|
|
854
|
+
* if (request.fresh()) {
|
|
855
|
+
* response.sendStatus(304)
|
|
856
|
+
* } else {
|
|
857
|
+
* response.send(responseBody)
|
|
858
|
+
* }
|
|
859
|
+
* ```
|
|
860
|
+
*/
|
|
861
|
+
fresh(): boolean {
|
|
862
|
+
if (['GET', 'HEAD'].indexOf(this.intended()) === -1) {
|
|
863
|
+
return false
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const status = this.response.statusCode
|
|
867
|
+
if ((status >= 200 && status < 300) || status === 304) {
|
|
868
|
+
return fresh(this.headers(), this.response.getHeaders())
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return false
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Opposite of [[fresh]]
|
|
876
|
+
*/
|
|
877
|
+
stale(): boolean {
|
|
878
|
+
return !this.fresh()
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Returns all parsed and signed cookies. Signed cookies ensures
|
|
883
|
+
* that their value isn't tampered.
|
|
884
|
+
*/
|
|
885
|
+
cookiesList() {
|
|
886
|
+
this.#initiateCookieParser()
|
|
887
|
+
return this.#cookieParser!.list()
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Returns value for a given key from signed cookies. Optional
|
|
892
|
+
* defaultValue is returned when actual value is undefined.
|
|
893
|
+
*/
|
|
894
|
+
cookie(key: string, defaultValue?: string): any {
|
|
895
|
+
this.#initiateCookieParser()
|
|
896
|
+
return this.#cookieParser!.unsign(key) || defaultValue
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Returns value for a given key from signed cookies. Optional
|
|
901
|
+
* defaultValue is returned when actual value is undefined.
|
|
902
|
+
*/
|
|
903
|
+
encryptedCookie(key: string, defaultValue?: string): any {
|
|
904
|
+
this.#initiateCookieParser()
|
|
905
|
+
return this.#cookieParser!.decrypt(key) || defaultValue
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* Returns value for a given key from unsigned cookies. Optional
|
|
910
|
+
* defaultValue is returned when actual value is undefined.
|
|
911
|
+
*/
|
|
912
|
+
plainCookie(key: string, options?: { defaultValue?: string; encoded?: boolean }): any
|
|
913
|
+
plainCookie(key: string, defaultValue?: string, encoded?: boolean): any
|
|
914
|
+
plainCookie(
|
|
915
|
+
key: string,
|
|
916
|
+
defaultValueOrOptions?: string | { defaultValue?: string; encoded?: boolean },
|
|
917
|
+
encoded?: boolean
|
|
918
|
+
): any {
|
|
919
|
+
this.#initiateCookieParser()
|
|
920
|
+
|
|
921
|
+
if (is.object(defaultValueOrOptions)) {
|
|
922
|
+
return (
|
|
923
|
+
this.#cookieParser!.decode(key, defaultValueOrOptions?.encoded) ||
|
|
924
|
+
defaultValueOrOptions.defaultValue
|
|
925
|
+
)
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
return this.#cookieParser!.decode(key, encoded) || defaultValueOrOptions
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Returns a boolean telling if a signed url as a valid signature
|
|
933
|
+
* or not.
|
|
934
|
+
*/
|
|
935
|
+
hasValidSignature(purpose?: string) {
|
|
936
|
+
const { signature, ...rest } = this.qs()
|
|
937
|
+
if (!signature) {
|
|
938
|
+
return false
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/*
|
|
942
|
+
* Return false when signature fails
|
|
943
|
+
*/
|
|
944
|
+
const signedUrl = this.#encryption.verifier.unsign(signature, purpose)
|
|
945
|
+
if (!signedUrl) {
|
|
946
|
+
return false
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
const queryString = this.#qsParser.stringify(rest)
|
|
950
|
+
|
|
951
|
+
return queryString
|
|
952
|
+
? safeEqual(signedUrl, `${this.url()}?${queryString}`)
|
|
953
|
+
: safeEqual(signedUrl, this.url())
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Serializes request to JSON format
|
|
958
|
+
*/
|
|
959
|
+
serialize() {
|
|
960
|
+
return {
|
|
961
|
+
id: this.id(),
|
|
962
|
+
url: this.url(),
|
|
963
|
+
query: this.parsedUrl.query,
|
|
964
|
+
body: this.all(),
|
|
965
|
+
params: this.params(),
|
|
966
|
+
headers: this.headers(),
|
|
967
|
+
method: this.method(),
|
|
968
|
+
protocol: this.protocol(),
|
|
969
|
+
cookies: this.cookiesList(),
|
|
970
|
+
hostname: this.hostname(),
|
|
971
|
+
ip: this.ip(),
|
|
972
|
+
subdomains: this.ctx?.subdomains || {},
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* toJSON copy of the request
|
|
978
|
+
*/
|
|
979
|
+
toJSON() {
|
|
980
|
+
return this.serialize()
|
|
981
|
+
}
|
|
982
|
+
}
|