@adonisjs/http-server 6.8.2-1 → 6.8.2-11
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 +427 -2
- 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 +29 -2
- 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
|
@@ -1,57 +1,73 @@
|
|
|
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 is from '@sindresorhus/is';
|
|
2
10
|
import { parseRange } from './helpers.js';
|
|
3
11
|
import * as errors from './exceptions.js';
|
|
12
|
+
/**
|
|
13
|
+
* The base HTTP exception handler one can inherit from to handle
|
|
14
|
+
* HTTP exceptions.
|
|
15
|
+
*
|
|
16
|
+
* The HTTP exception handler has support for
|
|
17
|
+
*
|
|
18
|
+
* - Ability to render exceptions by calling the render method on the exception.
|
|
19
|
+
* - Rendering status pages
|
|
20
|
+
* - Pretty printing errors during development
|
|
21
|
+
* - Transforming errors to JSON or HTML using content negotiation
|
|
22
|
+
* - Reporting errors
|
|
23
|
+
*/
|
|
4
24
|
export class ExceptionHandler {
|
|
25
|
+
/**
|
|
26
|
+
* Computed from the status pages property
|
|
27
|
+
*/
|
|
28
|
+
#expandedStatusPages;
|
|
29
|
+
/**
|
|
30
|
+
* Whether or not to render debug info. When set to true, the errors
|
|
31
|
+
* will have the complete error stack.
|
|
32
|
+
*/
|
|
5
33
|
debug = process.env.NODE_ENV !== 'production';
|
|
34
|
+
/**
|
|
35
|
+
* Whether or not to render status pages. When set to true, the unhandled
|
|
36
|
+
* errors with matching status codes will be rendered using a status
|
|
37
|
+
* page.
|
|
38
|
+
*/
|
|
6
39
|
renderStatusPages = process.env.NODE_ENV === 'production';
|
|
40
|
+
/**
|
|
41
|
+
* A collection of error status code range and the view to render.
|
|
42
|
+
*/
|
|
7
43
|
statusPages = {};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (this.isDebuggingEnabled(ctx)) {
|
|
12
|
-
const { default: Youch } = await import('youch');
|
|
13
|
-
const html = await new Youch(error, ctx.request.request).toHTML();
|
|
14
|
-
ctx.response.status(error.status).send(html);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
ctx.response.status(error.status).send(`<p> ${error.message} </p>`);
|
|
18
|
-
},
|
|
19
|
-
json: async (error, ctx) => {
|
|
20
|
-
if (this.isDebuggingEnabled(ctx)) {
|
|
21
|
-
const { default: Youch } = await import('youch');
|
|
22
|
-
const json = await new Youch(error, ctx.request.request).toJSON();
|
|
23
|
-
ctx.response.status(error.status).send(json.error);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
ctx.response.status(error.status).send({ message: error.message });
|
|
27
|
-
},
|
|
28
|
-
json_api: async (error, ctx) => {
|
|
29
|
-
if (this.isDebuggingEnabled(ctx)) {
|
|
30
|
-
const { default: Youch } = await import('youch');
|
|
31
|
-
const json = await new Youch(error, ctx.request.request).toJSON();
|
|
32
|
-
ctx.response.status(error.status).send(json.error);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
ctx.response.status(error.status).send({
|
|
36
|
-
errors: [
|
|
37
|
-
{
|
|
38
|
-
title: error.message,
|
|
39
|
-
code: error.code,
|
|
40
|
-
status: error.status,
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
});
|
|
44
|
-
},
|
|
45
|
-
};
|
|
44
|
+
/**
|
|
45
|
+
* Enable/disable errors reporting
|
|
46
|
+
*/
|
|
46
47
|
reportErrors = true;
|
|
48
|
+
/**
|
|
49
|
+
* An array of exception classes to ignore when
|
|
50
|
+
* reporting an error
|
|
51
|
+
*/
|
|
47
52
|
ignoreExceptions = [
|
|
48
53
|
errors.E_HTTP_EXCEPTION,
|
|
49
54
|
errors.E_ROUTE_NOT_FOUND,
|
|
50
55
|
errors.E_CANNOT_LOOKUP_ROUTE,
|
|
51
56
|
errors.E_HTTP_REQUEST_ABORTED,
|
|
52
57
|
];
|
|
58
|
+
/**
|
|
59
|
+
* An array of HTTP status codes to ignore when reporting
|
|
60
|
+
* an error
|
|
61
|
+
*/
|
|
53
62
|
ignoreStatuses = [400, 422, 401];
|
|
63
|
+
/**
|
|
64
|
+
* An array of error codes to ignore when reporting
|
|
65
|
+
* an error
|
|
66
|
+
*/
|
|
54
67
|
ignoreCodes = [];
|
|
68
|
+
/**
|
|
69
|
+
* Expands status pages
|
|
70
|
+
*/
|
|
55
71
|
#expandStatusPages() {
|
|
56
72
|
if (!this.#expandedStatusPages) {
|
|
57
73
|
this.#expandedStatusPages = Object.keys(this.statusPages).reduce((result, range) => {
|
|
@@ -62,12 +78,19 @@ export class ExceptionHandler {
|
|
|
62
78
|
}
|
|
63
79
|
return this.#expandedStatusPages;
|
|
64
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Forcefully tweaking the type of the error object to
|
|
83
|
+
* have known properties.
|
|
84
|
+
*/
|
|
65
85
|
#toHttpError(error) {
|
|
66
86
|
const httpError = is.object(error) ? error : new Error(String(error));
|
|
67
87
|
httpError.message = httpError.message || 'Internal server error';
|
|
68
88
|
httpError.status = httpError.status || 500;
|
|
69
89
|
return httpError;
|
|
70
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Error reporting context
|
|
93
|
+
*/
|
|
71
94
|
context(ctx) {
|
|
72
95
|
const requestId = ctx.request.id();
|
|
73
96
|
return requestId
|
|
@@ -76,17 +99,122 @@ export class ExceptionHandler {
|
|
|
76
99
|
}
|
|
77
100
|
: {};
|
|
78
101
|
}
|
|
79
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Renders an error to JSON response
|
|
104
|
+
*/
|
|
105
|
+
async renderErrorAsJSON(error, ctx) {
|
|
106
|
+
if (this.isDebuggingEnabled(ctx)) {
|
|
107
|
+
const { default: Youch } = await import('youch');
|
|
108
|
+
const json = await new Youch(error, ctx.request.request).toJSON();
|
|
109
|
+
ctx.response.status(error.status).send(json.error);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
ctx.response.status(error.status).send({ message: error.message });
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Renders an error to JSON API response
|
|
116
|
+
*/
|
|
117
|
+
async renderErrorAsJSONAPI(error, ctx) {
|
|
118
|
+
if (this.isDebuggingEnabled(ctx)) {
|
|
119
|
+
const { default: Youch } = await import('youch');
|
|
120
|
+
const json = await new Youch(error, ctx.request.request).toJSON();
|
|
121
|
+
ctx.response.status(error.status).send(json.error);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
ctx.response.status(error.status).send({
|
|
125
|
+
errors: [
|
|
126
|
+
{
|
|
127
|
+
title: error.message,
|
|
128
|
+
code: error.code,
|
|
129
|
+
status: error.status,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Renders an error to HTML response
|
|
136
|
+
*/
|
|
137
|
+
async renderErrorAsHTML(error, ctx) {
|
|
138
|
+
if (this.isDebuggingEnabled(ctx)) {
|
|
139
|
+
const { default: Youch } = await import('youch');
|
|
140
|
+
const html = await new Youch(error, ctx.request.request).toHTML();
|
|
141
|
+
ctx.response.status(error.status).send(html);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
ctx.response.status(error.status).send(`<p> ${error.message} </p>`);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Renders the validation error message to a JSON
|
|
148
|
+
* response
|
|
149
|
+
*/
|
|
150
|
+
async renderValidationErrorAsJSON(error, ctx) {
|
|
151
|
+
ctx.response.status(error.status).send({
|
|
152
|
+
errors: error.messages,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Renders the validation error message as per JSON API
|
|
157
|
+
* spec
|
|
158
|
+
*/
|
|
159
|
+
async renderValidationErrorAsJSONAPI(error, ctx) {
|
|
160
|
+
ctx.response.status(error.status).send({
|
|
161
|
+
errors: error.messages.map((message) => {
|
|
162
|
+
return {
|
|
163
|
+
title: message.message,
|
|
164
|
+
code: message.rule,
|
|
165
|
+
source: {
|
|
166
|
+
pointer: message.field,
|
|
167
|
+
},
|
|
168
|
+
meta: message.meta,
|
|
169
|
+
};
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Renders the validation error as an HTML string
|
|
175
|
+
*/
|
|
176
|
+
async renderValidationErrorAsHTML(error, ctx) {
|
|
177
|
+
ctx.response
|
|
178
|
+
.status(error.status)
|
|
179
|
+
.type('html')
|
|
180
|
+
.send(error.messages
|
|
181
|
+
.map((message) => {
|
|
182
|
+
return `${message.field} - ${message.message}`;
|
|
183
|
+
})
|
|
184
|
+
.join('<br />'));
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Renders the error to response
|
|
188
|
+
*/
|
|
189
|
+
renderError(error, ctx) {
|
|
80
190
|
switch (ctx.request.accepts(['html', 'application/vnd.api+json', 'json'])) {
|
|
81
191
|
case 'application/vnd.api+json':
|
|
82
|
-
return
|
|
192
|
+
return this.renderErrorAsJSONAPI(error, ctx);
|
|
83
193
|
case 'json':
|
|
84
|
-
return
|
|
194
|
+
return this.renderErrorAsJSON(error, ctx);
|
|
85
195
|
case 'html':
|
|
86
196
|
default:
|
|
87
|
-
return
|
|
197
|
+
return this.renderErrorAsHTML(error, ctx);
|
|
88
198
|
}
|
|
89
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Renders the validation error to response
|
|
202
|
+
*/
|
|
203
|
+
renderValidationError(error, ctx) {
|
|
204
|
+
switch (ctx.request.accepts(['html', 'application/vnd.api+json', 'json'])) {
|
|
205
|
+
case 'application/vnd.api+json':
|
|
206
|
+
return this.renderValidationErrorAsJSONAPI(error, ctx);
|
|
207
|
+
case 'json':
|
|
208
|
+
return this.renderValidationErrorAsJSON(error, ctx);
|
|
209
|
+
case 'html':
|
|
210
|
+
default:
|
|
211
|
+
return this.renderValidationErrorAsHTML(error, ctx);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Returns the log level for an error based upon the error
|
|
216
|
+
* status code.
|
|
217
|
+
*/
|
|
90
218
|
getErrorLogLevel(error) {
|
|
91
219
|
if (error.status >= 500) {
|
|
92
220
|
return 'error';
|
|
@@ -96,9 +224,16 @@ export class ExceptionHandler {
|
|
|
96
224
|
}
|
|
97
225
|
return 'info';
|
|
98
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* A boolean to control if errors should be rendered with
|
|
229
|
+
* all the available debugging info.
|
|
230
|
+
*/
|
|
99
231
|
isDebuggingEnabled(_) {
|
|
100
232
|
return this.debug;
|
|
101
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Returns a boolean by checking if an error should be reported.
|
|
236
|
+
*/
|
|
102
237
|
shouldReport(error) {
|
|
103
238
|
if (this.reportErrors === false) {
|
|
104
239
|
return false;
|
|
@@ -114,6 +249,9 @@ export class ExceptionHandler {
|
|
|
114
249
|
}
|
|
115
250
|
return true;
|
|
116
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Reports an error during an HTTP request
|
|
254
|
+
*/
|
|
117
255
|
async report(error, ctx) {
|
|
118
256
|
const httpError = this.#toHttpError(error);
|
|
119
257
|
if (!this.shouldReport(httpError)) {
|
|
@@ -123,22 +261,43 @@ export class ExceptionHandler {
|
|
|
123
261
|
httpError.report(httpError, ctx);
|
|
124
262
|
return;
|
|
125
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Log the error using the logger
|
|
266
|
+
*/
|
|
126
267
|
const level = this.getErrorLogLevel(httpError);
|
|
127
268
|
ctx.logger.log(level, {
|
|
128
269
|
...(level === 'error' || level === 'fatal' ? { err: httpError } : {}),
|
|
129
270
|
...this.context(ctx),
|
|
130
271
|
}, httpError.message);
|
|
131
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Handles the error during the HTTP request.
|
|
275
|
+
*/
|
|
132
276
|
async handle(error, ctx) {
|
|
133
277
|
const httpError = this.#toHttpError(error);
|
|
278
|
+
/**
|
|
279
|
+
* Self handle exception
|
|
280
|
+
*/
|
|
134
281
|
if (typeof httpError.handle === 'function') {
|
|
135
282
|
return httpError.handle(httpError, ctx);
|
|
136
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Handle validation error using the validation error
|
|
286
|
+
* renderers
|
|
287
|
+
*/
|
|
288
|
+
if (httpError.code === 'E_VALIDATION_ERROR' && 'messages' in httpError) {
|
|
289
|
+
return this.renderValidationError(httpError, ctx);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Render status page
|
|
293
|
+
*/
|
|
137
294
|
const statusPages = this.#expandStatusPages();
|
|
138
295
|
if (this.renderStatusPages && statusPages[httpError.status]) {
|
|
139
296
|
return statusPages[httpError.status](httpError, ctx);
|
|
140
297
|
}
|
|
141
|
-
|
|
142
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Use the format renderers.
|
|
300
|
+
*/
|
|
301
|
+
return this.renderError(httpError, ctx);
|
|
143
302
|
}
|
|
144
303
|
}
|
|
@@ -20,6 +20,9 @@ export declare const E_HTTP_EXCEPTION: {
|
|
|
20
20
|
cause?: unknown;
|
|
21
21
|
};
|
|
22
22
|
code: string;
|
|
23
|
+
/**
|
|
24
|
+
* This method returns an instance of the exception class
|
|
25
|
+
*/
|
|
23
26
|
invoke(body: any, status: number, code?: string): {
|
|
24
27
|
body: any;
|
|
25
28
|
name: string;
|
|
@@ -57,6 +60,9 @@ export declare const E_HTTP_REQUEST_ABORTED: {
|
|
|
57
60
|
cause?: unknown;
|
|
58
61
|
};
|
|
59
62
|
code: string;
|
|
63
|
+
/**
|
|
64
|
+
* This method returns an instance of the exception class
|
|
65
|
+
*/
|
|
60
66
|
invoke(body: any, status: number, code?: string): {
|
|
61
67
|
body: any;
|
|
62
68
|
name: string;
|
package/build/src/exceptions.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
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 { createError, Exception } from '@poppinss/utils';
|
|
2
10
|
export const E_ROUTE_NOT_FOUND = createError('Cannot %s:%s', 'E_ROUTE_NOT_FOUND', 404);
|
|
3
11
|
export const E_CANNOT_LOOKUP_ROUTE = createError('Cannot lookup route "%s"', 'E_CANNOT_LOOKUP_ROUTE', 500);
|
|
4
12
|
export const E_HTTP_EXCEPTION = class HttpException extends Exception {
|
|
5
13
|
body;
|
|
6
14
|
static code = 'E_HTTP_EXCEPTION';
|
|
15
|
+
/**
|
|
16
|
+
* This method returns an instance of the exception class
|
|
17
|
+
*/
|
|
7
18
|
static invoke(body, status, code = 'E_HTTP_EXCEPTION') {
|
|
8
19
|
if (body === null || body === undefined) {
|
|
9
20
|
const error = new this('HTTP Exception', { status, code });
|
package/build/src/helpers.d.ts
CHANGED
|
@@ -3,7 +3,21 @@ import { BriskRoute } from './router/brisk.js';
|
|
|
3
3
|
import { RouteGroup } from './router/group.js';
|
|
4
4
|
import type { RouteJSON } from './types/route.js';
|
|
5
5
|
import { RouteResource } from './router/resource.js';
|
|
6
|
+
/**
|
|
7
|
+
* Makes input string consistent by having only the starting
|
|
8
|
+
* slash
|
|
9
|
+
*/
|
|
6
10
|
export declare function dropSlash(input: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Returns a flat list of routes from the route groups and resources
|
|
13
|
+
*/
|
|
7
14
|
export declare function toRoutesJSON(routes: (RouteGroup | Route | RouteResource | BriskRoute)[]): RouteJSON[];
|
|
15
|
+
/**
|
|
16
|
+
* Helper to know if the remote address should
|
|
17
|
+
* be trusted.
|
|
18
|
+
*/
|
|
8
19
|
export declare function trustProxy(remoteAddress: string, proxyFn: (addr: string, distance: number) => boolean): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Parses a range expression to an object filled with the range
|
|
22
|
+
*/
|
|
9
23
|
export declare function parseRange<T>(range: string, value: T): Record<number, T>;
|
package/build/src/helpers.js
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
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 Cache from 'tmp-cache';
|
|
2
10
|
import { InvalidArgumentsException } from '@poppinss/utils';
|
|
3
11
|
import { BriskRoute } from './router/brisk.js';
|
|
4
12
|
import { RouteGroup } from './router/group.js';
|
|
5
13
|
import { RouteResource } from './router/resource.js';
|
|
6
14
|
const proxyCache = new Cache({ max: 200 });
|
|
15
|
+
/**
|
|
16
|
+
* Makes input string consistent by having only the starting
|
|
17
|
+
* slash
|
|
18
|
+
*/
|
|
7
19
|
export function dropSlash(input) {
|
|
8
20
|
if (input === '/') {
|
|
9
21
|
return '/';
|
|
10
22
|
}
|
|
11
23
|
return `/${input.replace(/^\//, '').replace(/\/$/, '')}`;
|
|
12
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns a flat list of routes from the route groups and resources
|
|
27
|
+
*/
|
|
13
28
|
export function toRoutesJSON(routes) {
|
|
14
29
|
return routes.reduce((list, route) => {
|
|
15
30
|
if (route instanceof RouteGroup) {
|
|
@@ -32,6 +47,10 @@ export function toRoutesJSON(routes) {
|
|
|
32
47
|
return list;
|
|
33
48
|
}, []);
|
|
34
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Helper to know if the remote address should
|
|
52
|
+
* be trusted.
|
|
53
|
+
*/
|
|
35
54
|
export function trustProxy(remoteAddress, proxyFn) {
|
|
36
55
|
if (proxyCache.has(remoteAddress)) {
|
|
37
56
|
return proxyCache.get(remoteAddress);
|
|
@@ -40,21 +59,45 @@ export function trustProxy(remoteAddress, proxyFn) {
|
|
|
40
59
|
proxyCache.set(remoteAddress, result);
|
|
41
60
|
return result;
|
|
42
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Parses a range expression to an object filled with the range
|
|
64
|
+
*/
|
|
43
65
|
export function parseRange(range, value) {
|
|
44
66
|
const parts = range.split('..');
|
|
45
67
|
const min = Number(parts[0]);
|
|
46
68
|
const max = Number(parts[1]);
|
|
69
|
+
/**
|
|
70
|
+
* The ending status code does not exists
|
|
71
|
+
*/
|
|
72
|
+
if (parts.length === 1 && !Number.isNaN(min)) {
|
|
73
|
+
return {
|
|
74
|
+
[min]: value,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The starting status code is not a number
|
|
79
|
+
*/
|
|
47
80
|
if (Number.isNaN(min) || Number.isNaN(max)) {
|
|
48
81
|
return {};
|
|
49
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Min and max are same
|
|
85
|
+
*/
|
|
50
86
|
if (min === max) {
|
|
51
87
|
return {
|
|
52
88
|
[min]: value,
|
|
53
89
|
};
|
|
54
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Max cannot be smaller than min
|
|
93
|
+
*/
|
|
55
94
|
if (max < min) {
|
|
56
95
|
throw new InvalidArgumentsException(`Invalid range "${range}"`);
|
|
57
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Loop over the range and create a collection
|
|
99
|
+
* of status codes
|
|
100
|
+
*/
|
|
58
101
|
return [...Array(max - min + 1).keys()].reduce((result, step) => {
|
|
59
102
|
result[min + step] = value;
|
|
60
103
|
return result;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
3
|
import type { HttpContext } from './main.js';
|
|
4
|
+
/**
|
|
5
|
+
* Async local storage for HTTP context
|
|
6
|
+
*/
|
|
4
7
|
export declare const asyncLocalStorage: {
|
|
5
8
|
isEnabled: boolean;
|
|
6
9
|
storage: null | AsyncLocalStorage<HttpContext>;
|
|
@@ -1,12 +1,37 @@
|
|
|
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 { AsyncLocalStorage } from 'node:async_hooks';
|
|
10
|
+
/**
|
|
11
|
+
* Async local storage for HTTP context
|
|
12
|
+
*/
|
|
2
13
|
export const asyncLocalStorage = {
|
|
14
|
+
/**
|
|
15
|
+
* Check if the async local storage for the HTTP
|
|
16
|
+
* context is enabled or not
|
|
17
|
+
*/
|
|
3
18
|
isEnabled: false,
|
|
19
|
+
/**
|
|
20
|
+
* HTTP context storage instance for the current scope
|
|
21
|
+
*/
|
|
4
22
|
storage: null,
|
|
23
|
+
/**
|
|
24
|
+
* Create the storage instance. This method must be called only
|
|
25
|
+
* once.
|
|
26
|
+
*/
|
|
5
27
|
create() {
|
|
6
28
|
this.isEnabled = true;
|
|
7
29
|
this.storage = new AsyncLocalStorage();
|
|
8
30
|
return this.storage;
|
|
9
31
|
},
|
|
32
|
+
/**
|
|
33
|
+
* Destroy the create storage instance
|
|
34
|
+
*/
|
|
10
35
|
destroy() {
|
|
11
36
|
this.isEnabled = false;
|
|
12
37
|
this.storage = null;
|
|
@@ -4,19 +4,55 @@ import { ContainerResolver } from '@adonisjs/fold';
|
|
|
4
4
|
import type { Request } from '../request.js';
|
|
5
5
|
import type { Response } from '../response.js';
|
|
6
6
|
import type { StoreRouteNode } from '../types/route.js';
|
|
7
|
+
/**
|
|
8
|
+
* Http context encapsulates properties for a given HTTP request. The
|
|
9
|
+
* context class can be extended using macros and getters.
|
|
10
|
+
*/
|
|
7
11
|
export declare class HttpContext extends Macroable {
|
|
8
12
|
request: Request;
|
|
9
13
|
response: Response;
|
|
10
14
|
logger: Logger;
|
|
11
15
|
containerResolver: ContainerResolver<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Find if async localstorage is enabled for HTTP requests
|
|
18
|
+
* or not
|
|
19
|
+
*/
|
|
12
20
|
static get usingAsyncLocalStorage(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Get access to the HTTP context. Available only when
|
|
23
|
+
* "usingAsyncLocalStorage" is true
|
|
24
|
+
*/
|
|
13
25
|
static get(): HttpContext | null;
|
|
26
|
+
/**
|
|
27
|
+
* Get the HttpContext instance or raise an exception if not
|
|
28
|
+
* available
|
|
29
|
+
*/
|
|
14
30
|
static getOrFail(): HttpContext;
|
|
31
|
+
/**
|
|
32
|
+
* Run a method that doesn't have access to HTTP context from
|
|
33
|
+
* the async local storage.
|
|
34
|
+
*/
|
|
15
35
|
static runOutsideContext<T>(callback: (...args: any[]) => T, ...args: any[]): T;
|
|
36
|
+
/**
|
|
37
|
+
* Reference to the current route. Not available inside
|
|
38
|
+
* server middleware
|
|
39
|
+
*/
|
|
16
40
|
route?: StoreRouteNode;
|
|
41
|
+
/**
|
|
42
|
+
* A unique key for the current route
|
|
43
|
+
*/
|
|
17
44
|
routeKey?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Route params
|
|
47
|
+
*/
|
|
18
48
|
params: Record<string, any>;
|
|
49
|
+
/**
|
|
50
|
+
* Route subdomains
|
|
51
|
+
*/
|
|
19
52
|
subdomains: Record<string, any>;
|
|
20
53
|
constructor(request: Request, response: Response, logger: Logger, containerResolver: ContainerResolver<any>);
|
|
54
|
+
/**
|
|
55
|
+
* A helper to see top level properties on the context object
|
|
56
|
+
*/
|
|
21
57
|
inspect(): string;
|
|
22
58
|
}
|
|
@@ -1,22 +1,49 @@
|
|
|
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 { inspect } from 'node:util';
|
|
2
10
|
import Macroable from '@poppinss/macroable';
|
|
3
11
|
import { RuntimeException } from '@poppinss/utils';
|
|
4
12
|
import { asyncLocalStorage } from './local_storage.js';
|
|
13
|
+
/**
|
|
14
|
+
* Http context encapsulates properties for a given HTTP request. The
|
|
15
|
+
* context class can be extended using macros and getters.
|
|
16
|
+
*/
|
|
5
17
|
export class HttpContext extends Macroable {
|
|
6
18
|
request;
|
|
7
19
|
response;
|
|
8
20
|
logger;
|
|
9
21
|
containerResolver;
|
|
22
|
+
/**
|
|
23
|
+
* Find if async localstorage is enabled for HTTP requests
|
|
24
|
+
* or not
|
|
25
|
+
*/
|
|
10
26
|
static get usingAsyncLocalStorage() {
|
|
11
27
|
return asyncLocalStorage.isEnabled;
|
|
12
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Get access to the HTTP context. Available only when
|
|
31
|
+
* "usingAsyncLocalStorage" is true
|
|
32
|
+
*/
|
|
13
33
|
static get() {
|
|
14
34
|
if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
|
|
15
35
|
return null;
|
|
16
36
|
}
|
|
17
37
|
return asyncLocalStorage.storage.getStore() || null;
|
|
18
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the HttpContext instance or raise an exception if not
|
|
41
|
+
* available
|
|
42
|
+
*/
|
|
19
43
|
static getOrFail() {
|
|
44
|
+
/**
|
|
45
|
+
* Localstorage is not enabled
|
|
46
|
+
*/
|
|
20
47
|
if (!this.usingAsyncLocalStorage || !asyncLocalStorage.storage) {
|
|
21
48
|
throw new RuntimeException('HTTP context is not available. Enable "useAsyncLocalStorage" inside "config/app.ts" file');
|
|
22
49
|
}
|
|
@@ -26,15 +53,32 @@ export class HttpContext extends Macroable {
|
|
|
26
53
|
}
|
|
27
54
|
return store;
|
|
28
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Run a method that doesn't have access to HTTP context from
|
|
58
|
+
* the async local storage.
|
|
59
|
+
*/
|
|
29
60
|
static runOutsideContext(callback, ...args) {
|
|
30
61
|
if (!asyncLocalStorage.storage) {
|
|
31
62
|
return callback(...args);
|
|
32
63
|
}
|
|
33
64
|
return asyncLocalStorage.storage.exit(callback, ...args);
|
|
34
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Reference to the current route. Not available inside
|
|
68
|
+
* server middleware
|
|
69
|
+
*/
|
|
35
70
|
route;
|
|
71
|
+
/**
|
|
72
|
+
* A unique key for the current route
|
|
73
|
+
*/
|
|
36
74
|
routeKey;
|
|
75
|
+
/**
|
|
76
|
+
* Route params
|
|
77
|
+
*/
|
|
37
78
|
params = {};
|
|
79
|
+
/**
|
|
80
|
+
* Route subdomains
|
|
81
|
+
*/
|
|
38
82
|
subdomains = {};
|
|
39
83
|
constructor(request, response, logger, containerResolver) {
|
|
40
84
|
super();
|
|
@@ -42,9 +86,19 @@ export class HttpContext extends Macroable {
|
|
|
42
86
|
this.response = response;
|
|
43
87
|
this.logger = logger;
|
|
44
88
|
this.containerResolver = containerResolver;
|
|
89
|
+
/*
|
|
90
|
+
* Creating the circular reference. We do this, since request and response
|
|
91
|
+
* are meant to be extended and at times people would want to access
|
|
92
|
+
* other ctx properties like `logger`, `profiler` inside those
|
|
93
|
+
* extended methods.
|
|
94
|
+
*/
|
|
45
95
|
this.request.ctx = this;
|
|
46
96
|
this.response.ctx = this;
|
|
47
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* A helper to see top level properties on the context object
|
|
100
|
+
*/
|
|
101
|
+
/* c8 ignore next 3 */
|
|
48
102
|
inspect() {
|
|
49
103
|
return inspect(this, false, 1, true);
|
|
50
104
|
}
|