@adonisjs/http-server 6.8.2-1 → 6.8.2-10
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/README.md +3 -6
- package/build/factories/http_context.d.ts +10 -0
- package/build/factories/http_context.js +27 -0
- package/build/factories/http_server.d.ts +8 -0
- package/build/factories/http_server.js +26 -0
- package/build/factories/main.js +8 -0
- package/build/factories/qs_parser_factory.d.ts +10 -0
- package/build/factories/qs_parser_factory.js +18 -0
- package/build/factories/request.d.ts +10 -0
- package/build/factories/request.js +31 -0
- package/build/factories/response.d.ts +10 -0
- package/build/factories/response.js +34 -0
- package/build/factories/router.d.ts +10 -0
- package/build/factories/router.js +25 -0
- package/build/factories/server_factory.d.ts +10 -0
- package/build/factories/server_factory.js +34 -0
- package/build/index.js +8 -0
- package/build/src/cookies/client.d.ts +25 -0
- package/build/src/cookies/client.js +42 -0
- package/build/src/cookies/drivers/encrypted.d.ts +12 -0
- package/build/src/cookies/drivers/encrypted.js +20 -0
- package/build/src/cookies/drivers/plain.d.ts +12 -0
- package/build/src/cookies/drivers/plain.js +20 -0
- package/build/src/cookies/drivers/signed.d.ts +12 -0
- package/build/src/cookies/drivers/signed.js +20 -0
- package/build/src/cookies/parser.d.ts +28 -0
- package/build/src/cookies/parser.js +98 -0
- package/build/src/cookies/serializer.d.ts +22 -0
- package/build/src/cookies/serializer.js +40 -0
- package/build/src/debug.js +8 -0
- package/build/src/define_config.d.ts +3 -0
- package/build/src/define_config.js +11 -0
- package/build/src/define_middleware.d.ts +5 -0
- package/build/src/define_middleware.js +18 -0
- package/build/src/exception_handler.d.ts +93 -6
- package/build/src/exception_handler.js +203 -44
- package/build/src/exceptions.d.ts +6 -0
- package/build/src/exceptions.js +11 -0
- package/build/src/helpers.d.ts +14 -0
- package/build/src/helpers.js +43 -0
- package/build/src/http_context/local_storage.d.ts +3 -0
- package/build/src/http_context/local_storage.js +25 -0
- package/build/src/http_context/main.d.ts +36 -0
- package/build/src/http_context/main.js +54 -0
- package/build/src/qs.d.ts +4 -0
- package/build/src/qs.js +12 -0
- package/build/src/redirect.d.ts +24 -0
- package/build/src/redirect.js +60 -0
- package/build/src/request.d.ts +466 -0
- package/build/src/request.js +542 -0
- package/build/src/response.d.ts +425 -1
- package/build/src/response.js +611 -11
- package/build/src/router/brisk.d.ts +22 -0
- package/build/src/router/brisk.js +44 -2
- package/build/src/router/executor.d.ts +6 -1
- package/build/src/router/executor.js +14 -1
- package/build/src/router/factories/use_return_value.d.ts +4 -0
- package/build/src/router/factories/use_return_value.js +16 -3
- package/build/src/router/group.d.ts +47 -0
- package/build/src/router/group.js +88 -0
- package/build/src/router/lookup_store/main.d.ts +32 -0
- package/build/src/router/lookup_store/main.js +49 -0
- package/build/src/router/lookup_store/route_finder.d.ts +13 -0
- package/build/src/router/lookup_store/route_finder.js +21 -0
- package/build/src/router/lookup_store/url_builder.d.ts +36 -0
- package/build/src/router/lookup_store/url_builder.js +99 -2
- package/build/src/router/main.d.ts +92 -4
- package/build/src/router/main.js +146 -0
- package/build/src/router/matchers.d.ts +13 -0
- package/build/src/router/matchers.js +21 -0
- package/build/src/router/parser.d.ts +5 -0
- package/build/src/router/parser.js +17 -0
- package/build/src/router/resource.d.ts +30 -1
- package/build/src/router/resource.js +93 -1
- package/build/src/router/route.d.ts +65 -0
- package/build/src/router/route.js +151 -2
- package/build/src/router/store.d.ts +54 -0
- package/build/src/router/store.js +110 -2
- package/build/src/server/factories/final_handler.d.ts +7 -1
- package/build/src/server/factories/final_handler.js +15 -2
- package/build/src/server/factories/middleware_handler.d.ts +3 -0
- package/build/src/server/factories/middleware_handler.js +11 -0
- package/build/src/server/factories/write_response.d.ts +4 -0
- package/build/src/server/factories/write_response.js +12 -0
- package/build/src/server/main.d.ts +48 -0
- package/build/src/server/main.js +142 -5
- package/build/src/types/base.d.ts +12 -0
- package/build/src/types/base.js +8 -0
- package/build/src/types/main.js +8 -0
- package/build/src/types/middleware.d.ts +18 -0
- package/build/src/types/middleware.js +8 -0
- package/build/src/types/qs.d.ts +53 -0
- package/build/src/types/qs.js +8 -0
- package/build/src/types/request.d.ts +32 -0
- package/build/src/types/request.js +8 -0
- package/build/src/types/response.d.ts +27 -0
- package/build/src/types/response.js +8 -0
- package/build/src/types/route.d.ts +89 -1
- package/build/src/types/route.js +8 -0
- package/build/src/types/server.d.ts +36 -1
- package/build/src/types/server.js +8 -0
- package/package.json +52 -74
package/build/src/response.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
*/
|
|
1
9
|
import etag from 'etag';
|
|
2
10
|
import vary from 'vary';
|
|
3
11
|
import fresh from 'fresh';
|
|
@@ -5,44 +13,92 @@ import mime from 'mime-types';
|
|
|
5
13
|
import destroy from 'destroy';
|
|
6
14
|
import { extname } from 'node:path';
|
|
7
15
|
import onFinished from 'on-finished';
|
|
8
|
-
import { promisify } from 'node:util';
|
|
9
16
|
import json from '@poppinss/utils/json';
|
|
10
17
|
import Macroable from '@poppinss/macroable';
|
|
11
|
-
import { createReadStream
|
|
18
|
+
import { createReadStream } from 'node:fs';
|
|
19
|
+
import { stat } from 'node:fs/promises';
|
|
12
20
|
import { RuntimeException } from '@poppinss/utils';
|
|
13
21
|
import contentDisposition from 'content-disposition';
|
|
14
22
|
import { Redirect } from './redirect.js';
|
|
15
23
|
import { CookieSerializer } from './cookies/serializer.js';
|
|
16
24
|
import { E_HTTP_REQUEST_ABORTED } from './exceptions.js';
|
|
17
|
-
const statFn = promisify(stat);
|
|
18
25
|
const CACHEABLE_HTTP_METHODS = ['GET', 'HEAD'];
|
|
26
|
+
/**
|
|
27
|
+
* The response is a wrapper over [ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse)
|
|
28
|
+
* streamlining the process of writing response body and automatically setting up appropriate headers.
|
|
29
|
+
*/
|
|
19
30
|
export class Response extends Macroable {
|
|
20
31
|
request;
|
|
21
32
|
response;
|
|
33
|
+
/**
|
|
34
|
+
* Query string parser
|
|
35
|
+
*/
|
|
22
36
|
#qs;
|
|
37
|
+
/**
|
|
38
|
+
* Outgoing headers
|
|
39
|
+
*/
|
|
23
40
|
#headers = {};
|
|
41
|
+
/**
|
|
42
|
+
* Has explicit status been set
|
|
43
|
+
*/
|
|
24
44
|
#hasExplicitStatus = false;
|
|
45
|
+
/**
|
|
46
|
+
* Cookies serializer to serialize the outgoing cookies
|
|
47
|
+
*/
|
|
25
48
|
#cookieSerializer;
|
|
49
|
+
/**
|
|
50
|
+
* Router is used to make the redirect URLs from routes
|
|
51
|
+
*/
|
|
26
52
|
#router;
|
|
53
|
+
/**
|
|
54
|
+
* Response config
|
|
55
|
+
*/
|
|
27
56
|
#config;
|
|
57
|
+
/**
|
|
58
|
+
* Does response has body set that will written to the
|
|
59
|
+
* response socket at the end of the request
|
|
60
|
+
*/
|
|
28
61
|
get hasLazyBody() {
|
|
29
62
|
return !!(this.lazyBody.content || this.lazyBody.fileToStream || this.lazyBody.stream);
|
|
30
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Find if the response has non-stream content
|
|
66
|
+
*/
|
|
31
67
|
get hasContent() {
|
|
32
68
|
return !!this.lazyBody.content;
|
|
33
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns true when response body is set using "response.stream"
|
|
72
|
+
* method
|
|
73
|
+
*/
|
|
34
74
|
get hasStream() {
|
|
35
75
|
return !!this.lazyBody.stream;
|
|
36
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns true when response body is set using "response.download"
|
|
79
|
+
* or "response.attachment" methods
|
|
80
|
+
*/
|
|
37
81
|
get hasFileToStream() {
|
|
38
82
|
return !!this.lazyBody.fileToStream;
|
|
39
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Returns the response content. Check if the response
|
|
86
|
+
* has content using the "hasContent" method
|
|
87
|
+
*/
|
|
40
88
|
get content() {
|
|
41
89
|
return this.lazyBody.content;
|
|
42
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns reference to the stream set using "response.stream"
|
|
93
|
+
* method
|
|
94
|
+
*/
|
|
43
95
|
get outgoingStream() {
|
|
44
96
|
return this.lazyBody.stream?.[0];
|
|
45
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns reference to the file path set using "response.stream"
|
|
100
|
+
* method.
|
|
101
|
+
*/
|
|
46
102
|
get fileToStream() {
|
|
47
103
|
return this.lazyBody.fileToStream
|
|
48
104
|
? {
|
|
@@ -51,7 +107,16 @@ export class Response extends Macroable {
|
|
|
51
107
|
}
|
|
52
108
|
: undefined;
|
|
53
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Lazy body is used to set the response body. However, do not
|
|
112
|
+
* write it on the socket immediately unless `response.finish`
|
|
113
|
+
* is called.
|
|
114
|
+
*/
|
|
54
115
|
lazyBody = {};
|
|
116
|
+
/**
|
|
117
|
+
* The ctx will be set by the context itself. It creates a circular
|
|
118
|
+
* reference
|
|
119
|
+
*/
|
|
55
120
|
ctx;
|
|
56
121
|
constructor(request, response, encryption, config, router, qs) {
|
|
57
122
|
super();
|
|
@@ -62,30 +127,68 @@ export class Response extends Macroable {
|
|
|
62
127
|
this.#router = router;
|
|
63
128
|
this.#cookieSerializer = new CookieSerializer(encryption);
|
|
64
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Returns a boolean telling if response is finished or not.
|
|
132
|
+
* Any more attempts to update headers or body will result
|
|
133
|
+
* in raised exceptions.
|
|
134
|
+
*/
|
|
65
135
|
get finished() {
|
|
66
136
|
return this.response.writableFinished;
|
|
67
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Returns a boolean telling if response headers has been sent or not.
|
|
140
|
+
* Any more attempts to update headers will result in raised
|
|
141
|
+
* exceptions.
|
|
142
|
+
*/
|
|
68
143
|
get headersSent() {
|
|
69
144
|
return this.response.headersSent;
|
|
70
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns a boolean telling if response headers and body is written
|
|
148
|
+
* or not. When value is `true`, you can feel free to write headers
|
|
149
|
+
* and body.
|
|
150
|
+
*/
|
|
71
151
|
get isPending() {
|
|
72
152
|
return !this.headersSent && !this.finished;
|
|
73
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Normalizes header value to a string or an array of string
|
|
156
|
+
*/
|
|
74
157
|
#castHeaderValue(value) {
|
|
75
158
|
return Array.isArray(value) ? value.map(String) : String(value);
|
|
76
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Ends the response by flushing headers and writing body
|
|
162
|
+
*/
|
|
77
163
|
#endResponse(body, statusCode) {
|
|
78
|
-
this.
|
|
164
|
+
this.writeHead(statusCode);
|
|
165
|
+
// avoid ArgumentsAdaptorTrampoline from V8 (inspired by fastify)
|
|
79
166
|
const res = this.response;
|
|
80
167
|
res.end(body, null, null);
|
|
81
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Returns type for the content body. Only following types are allowed
|
|
171
|
+
*
|
|
172
|
+
* - Dates
|
|
173
|
+
* - Arrays
|
|
174
|
+
* - Booleans
|
|
175
|
+
* - Objects
|
|
176
|
+
* - Strings
|
|
177
|
+
* - Buffer
|
|
178
|
+
*/
|
|
82
179
|
#getDataType(content) {
|
|
83
180
|
if (Buffer.isBuffer(content)) {
|
|
84
181
|
return 'buffer';
|
|
85
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Date instance
|
|
185
|
+
*/
|
|
86
186
|
if (content instanceof Date) {
|
|
87
187
|
return 'date';
|
|
88
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Regular expression
|
|
191
|
+
*/
|
|
89
192
|
if (content instanceof RegExp) {
|
|
90
193
|
return 'regexp';
|
|
91
194
|
}
|
|
@@ -96,17 +199,34 @@ export class Response extends Macroable {
|
|
|
96
199
|
dataType === 'bigint') {
|
|
97
200
|
return dataType;
|
|
98
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Object
|
|
204
|
+
*/
|
|
99
205
|
if (dataType === 'object') {
|
|
100
206
|
return 'object';
|
|
101
207
|
}
|
|
102
208
|
throw new RuntimeException(`Cannot serialize "${dataType}" to HTTP response`);
|
|
103
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Writes the body with appropriate response headers. Etag header is set
|
|
212
|
+
* when `generateEtag` is set to `true`.
|
|
213
|
+
*
|
|
214
|
+
* Empty body results in `204`.
|
|
215
|
+
*/
|
|
104
216
|
writeBody(content, generateEtag, jsonpCallbackName) {
|
|
105
217
|
const hasEmptyBody = content === null || content === undefined || content === '';
|
|
218
|
+
/**
|
|
219
|
+
* Set status to "204" when body is empty. The `safeStatus` method only
|
|
220
|
+
* sets the status when no explicit status has been set already
|
|
221
|
+
*/
|
|
106
222
|
if (hasEmptyBody) {
|
|
107
223
|
this.safeStatus(204);
|
|
108
224
|
}
|
|
109
225
|
const statusCode = this.response.statusCode;
|
|
226
|
+
/**
|
|
227
|
+
* Do not process body when status code is less than 200 or is 204 or 304. As per
|
|
228
|
+
* https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
229
|
+
*/
|
|
110
230
|
if (statusCode && (statusCode < 200 || statusCode === 204 || statusCode === 304)) {
|
|
111
231
|
this.removeHeader('Content-Type');
|
|
112
232
|
this.removeHeader('Content-Length');
|
|
@@ -114,12 +234,27 @@ export class Response extends Macroable {
|
|
|
114
234
|
this.#endResponse();
|
|
115
235
|
return;
|
|
116
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Body is empty and status code is not "204", "304" and neither under 200.
|
|
239
|
+
*/
|
|
117
240
|
if (hasEmptyBody) {
|
|
118
241
|
this.removeHeader('Content-Length');
|
|
119
242
|
this.#endResponse();
|
|
120
243
|
return;
|
|
121
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Javascript data type for the content. We only handle a subset
|
|
247
|
+
* of data types. Check [[this.getDataType]] method for more
|
|
248
|
+
* info
|
|
249
|
+
*/
|
|
122
250
|
const dataType = this.#getDataType(content);
|
|
251
|
+
/**
|
|
252
|
+
* ----------------------------------------
|
|
253
|
+
* SERIALIZE CONTENT TO A STRING
|
|
254
|
+
* ----------------------------------------
|
|
255
|
+
*
|
|
256
|
+
* Transforming date, number, boolean and object to a string
|
|
257
|
+
*/
|
|
123
258
|
if (dataType === 'object') {
|
|
124
259
|
content = json.safeStringify(content);
|
|
125
260
|
}
|
|
@@ -132,13 +267,39 @@ export class Response extends Macroable {
|
|
|
132
267
|
else if (dataType === 'date') {
|
|
133
268
|
content = content.toISOString();
|
|
134
269
|
}
|
|
270
|
+
/*
|
|
271
|
+
* ----------------------------------------
|
|
272
|
+
* MORE MODIFICATIONS FOR JSONP BODY
|
|
273
|
+
* ----------------------------------------
|
|
274
|
+
*
|
|
275
|
+
* If JSONP callback exists, then update the body to be a
|
|
276
|
+
* valid JSONP response
|
|
277
|
+
*/
|
|
135
278
|
if (jsonpCallbackName) {
|
|
279
|
+
/*
|
|
280
|
+
* replace chars not allowed in JavaScript that are in JSON
|
|
281
|
+
* https://github.com/rack/rack-contrib/pull/37
|
|
282
|
+
*/
|
|
136
283
|
content = content.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
|
|
284
|
+
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
|
|
285
|
+
// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-4671
|
|
286
|
+
// http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/
|
|
287
|
+
// http://drops.wooyun.org/tips/2554
|
|
137
288
|
content = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${content});`;
|
|
138
289
|
}
|
|
290
|
+
/*
|
|
291
|
+
* ----------------------------------------
|
|
292
|
+
* FINALY GENERATE AN ETAG
|
|
293
|
+
* ----------------------------------------
|
|
294
|
+
*
|
|
295
|
+
* Generate etag if instructed.
|
|
296
|
+
*/
|
|
139
297
|
if (generateEtag) {
|
|
140
298
|
this.setEtag(content);
|
|
141
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* End response when cache is fresh
|
|
302
|
+
*/
|
|
142
303
|
if (generateEtag && this.fresh()) {
|
|
143
304
|
this.removeHeader('Content-Type');
|
|
144
305
|
this.removeHeader('Content-Length');
|
|
@@ -146,7 +307,29 @@ export class Response extends Macroable {
|
|
|
146
307
|
this.#endResponse(null, 304);
|
|
147
308
|
return;
|
|
148
309
|
}
|
|
310
|
+
/*
|
|
311
|
+
* ----------------------------------------
|
|
312
|
+
* SET CONTENT-LENGTH HEADER
|
|
313
|
+
* ----------------------------------------
|
|
314
|
+
*/
|
|
149
315
|
this.header('Content-Length', Buffer.byteLength(content));
|
|
316
|
+
/**
|
|
317
|
+
* ----------------------------------------
|
|
318
|
+
* SET CONTENT-TYPE HEADER
|
|
319
|
+
* ----------------------------------------
|
|
320
|
+
*
|
|
321
|
+
* - If it is a JSONP response, then we always set the content type
|
|
322
|
+
* to "text/javascript"
|
|
323
|
+
*
|
|
324
|
+
* - String are checked for HTML and "text/plain" or "text/html" is set
|
|
325
|
+
* accordingly.
|
|
326
|
+
*
|
|
327
|
+
* - "text/plain" is set for "numbers" and "booleans" and "dates"
|
|
328
|
+
*
|
|
329
|
+
* - "application/octet-stream" is set for buffers
|
|
330
|
+
*
|
|
331
|
+
* - "application/json" is set for objects and arrays
|
|
332
|
+
*/
|
|
150
333
|
if (jsonpCallbackName) {
|
|
151
334
|
this.header('X-Content-Type-Options', 'nosniff');
|
|
152
335
|
this.safeHeader('Content-Type', 'text/javascript; charset=utf-8');
|
|
@@ -174,53 +357,110 @@ export class Response extends Macroable {
|
|
|
174
357
|
}
|
|
175
358
|
this.#endResponse(content);
|
|
176
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Stream the body to the response and handles cleaning up the stream
|
|
362
|
+
*/
|
|
177
363
|
streamBody(body, errorCallback) {
|
|
178
364
|
return new Promise((resolve) => {
|
|
179
365
|
let finished = false;
|
|
366
|
+
/*
|
|
367
|
+
* Listen for errors on the stream and properly destroy
|
|
368
|
+
* stream
|
|
369
|
+
*/
|
|
180
370
|
body.on('error', (error) => {
|
|
371
|
+
/* c8 ignore next 3 */
|
|
181
372
|
if (finished) {
|
|
182
373
|
return;
|
|
183
374
|
}
|
|
184
375
|
finished = true;
|
|
185
376
|
destroy(body);
|
|
186
377
|
this.type('text');
|
|
187
|
-
if (
|
|
188
|
-
|
|
378
|
+
if (!this.headersSent) {
|
|
379
|
+
if (typeof errorCallback === 'function') {
|
|
380
|
+
this.#endResponse(...errorCallback(error));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
this.#endResponse(error.code === 'ENOENT' ? 'File not found' : 'Cannot process file', error.code === 'ENOENT' ? 404 : 500);
|
|
384
|
+
}
|
|
189
385
|
}
|
|
190
386
|
else {
|
|
191
|
-
this
|
|
192
|
-
resolve();
|
|
387
|
+
this.response.destroy();
|
|
193
388
|
}
|
|
389
|
+
resolve();
|
|
194
390
|
});
|
|
195
|
-
|
|
391
|
+
/*
|
|
392
|
+
* Listen for end and resolve the promise
|
|
393
|
+
*/
|
|
394
|
+
body.on('end', () => {
|
|
395
|
+
if (!this.headersSent) {
|
|
396
|
+
this.#endResponse();
|
|
397
|
+
}
|
|
398
|
+
resolve();
|
|
399
|
+
});
|
|
400
|
+
/*
|
|
401
|
+
* Cleanup stream when finishing response
|
|
402
|
+
*/
|
|
196
403
|
onFinished(this.response, () => {
|
|
197
404
|
finished = true;
|
|
198
405
|
destroy(body);
|
|
199
406
|
});
|
|
407
|
+
/*
|
|
408
|
+
* Pipe stream
|
|
409
|
+
*/
|
|
200
410
|
this.flushHeaders();
|
|
201
411
|
body.pipe(this.response);
|
|
202
412
|
});
|
|
203
413
|
}
|
|
414
|
+
/**
|
|
415
|
+
* Downloads a file by streaming it to the response
|
|
416
|
+
*/
|
|
204
417
|
async streamFileForDownload(filePath, generateEtag, errorCallback) {
|
|
205
418
|
try {
|
|
206
|
-
const stats = await
|
|
419
|
+
const stats = await stat(filePath);
|
|
207
420
|
if (!stats || !stats.isFile()) {
|
|
208
421
|
throw new TypeError('response.download only accepts path to a file');
|
|
209
422
|
}
|
|
423
|
+
/*
|
|
424
|
+
* Set appropriate headers
|
|
425
|
+
*/
|
|
210
426
|
this.header('Last-Modified', stats.mtime.toUTCString());
|
|
211
427
|
this.type(extname(filePath));
|
|
428
|
+
/*
|
|
429
|
+
* Set the etag when instructed.
|
|
430
|
+
*/
|
|
212
431
|
if (generateEtag) {
|
|
213
432
|
this.setEtag(stats, true);
|
|
214
433
|
}
|
|
434
|
+
/*
|
|
435
|
+
* Do not stream files for HEAD request, but set the appropriate
|
|
436
|
+
* status code.
|
|
437
|
+
*
|
|
438
|
+
* 200: When not using etags or cache is not fresh. This forces browser
|
|
439
|
+
* to always make a GET request
|
|
440
|
+
*
|
|
441
|
+
* 304: When etags are used and cache is fresh
|
|
442
|
+
*/
|
|
215
443
|
if (this.request.method === 'HEAD') {
|
|
216
444
|
this.#endResponse(null, generateEtag && this.fresh() ? 304 : 200);
|
|
217
445
|
return;
|
|
218
446
|
}
|
|
447
|
+
/*
|
|
448
|
+
* Regardless of request method, if we are using etags and
|
|
449
|
+
* cache is fresh, then we must respond with 304
|
|
450
|
+
*/
|
|
219
451
|
if (generateEtag && this.fresh()) {
|
|
220
452
|
this.#endResponse(null, 304);
|
|
221
453
|
return;
|
|
222
454
|
}
|
|
455
|
+
/*
|
|
456
|
+
* Fix for https://tools.ietf.org/html/rfc7232#section-4.1. It is
|
|
457
|
+
* recommended to ignore headers other than Cache-Control,
|
|
458
|
+
* Content-Location, Date, ETag, Expires, and Vary.
|
|
459
|
+
*/
|
|
223
460
|
this.header('Content-length', stats.size);
|
|
461
|
+
/*
|
|
462
|
+
* Finally stream the file
|
|
463
|
+
*/
|
|
224
464
|
return this.streamBody(createReadStream(filePath), errorCallback);
|
|
225
465
|
}
|
|
226
466
|
catch (error) {
|
|
@@ -234,20 +474,55 @@ export class Response extends Macroable {
|
|
|
234
474
|
}
|
|
235
475
|
}
|
|
236
476
|
}
|
|
237
|
-
|
|
477
|
+
/**
|
|
478
|
+
* Writes headers with the Node.js res object using the
|
|
479
|
+
* response.setHeader method
|
|
480
|
+
*/
|
|
481
|
+
flushHeaders() {
|
|
482
|
+
if (!this.headersSent) {
|
|
483
|
+
for (let key in this.#headers) {
|
|
484
|
+
const value = this.#headers[key];
|
|
485
|
+
if (value) {
|
|
486
|
+
this.response.setHeader(key, value);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Calls res.writeHead on the Node.js res object.
|
|
493
|
+
*/
|
|
494
|
+
writeHead(statusCode) {
|
|
238
495
|
this.response.writeHead(statusCode || this.response.statusCode, this.#headers);
|
|
239
496
|
return this;
|
|
240
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Returns the existing value for a given HTTP response
|
|
500
|
+
* header.
|
|
501
|
+
*/
|
|
241
502
|
getHeader(key) {
|
|
242
503
|
const value = this.#headers[key.toLowerCase()];
|
|
243
504
|
return value === undefined ? this.response.getHeader(key) : value;
|
|
244
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Get response headers
|
|
508
|
+
*/
|
|
245
509
|
getHeaders() {
|
|
246
510
|
return {
|
|
247
511
|
...this.response.getHeaders(),
|
|
248
512
|
...this.#headers,
|
|
249
513
|
};
|
|
250
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Set header on the response. To `append` values to the existing header, we suggest
|
|
517
|
+
* using [[append]] method.
|
|
518
|
+
*
|
|
519
|
+
* If `value` is non existy, then header won't be set.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```js
|
|
523
|
+
* response.header('content-type', 'application/json')
|
|
524
|
+
* ```
|
|
525
|
+
*/
|
|
251
526
|
header(key, value) {
|
|
252
527
|
if (value === null || value === undefined) {
|
|
253
528
|
return this;
|
|
@@ -255,6 +530,17 @@ export class Response extends Macroable {
|
|
|
255
530
|
this.#headers[key.toLowerCase()] = this.#castHeaderValue(value);
|
|
256
531
|
return this;
|
|
257
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Append value to an existing header. To replace the value, we suggest using
|
|
535
|
+
* [[header]] method.
|
|
536
|
+
*
|
|
537
|
+
* If `value` is not existy, then header won't be set.
|
|
538
|
+
*
|
|
539
|
+
* @example
|
|
540
|
+
* ```js
|
|
541
|
+
* response.append('set-cookie', 'username=virk')
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
258
544
|
append(key, value) {
|
|
259
545
|
if (value === null || value === undefined) {
|
|
260
546
|
return this;
|
|
@@ -262,6 +548,10 @@ export class Response extends Macroable {
|
|
|
262
548
|
key = key.toLowerCase();
|
|
263
549
|
let existingHeader = this.getHeader(key);
|
|
264
550
|
let casted = this.#castHeaderValue(value);
|
|
551
|
+
/**
|
|
552
|
+
* If there isn't any header, then setHeader right
|
|
553
|
+
* away
|
|
554
|
+
*/
|
|
265
555
|
if (!existingHeader) {
|
|
266
556
|
this.#headers[key] = casted;
|
|
267
557
|
return this;
|
|
@@ -273,12 +563,18 @@ export class Response extends Macroable {
|
|
|
273
563
|
this.#headers[key] = casted;
|
|
274
564
|
return this;
|
|
275
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Adds HTTP response header, when it doesn't exists already.
|
|
568
|
+
*/
|
|
276
569
|
safeHeader(key, value) {
|
|
277
570
|
if (!this.getHeader(key)) {
|
|
278
571
|
this.header(key, value);
|
|
279
572
|
}
|
|
280
573
|
return this;
|
|
281
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Removes the existing response header from being sent.
|
|
577
|
+
*/
|
|
282
578
|
removeHeader(key) {
|
|
283
579
|
key = key.toLowerCase();
|
|
284
580
|
this.response.removeHeader(key);
|
|
@@ -287,14 +583,24 @@ export class Response extends Macroable {
|
|
|
287
583
|
}
|
|
288
584
|
return this;
|
|
289
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Returns the status code for the response
|
|
588
|
+
*/
|
|
290
589
|
getStatus() {
|
|
291
590
|
return this.response.statusCode;
|
|
292
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Set HTTP status code
|
|
594
|
+
*/
|
|
293
595
|
status(code) {
|
|
294
596
|
this.#hasExplicitStatus = true;
|
|
295
597
|
this.response.statusCode = code;
|
|
296
598
|
return this;
|
|
297
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Set's status code only when it's not explictly
|
|
602
|
+
* set
|
|
603
|
+
*/
|
|
298
604
|
safeStatus(code) {
|
|
299
605
|
if (this.#hasExplicitStatus) {
|
|
300
606
|
return this;
|
|
@@ -302,19 +608,65 @@ export class Response extends Macroable {
|
|
|
302
608
|
this.response.statusCode = code;
|
|
303
609
|
return this;
|
|
304
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* Set response type by looking up for the mime-type using
|
|
613
|
+
* partial types like file extensions.
|
|
614
|
+
*
|
|
615
|
+
* Make sure to read [mime-types](https://www.npmjs.com/package/mime-types) docs
|
|
616
|
+
* too.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```js
|
|
620
|
+
* response.type('.json') // Content-type: application/json
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
305
623
|
type(type, charset) {
|
|
306
624
|
type = charset ? `${type}; charset=${charset}` : type;
|
|
307
625
|
this.header('Content-Type', mime.contentType(type));
|
|
308
626
|
return this;
|
|
309
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* Set the Vary HTTP header
|
|
630
|
+
*/
|
|
310
631
|
vary(field) {
|
|
311
632
|
vary(this.response, field);
|
|
312
633
|
return this;
|
|
313
634
|
}
|
|
635
|
+
/**
|
|
636
|
+
* Set etag by computing hash from the body. This class will set the etag automatically
|
|
637
|
+
* when `etag = true` in the defined config object.
|
|
638
|
+
*
|
|
639
|
+
* Use this function, when you want to compute etag manually for some other resons.
|
|
640
|
+
*/
|
|
314
641
|
setEtag(body, weak = false) {
|
|
315
642
|
this.header('Etag', etag(body, { weak }));
|
|
316
643
|
return this;
|
|
317
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* Returns a boolean telling if the new response etag evaluates same
|
|
647
|
+
* as the request header `if-none-match`. In case of `true`, the
|
|
648
|
+
* server must return `304` response, telling the browser to
|
|
649
|
+
* use the client cache.
|
|
650
|
+
*
|
|
651
|
+
* You won't have to deal with this method directly, since AdonisJs will
|
|
652
|
+
* handle this for you when `http.etag = true` inside `config/app.js` file.
|
|
653
|
+
*
|
|
654
|
+
* However, this is how you can use it manually.
|
|
655
|
+
*
|
|
656
|
+
* @example
|
|
657
|
+
* ```js
|
|
658
|
+
* const responseBody = view.render('some-view')
|
|
659
|
+
*
|
|
660
|
+
* // sets the HTTP etag header for response
|
|
661
|
+
* response.setEtag(responseBody)
|
|
662
|
+
*
|
|
663
|
+
* if (response.fresh()) {
|
|
664
|
+
* response.sendStatus(304)
|
|
665
|
+
* } else {
|
|
666
|
+
* response.send(responseBody)
|
|
667
|
+
* }
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
318
670
|
fresh() {
|
|
319
671
|
if (this.request.method && !CACHEABLE_HTTP_METHODS.includes(this.request.method)) {
|
|
320
672
|
return false;
|
|
@@ -325,35 +677,124 @@ export class Response extends Macroable {
|
|
|
325
677
|
}
|
|
326
678
|
return false;
|
|
327
679
|
}
|
|
680
|
+
/**
|
|
681
|
+
* Returns the response body. Returns null when response
|
|
682
|
+
* body is a stream
|
|
683
|
+
*/
|
|
328
684
|
getBody() {
|
|
329
685
|
if (this.lazyBody.content) {
|
|
330
686
|
return this.lazyBody.content[0];
|
|
331
687
|
}
|
|
332
688
|
return null;
|
|
333
689
|
}
|
|
690
|
+
/**
|
|
691
|
+
* Send the body as response and optionally generate etag. The default value
|
|
692
|
+
* is read from `config/app.js` file, using `http.etag` property.
|
|
693
|
+
*
|
|
694
|
+
* This method buffers the body if `explicitEnd = true`, which is the default
|
|
695
|
+
* behavior and do not change, unless you know what you are doing.
|
|
696
|
+
*/
|
|
334
697
|
send(body, generateEtag = this.#config.etag) {
|
|
335
698
|
this.lazyBody.content = [body, generateEtag];
|
|
336
699
|
}
|
|
700
|
+
/**
|
|
701
|
+
* Alias of [[send]]
|
|
702
|
+
*/
|
|
337
703
|
json(body, generateEtag = this.#config.etag) {
|
|
338
704
|
return this.send(body, generateEtag);
|
|
339
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Writes response as JSONP. The callback name is resolved as follows, with priority
|
|
708
|
+
* from top to bottom.
|
|
709
|
+
*
|
|
710
|
+
* 1. Explicitly defined as 2nd Param.
|
|
711
|
+
* 2. Fetch from request query string.
|
|
712
|
+
* 3. Use the config value `http.jsonpCallbackName` from `config/app.js`.
|
|
713
|
+
* 4. Fallback to `callback`.
|
|
714
|
+
*
|
|
715
|
+
* This method buffers the body if `explicitEnd = true`, which is the default
|
|
716
|
+
* behavior and do not change, unless you know what you are doing.
|
|
717
|
+
*/
|
|
340
718
|
jsonp(body, callbackName = this.#config.jsonpCallbackName, generateEtag = this.#config.etag) {
|
|
341
719
|
this.lazyBody.content = [body, generateEtag, callbackName];
|
|
342
720
|
}
|
|
721
|
+
/**
|
|
722
|
+
* Pipe stream to the response. This method will gracefully destroy
|
|
723
|
+
* the stream, avoiding memory leaks.
|
|
724
|
+
*
|
|
725
|
+
* If `raiseErrors=false`, then this method will self handle all the exceptions by
|
|
726
|
+
* writing a generic HTTP response. To have more control over the error, it is
|
|
727
|
+
* recommended to set `raiseErrors=true` and wrap this function inside a
|
|
728
|
+
* `try/catch` statement.
|
|
729
|
+
*
|
|
730
|
+
* Streaming a file from the disk and showing 404 when file is missing.
|
|
731
|
+
*
|
|
732
|
+
* @example
|
|
733
|
+
* ```js
|
|
734
|
+
* // Errors handled automatically with generic HTTP response
|
|
735
|
+
* response.stream(fs.createReadStream('file.txt'))
|
|
736
|
+
*
|
|
737
|
+
* // Manually handle (note the await call)
|
|
738
|
+
* try {
|
|
739
|
+
* await response.stream(fs.createReadStream('file.txt'))
|
|
740
|
+
* } catch () {
|
|
741
|
+
* response.status(404).send('File not found')
|
|
742
|
+
* }
|
|
743
|
+
* ```
|
|
744
|
+
*/
|
|
343
745
|
stream(body, errorCallback) {
|
|
344
746
|
if (typeof body.pipe !== 'function' || !body.readable || typeof body.read !== 'function') {
|
|
345
747
|
throw new TypeError('response.stream accepts a readable stream only');
|
|
346
748
|
}
|
|
347
749
|
this.lazyBody.stream = [body, errorCallback];
|
|
348
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Download file by streaming it from the file path. This method will setup
|
|
753
|
+
* appropriate `Content-type`, `Content-type` and `Last-modified` headers.
|
|
754
|
+
*
|
|
755
|
+
* Unexpected stream errors are handled gracefully to avoid memory leaks.
|
|
756
|
+
*
|
|
757
|
+
* If `raiseErrors=false`, then this method will self handle all the exceptions by
|
|
758
|
+
* writing a generic HTTP response. To have more control over the error, it is
|
|
759
|
+
* recommended to set `raiseErrors=true` and wrap this function inside a
|
|
760
|
+
* `try/catch` statement.
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* ```js
|
|
764
|
+
* // Errors handled automatically with generic HTTP response
|
|
765
|
+
* response.download('somefile.jpg')
|
|
766
|
+
*
|
|
767
|
+
* // Manually handle (note the await call)
|
|
768
|
+
* try {
|
|
769
|
+
* await response.download('somefile.jpg')
|
|
770
|
+
* } catch (error) {
|
|
771
|
+
* response.status(error.code === 'ENOENT' ? 404 : 500)
|
|
772
|
+
* response.send('Cannot process file')
|
|
773
|
+
* }
|
|
774
|
+
* ```
|
|
775
|
+
*/
|
|
349
776
|
download(filePath, generateEtag = this.#config.etag, errorCallback) {
|
|
350
777
|
this.lazyBody.fileToStream = [filePath, generateEtag, errorCallback];
|
|
351
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Download the file by forcing the user to save the file vs displaying it
|
|
781
|
+
* within the browser.
|
|
782
|
+
*
|
|
783
|
+
* Internally calls [[download]]
|
|
784
|
+
*/
|
|
352
785
|
attachment(filePath, name, disposition, generateEtag, errorCallback) {
|
|
353
786
|
name = name || filePath;
|
|
354
787
|
this.header('Content-Disposition', contentDisposition(name, { type: disposition }));
|
|
355
788
|
return this.download(filePath, generateEtag, errorCallback);
|
|
356
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* Set the location header.
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```js
|
|
795
|
+
* response.location('/login')
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
357
798
|
location(url) {
|
|
358
799
|
this.header('Location', url);
|
|
359
800
|
return this;
|
|
@@ -371,19 +812,35 @@ export class Response extends Macroable {
|
|
|
371
812
|
}
|
|
372
813
|
return handler;
|
|
373
814
|
}
|
|
815
|
+
/**
|
|
816
|
+
* Abort the request with custom body and a status code. 400 is
|
|
817
|
+
* used when status is not defined
|
|
818
|
+
*/
|
|
374
819
|
abort(body, status) {
|
|
375
820
|
throw E_HTTP_REQUEST_ABORTED.invoke(body, status || 400);
|
|
376
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Abort the request with custom body and a status code when
|
|
824
|
+
* passed condition returns `true`
|
|
825
|
+
*/
|
|
377
826
|
abortIf(condition, body, status) {
|
|
378
827
|
if (condition) {
|
|
379
828
|
this.abort(body, status);
|
|
380
829
|
}
|
|
381
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* Abort the request with custom body and a status code when
|
|
833
|
+
* passed condition returns `false`
|
|
834
|
+
*/
|
|
382
835
|
abortUnless(condition, body, status) {
|
|
383
836
|
if (!condition) {
|
|
384
837
|
this.abort(body, status);
|
|
385
838
|
}
|
|
386
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Set signed cookie as the response header. The inline options overrides
|
|
842
|
+
* all options from the config.
|
|
843
|
+
*/
|
|
387
844
|
cookie(key, value, options) {
|
|
388
845
|
options = Object.assign({}, this.#config.cookie, options);
|
|
389
846
|
const serialized = this.#cookieSerializer.sign(key, value, options);
|
|
@@ -393,6 +850,10 @@ export class Response extends Macroable {
|
|
|
393
850
|
this.append('set-cookie', serialized);
|
|
394
851
|
return this;
|
|
395
852
|
}
|
|
853
|
+
/**
|
|
854
|
+
* Set encrypted cookie as the response header. The inline options overrides
|
|
855
|
+
* all options from the config.
|
|
856
|
+
*/
|
|
396
857
|
encryptedCookie(key, value, options) {
|
|
397
858
|
options = Object.assign({}, this.#config.cookie, options);
|
|
398
859
|
const serialized = this.#cookieSerializer.encrypt(key, value, options);
|
|
@@ -402,6 +863,10 @@ export class Response extends Macroable {
|
|
|
402
863
|
this.append('set-cookie', serialized);
|
|
403
864
|
return this;
|
|
404
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* Set unsigned cookie as the response header. The inline options overrides
|
|
868
|
+
* all options from the config.
|
|
869
|
+
*/
|
|
405
870
|
plainCookie(key, value, options) {
|
|
406
871
|
options = Object.assign({}, this.#config.cookie, options);
|
|
407
872
|
const serialized = this.#cookieSerializer.encode(key, value, options);
|
|
@@ -411,6 +876,9 @@ export class Response extends Macroable {
|
|
|
411
876
|
this.append('set-cookie', serialized);
|
|
412
877
|
return this;
|
|
413
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Clear existing cookie.
|
|
881
|
+
*/
|
|
414
882
|
clearCookie(key, options) {
|
|
415
883
|
options = Object.assign({}, this.#config.cookie, options);
|
|
416
884
|
options.expires = new Date(1);
|
|
@@ -419,6 +887,12 @@ export class Response extends Macroable {
|
|
|
419
887
|
this.append('set-cookie', serialized);
|
|
420
888
|
return this;
|
|
421
889
|
}
|
|
890
|
+
/**
|
|
891
|
+
* Finishes the response by writing the lazy body, when `explicitEnd = true`
|
|
892
|
+
* and response is already pending.
|
|
893
|
+
*
|
|
894
|
+
* Calling this method twice or when `explicitEnd = false` is noop.
|
|
895
|
+
*/
|
|
422
896
|
finish() {
|
|
423
897
|
if (!this.isPending) {
|
|
424
898
|
return;
|
|
@@ -437,170 +911,296 @@ export class Response extends Macroable {
|
|
|
437
911
|
}
|
|
438
912
|
this.#endResponse();
|
|
439
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Shorthand method to finish request with "100" status code
|
|
916
|
+
*/
|
|
440
917
|
continue() {
|
|
441
918
|
this.status(100);
|
|
442
919
|
return this.send(null, false);
|
|
443
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* Shorthand method to finish request with "101" status code
|
|
923
|
+
*/
|
|
444
924
|
switchingProtocols() {
|
|
445
925
|
this.status(101);
|
|
446
926
|
return this.send(null, false);
|
|
447
927
|
}
|
|
928
|
+
/**
|
|
929
|
+
* Shorthand method to finish request with "200" status code
|
|
930
|
+
*/
|
|
448
931
|
ok(body, generateEtag) {
|
|
449
932
|
this.status(200);
|
|
450
933
|
return this.send(body, generateEtag);
|
|
451
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* Shorthand method to finish request with "201" status code
|
|
937
|
+
*/
|
|
452
938
|
created(body, generateEtag) {
|
|
453
939
|
this.status(201);
|
|
454
940
|
return this.send(body, generateEtag);
|
|
455
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Shorthand method to finish request with "202" status code
|
|
944
|
+
*/
|
|
456
945
|
accepted(body, generateEtag) {
|
|
457
946
|
this.status(202);
|
|
458
947
|
return this.send(body, generateEtag);
|
|
459
948
|
}
|
|
949
|
+
/**
|
|
950
|
+
* Shorthand method to finish request with "203" status code
|
|
951
|
+
*/
|
|
460
952
|
nonAuthoritativeInformation(body, generateEtag) {
|
|
461
953
|
this.status(203);
|
|
462
954
|
return this.send(body, generateEtag);
|
|
463
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Shorthand method to finish request with "204" status code
|
|
958
|
+
*/
|
|
464
959
|
noContent() {
|
|
465
960
|
this.status(204);
|
|
466
961
|
return this.send(null, false);
|
|
467
962
|
}
|
|
963
|
+
/**
|
|
964
|
+
* Shorthand method to finish request with "205" status code
|
|
965
|
+
*/
|
|
468
966
|
resetContent() {
|
|
469
967
|
this.status(205);
|
|
470
968
|
return this.send(null, false);
|
|
471
969
|
}
|
|
970
|
+
/**
|
|
971
|
+
* Shorthand method to finish request with "206" status code
|
|
972
|
+
*/
|
|
472
973
|
partialContent(body, generateEtag) {
|
|
473
974
|
this.status(206);
|
|
474
975
|
return this.send(body, generateEtag);
|
|
475
976
|
}
|
|
977
|
+
/**
|
|
978
|
+
* Shorthand method to finish request with "300" status code
|
|
979
|
+
*/
|
|
476
980
|
multipleChoices(body, generateEtag) {
|
|
477
981
|
this.status(300);
|
|
478
982
|
return this.send(body, generateEtag);
|
|
479
983
|
}
|
|
984
|
+
/**
|
|
985
|
+
* Shorthand method to finish request with "301" status code
|
|
986
|
+
*/
|
|
480
987
|
movedPermanently(body, generateEtag) {
|
|
481
988
|
this.status(301);
|
|
482
989
|
return this.send(body, generateEtag);
|
|
483
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* Shorthand method to finish request with "302" status code
|
|
993
|
+
*/
|
|
484
994
|
movedTemporarily(body, generateEtag) {
|
|
485
995
|
this.status(302);
|
|
486
996
|
return this.send(body, generateEtag);
|
|
487
997
|
}
|
|
998
|
+
/**
|
|
999
|
+
* Shorthand method to finish request with "303" status code
|
|
1000
|
+
*/
|
|
488
1001
|
seeOther(body, generateEtag) {
|
|
489
1002
|
this.status(303);
|
|
490
1003
|
return this.send(body, generateEtag);
|
|
491
1004
|
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Shorthand method to finish request with "304" status code
|
|
1007
|
+
*/
|
|
492
1008
|
notModified(body, generateEtag) {
|
|
493
1009
|
this.status(304);
|
|
494
1010
|
return this.send(body, generateEtag);
|
|
495
1011
|
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Shorthand method to finish request with "305" status code
|
|
1014
|
+
*/
|
|
496
1015
|
useProxy(body, generateEtag) {
|
|
497
1016
|
this.status(305);
|
|
498
1017
|
return this.send(body, generateEtag);
|
|
499
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Shorthand method to finish request with "307" status code
|
|
1021
|
+
*/
|
|
500
1022
|
temporaryRedirect(body, generateEtag) {
|
|
501
1023
|
this.status(307);
|
|
502
1024
|
return this.send(body, generateEtag);
|
|
503
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Shorthand method to finish request with "400" status code
|
|
1028
|
+
*/
|
|
504
1029
|
badRequest(body, generateEtag) {
|
|
505
1030
|
this.status(400);
|
|
506
1031
|
return this.send(body, generateEtag);
|
|
507
1032
|
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Shorthand method to finish request with "401" status code
|
|
1035
|
+
*/
|
|
508
1036
|
unauthorized(body, generateEtag) {
|
|
509
1037
|
this.status(401);
|
|
510
1038
|
return this.send(body, generateEtag);
|
|
511
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Shorthand method to finish request with "402" status code
|
|
1042
|
+
*/
|
|
512
1043
|
paymentRequired(body, generateEtag) {
|
|
513
1044
|
this.status(402);
|
|
514
1045
|
return this.send(body, generateEtag);
|
|
515
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Shorthand method to finish request with "403" status code
|
|
1049
|
+
*/
|
|
516
1050
|
forbidden(body, generateEtag) {
|
|
517
1051
|
this.status(403);
|
|
518
1052
|
return this.send(body, generateEtag);
|
|
519
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Shorthand method to finish request with "404" status code
|
|
1056
|
+
*/
|
|
520
1057
|
notFound(body, generateEtag) {
|
|
521
1058
|
this.status(404);
|
|
522
1059
|
return this.send(body, generateEtag);
|
|
523
1060
|
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Shorthand method to finish request with "405" status code
|
|
1063
|
+
*/
|
|
524
1064
|
methodNotAllowed(body, generateEtag) {
|
|
525
1065
|
this.status(405);
|
|
526
1066
|
return this.send(body, generateEtag);
|
|
527
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Shorthand method to finish request with "406" status code
|
|
1070
|
+
*/
|
|
528
1071
|
notAcceptable(body, generateEtag) {
|
|
529
1072
|
this.status(406);
|
|
530
1073
|
return this.send(body, generateEtag);
|
|
531
1074
|
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Shorthand method to finish request with "407" status code
|
|
1077
|
+
*/
|
|
532
1078
|
proxyAuthenticationRequired(body, generateEtag) {
|
|
533
1079
|
this.status(407);
|
|
534
1080
|
return this.send(body, generateEtag);
|
|
535
1081
|
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Shorthand method to finish request with "408" status code
|
|
1084
|
+
*/
|
|
536
1085
|
requestTimeout(body, generateEtag) {
|
|
537
1086
|
this.status(408);
|
|
538
1087
|
return this.send(body, generateEtag);
|
|
539
1088
|
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Shorthand method to finish request with "409" status code
|
|
1091
|
+
*/
|
|
540
1092
|
conflict(body, generateEtag) {
|
|
541
1093
|
this.status(409);
|
|
542
1094
|
return this.send(body, generateEtag);
|
|
543
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Shorthand method to finish request with "401" status code
|
|
1098
|
+
*/
|
|
544
1099
|
gone(body, generateEtag) {
|
|
545
1100
|
this.status(410);
|
|
546
1101
|
return this.send(body, generateEtag);
|
|
547
1102
|
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Shorthand method to finish request with "411" status code
|
|
1105
|
+
*/
|
|
548
1106
|
lengthRequired(body, generateEtag) {
|
|
549
1107
|
this.status(411);
|
|
550
1108
|
return this.send(body, generateEtag);
|
|
551
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Shorthand method to finish request with "412" status code
|
|
1112
|
+
*/
|
|
552
1113
|
preconditionFailed(body, generateEtag) {
|
|
553
1114
|
this.status(412);
|
|
554
1115
|
return this.send(body, generateEtag);
|
|
555
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Shorthand method to finish request with "413" status code
|
|
1119
|
+
*/
|
|
556
1120
|
requestEntityTooLarge(body, generateEtag) {
|
|
557
1121
|
this.status(413);
|
|
558
1122
|
return this.send(body, generateEtag);
|
|
559
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Shorthand method to finish request with "414" status code
|
|
1126
|
+
*/
|
|
560
1127
|
requestUriTooLong(body, generateEtag) {
|
|
561
1128
|
this.status(414);
|
|
562
1129
|
return this.send(body, generateEtag);
|
|
563
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Shorthand method to finish request with "415" status code
|
|
1133
|
+
*/
|
|
564
1134
|
unsupportedMediaType(body, generateEtag) {
|
|
565
1135
|
this.status(415);
|
|
566
1136
|
return this.send(body, generateEtag);
|
|
567
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Shorthand method to finish request with "416" status code
|
|
1140
|
+
*/
|
|
568
1141
|
requestedRangeNotSatisfiable(body, generateEtag) {
|
|
569
1142
|
this.status(416);
|
|
570
1143
|
return this.send(body, generateEtag);
|
|
571
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Shorthand method to finish request with "417" status code
|
|
1147
|
+
*/
|
|
572
1148
|
expectationFailed(body, generateEtag) {
|
|
573
1149
|
this.status(417);
|
|
574
1150
|
return this.send(body, generateEtag);
|
|
575
1151
|
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Shorthand method to finish request with "422" status code
|
|
1154
|
+
*/
|
|
576
1155
|
unprocessableEntity(body, generateEtag) {
|
|
577
1156
|
this.status(422);
|
|
578
1157
|
return this.send(body, generateEtag);
|
|
579
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Shorthand method to finish request with "429" status code
|
|
1161
|
+
*/
|
|
580
1162
|
tooManyRequests(body, generateEtag) {
|
|
581
1163
|
this.status(429);
|
|
582
1164
|
return this.send(body, generateEtag);
|
|
583
1165
|
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Shorthand method to finish request with "500" status code
|
|
1168
|
+
*/
|
|
584
1169
|
internalServerError(body, generateEtag) {
|
|
585
1170
|
this.status(500);
|
|
586
1171
|
return this.send(body, generateEtag);
|
|
587
1172
|
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Shorthand method to finish request with "501" status code
|
|
1175
|
+
*/
|
|
588
1176
|
notImplemented(body, generateEtag) {
|
|
589
1177
|
this.status(501);
|
|
590
1178
|
return this.send(body, generateEtag);
|
|
591
1179
|
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Shorthand method to finish request with "502" status code
|
|
1182
|
+
*/
|
|
592
1183
|
badGateway(body, generateEtag) {
|
|
593
1184
|
this.status(502);
|
|
594
1185
|
return this.send(body, generateEtag);
|
|
595
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Shorthand method to finish request with "503" status code
|
|
1189
|
+
*/
|
|
596
1190
|
serviceUnavailable(body, generateEtag) {
|
|
597
1191
|
this.status(503);
|
|
598
1192
|
return this.send(body, generateEtag);
|
|
599
1193
|
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Shorthand method to finish request with "504" status code
|
|
1196
|
+
*/
|
|
600
1197
|
gatewayTimeout(body, generateEtag) {
|
|
601
1198
|
this.status(504);
|
|
602
1199
|
return this.send(body, generateEtag);
|
|
603
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Shorthand method to finish request with "505" status code
|
|
1203
|
+
*/
|
|
604
1204
|
httpVersionNotSupported(body, generateEtag) {
|
|
605
1205
|
this.status(505);
|
|
606
1206
|
return this.send(body, generateEtag);
|