@adonisjs/http-server 6.8.2-6 → 6.8.2-8
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/README.md +3 -6
- package/build/factories/http_context.d.ts +10 -1
- 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.d.ts +0 -1
- package/build/factories/main.js +8 -0
- package/build/factories/qs_parser_factory.d.ts +10 -1
- package/build/factories/qs_parser_factory.js +18 -0
- package/build/factories/request.d.ts +10 -1
- package/build/factories/request.js +31 -0
- package/build/factories/response.d.ts +10 -1
- package/build/factories/response.js +34 -0
- package/build/factories/router.d.ts +10 -1
- package/build/factories/router.js +25 -0
- package/build/factories/server_factory.d.ts +10 -1
- package/build/factories/server_factory.js +34 -0
- package/build/index.d.ts +0 -1
- package/build/index.js +8 -0
- package/build/src/cookies/client.d.ts +25 -1
- package/build/src/cookies/client.js +42 -0
- package/build/src/cookies/drivers/encrypted.d.ts +12 -1
- package/build/src/cookies/drivers/encrypted.js +20 -0
- package/build/src/cookies/drivers/plain.d.ts +12 -1
- package/build/src/cookies/drivers/plain.js +20 -0
- package/build/src/cookies/drivers/signed.d.ts +12 -1
- package/build/src/cookies/drivers/signed.js +20 -0
- package/build/src/cookies/parser.d.ts +28 -1
- package/build/src/cookies/parser.js +98 -0
- package/build/src/cookies/serializer.d.ts +22 -1
- package/build/src/cookies/serializer.js +40 -0
- package/build/src/debug.d.ts +0 -1
- package/build/src/debug.js +8 -0
- package/build/src/define_config.d.ts +3 -1
- package/build/src/define_config.js +11 -0
- package/build/src/define_middleware.d.ts +5 -1
- package/build/src/define_middleware.js +18 -0
- package/build/src/exception_handler.d.ts +65 -1
- package/build/src/exception_handler.js +95 -0
- package/build/src/exceptions.d.ts +6 -1
- package/build/src/exceptions.js +11 -0
- package/build/src/helpers.d.ts +14 -1
- package/build/src/helpers.js +22 -0
- package/build/src/http_context/local_storage.d.ts +3 -1
- package/build/src/http_context/local_storage.js +25 -0
- package/build/src/http_context/main.d.ts +36 -1
- package/build/src/http_context/main.js +54 -0
- package/build/src/qs.d.ts +4 -1
- package/build/src/qs.js +12 -0
- package/build/src/redirect.d.ts +24 -1
- package/build/src/redirect.js +60 -0
- package/build/src/request.d.ts +466 -1
- package/build/src/request.js +542 -0
- package/build/src/response.d.ts +425 -2
- package/build/src/response.js +608 -7
- package/build/src/router/brisk.d.ts +22 -1
- package/build/src/router/brisk.js +42 -0
- package/build/src/router/executor.d.ts +4 -1
- package/build/src/router/executor.js +12 -0
- package/build/src/router/factories/use_return_value.d.ts +4 -1
- package/build/src/router/factories/use_return_value.js +16 -3
- package/build/src/router/group.d.ts +47 -1
- package/build/src/router/group.js +88 -0
- package/build/src/router/lookup_store/main.d.ts +32 -1
- package/build/src/router/lookup_store/main.js +49 -0
- package/build/src/router/lookup_store/route_finder.d.ts +13 -1
- package/build/src/router/lookup_store/route_finder.js +21 -0
- package/build/src/router/lookup_store/url_builder.d.ts +36 -1
- package/build/src/router/lookup_store/url_builder.js +97 -0
- package/build/src/router/main.d.ts +87 -1
- package/build/src/router/main.js +142 -0
- package/build/src/router/matchers.d.ts +13 -1
- package/build/src/router/matchers.js +21 -0
- package/build/src/router/parser.d.ts +3 -1
- package/build/src/router/parser.js +12 -0
- package/build/src/router/resource.d.ts +28 -1
- package/build/src/router/resource.js +90 -0
- package/build/src/router/route.d.ts +65 -1
- package/build/src/router/route.js +151 -2
- package/build/src/router/store.d.ts +54 -1
- package/build/src/router/store.js +107 -0
- package/build/src/server/factories/final_handler.d.ts +5 -1
- package/build/src/server/factories/final_handler.js +13 -0
- package/build/src/server/factories/middleware_handler.d.ts +3 -1
- package/build/src/server/factories/middleware_handler.js +11 -0
- package/build/src/server/factories/write_response.d.ts +4 -1
- package/build/src/server/factories/write_response.js +12 -0
- package/build/src/server/main.d.ts +48 -1
- package/build/src/server/main.js +128 -0
- package/build/src/types/base.d.ts +12 -1
- package/build/src/types/base.js +8 -0
- package/build/src/types/main.d.ts +0 -1
- package/build/src/types/main.js +8 -0
- package/build/src/types/middleware.d.ts +18 -1
- package/build/src/types/middleware.js +8 -0
- package/build/src/types/qs.d.ts +53 -1
- package/build/src/types/qs.js +8 -0
- package/build/src/types/request.d.ts +32 -1
- package/build/src/types/request.js +8 -0
- package/build/src/types/response.d.ts +27 -1
- package/build/src/types/response.js +8 -0
- package/build/src/types/route.d.ts +87 -1
- package/build/src/types/route.js +8 -0
- package/build/src/types/server.d.ts +35 -1
- package/build/src/types/server.js +8 -0
- package/package.json +44 -71
- package/build/factories/http_context.d.ts.map +0 -1
- package/build/factories/main.d.ts.map +0 -1
- package/build/factories/qs_parser_factory.d.ts.map +0 -1
- package/build/factories/request.d.ts.map +0 -1
- package/build/factories/response.d.ts.map +0 -1
- package/build/factories/router.d.ts.map +0 -1
- package/build/factories/server_factory.d.ts.map +0 -1
- package/build/index.d.ts.map +0 -1
- package/build/src/cookies/client.d.ts.map +0 -1
- package/build/src/cookies/drivers/encrypted.d.ts.map +0 -1
- package/build/src/cookies/drivers/plain.d.ts.map +0 -1
- package/build/src/cookies/drivers/signed.d.ts.map +0 -1
- package/build/src/cookies/parser.d.ts.map +0 -1
- package/build/src/cookies/serializer.d.ts.map +0 -1
- package/build/src/debug.d.ts.map +0 -1
- package/build/src/define_config.d.ts.map +0 -1
- package/build/src/define_middleware.d.ts.map +0 -1
- package/build/src/exception_handler.d.ts.map +0 -1
- package/build/src/exceptions.d.ts.map +0 -1
- package/build/src/helpers.d.ts.map +0 -1
- package/build/src/http_context/local_storage.d.ts.map +0 -1
- package/build/src/http_context/main.d.ts.map +0 -1
- package/build/src/qs.d.ts.map +0 -1
- package/build/src/redirect.d.ts.map +0 -1
- package/build/src/request.d.ts.map +0 -1
- package/build/src/response.d.ts.map +0 -1
- package/build/src/router/brisk.d.ts.map +0 -1
- package/build/src/router/executor.d.ts.map +0 -1
- package/build/src/router/factories/use_return_value.d.ts.map +0 -1
- package/build/src/router/group.d.ts.map +0 -1
- package/build/src/router/lookup_store/main.d.ts.map +0 -1
- package/build/src/router/lookup_store/route_finder.d.ts.map +0 -1
- package/build/src/router/lookup_store/url_builder.d.ts.map +0 -1
- package/build/src/router/main.d.ts.map +0 -1
- package/build/src/router/matchers.d.ts.map +0 -1
- package/build/src/router/parser.d.ts.map +0 -1
- package/build/src/router/resource.d.ts.map +0 -1
- package/build/src/router/route.d.ts.map +0 -1
- package/build/src/router/store.d.ts.map +0 -1
- package/build/src/server/factories/final_handler.d.ts.map +0 -1
- package/build/src/server/factories/middleware_handler.d.ts.map +0 -1
- package/build/src/server/factories/write_response.d.ts.map +0 -1
- package/build/src/server/main.d.ts.map +0 -1
- package/build/src/types/base.d.ts.map +0 -1
- package/build/src/types/main.d.ts.map +0 -1
- package/build/src/types/middleware.d.ts.map +0 -1
- package/build/src/types/qs.d.ts.map +0 -1
- package/build/src/types/request.d.ts.map +0 -1
- package/build/src/types/response.d.ts.map +0 -1
- package/build/src/types/route.d.ts.map +0 -1
- package/build/src/types/server.d.ts.map +0 -1
- package/factories/http_context.ts +0 -73
- package/factories/main.ts +0 -15
- package/factories/qs_parser_factory.ts +0 -54
- package/factories/request.ts +0 -101
- package/factories/response.ts +0 -106
- package/factories/router.ts +0 -61
- package/factories/server_factory.ts +0 -94
- package/index.ts +0 -23
- package/src/cookies/client.ts +0 -98
- package/src/cookies/drivers/encrypted.ts +0 -42
- package/src/cookies/drivers/plain.ts +0 -37
- package/src/cookies/drivers/signed.ts +0 -42
- package/src/cookies/parser.ts +0 -196
- package/src/cookies/serializer.ts +0 -98
- package/src/debug.ts +0 -11
- package/src/define_config.ts +0 -56
- package/src/define_middleware.ts +0 -61
- package/src/exception_handler.ts +0 -290
- package/src/exceptions.ts +0 -55
- package/src/helpers.ts +0 -108
- package/src/http_context/local_storage.ts +0 -50
- package/src/http_context/main.ts +0 -126
- package/src/qs.ts +0 -31
- package/src/redirect.ts +0 -181
- package/src/request.ts +0 -982
- package/src/response.ts +0 -1421
- package/src/router/brisk.ts +0 -113
- package/src/router/executor.ts +0 -36
- package/src/router/factories/use_return_value.ts +0 -26
- package/src/router/group.ts +0 -243
- package/src/router/lookup_store/main.ts +0 -102
- package/src/router/lookup_store/route_finder.ts +0 -60
- package/src/router/lookup_store/url_builder.ts +0 -250
- package/src/router/main.ts +0 -431
- package/src/router/matchers.ts +0 -40
- package/src/router/parser.ts +0 -20
- package/src/router/resource.ts +0 -277
- package/src/router/route.ts +0 -363
- package/src/router/store.ts +0 -239
- package/src/server/factories/final_handler.ts +0 -38
- package/src/server/factories/middleware_handler.ts +0 -23
- package/src/server/factories/write_response.ts +0 -26
- package/src/server/main.ts +0 -356
- package/src/types/base.ts +0 -30
- package/src/types/main.ts +0 -16
- package/src/types/middleware.ts +0 -59
- package/src/types/qs.ts +0 -85
- package/src/types/request.ts +0 -52
- package/src/types/response.ts +0 -57
- package/src/types/route.ts +0 -217
- package/src/types/server.ts +0 -92
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';
|
|
@@ -15,33 +23,82 @@ import { Redirect } from './redirect.js';
|
|
|
15
23
|
import { CookieSerializer } from './cookies/serializer.js';
|
|
16
24
|
import { E_HTTP_REQUEST_ABORTED } from './exceptions.js';
|
|
17
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
|
+
*/
|
|
18
30
|
export class Response extends Macroable {
|
|
19
31
|
request;
|
|
20
32
|
response;
|
|
33
|
+
/**
|
|
34
|
+
* Query string parser
|
|
35
|
+
*/
|
|
21
36
|
#qs;
|
|
37
|
+
/**
|
|
38
|
+
* Outgoing headers
|
|
39
|
+
*/
|
|
22
40
|
#headers = {};
|
|
41
|
+
/**
|
|
42
|
+
* Has explicit status been set
|
|
43
|
+
*/
|
|
23
44
|
#hasExplicitStatus = false;
|
|
45
|
+
/**
|
|
46
|
+
* Cookies serializer to serialize the outgoing cookies
|
|
47
|
+
*/
|
|
24
48
|
#cookieSerializer;
|
|
49
|
+
/**
|
|
50
|
+
* Router is used to make the redirect URLs from routes
|
|
51
|
+
*/
|
|
25
52
|
#router;
|
|
53
|
+
/**
|
|
54
|
+
* Response config
|
|
55
|
+
*/
|
|
26
56
|
#config;
|
|
57
|
+
/**
|
|
58
|
+
* Does response has body set that will written to the
|
|
59
|
+
* response socket at the end of the request
|
|
60
|
+
*/
|
|
27
61
|
get hasLazyBody() {
|
|
28
62
|
return !!(this.lazyBody.content || this.lazyBody.fileToStream || this.lazyBody.stream);
|
|
29
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Find if the response has non-stream content
|
|
66
|
+
*/
|
|
30
67
|
get hasContent() {
|
|
31
68
|
return !!this.lazyBody.content;
|
|
32
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns true when response body is set using "response.stream"
|
|
72
|
+
* method
|
|
73
|
+
*/
|
|
33
74
|
get hasStream() {
|
|
34
75
|
return !!this.lazyBody.stream;
|
|
35
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns true when response body is set using "response.download"
|
|
79
|
+
* or "response.attachment" methods
|
|
80
|
+
*/
|
|
36
81
|
get hasFileToStream() {
|
|
37
82
|
return !!this.lazyBody.fileToStream;
|
|
38
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Returns the response content. Check if the response
|
|
86
|
+
* has content using the "hasContent" method
|
|
87
|
+
*/
|
|
39
88
|
get content() {
|
|
40
89
|
return this.lazyBody.content;
|
|
41
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns reference to the stream set using "response.stream"
|
|
93
|
+
* method
|
|
94
|
+
*/
|
|
42
95
|
get outgoingStream() {
|
|
43
96
|
return this.lazyBody.stream?.[0];
|
|
44
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns reference to the file path set using "response.stream"
|
|
100
|
+
* method.
|
|
101
|
+
*/
|
|
45
102
|
get fileToStream() {
|
|
46
103
|
return this.lazyBody.fileToStream
|
|
47
104
|
? {
|
|
@@ -50,7 +107,16 @@ export class Response extends Macroable {
|
|
|
50
107
|
}
|
|
51
108
|
: undefined;
|
|
52
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
|
+
*/
|
|
53
115
|
lazyBody = {};
|
|
116
|
+
/**
|
|
117
|
+
* The ctx will be set by the context itself. It creates a circular
|
|
118
|
+
* reference
|
|
119
|
+
*/
|
|
54
120
|
ctx;
|
|
55
121
|
constructor(request, response, encryption, config, router, qs) {
|
|
56
122
|
super();
|
|
@@ -61,30 +127,68 @@ export class Response extends Macroable {
|
|
|
61
127
|
this.#router = router;
|
|
62
128
|
this.#cookieSerializer = new CookieSerializer(encryption);
|
|
63
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
|
+
*/
|
|
64
135
|
get finished() {
|
|
65
136
|
return this.response.writableFinished;
|
|
66
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
|
+
*/
|
|
67
143
|
get headersSent() {
|
|
68
144
|
return this.response.headersSent;
|
|
69
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
|
+
*/
|
|
70
151
|
get isPending() {
|
|
71
152
|
return !this.headersSent && !this.finished;
|
|
72
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Normalizes header value to a string or an array of string
|
|
156
|
+
*/
|
|
73
157
|
#castHeaderValue(value) {
|
|
74
158
|
return Array.isArray(value) ? value.map(String) : String(value);
|
|
75
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Ends the response by flushing headers and writing body
|
|
162
|
+
*/
|
|
76
163
|
#endResponse(body, statusCode) {
|
|
77
|
-
this.
|
|
164
|
+
this.writeHead(statusCode);
|
|
165
|
+
// avoid ArgumentsAdaptorTrampoline from V8 (inspired by fastify)
|
|
78
166
|
const res = this.response;
|
|
79
167
|
res.end(body, null, null);
|
|
80
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
|
+
*/
|
|
81
179
|
#getDataType(content) {
|
|
82
180
|
if (Buffer.isBuffer(content)) {
|
|
83
181
|
return 'buffer';
|
|
84
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Date instance
|
|
185
|
+
*/
|
|
85
186
|
if (content instanceof Date) {
|
|
86
187
|
return 'date';
|
|
87
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Regular expression
|
|
191
|
+
*/
|
|
88
192
|
if (content instanceof RegExp) {
|
|
89
193
|
return 'regexp';
|
|
90
194
|
}
|
|
@@ -95,17 +199,34 @@ export class Response extends Macroable {
|
|
|
95
199
|
dataType === 'bigint') {
|
|
96
200
|
return dataType;
|
|
97
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Object
|
|
204
|
+
*/
|
|
98
205
|
if (dataType === 'object') {
|
|
99
206
|
return 'object';
|
|
100
207
|
}
|
|
101
208
|
throw new RuntimeException(`Cannot serialize "${dataType}" to HTTP response`);
|
|
102
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
|
+
*/
|
|
103
216
|
writeBody(content, generateEtag, jsonpCallbackName) {
|
|
104
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
|
+
*/
|
|
105
222
|
if (hasEmptyBody) {
|
|
106
223
|
this.safeStatus(204);
|
|
107
224
|
}
|
|
108
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
|
+
*/
|
|
109
230
|
if (statusCode && (statusCode < 200 || statusCode === 204 || statusCode === 304)) {
|
|
110
231
|
this.removeHeader('Content-Type');
|
|
111
232
|
this.removeHeader('Content-Length');
|
|
@@ -113,12 +234,27 @@ export class Response extends Macroable {
|
|
|
113
234
|
this.#endResponse();
|
|
114
235
|
return;
|
|
115
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Body is empty and status code is not "204", "304" and neither under 200.
|
|
239
|
+
*/
|
|
116
240
|
if (hasEmptyBody) {
|
|
117
241
|
this.removeHeader('Content-Length');
|
|
118
242
|
this.#endResponse();
|
|
119
243
|
return;
|
|
120
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
|
+
*/
|
|
121
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
|
+
*/
|
|
122
258
|
if (dataType === 'object') {
|
|
123
259
|
content = json.safeStringify(content);
|
|
124
260
|
}
|
|
@@ -131,13 +267,39 @@ export class Response extends Macroable {
|
|
|
131
267
|
else if (dataType === 'date') {
|
|
132
268
|
content = content.toISOString();
|
|
133
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
|
+
*/
|
|
134
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
|
+
*/
|
|
135
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
|
|
136
288
|
content = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${content});`;
|
|
137
289
|
}
|
|
290
|
+
/*
|
|
291
|
+
* ----------------------------------------
|
|
292
|
+
* FINALY GENERATE AN ETAG
|
|
293
|
+
* ----------------------------------------
|
|
294
|
+
*
|
|
295
|
+
* Generate etag if instructed.
|
|
296
|
+
*/
|
|
138
297
|
if (generateEtag) {
|
|
139
298
|
this.setEtag(content);
|
|
140
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* End response when cache is fresh
|
|
302
|
+
*/
|
|
141
303
|
if (generateEtag && this.fresh()) {
|
|
142
304
|
this.removeHeader('Content-Type');
|
|
143
305
|
this.removeHeader('Content-Length');
|
|
@@ -145,7 +307,29 @@ export class Response extends Macroable {
|
|
|
145
307
|
this.#endResponse(null, 304);
|
|
146
308
|
return;
|
|
147
309
|
}
|
|
310
|
+
/*
|
|
311
|
+
* ----------------------------------------
|
|
312
|
+
* SET CONTENT-LENGTH HEADER
|
|
313
|
+
* ----------------------------------------
|
|
314
|
+
*/
|
|
148
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
|
+
*/
|
|
149
333
|
if (jsonpCallbackName) {
|
|
150
334
|
this.header('X-Content-Type-Options', 'nosniff');
|
|
151
335
|
this.safeHeader('Content-Type', 'text/javascript; charset=utf-8');
|
|
@@ -173,53 +357,110 @@ export class Response extends Macroable {
|
|
|
173
357
|
}
|
|
174
358
|
this.#endResponse(content);
|
|
175
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Stream the body to the response and handles cleaning up the stream
|
|
362
|
+
*/
|
|
176
363
|
streamBody(body, errorCallback) {
|
|
177
364
|
return new Promise((resolve) => {
|
|
178
365
|
let finished = false;
|
|
366
|
+
/*
|
|
367
|
+
* Listen for errors on the stream and properly destroy
|
|
368
|
+
* stream
|
|
369
|
+
*/
|
|
179
370
|
body.on('error', (error) => {
|
|
371
|
+
/* c8 ignore next 3 */
|
|
180
372
|
if (finished) {
|
|
181
373
|
return;
|
|
182
374
|
}
|
|
183
375
|
finished = true;
|
|
184
376
|
destroy(body);
|
|
185
377
|
this.type('text');
|
|
186
|
-
if (
|
|
187
|
-
|
|
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
|
+
}
|
|
188
385
|
}
|
|
189
386
|
else {
|
|
190
|
-
this
|
|
191
|
-
resolve();
|
|
387
|
+
this.response.destroy();
|
|
192
388
|
}
|
|
389
|
+
resolve();
|
|
193
390
|
});
|
|
194
|
-
|
|
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
|
+
*/
|
|
195
403
|
onFinished(this.response, () => {
|
|
196
404
|
finished = true;
|
|
197
405
|
destroy(body);
|
|
198
406
|
});
|
|
407
|
+
/*
|
|
408
|
+
* Pipe stream
|
|
409
|
+
*/
|
|
199
410
|
this.flushHeaders();
|
|
200
411
|
body.pipe(this.response);
|
|
201
412
|
});
|
|
202
413
|
}
|
|
414
|
+
/**
|
|
415
|
+
* Downloads a file by streaming it to the response
|
|
416
|
+
*/
|
|
203
417
|
async streamFileForDownload(filePath, generateEtag, errorCallback) {
|
|
204
418
|
try {
|
|
205
419
|
const stats = await stat(filePath);
|
|
206
420
|
if (!stats || !stats.isFile()) {
|
|
207
421
|
throw new TypeError('response.download only accepts path to a file');
|
|
208
422
|
}
|
|
423
|
+
/*
|
|
424
|
+
* Set appropriate headers
|
|
425
|
+
*/
|
|
209
426
|
this.header('Last-Modified', stats.mtime.toUTCString());
|
|
210
427
|
this.type(extname(filePath));
|
|
428
|
+
/*
|
|
429
|
+
* Set the etag when instructed.
|
|
430
|
+
*/
|
|
211
431
|
if (generateEtag) {
|
|
212
432
|
this.setEtag(stats, true);
|
|
213
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
|
+
*/
|
|
214
443
|
if (this.request.method === 'HEAD') {
|
|
215
444
|
this.#endResponse(null, generateEtag && this.fresh() ? 304 : 200);
|
|
216
445
|
return;
|
|
217
446
|
}
|
|
447
|
+
/*
|
|
448
|
+
* Regardless of request method, if we are using etags and
|
|
449
|
+
* cache is fresh, then we must respond with 304
|
|
450
|
+
*/
|
|
218
451
|
if (generateEtag && this.fresh()) {
|
|
219
452
|
this.#endResponse(null, 304);
|
|
220
453
|
return;
|
|
221
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
|
+
*/
|
|
222
460
|
this.header('Content-length', stats.size);
|
|
461
|
+
/*
|
|
462
|
+
* Finally stream the file
|
|
463
|
+
*/
|
|
223
464
|
return this.streamBody(createReadStream(filePath), errorCallback);
|
|
224
465
|
}
|
|
225
466
|
catch (error) {
|
|
@@ -233,20 +474,55 @@ export class Response extends Macroable {
|
|
|
233
474
|
}
|
|
234
475
|
}
|
|
235
476
|
}
|
|
236
|
-
|
|
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) {
|
|
237
495
|
this.response.writeHead(statusCode || this.response.statusCode, this.#headers);
|
|
238
496
|
return this;
|
|
239
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Returns the existing value for a given HTTP response
|
|
500
|
+
* header.
|
|
501
|
+
*/
|
|
240
502
|
getHeader(key) {
|
|
241
503
|
const value = this.#headers[key.toLowerCase()];
|
|
242
504
|
return value === undefined ? this.response.getHeader(key) : value;
|
|
243
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Get response headers
|
|
508
|
+
*/
|
|
244
509
|
getHeaders() {
|
|
245
510
|
return {
|
|
246
511
|
...this.response.getHeaders(),
|
|
247
512
|
...this.#headers,
|
|
248
513
|
};
|
|
249
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
|
+
*/
|
|
250
526
|
header(key, value) {
|
|
251
527
|
if (value === null || value === undefined) {
|
|
252
528
|
return this;
|
|
@@ -254,6 +530,17 @@ export class Response extends Macroable {
|
|
|
254
530
|
this.#headers[key.toLowerCase()] = this.#castHeaderValue(value);
|
|
255
531
|
return this;
|
|
256
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
|
+
*/
|
|
257
544
|
append(key, value) {
|
|
258
545
|
if (value === null || value === undefined) {
|
|
259
546
|
return this;
|
|
@@ -261,6 +548,10 @@ export class Response extends Macroable {
|
|
|
261
548
|
key = key.toLowerCase();
|
|
262
549
|
let existingHeader = this.getHeader(key);
|
|
263
550
|
let casted = this.#castHeaderValue(value);
|
|
551
|
+
/**
|
|
552
|
+
* If there isn't any header, then setHeader right
|
|
553
|
+
* away
|
|
554
|
+
*/
|
|
264
555
|
if (!existingHeader) {
|
|
265
556
|
this.#headers[key] = casted;
|
|
266
557
|
return this;
|
|
@@ -272,12 +563,18 @@ export class Response extends Macroable {
|
|
|
272
563
|
this.#headers[key] = casted;
|
|
273
564
|
return this;
|
|
274
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Adds HTTP response header, when it doesn't exists already.
|
|
568
|
+
*/
|
|
275
569
|
safeHeader(key, value) {
|
|
276
570
|
if (!this.getHeader(key)) {
|
|
277
571
|
this.header(key, value);
|
|
278
572
|
}
|
|
279
573
|
return this;
|
|
280
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Removes the existing response header from being sent.
|
|
577
|
+
*/
|
|
281
578
|
removeHeader(key) {
|
|
282
579
|
key = key.toLowerCase();
|
|
283
580
|
this.response.removeHeader(key);
|
|
@@ -286,14 +583,24 @@ export class Response extends Macroable {
|
|
|
286
583
|
}
|
|
287
584
|
return this;
|
|
288
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Returns the status code for the response
|
|
588
|
+
*/
|
|
289
589
|
getStatus() {
|
|
290
590
|
return this.response.statusCode;
|
|
291
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Set HTTP status code
|
|
594
|
+
*/
|
|
292
595
|
status(code) {
|
|
293
596
|
this.#hasExplicitStatus = true;
|
|
294
597
|
this.response.statusCode = code;
|
|
295
598
|
return this;
|
|
296
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Set's status code only when it's not explictly
|
|
602
|
+
* set
|
|
603
|
+
*/
|
|
297
604
|
safeStatus(code) {
|
|
298
605
|
if (this.#hasExplicitStatus) {
|
|
299
606
|
return this;
|
|
@@ -301,19 +608,65 @@ export class Response extends Macroable {
|
|
|
301
608
|
this.response.statusCode = code;
|
|
302
609
|
return this;
|
|
303
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
|
+
*/
|
|
304
623
|
type(type, charset) {
|
|
305
624
|
type = charset ? `${type}; charset=${charset}` : type;
|
|
306
625
|
this.header('Content-Type', mime.contentType(type));
|
|
307
626
|
return this;
|
|
308
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* Set the Vary HTTP header
|
|
630
|
+
*/
|
|
309
631
|
vary(field) {
|
|
310
632
|
vary(this.response, field);
|
|
311
633
|
return this;
|
|
312
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
|
+
*/
|
|
313
641
|
setEtag(body, weak = false) {
|
|
314
642
|
this.header('Etag', etag(body, { weak }));
|
|
315
643
|
return this;
|
|
316
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
|
+
*/
|
|
317
670
|
fresh() {
|
|
318
671
|
if (this.request.method && !CACHEABLE_HTTP_METHODS.includes(this.request.method)) {
|
|
319
672
|
return false;
|
|
@@ -324,35 +677,124 @@ export class Response extends Macroable {
|
|
|
324
677
|
}
|
|
325
678
|
return false;
|
|
326
679
|
}
|
|
680
|
+
/**
|
|
681
|
+
* Returns the response body. Returns null when response
|
|
682
|
+
* body is a stream
|
|
683
|
+
*/
|
|
327
684
|
getBody() {
|
|
328
685
|
if (this.lazyBody.content) {
|
|
329
686
|
return this.lazyBody.content[0];
|
|
330
687
|
}
|
|
331
688
|
return null;
|
|
332
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
|
+
*/
|
|
333
697
|
send(body, generateEtag = this.#config.etag) {
|
|
334
698
|
this.lazyBody.content = [body, generateEtag];
|
|
335
699
|
}
|
|
700
|
+
/**
|
|
701
|
+
* Alias of [[send]]
|
|
702
|
+
*/
|
|
336
703
|
json(body, generateEtag = this.#config.etag) {
|
|
337
704
|
return this.send(body, generateEtag);
|
|
338
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
|
+
*/
|
|
339
718
|
jsonp(body, callbackName = this.#config.jsonpCallbackName, generateEtag = this.#config.etag) {
|
|
340
719
|
this.lazyBody.content = [body, generateEtag, callbackName];
|
|
341
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
|
+
*/
|
|
342
745
|
stream(body, errorCallback) {
|
|
343
746
|
if (typeof body.pipe !== 'function' || !body.readable || typeof body.read !== 'function') {
|
|
344
747
|
throw new TypeError('response.stream accepts a readable stream only');
|
|
345
748
|
}
|
|
346
749
|
this.lazyBody.stream = [body, errorCallback];
|
|
347
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
|
+
*/
|
|
348
776
|
download(filePath, generateEtag = this.#config.etag, errorCallback) {
|
|
349
777
|
this.lazyBody.fileToStream = [filePath, generateEtag, errorCallback];
|
|
350
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
|
+
*/
|
|
351
785
|
attachment(filePath, name, disposition, generateEtag, errorCallback) {
|
|
352
786
|
name = name || filePath;
|
|
353
787
|
this.header('Content-Disposition', contentDisposition(name, { type: disposition }));
|
|
354
788
|
return this.download(filePath, generateEtag, errorCallback);
|
|
355
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* Set the location header.
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```js
|
|
795
|
+
* response.location('/login')
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
356
798
|
location(url) {
|
|
357
799
|
this.header('Location', url);
|
|
358
800
|
return this;
|
|
@@ -370,19 +812,35 @@ export class Response extends Macroable {
|
|
|
370
812
|
}
|
|
371
813
|
return handler;
|
|
372
814
|
}
|
|
815
|
+
/**
|
|
816
|
+
* Abort the request with custom body and a status code. 400 is
|
|
817
|
+
* used when status is not defined
|
|
818
|
+
*/
|
|
373
819
|
abort(body, status) {
|
|
374
820
|
throw E_HTTP_REQUEST_ABORTED.invoke(body, status || 400);
|
|
375
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Abort the request with custom body and a status code when
|
|
824
|
+
* passed condition returns `true`
|
|
825
|
+
*/
|
|
376
826
|
abortIf(condition, body, status) {
|
|
377
827
|
if (condition) {
|
|
378
828
|
this.abort(body, status);
|
|
379
829
|
}
|
|
380
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* Abort the request with custom body and a status code when
|
|
833
|
+
* passed condition returns `false`
|
|
834
|
+
*/
|
|
381
835
|
abortUnless(condition, body, status) {
|
|
382
836
|
if (!condition) {
|
|
383
837
|
this.abort(body, status);
|
|
384
838
|
}
|
|
385
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Set signed cookie as the response header. The inline options overrides
|
|
842
|
+
* all options from the config.
|
|
843
|
+
*/
|
|
386
844
|
cookie(key, value, options) {
|
|
387
845
|
options = Object.assign({}, this.#config.cookie, options);
|
|
388
846
|
const serialized = this.#cookieSerializer.sign(key, value, options);
|
|
@@ -392,6 +850,10 @@ export class Response extends Macroable {
|
|
|
392
850
|
this.append('set-cookie', serialized);
|
|
393
851
|
return this;
|
|
394
852
|
}
|
|
853
|
+
/**
|
|
854
|
+
* Set encrypted cookie as the response header. The inline options overrides
|
|
855
|
+
* all options from the config.
|
|
856
|
+
*/
|
|
395
857
|
encryptedCookie(key, value, options) {
|
|
396
858
|
options = Object.assign({}, this.#config.cookie, options);
|
|
397
859
|
const serialized = this.#cookieSerializer.encrypt(key, value, options);
|
|
@@ -401,6 +863,10 @@ export class Response extends Macroable {
|
|
|
401
863
|
this.append('set-cookie', serialized);
|
|
402
864
|
return this;
|
|
403
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* Set unsigned cookie as the response header. The inline options overrides
|
|
868
|
+
* all options from the config.
|
|
869
|
+
*/
|
|
404
870
|
plainCookie(key, value, options) {
|
|
405
871
|
options = Object.assign({}, this.#config.cookie, options);
|
|
406
872
|
const serialized = this.#cookieSerializer.encode(key, value, options);
|
|
@@ -410,6 +876,9 @@ export class Response extends Macroable {
|
|
|
410
876
|
this.append('set-cookie', serialized);
|
|
411
877
|
return this;
|
|
412
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Clear existing cookie.
|
|
881
|
+
*/
|
|
413
882
|
clearCookie(key, options) {
|
|
414
883
|
options = Object.assign({}, this.#config.cookie, options);
|
|
415
884
|
options.expires = new Date(1);
|
|
@@ -418,6 +887,12 @@ export class Response extends Macroable {
|
|
|
418
887
|
this.append('set-cookie', serialized);
|
|
419
888
|
return this;
|
|
420
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
|
+
*/
|
|
421
896
|
finish() {
|
|
422
897
|
if (!this.isPending) {
|
|
423
898
|
return;
|
|
@@ -436,170 +911,296 @@ export class Response extends Macroable {
|
|
|
436
911
|
}
|
|
437
912
|
this.#endResponse();
|
|
438
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Shorthand method to finish request with "100" status code
|
|
916
|
+
*/
|
|
439
917
|
continue() {
|
|
440
918
|
this.status(100);
|
|
441
919
|
return this.send(null, false);
|
|
442
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* Shorthand method to finish request with "101" status code
|
|
923
|
+
*/
|
|
443
924
|
switchingProtocols() {
|
|
444
925
|
this.status(101);
|
|
445
926
|
return this.send(null, false);
|
|
446
927
|
}
|
|
928
|
+
/**
|
|
929
|
+
* Shorthand method to finish request with "200" status code
|
|
930
|
+
*/
|
|
447
931
|
ok(body, generateEtag) {
|
|
448
932
|
this.status(200);
|
|
449
933
|
return this.send(body, generateEtag);
|
|
450
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* Shorthand method to finish request with "201" status code
|
|
937
|
+
*/
|
|
451
938
|
created(body, generateEtag) {
|
|
452
939
|
this.status(201);
|
|
453
940
|
return this.send(body, generateEtag);
|
|
454
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Shorthand method to finish request with "202" status code
|
|
944
|
+
*/
|
|
455
945
|
accepted(body, generateEtag) {
|
|
456
946
|
this.status(202);
|
|
457
947
|
return this.send(body, generateEtag);
|
|
458
948
|
}
|
|
949
|
+
/**
|
|
950
|
+
* Shorthand method to finish request with "203" status code
|
|
951
|
+
*/
|
|
459
952
|
nonAuthoritativeInformation(body, generateEtag) {
|
|
460
953
|
this.status(203);
|
|
461
954
|
return this.send(body, generateEtag);
|
|
462
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* Shorthand method to finish request with "204" status code
|
|
958
|
+
*/
|
|
463
959
|
noContent() {
|
|
464
960
|
this.status(204);
|
|
465
961
|
return this.send(null, false);
|
|
466
962
|
}
|
|
963
|
+
/**
|
|
964
|
+
* Shorthand method to finish request with "205" status code
|
|
965
|
+
*/
|
|
467
966
|
resetContent() {
|
|
468
967
|
this.status(205);
|
|
469
968
|
return this.send(null, false);
|
|
470
969
|
}
|
|
970
|
+
/**
|
|
971
|
+
* Shorthand method to finish request with "206" status code
|
|
972
|
+
*/
|
|
471
973
|
partialContent(body, generateEtag) {
|
|
472
974
|
this.status(206);
|
|
473
975
|
return this.send(body, generateEtag);
|
|
474
976
|
}
|
|
977
|
+
/**
|
|
978
|
+
* Shorthand method to finish request with "300" status code
|
|
979
|
+
*/
|
|
475
980
|
multipleChoices(body, generateEtag) {
|
|
476
981
|
this.status(300);
|
|
477
982
|
return this.send(body, generateEtag);
|
|
478
983
|
}
|
|
984
|
+
/**
|
|
985
|
+
* Shorthand method to finish request with "301" status code
|
|
986
|
+
*/
|
|
479
987
|
movedPermanently(body, generateEtag) {
|
|
480
988
|
this.status(301);
|
|
481
989
|
return this.send(body, generateEtag);
|
|
482
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* Shorthand method to finish request with "302" status code
|
|
993
|
+
*/
|
|
483
994
|
movedTemporarily(body, generateEtag) {
|
|
484
995
|
this.status(302);
|
|
485
996
|
return this.send(body, generateEtag);
|
|
486
997
|
}
|
|
998
|
+
/**
|
|
999
|
+
* Shorthand method to finish request with "303" status code
|
|
1000
|
+
*/
|
|
487
1001
|
seeOther(body, generateEtag) {
|
|
488
1002
|
this.status(303);
|
|
489
1003
|
return this.send(body, generateEtag);
|
|
490
1004
|
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Shorthand method to finish request with "304" status code
|
|
1007
|
+
*/
|
|
491
1008
|
notModified(body, generateEtag) {
|
|
492
1009
|
this.status(304);
|
|
493
1010
|
return this.send(body, generateEtag);
|
|
494
1011
|
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Shorthand method to finish request with "305" status code
|
|
1014
|
+
*/
|
|
495
1015
|
useProxy(body, generateEtag) {
|
|
496
1016
|
this.status(305);
|
|
497
1017
|
return this.send(body, generateEtag);
|
|
498
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Shorthand method to finish request with "307" status code
|
|
1021
|
+
*/
|
|
499
1022
|
temporaryRedirect(body, generateEtag) {
|
|
500
1023
|
this.status(307);
|
|
501
1024
|
return this.send(body, generateEtag);
|
|
502
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Shorthand method to finish request with "400" status code
|
|
1028
|
+
*/
|
|
503
1029
|
badRequest(body, generateEtag) {
|
|
504
1030
|
this.status(400);
|
|
505
1031
|
return this.send(body, generateEtag);
|
|
506
1032
|
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Shorthand method to finish request with "401" status code
|
|
1035
|
+
*/
|
|
507
1036
|
unauthorized(body, generateEtag) {
|
|
508
1037
|
this.status(401);
|
|
509
1038
|
return this.send(body, generateEtag);
|
|
510
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Shorthand method to finish request with "402" status code
|
|
1042
|
+
*/
|
|
511
1043
|
paymentRequired(body, generateEtag) {
|
|
512
1044
|
this.status(402);
|
|
513
1045
|
return this.send(body, generateEtag);
|
|
514
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Shorthand method to finish request with "403" status code
|
|
1049
|
+
*/
|
|
515
1050
|
forbidden(body, generateEtag) {
|
|
516
1051
|
this.status(403);
|
|
517
1052
|
return this.send(body, generateEtag);
|
|
518
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Shorthand method to finish request with "404" status code
|
|
1056
|
+
*/
|
|
519
1057
|
notFound(body, generateEtag) {
|
|
520
1058
|
this.status(404);
|
|
521
1059
|
return this.send(body, generateEtag);
|
|
522
1060
|
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Shorthand method to finish request with "405" status code
|
|
1063
|
+
*/
|
|
523
1064
|
methodNotAllowed(body, generateEtag) {
|
|
524
1065
|
this.status(405);
|
|
525
1066
|
return this.send(body, generateEtag);
|
|
526
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Shorthand method to finish request with "406" status code
|
|
1070
|
+
*/
|
|
527
1071
|
notAcceptable(body, generateEtag) {
|
|
528
1072
|
this.status(406);
|
|
529
1073
|
return this.send(body, generateEtag);
|
|
530
1074
|
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Shorthand method to finish request with "407" status code
|
|
1077
|
+
*/
|
|
531
1078
|
proxyAuthenticationRequired(body, generateEtag) {
|
|
532
1079
|
this.status(407);
|
|
533
1080
|
return this.send(body, generateEtag);
|
|
534
1081
|
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Shorthand method to finish request with "408" status code
|
|
1084
|
+
*/
|
|
535
1085
|
requestTimeout(body, generateEtag) {
|
|
536
1086
|
this.status(408);
|
|
537
1087
|
return this.send(body, generateEtag);
|
|
538
1088
|
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Shorthand method to finish request with "409" status code
|
|
1091
|
+
*/
|
|
539
1092
|
conflict(body, generateEtag) {
|
|
540
1093
|
this.status(409);
|
|
541
1094
|
return this.send(body, generateEtag);
|
|
542
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Shorthand method to finish request with "401" status code
|
|
1098
|
+
*/
|
|
543
1099
|
gone(body, generateEtag) {
|
|
544
1100
|
this.status(410);
|
|
545
1101
|
return this.send(body, generateEtag);
|
|
546
1102
|
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Shorthand method to finish request with "411" status code
|
|
1105
|
+
*/
|
|
547
1106
|
lengthRequired(body, generateEtag) {
|
|
548
1107
|
this.status(411);
|
|
549
1108
|
return this.send(body, generateEtag);
|
|
550
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Shorthand method to finish request with "412" status code
|
|
1112
|
+
*/
|
|
551
1113
|
preconditionFailed(body, generateEtag) {
|
|
552
1114
|
this.status(412);
|
|
553
1115
|
return this.send(body, generateEtag);
|
|
554
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Shorthand method to finish request with "413" status code
|
|
1119
|
+
*/
|
|
555
1120
|
requestEntityTooLarge(body, generateEtag) {
|
|
556
1121
|
this.status(413);
|
|
557
1122
|
return this.send(body, generateEtag);
|
|
558
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Shorthand method to finish request with "414" status code
|
|
1126
|
+
*/
|
|
559
1127
|
requestUriTooLong(body, generateEtag) {
|
|
560
1128
|
this.status(414);
|
|
561
1129
|
return this.send(body, generateEtag);
|
|
562
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Shorthand method to finish request with "415" status code
|
|
1133
|
+
*/
|
|
563
1134
|
unsupportedMediaType(body, generateEtag) {
|
|
564
1135
|
this.status(415);
|
|
565
1136
|
return this.send(body, generateEtag);
|
|
566
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Shorthand method to finish request with "416" status code
|
|
1140
|
+
*/
|
|
567
1141
|
requestedRangeNotSatisfiable(body, generateEtag) {
|
|
568
1142
|
this.status(416);
|
|
569
1143
|
return this.send(body, generateEtag);
|
|
570
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Shorthand method to finish request with "417" status code
|
|
1147
|
+
*/
|
|
571
1148
|
expectationFailed(body, generateEtag) {
|
|
572
1149
|
this.status(417);
|
|
573
1150
|
return this.send(body, generateEtag);
|
|
574
1151
|
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Shorthand method to finish request with "422" status code
|
|
1154
|
+
*/
|
|
575
1155
|
unprocessableEntity(body, generateEtag) {
|
|
576
1156
|
this.status(422);
|
|
577
1157
|
return this.send(body, generateEtag);
|
|
578
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Shorthand method to finish request with "429" status code
|
|
1161
|
+
*/
|
|
579
1162
|
tooManyRequests(body, generateEtag) {
|
|
580
1163
|
this.status(429);
|
|
581
1164
|
return this.send(body, generateEtag);
|
|
582
1165
|
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Shorthand method to finish request with "500" status code
|
|
1168
|
+
*/
|
|
583
1169
|
internalServerError(body, generateEtag) {
|
|
584
1170
|
this.status(500);
|
|
585
1171
|
return this.send(body, generateEtag);
|
|
586
1172
|
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Shorthand method to finish request with "501" status code
|
|
1175
|
+
*/
|
|
587
1176
|
notImplemented(body, generateEtag) {
|
|
588
1177
|
this.status(501);
|
|
589
1178
|
return this.send(body, generateEtag);
|
|
590
1179
|
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Shorthand method to finish request with "502" status code
|
|
1182
|
+
*/
|
|
591
1183
|
badGateway(body, generateEtag) {
|
|
592
1184
|
this.status(502);
|
|
593
1185
|
return this.send(body, generateEtag);
|
|
594
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Shorthand method to finish request with "503" status code
|
|
1189
|
+
*/
|
|
595
1190
|
serviceUnavailable(body, generateEtag) {
|
|
596
1191
|
this.status(503);
|
|
597
1192
|
return this.send(body, generateEtag);
|
|
598
1193
|
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Shorthand method to finish request with "504" status code
|
|
1196
|
+
*/
|
|
599
1197
|
gatewayTimeout(body, generateEtag) {
|
|
600
1198
|
this.status(504);
|
|
601
1199
|
return this.send(body, generateEtag);
|
|
602
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Shorthand method to finish request with "505" status code
|
|
1203
|
+
*/
|
|
603
1204
|
httpVersionNotSupported(body, generateEtag) {
|
|
604
1205
|
this.status(505);
|
|
605
1206
|
return this.send(body, generateEtag);
|