@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
|
@@ -1,16 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/http-server
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
// @ts-expect-error
|
|
1
10
|
import matchit from '@poppinss/matchit';
|
|
2
11
|
import lodash from '@poppinss/utils/lodash';
|
|
3
12
|
import { RuntimeException } from '@poppinss/utils';
|
|
13
|
+
import { parseRoutePattern } from './parser.js';
|
|
14
|
+
import debug from '../debug.js';
|
|
15
|
+
/**
|
|
16
|
+
* Store class is used to store a list of routes, along side with their tokens
|
|
17
|
+
* to match the URLs.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* const store = new Store()
|
|
21
|
+
*
|
|
22
|
+
* store.add({
|
|
23
|
+
* pattern: 'posts/:id',
|
|
24
|
+
* handler: function onRoute () {},
|
|
25
|
+
* middleware: [],
|
|
26
|
+
* matchers: {
|
|
27
|
+
* id: '^[0-9]$+'
|
|
28
|
+
* },
|
|
29
|
+
* meta: {},
|
|
30
|
+
* methods: ['GET']
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* store.match('posts/1', 'GET')
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
4
36
|
export class RoutesStore {
|
|
37
|
+
/**
|
|
38
|
+
* A flag to know if routes for explicit domains
|
|
39
|
+
* have been registered
|
|
40
|
+
*/
|
|
5
41
|
usingDomains = false;
|
|
42
|
+
/**
|
|
43
|
+
* Tree of registered routes and their matchit tokens
|
|
44
|
+
*/
|
|
6
45
|
tree = { tokens: [], domains: {} };
|
|
46
|
+
/**
|
|
47
|
+
* Returns the domain node for a given domain.
|
|
48
|
+
*/
|
|
7
49
|
#getDomainNode(domain) {
|
|
8
50
|
if (!this.tree.domains[domain]) {
|
|
9
|
-
this.tree.tokens.push(
|
|
51
|
+
this.tree.tokens.push(parseRoutePattern(domain));
|
|
10
52
|
this.tree.domains[domain] = {};
|
|
11
53
|
}
|
|
12
54
|
return this.tree.domains[domain];
|
|
13
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns the method node for a given domain and method.
|
|
58
|
+
*/
|
|
14
59
|
#getMethodNode(domain, method) {
|
|
15
60
|
const domainNode = this.#getDomainNode(domain);
|
|
16
61
|
if (!domainNode[method]) {
|
|
@@ -18,6 +63,9 @@ export class RoutesStore {
|
|
|
18
63
|
}
|
|
19
64
|
return domainNode[method];
|
|
20
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Collects route params
|
|
68
|
+
*/
|
|
21
69
|
#collectRouteParams(route, tokens) {
|
|
22
70
|
const collectedParams = new Set();
|
|
23
71
|
for (let token of tokens) {
|
|
@@ -34,38 +82,95 @@ export class RoutesStore {
|
|
|
34
82
|
collectedParams.clear();
|
|
35
83
|
return params;
|
|
36
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Register route for a given domain and method
|
|
87
|
+
*/
|
|
37
88
|
#registerRoute(domain, method, tokens, route) {
|
|
38
89
|
const methodRoutes = this.#getMethodNode(domain, method);
|
|
90
|
+
/*
|
|
91
|
+
* Check for duplicate route for the same domain and method
|
|
92
|
+
*/
|
|
39
93
|
if (methodRoutes.routes[route.pattern]) {
|
|
40
94
|
throw new RuntimeException(`Duplicate route found. "${method}: ${route.pattern}" route already exists`);
|
|
41
95
|
}
|
|
96
|
+
if (debug.enabled) {
|
|
97
|
+
debug('registering route to the store %O', route);
|
|
98
|
+
debug('route middleware %O', route.middleware.all().entries());
|
|
99
|
+
}
|
|
42
100
|
methodRoutes.tokens.push(tokens);
|
|
43
101
|
methodRoutes.routes[route.pattern] = route;
|
|
44
102
|
methodRoutes.routeKeys[route.pattern] =
|
|
45
103
|
domain !== 'root' ? `${domain}-${method}-${route.pattern}` : `${method}-${route.pattern}`;
|
|
46
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Add a route to the store
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* store.add({
|
|
110
|
+
* pattern: 'post/:id',
|
|
111
|
+
* methods: ['GET'],
|
|
112
|
+
* matchers: {},
|
|
113
|
+
* meta: {},
|
|
114
|
+
* handler: function handler () {
|
|
115
|
+
* }
|
|
116
|
+
* })
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
47
119
|
add(route) {
|
|
120
|
+
/**
|
|
121
|
+
* Set flag when a custom domain is used
|
|
122
|
+
*/
|
|
48
123
|
if (route.domain !== 'root') {
|
|
49
124
|
this.usingDomains = true;
|
|
50
125
|
}
|
|
51
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Generate tokens for the route
|
|
128
|
+
*/
|
|
129
|
+
const tokens = parseRoutePattern(route.pattern, route.matchers);
|
|
130
|
+
/**
|
|
131
|
+
* Create route node object for persistence
|
|
132
|
+
*/
|
|
52
133
|
const routeNode = lodash.merge({ meta: {} }, lodash.pick(route, ['pattern', 'handler', 'meta', 'middleware', 'name', 'execute']));
|
|
134
|
+
/**
|
|
135
|
+
* Set route params
|
|
136
|
+
*/
|
|
53
137
|
routeNode.meta.params = this.#collectRouteParams(routeNode, tokens);
|
|
138
|
+
/**
|
|
139
|
+
* Register route for every method
|
|
140
|
+
*/
|
|
54
141
|
route.methods.forEach((method) => {
|
|
55
142
|
this.#registerRoute(route.domain, method, tokens, routeNode);
|
|
56
143
|
});
|
|
57
144
|
return this;
|
|
58
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Matches the url, method and optionally domain to pull the matching
|
|
148
|
+
* route. `null` is returned when unable to match the URL against
|
|
149
|
+
* registered routes.
|
|
150
|
+
*
|
|
151
|
+
* The domain parameter has to be a registered pattern and not the fully
|
|
152
|
+
* qualified runtime domain. You must call `matchDomain` first to fetch
|
|
153
|
+
* the pattern for qualified domain
|
|
154
|
+
*/
|
|
59
155
|
match(url, method, domain) {
|
|
60
156
|
const domainName = domain?.tokens[0]?.old || 'root';
|
|
61
157
|
const matchedDomain = this.tree.domains[domainName];
|
|
62
158
|
if (!matchedDomain) {
|
|
63
159
|
return null;
|
|
64
160
|
}
|
|
161
|
+
/*
|
|
162
|
+
* Next get the method node for the given method inside the domain. If
|
|
163
|
+
* method node is missing, means no routes ever got registered for that
|
|
164
|
+
* method
|
|
165
|
+
*/
|
|
65
166
|
const matchedMethod = this.tree.domains[domainName][method];
|
|
66
167
|
if (!matchedMethod) {
|
|
67
168
|
return null;
|
|
68
169
|
}
|
|
170
|
+
/*
|
|
171
|
+
* Next, match route for the given url inside the tokens list for the
|
|
172
|
+
* matchedMethod
|
|
173
|
+
*/
|
|
69
174
|
const matchedRoute = matchit.match(url, matchedMethod.tokens);
|
|
70
175
|
if (!matchedRoute.length) {
|
|
71
176
|
return null;
|
|
@@ -78,6 +183,9 @@ export class RoutesStore {
|
|
|
78
183
|
subdomains: domain?.hostname ? matchit.exec(domain.hostname, domain.tokens) : {},
|
|
79
184
|
};
|
|
80
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Match hostname against registered domains.
|
|
188
|
+
*/
|
|
81
189
|
matchDomain(hostname) {
|
|
82
190
|
if (!hostname || !this.usingDomains) {
|
|
83
191
|
return [];
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { ContainerResolver } from '@adonisjs/fold';
|
|
2
2
|
import type { Router } from '../../router/main.js';
|
|
3
3
|
import type { HttpContext } from '../../http_context/main.js';
|
|
4
|
-
|
|
4
|
+
import type { ServerErrorHandler } from '../../types/server.js';
|
|
5
|
+
/**
|
|
6
|
+
* The final handler is executed after the server middleware stack.
|
|
7
|
+
* It looks for a matching route and executes the route middleware
|
|
8
|
+
* stack.
|
|
9
|
+
*/
|
|
10
|
+
export declare function finalHandler(router: Router, resolver: ContainerResolver<any>, ctx: HttpContext, errorResponder: ServerErrorHandler['handle']): () => any;
|
|
@@ -1,5 +1,18 @@
|
|
|
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 * as errors from '../../exceptions.js';
|
|
2
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The final handler is executed after the server middleware stack.
|
|
12
|
+
* It looks for a matching route and executes the route middleware
|
|
13
|
+
* stack.
|
|
14
|
+
*/
|
|
15
|
+
export function finalHandler(router, resolver, ctx, errorResponder) {
|
|
3
16
|
return function () {
|
|
4
17
|
const url = ctx.request.url();
|
|
5
18
|
const method = ctx.request.method();
|
|
@@ -10,7 +23,7 @@ export function finalHandler(router, resolver, ctx) {
|
|
|
10
23
|
ctx.subdomains = route.subdomains;
|
|
11
24
|
ctx.route = route.route;
|
|
12
25
|
ctx.routeKey = route.routeKey;
|
|
13
|
-
return route.route.execute(route.route, resolver, ctx);
|
|
26
|
+
return route.route.execute(route.route, resolver, ctx, errorResponder);
|
|
14
27
|
}
|
|
15
28
|
return Promise.reject(new errors.E_ROUTE_NOT_FOUND([method, url]));
|
|
16
29
|
};
|
|
@@ -2,4 +2,7 @@ import type { NextFn } from '@poppinss/middleware/types';
|
|
|
2
2
|
import type { ContainerResolver } from '@adonisjs/fold';
|
|
3
3
|
import type { HttpContext } from '../../http_context/main.js';
|
|
4
4
|
import { ParsedGlobalMiddleware } from '../../types/middleware.js';
|
|
5
|
+
/**
|
|
6
|
+
* The middleware handler invokes the middleware functions.
|
|
7
|
+
*/
|
|
5
8
|
export declare function middlewareHandler(resolver: ContainerResolver<any>, ctx: HttpContext): (fn: ParsedGlobalMiddleware, next: NextFn) => any;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/http-server
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The middleware handler invokes the middleware functions.
|
|
11
|
+
*/
|
|
1
12
|
export function middlewareHandler(resolver, ctx) {
|
|
2
13
|
return function (fn, next) {
|
|
3
14
|
return fn.handle(resolver, ctx, next);
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/http-server
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Writes the response to the socket. The "finish" method can
|
|
11
|
+
* raise error when unable to serialize the response.
|
|
12
|
+
*/
|
|
1
13
|
export function writeResponse(ctx) {
|
|
2
14
|
return function () {
|
|
3
15
|
try {
|
|
@@ -14,19 +14,67 @@ import { Request } from '../request.js';
|
|
|
14
14
|
import { Response } from '../response.js';
|
|
15
15
|
import { Router } from '../router/main.js';
|
|
16
16
|
import { HttpContext } from '../http_context/main.js';
|
|
17
|
+
/**
|
|
18
|
+
* The HTTP server implementation to handle incoming requests and respond using the
|
|
19
|
+
* registered routes.
|
|
20
|
+
*/
|
|
17
21
|
export declare class Server {
|
|
18
22
|
#private;
|
|
23
|
+
/**
|
|
24
|
+
* Know if async local storage is enabled or not.
|
|
25
|
+
*/
|
|
19
26
|
get usingAsyncLocalStorage(): boolean;
|
|
20
27
|
constructor(app: Application<any>, encryption: Encryption, emitter: Emitter<any>, logger: Logger, config: ServerConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Creates a pipeline of middleware.
|
|
30
|
+
*/
|
|
21
31
|
pipeline(middleware: MiddlewareAsClass[]): TestingMiddlewarePipeline;
|
|
32
|
+
/**
|
|
33
|
+
* Define an array of middleware to use on all the incoming HTTP request.
|
|
34
|
+
* Calling this method multiple times pushes to the existing list
|
|
35
|
+
* of middleware
|
|
36
|
+
*/
|
|
22
37
|
use(middleware: LazyImport<MiddlewareAsClass>[]): this;
|
|
38
|
+
/**
|
|
39
|
+
* Register a custom error handler for HTTP requests.
|
|
40
|
+
* All errors will be reported to this method
|
|
41
|
+
*/
|
|
23
42
|
errorHandler(handler: LazyImport<ErrorHandlerAsAClass>): this;
|
|
43
|
+
/**
|
|
44
|
+
* Boot the server. Calling this method performs the following actions.
|
|
45
|
+
*
|
|
46
|
+
* - Register routes with the store.
|
|
47
|
+
* - Resolve and construct the error handler.
|
|
48
|
+
*/
|
|
24
49
|
boot(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Set the HTTP server instance used to listen for requests.
|
|
52
|
+
*/
|
|
25
53
|
setNodeServer(server: HttpServer | HttpsServer): void;
|
|
54
|
+
/**
|
|
55
|
+
* Returns reference to the underlying HTTP server
|
|
56
|
+
* in use
|
|
57
|
+
*/
|
|
26
58
|
getNodeServer(): HttpServer<typeof IncomingMessage, typeof ServerResponse> | HttpsServer<typeof IncomingMessage, typeof ServerResponse> | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Returns reference to the router instance used
|
|
61
|
+
* by the server.
|
|
62
|
+
*/
|
|
27
63
|
getRouter(): Router;
|
|
64
|
+
/**
|
|
65
|
+
* Creates an instance of the [[Request]] class
|
|
66
|
+
*/
|
|
28
67
|
createRequest(req: IncomingMessage, res: ServerResponse): Request;
|
|
68
|
+
/**
|
|
69
|
+
* Creates an instance of the [[Response]] class
|
|
70
|
+
*/
|
|
29
71
|
createResponse(req: IncomingMessage, res: ServerResponse): Response;
|
|
72
|
+
/**
|
|
73
|
+
* Creates an instance of the [[HttpContext]] class
|
|
74
|
+
*/
|
|
30
75
|
createHttpContext(request: Request, response: Response, resolver: ContainerResolver<any>): HttpContext;
|
|
76
|
+
/**
|
|
77
|
+
* Handle request
|
|
78
|
+
*/
|
|
31
79
|
handle(req: IncomingMessage, res: ServerResponse): Promise<any>;
|
|
32
80
|
}
|
package/build/src/server/main.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 onFinished from 'on-finished';
|
|
2
10
|
import Middleware from '@poppinss/middleware';
|
|
3
11
|
import { moduleCaller, moduleImporter } from '@adonisjs/fold';
|
|
@@ -11,25 +19,86 @@ import { finalHandler } from './factories/final_handler.js';
|
|
|
11
19
|
import { writeResponse } from './factories/write_response.js';
|
|
12
20
|
import { asyncLocalStorage } from '../http_context/local_storage.js';
|
|
13
21
|
import { middlewareHandler } from './factories/middleware_handler.js';
|
|
22
|
+
/**
|
|
23
|
+
* The HTTP server implementation to handle incoming requests and respond using the
|
|
24
|
+
* registered routes.
|
|
25
|
+
*/
|
|
14
26
|
export class Server {
|
|
27
|
+
/**
|
|
28
|
+
* The default error handler to use
|
|
29
|
+
*/
|
|
15
30
|
#defaultErrorHandler = {
|
|
16
31
|
report() { },
|
|
17
32
|
handle(error, ctx) {
|
|
18
33
|
ctx.response.status(error.status || 500).send(error.message || 'Internal server error');
|
|
19
34
|
},
|
|
20
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Logger instance, a child logger is added
|
|
38
|
+
* to the context to have request specific
|
|
39
|
+
* logging capabilities.
|
|
40
|
+
*/
|
|
21
41
|
#logger;
|
|
42
|
+
/**
|
|
43
|
+
* Registered error handler (if any)
|
|
44
|
+
*/
|
|
22
45
|
#errorHandler;
|
|
46
|
+
/**
|
|
47
|
+
* Resolved error handler is an instance of the lazily imported error
|
|
48
|
+
* handler class.
|
|
49
|
+
*/
|
|
23
50
|
#resolvedErrorHandler = this.#defaultErrorHandler;
|
|
51
|
+
/**
|
|
52
|
+
* Emitter is required to notify when a request finishes
|
|
53
|
+
*/
|
|
24
54
|
#emitter;
|
|
55
|
+
/**
|
|
56
|
+
* The application instance to be shared with the router
|
|
57
|
+
*/
|
|
25
58
|
#app;
|
|
59
|
+
/**
|
|
60
|
+
* The encryption instance to be shared with the router
|
|
61
|
+
*/
|
|
26
62
|
#encryption;
|
|
63
|
+
/**
|
|
64
|
+
* Server config
|
|
65
|
+
*/
|
|
27
66
|
#config;
|
|
67
|
+
/**
|
|
68
|
+
* Query string parser used by the server
|
|
69
|
+
*/
|
|
28
70
|
#qsParser;
|
|
71
|
+
/**
|
|
72
|
+
* Server middleware stack runs on every incoming HTTP request
|
|
73
|
+
*/
|
|
29
74
|
#serverMiddlewareStack;
|
|
75
|
+
/**
|
|
76
|
+
* Reference to the router used by the server
|
|
77
|
+
*/
|
|
30
78
|
#router;
|
|
79
|
+
/**
|
|
80
|
+
* Reference to the underlying Node HTTP server in use
|
|
81
|
+
*/
|
|
31
82
|
#nodeHttpServer;
|
|
83
|
+
/**
|
|
84
|
+
* Middleware store to be shared with the routes
|
|
85
|
+
*/
|
|
32
86
|
#middleware = [];
|
|
87
|
+
/**
|
|
88
|
+
* The request error response is attached to the middleware
|
|
89
|
+
* pipeline to intercept errors and invoke the user
|
|
90
|
+
* registered error handler.
|
|
91
|
+
*
|
|
92
|
+
* We share this with the route middleware pipeline as well,
|
|
93
|
+
* so that it does not throw any exceptions
|
|
94
|
+
*/
|
|
95
|
+
#requestErrorResponder = (error, ctx) => {
|
|
96
|
+
this.#resolvedErrorHandler.report(error, ctx);
|
|
97
|
+
return this.#resolvedErrorHandler.handle(error, ctx);
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Know if async local storage is enabled or not.
|
|
101
|
+
*/
|
|
33
102
|
get usingAsyncLocalStorage() {
|
|
34
103
|
return asyncLocalStorage.isEnabled;
|
|
35
104
|
}
|
|
@@ -44,6 +113,9 @@ export class Server {
|
|
|
44
113
|
this.#createAsyncLocalStore();
|
|
45
114
|
debug('server config: %O', this.#config);
|
|
46
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Create async local storage store when enabled
|
|
118
|
+
*/
|
|
47
119
|
#createAsyncLocalStore() {
|
|
48
120
|
if (this.#config.useAsyncLocalStorage) {
|
|
49
121
|
debug('creating ALS store for HTTP context');
|
|
@@ -53,19 +125,22 @@ export class Server {
|
|
|
53
125
|
asyncLocalStorage.destroy();
|
|
54
126
|
}
|
|
55
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Creates an instance of the server middleware stack
|
|
130
|
+
*/
|
|
56
131
|
#createServerMiddlewareStack() {
|
|
57
132
|
this.#serverMiddlewareStack = new Middleware();
|
|
58
133
|
this.#middleware.forEach((middleware) => this.#serverMiddlewareStack.add(middleware));
|
|
59
134
|
this.#serverMiddlewareStack.freeze();
|
|
60
135
|
this.#middleware = [];
|
|
61
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Handles the HTTP request
|
|
139
|
+
*/
|
|
62
140
|
#handleRequest(ctx, resolver) {
|
|
63
141
|
return this.#serverMiddlewareStack.runner()
|
|
64
|
-
.errorHandler((error) =>
|
|
65
|
-
this.#
|
|
66
|
-
return this.#resolvedErrorHandler.handle(error, ctx);
|
|
67
|
-
})
|
|
68
|
-
.finalHandler(finalHandler(this.#router, resolver, ctx))
|
|
142
|
+
.errorHandler((error) => this.#requestErrorResponder(error, ctx))
|
|
143
|
+
.finalHandler(finalHandler(this.#router, resolver, ctx, this.#requestErrorResponder))
|
|
69
144
|
.run(middlewareHandler(resolver, ctx))
|
|
70
145
|
.catch((error) => {
|
|
71
146
|
ctx.logger.fatal({ err: error }, 'Exception raised by error handler');
|
|
@@ -73,6 +148,9 @@ export class Server {
|
|
|
73
148
|
})
|
|
74
149
|
.finally(writeResponse(ctx));
|
|
75
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Creates a pipeline of middleware.
|
|
153
|
+
*/
|
|
76
154
|
pipeline(middleware) {
|
|
77
155
|
const middlewareStack = new Middleware();
|
|
78
156
|
middleware.forEach((one) => {
|
|
@@ -96,18 +174,42 @@ export class Server {
|
|
|
96
174
|
},
|
|
97
175
|
};
|
|
98
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Define an array of middleware to use on all the incoming HTTP request.
|
|
179
|
+
* Calling this method multiple times pushes to the existing list
|
|
180
|
+
* of middleware
|
|
181
|
+
*/
|
|
99
182
|
use(middleware) {
|
|
100
183
|
middleware.forEach((one) => this.#middleware.push(moduleImporter(one, 'handle').toHandleMethod()));
|
|
101
184
|
return this;
|
|
102
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Register a custom error handler for HTTP requests.
|
|
188
|
+
* All errors will be reported to this method
|
|
189
|
+
*/
|
|
103
190
|
errorHandler(handler) {
|
|
104
191
|
this.#errorHandler = handler;
|
|
105
192
|
return this;
|
|
106
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Boot the server. Calling this method performs the following actions.
|
|
196
|
+
*
|
|
197
|
+
* - Register routes with the store.
|
|
198
|
+
* - Resolve and construct the error handler.
|
|
199
|
+
*/
|
|
107
200
|
async boot() {
|
|
108
201
|
debug('booting HTTP server');
|
|
202
|
+
/**
|
|
203
|
+
* Creates the middleware stack for the server
|
|
204
|
+
*/
|
|
109
205
|
this.#createServerMiddlewareStack();
|
|
206
|
+
/**
|
|
207
|
+
* Commit routes
|
|
208
|
+
*/
|
|
110
209
|
this.#router.commit();
|
|
210
|
+
/**
|
|
211
|
+
* Register custom error handler
|
|
212
|
+
*/
|
|
111
213
|
if (this.#errorHandler) {
|
|
112
214
|
if (debug.enabled) {
|
|
113
215
|
debug('using custom error handler "%s"', this.#errorHandler);
|
|
@@ -116,29 +218,61 @@ export class Server {
|
|
|
116
218
|
this.#resolvedErrorHandler = await this.#app.container.make(moduleExports.default);
|
|
117
219
|
}
|
|
118
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Set the HTTP server instance used to listen for requests.
|
|
223
|
+
*/
|
|
119
224
|
setNodeServer(server) {
|
|
120
225
|
this.#nodeHttpServer = server;
|
|
121
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Returns reference to the underlying HTTP server
|
|
229
|
+
* in use
|
|
230
|
+
*/
|
|
122
231
|
getNodeServer() {
|
|
123
232
|
return this.#nodeHttpServer;
|
|
124
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Returns reference to the router instance used
|
|
236
|
+
* by the server.
|
|
237
|
+
*/
|
|
125
238
|
getRouter() {
|
|
126
239
|
return this.#router;
|
|
127
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Creates an instance of the [[Request]] class
|
|
243
|
+
*/
|
|
128
244
|
createRequest(req, res) {
|
|
129
245
|
return new Request(req, res, this.#encryption, this.#config, this.#qsParser);
|
|
130
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Creates an instance of the [[Response]] class
|
|
249
|
+
*/
|
|
131
250
|
createResponse(req, res) {
|
|
132
251
|
return new Response(req, res, this.#encryption, this.#config, this.#router, this.#qsParser);
|
|
133
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Creates an instance of the [[HttpContext]] class
|
|
255
|
+
*/
|
|
134
256
|
createHttpContext(request, response, resolver) {
|
|
135
257
|
return new HttpContext(request, response, this.#logger.child({ request_id: request.id() }), resolver);
|
|
136
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Handle request
|
|
261
|
+
*/
|
|
137
262
|
handle(req, res) {
|
|
263
|
+
/**
|
|
264
|
+
* Setup for the "http:request_finished" event
|
|
265
|
+
*/
|
|
138
266
|
const hasRequestListener = this.#emitter.hasListeners('http:request_finished');
|
|
139
267
|
const startTime = hasRequestListener ? process.hrtime() : null;
|
|
268
|
+
/**
|
|
269
|
+
* Creating essential instances
|
|
270
|
+
*/
|
|
140
271
|
const resolver = this.#app.container.createResolver();
|
|
141
272
|
const ctx = this.createHttpContext(this.createRequest(req, res), this.createResponse(req, res), resolver);
|
|
273
|
+
/**
|
|
274
|
+
* Emit event when listening for the request_finished event
|
|
275
|
+
*/
|
|
142
276
|
if (startTime) {
|
|
143
277
|
onFinished(res, () => {
|
|
144
278
|
this.#emitter.emit('http:request_finished', {
|
|
@@ -147,6 +281,9 @@ export class Server {
|
|
|
147
281
|
});
|
|
148
282
|
});
|
|
149
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Handle request
|
|
286
|
+
*/
|
|
150
287
|
if (this.usingAsyncLocalStorage) {
|
|
151
288
|
return asyncLocalStorage.storage.run(ctx, () => this.#handleRequest(ctx, resolver));
|
|
152
289
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
export type { NextFn } from '@poppinss/middleware/types';
|
|
2
|
+
/**
|
|
3
|
+
* Accept one or more of the mentioned type
|
|
4
|
+
*/
|
|
2
5
|
export type OneOrMore<T> = T | T[];
|
|
6
|
+
/**
|
|
7
|
+
* Class constructor type
|
|
8
|
+
*/
|
|
3
9
|
export type Constructor<T> = new (...args: any[]) => T;
|
|
10
|
+
/**
|
|
11
|
+
* A function that lazily imports a middleware
|
|
12
|
+
*/
|
|
4
13
|
export type LazyImport<DefaultExport> = () => Promise<{
|
|
5
14
|
default: DefaultExport;
|
|
6
15
|
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Unwraps default export from a lazy import function
|
|
18
|
+
*/
|
|
7
19
|
export type UnWrapLazyImport<Fn extends LazyImport<any>> = Awaited<ReturnType<Fn>>['default'];
|
package/build/src/types/base.js
CHANGED
package/build/src/types/main.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
|
export * from './base.js';
|
|
2
10
|
export * from './middleware.js';
|
|
3
11
|
export * from './qs.js';
|
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import type { ContainerResolver } from '@adonisjs/fold';
|
|
2
2
|
import type { Constructor, NextFn } from './base.js';
|
|
3
3
|
import type { HttpContext } from '../http_context/main.js';
|
|
4
|
+
/**
|
|
5
|
+
* Middleware represented as a class
|
|
6
|
+
*/
|
|
4
7
|
export type MiddlewareAsClass = Constructor<{
|
|
5
8
|
handle: (ctx: HttpContext, next: NextFn, args?: any) => any;
|
|
6
9
|
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Check if a union has undefined or null
|
|
12
|
+
*/
|
|
7
13
|
type HasUndefined<T> = T extends NonNullable<T> ? true : false;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the arguments accepted by the middleware's handle method
|
|
16
|
+
*/
|
|
8
17
|
export type GetMiddlewareArgs<Middleware extends MiddlewareAsClass> = Parameters<InstanceType<Middleware>['handle']>[2] extends undefined ? [] : HasUndefined<Parameters<InstanceType<Middleware>['handle']>[2]> extends true ? [Parameters<InstanceType<Middleware>['handle']>[2]] : [Parameters<InstanceType<Middleware>['handle']>[2]?];
|
|
18
|
+
/**
|
|
19
|
+
* The middleware defined as a function on the router or the server
|
|
20
|
+
*/
|
|
9
21
|
export type MiddlewareFn = (ctx: HttpContext, next: NextFn) => any;
|
|
22
|
+
/**
|
|
23
|
+
* Parsed global middleware
|
|
24
|
+
*/
|
|
10
25
|
export type ParsedGlobalMiddleware = {
|
|
11
26
|
handle: (resolver: ContainerResolver<any>, ...args: [ctx: HttpContext, next: NextFn, params?: any]) => any;
|
|
12
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Parsed named middleware
|
|
30
|
+
*/
|
|
13
31
|
export type ParsedNamedMiddleware = ParsedGlobalMiddleware & {
|
|
14
32
|
name: string;
|
|
15
33
|
args: any;
|