@carno.js/core 0.2.9 → 0.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/dist/Carno.d.ts +6 -2
- package/dist/Carno.js +104 -85
- package/dist/container/InjectorService.js +6 -4
- package/dist/container/middleware.resolver.js +6 -6
- package/dist/domain/BaseContext.d.ts +15 -0
- package/dist/domain/BaseContext.js +2 -0
- package/dist/domain/Context.d.ts +46 -24
- package/dist/domain/Context.js +116 -89
- package/dist/domain/FastContext.d.ts +34 -0
- package/dist/domain/FastContext.js +59 -0
- package/dist/domain/cors-headers-cache.d.ts +2 -0
- package/dist/domain/cors-headers-cache.js +44 -0
- package/dist/route/FastPathExecutor.d.ts +10 -2
- package/dist/route/FastPathExecutor.js +43 -12
- package/dist/route/JITCompiler.d.ts +25 -1
- package/dist/route/JITCompiler.js +205 -98
- package/dist/route/Matcher.d.ts +4 -9
- package/dist/route/Matcher.js +10 -10
- package/dist/route/RouteCompiler.d.ts +0 -1
- package/dist/route/RouteCompiler.js +1 -44
- package/dist/route/RouteExecutor.d.ts +0 -2
- package/dist/route/RouteExecutor.js +19 -13
- package/dist/route/memoirist.d.ts +2 -0
- package/dist/route/memoirist.js +33 -3
- package/dist/services/logger.service.js +0 -7
- package/dist/testing/core-testing.js +5 -1
- package/package.json +2 -2
package/dist/Carno.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface ApplicationConfig<TAdapter extends ValidatorAdapterConstructor
|
|
|
12
12
|
providers?: any[];
|
|
13
13
|
cors?: CorsConfig;
|
|
14
14
|
globalMiddlewares?: any[];
|
|
15
|
+
disableStartupLog?: boolean;
|
|
15
16
|
}
|
|
16
17
|
export declare class Carno<TAdapter extends ValidatorAdapterConstructor = ValidatorAdapterConstructor> {
|
|
17
18
|
config: ApplicationConfig<TAdapter>;
|
|
@@ -20,6 +21,8 @@ export declare class Carno<TAdapter extends ValidatorAdapterConstructor = Valida
|
|
|
20
21
|
private corsCache?;
|
|
21
22
|
private readonly emptyLocals;
|
|
22
23
|
private validatorAdapter;
|
|
24
|
+
private corsEnabled;
|
|
25
|
+
private hasOnRequestHook;
|
|
23
26
|
private fetch;
|
|
24
27
|
private server;
|
|
25
28
|
constructor(config?: ApplicationConfig<TAdapter>);
|
|
@@ -53,15 +56,16 @@ export declare class Carno<TAdapter extends ValidatorAdapterConstructor = Valida
|
|
|
53
56
|
getHttpServer(): Server<any>;
|
|
54
57
|
getInjector(): import("./container").InjectorService;
|
|
55
58
|
private createHttpServer;
|
|
56
|
-
private
|
|
59
|
+
private fetcherAsync;
|
|
57
60
|
private catcher;
|
|
58
61
|
private bootstrapApplication;
|
|
59
62
|
private handleShutdownHook;
|
|
60
63
|
private closeHttpServer;
|
|
61
64
|
private exitProcess;
|
|
62
65
|
private reportHookFailure;
|
|
66
|
+
private resolveLogger;
|
|
63
67
|
private isCorsEnabled;
|
|
64
|
-
private
|
|
68
|
+
private errorResponse;
|
|
65
69
|
private handlePreflightRequest;
|
|
66
70
|
private applyCorsHeaders;
|
|
67
71
|
close(closeActiveConnections?: boolean): void;
|
package/dist/Carno.js
CHANGED
|
@@ -20,42 +20,56 @@ const HttpException_1 = require("./exceptions/HttpException");
|
|
|
20
20
|
const RouteExecutor_1 = require("./route/RouteExecutor");
|
|
21
21
|
const memoirist_1 = __importDefault(require("./route/memoirist"));
|
|
22
22
|
const CompiledRoute_1 = require("./route/CompiledRoute");
|
|
23
|
-
const FastPathExecutor_1 = require("./route/FastPathExecutor");
|
|
24
23
|
const logger_service_1 = require("./services/logger.service");
|
|
25
|
-
const
|
|
26
|
-
|
|
24
|
+
const METHOD_MAP = {
|
|
25
|
+
GET: 'get',
|
|
26
|
+
POST: 'post',
|
|
27
|
+
PUT: 'put',
|
|
28
|
+
DELETE: 'delete',
|
|
29
|
+
PATCH: 'patch',
|
|
30
|
+
HEAD: 'head',
|
|
31
|
+
OPTIONS: 'options'
|
|
32
|
+
};
|
|
27
33
|
class Carno {
|
|
28
34
|
constructor(config = {}) {
|
|
29
35
|
this.config = config;
|
|
30
36
|
this.router = new memoirist_1.default();
|
|
31
37
|
this.injector = (0, createInjector_1.createInjector)();
|
|
32
38
|
this.emptyLocals = new LocalsContainer_1.LocalsContainer();
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
statusCode: error.getStatus(),
|
|
42
|
-
}), {
|
|
43
|
-
status: error.statusCode,
|
|
44
|
-
headers: { "Content-Type": "application/json" },
|
|
45
|
-
});
|
|
46
|
-
if (this.isCorsEnabled()) {
|
|
47
|
-
const origin = request.headers.get("origin");
|
|
48
|
-
if (origin && this.isOriginAllowed(origin)) {
|
|
49
|
-
response = this.applyCorsHeaders(response, origin);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return response;
|
|
39
|
+
this.corsEnabled = false;
|
|
40
|
+
this.hasOnRequestHook = false;
|
|
41
|
+
this.fetch = (request, server) => {
|
|
42
|
+
const method = request.method;
|
|
43
|
+
if (this.corsEnabled) {
|
|
44
|
+
const origin = request.headers.get("origin");
|
|
45
|
+
if (method === "OPTIONS" && origin) {
|
|
46
|
+
return this.handlePreflightRequest(request);
|
|
53
47
|
}
|
|
54
|
-
throw error;
|
|
55
48
|
}
|
|
49
|
+
const url = request.url;
|
|
50
|
+
const startIndex = url.indexOf('/', 12);
|
|
51
|
+
const queryIndex = url.indexOf('?', startIndex);
|
|
52
|
+
const pathname = queryIndex === -1
|
|
53
|
+
? (startIndex === -1 ? '/' : url.slice(startIndex))
|
|
54
|
+
: url.slice(startIndex, queryIndex);
|
|
55
|
+
const methodLower = METHOD_MAP[method] || method.toLowerCase();
|
|
56
|
+
const route = this.router.find(methodLower, pathname);
|
|
57
|
+
if (!route) {
|
|
58
|
+
return this.errorResponse(request, "Method not allowed", 404);
|
|
59
|
+
}
|
|
60
|
+
const compiled = route.store;
|
|
61
|
+
const isCompiledRoute = compiled.routeType !== undefined;
|
|
62
|
+
const isSimpleRoute = isCompiledRoute && compiled.routeType === CompiledRoute_1.RouteType.SIMPLE;
|
|
63
|
+
const isGetOrHead = method === 'GET' || method === 'HEAD';
|
|
64
|
+
const hasQuery = queryIndex !== -1;
|
|
65
|
+
if (isSimpleRoute && isGetOrHead && !this.corsEnabled && !hasQuery && !compiled.isAsync) {
|
|
66
|
+
const context = Context_1.Context.createFastContext(request, route.params);
|
|
67
|
+
return compiled.boundHandler(context);
|
|
68
|
+
}
|
|
69
|
+
return this.fetcherAsync(request, server, route, compiled, isSimpleRoute, hasQuery, queryIndex, url);
|
|
56
70
|
};
|
|
57
71
|
this.catcher = (error) => {
|
|
58
|
-
|
|
72
|
+
this.resolveLogger().error("Unhandled error", error);
|
|
59
73
|
return new Response("Internal Server Error", { status: 500 });
|
|
60
74
|
};
|
|
61
75
|
this.validatorAdapter = this.resolveValidatorAdapter();
|
|
@@ -163,6 +177,8 @@ class Carno {
|
|
|
163
177
|
(0, ValidationCache_1.setValidatorAdapter)(this.validatorAdapter);
|
|
164
178
|
this.loadProvidersAndControllers();
|
|
165
179
|
await this.injector.loadModule((0, createContainer_1.createContainer)(), this.config, this.router, this.validatorAdapter);
|
|
180
|
+
this.corsEnabled = !!this.config.cors;
|
|
181
|
+
this.hasOnRequestHook = this.injector.hasOnRequestHook();
|
|
166
182
|
}
|
|
167
183
|
async listen(port = 3000) {
|
|
168
184
|
this.registerShutdownHandlers();
|
|
@@ -171,7 +187,7 @@ class Carno {
|
|
|
171
187
|
}
|
|
172
188
|
registerShutdownHandlers() {
|
|
173
189
|
const shutdown = async (signal) => {
|
|
174
|
-
|
|
190
|
+
this.resolveLogger().info(`Received ${signal}, starting graceful shutdown...`);
|
|
175
191
|
await this.handleShutdownHook();
|
|
176
192
|
};
|
|
177
193
|
node_process_1.default.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
@@ -185,47 +201,48 @@ class Carno {
|
|
|
185
201
|
}
|
|
186
202
|
createHttpServer(port) {
|
|
187
203
|
this.server = Bun.serve({ port, fetch: this.fetch, error: this.catcher });
|
|
188
|
-
|
|
204
|
+
if (!this.config.disableStartupLog) {
|
|
205
|
+
this.resolveLogger().info(`Server running on port ${port}`);
|
|
206
|
+
}
|
|
189
207
|
}
|
|
190
|
-
async
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
async fetcherAsync(request, server, route, compiled, isSimpleRoute, hasQuery, queryIndex, url) {
|
|
209
|
+
try {
|
|
210
|
+
let response;
|
|
211
|
+
const query = hasQuery ? url.slice(queryIndex + 1) : undefined;
|
|
212
|
+
const context = Context_1.Context.createFromRequestSync({ query }, request, server);
|
|
213
|
+
context.param = route.params;
|
|
214
|
+
if (isSimpleRoute) {
|
|
215
|
+
response = compiled.isAsync
|
|
216
|
+
? await compiled.boundHandler(context)
|
|
217
|
+
: compiled.boundHandler(context);
|
|
195
218
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
? compiled.needsLocalsContainer
|
|
215
|
-
: true;
|
|
216
|
-
const locals = this.resolveLocalsContainer(needsLocalsContainer, context);
|
|
217
|
-
if (this.injector.hasOnRequestHook()) {
|
|
218
|
-
await this.injector.callHook(on_event_1.EventType.OnRequest, { context });
|
|
219
|
+
else {
|
|
220
|
+
const needsLocalsContainer = compiled.routeType !== undefined
|
|
221
|
+
? compiled.needsLocalsContainer
|
|
222
|
+
: true;
|
|
223
|
+
const locals = this.resolveLocalsContainer(needsLocalsContainer, context);
|
|
224
|
+
if (this.hasOnRequestHook) {
|
|
225
|
+
await this.injector.callHook(on_event_1.EventType.OnRequest, { context });
|
|
226
|
+
}
|
|
227
|
+
response = await RouteExecutor_1.RouteExecutor.executeRoute(compiled, this.injector, context, locals);
|
|
228
|
+
}
|
|
229
|
+
if (this.corsEnabled) {
|
|
230
|
+
const origin = request.headers.get("origin");
|
|
231
|
+
if (origin && this.corsCache.isOriginAllowed(origin)) {
|
|
232
|
+
if (!(response instanceof Response)) {
|
|
233
|
+
response = RouteExecutor_1.RouteExecutor.mountResponse(response, context);
|
|
234
|
+
}
|
|
235
|
+
return this.applyCorsHeaders(response, origin);
|
|
236
|
+
}
|
|
219
237
|
}
|
|
220
|
-
response
|
|
238
|
+
return response;
|
|
221
239
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
response = this.applyCorsHeaders(response, origin);
|
|
240
|
+
catch (error) {
|
|
241
|
+
if (error instanceof HttpException_1.HttpException) {
|
|
242
|
+
return this.errorResponse(request, error.getResponse(), error.getStatus());
|
|
226
243
|
}
|
|
244
|
+
throw error;
|
|
227
245
|
}
|
|
228
|
-
return response;
|
|
229
246
|
}
|
|
230
247
|
async bootstrapApplication() {
|
|
231
248
|
try {
|
|
@@ -248,42 +265,44 @@ class Carno {
|
|
|
248
265
|
}
|
|
249
266
|
closeHttpServer() {
|
|
250
267
|
if (this.server) {
|
|
251
|
-
|
|
268
|
+
this.resolveLogger().info("Closing HTTP server...");
|
|
252
269
|
this.server.stop(true);
|
|
253
270
|
}
|
|
254
271
|
}
|
|
255
272
|
exitProcess(code = 0) {
|
|
256
|
-
|
|
273
|
+
this.resolveLogger().info("Shutdown complete.");
|
|
257
274
|
node_process_1.default.exit(code);
|
|
258
275
|
}
|
|
259
276
|
reportHookFailure(event, error) {
|
|
260
|
-
|
|
277
|
+
this.resolveLogger().error(`Lifecycle hook ${event} failed`, error);
|
|
278
|
+
}
|
|
279
|
+
resolveLogger() {
|
|
280
|
+
const provider = this.injector.get(logger_service_1.LoggerService);
|
|
281
|
+
const instance = provider?.instance;
|
|
282
|
+
return instance ?? new logger_service_1.LoggerService(this.injector);
|
|
261
283
|
}
|
|
262
284
|
isCorsEnabled() {
|
|
263
285
|
return !!this.config.cors;
|
|
264
286
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
if (typeof origins === "function") {
|
|
280
|
-
return origins(origin);
|
|
287
|
+
errorResponse(request, message, statusCode) {
|
|
288
|
+
let response = new Response(JSON.stringify({
|
|
289
|
+
message,
|
|
290
|
+
statusCode,
|
|
291
|
+
}), {
|
|
292
|
+
status: statusCode,
|
|
293
|
+
headers: { "Content-Type": "application/json" },
|
|
294
|
+
});
|
|
295
|
+
if (this.corsEnabled) {
|
|
296
|
+
const origin = request.headers.get("origin");
|
|
297
|
+
if (origin && this.corsCache.isOriginAllowed(origin)) {
|
|
298
|
+
response = this.applyCorsHeaders(response, origin);
|
|
299
|
+
}
|
|
281
300
|
}
|
|
282
|
-
return
|
|
301
|
+
return response;
|
|
283
302
|
}
|
|
284
303
|
handlePreflightRequest(request) {
|
|
285
304
|
const origin = request.headers.get("origin");
|
|
286
|
-
if (!this.isOriginAllowed(origin)) {
|
|
305
|
+
if (!origin || !this.corsCache.isOriginAllowed(origin)) {
|
|
287
306
|
return new Response(null, { status: 403 });
|
|
288
307
|
}
|
|
289
308
|
const corsHeaders = this.corsCache.get(origin);
|
|
@@ -310,10 +329,10 @@ class Carno {
|
|
|
310
329
|
return locals;
|
|
311
330
|
}
|
|
312
331
|
discoverRoutePath(url) {
|
|
313
|
-
if (url
|
|
314
|
-
return url
|
|
332
|
+
if (typeof url === 'string') {
|
|
333
|
+
return url;
|
|
315
334
|
}
|
|
316
|
-
return url?.path ||
|
|
335
|
+
return url?.pathname || url?.path || '/';
|
|
317
336
|
}
|
|
318
337
|
}
|
|
319
338
|
exports.Carno = Carno;
|
|
@@ -99,10 +99,12 @@ let InjectorService = InjectorService_1 = class InjectorService {
|
|
|
99
99
|
}
|
|
100
100
|
return this.invoke(token, locals);
|
|
101
101
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
invokeRoute(route, context, locals, instance) {
|
|
103
|
+
const middlewarePromise = middleware_resolver_1.MiddlewareRes.resolveMiddlewares(route, this, locals);
|
|
104
|
+
if (middlewarePromise instanceof Promise) {
|
|
105
|
+
return middlewarePromise.then(() => this.methodInvoker.invoke(instance, route.methodName, locals, context, (t, l) => this.invoke(t, l)));
|
|
106
|
+
}
|
|
107
|
+
return this.methodInvoker.invoke(instance, route.methodName, locals, context, (t, l) => this.invoke(t, l));
|
|
106
108
|
}
|
|
107
109
|
scopeOf(provider) {
|
|
108
110
|
return provider.scope || provider_scope_1.ProviderScope.SINGLETON;
|
|
@@ -14,21 +14,21 @@ class MiddlewareResolver {
|
|
|
14
14
|
let currentIndex = 0;
|
|
15
15
|
const next = async () => {
|
|
16
16
|
if (currentIndex >= middlewares.length) {
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
17
|
+
// If all middlewares are already processed, do nothing.
|
|
18
|
+
// This avoids "Middleware stack exhausted" if a middleware calls `next()`
|
|
19
|
+
// when there are no more middlewares.
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const middleware = middlewares[currentIndex++];
|
|
23
23
|
// @ts-ignore
|
|
24
24
|
const instance = injector.invoke(middleware, local);
|
|
25
|
-
// Await
|
|
26
|
-
//
|
|
25
|
+
// Await the middleware execution.
|
|
26
|
+
// If the middleware throws, the exception will propagate.
|
|
27
27
|
await instance.handle(context, next);
|
|
28
28
|
};
|
|
29
29
|
if (middlewares.length === 0)
|
|
30
30
|
return;
|
|
31
|
-
//
|
|
31
|
+
// Start the middleware execution
|
|
32
32
|
await next();
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseContext - Interface mínima que todo contexto deve implementar.
|
|
3
|
+
*
|
|
4
|
+
* Define o contrato básico para FastContext e Context,
|
|
5
|
+
* permitindo que handlers compilados trabalhem com ambos.
|
|
6
|
+
*/
|
|
7
|
+
export interface BaseContext {
|
|
8
|
+
readonly req: Request;
|
|
9
|
+
param: Record<string, string>;
|
|
10
|
+
readonly headers: Headers;
|
|
11
|
+
readonly query: Record<string, string>;
|
|
12
|
+
status: number;
|
|
13
|
+
setResponseStatus(status: number): void;
|
|
14
|
+
getResponseStatus(): number;
|
|
15
|
+
}
|
package/dist/domain/Context.d.ts
CHANGED
|
@@ -1,36 +1,58 @@
|
|
|
1
1
|
import { Server } from 'bun';
|
|
2
|
+
/**
|
|
3
|
+
* Context otimizado com shape mínimo e lazy loading.
|
|
4
|
+
*
|
|
5
|
+
* Shape fixo mínimo (sempre alocado):
|
|
6
|
+
* - req: Request
|
|
7
|
+
* - param: Record<string, string>
|
|
8
|
+
* - status: number
|
|
9
|
+
*
|
|
10
|
+
* Lazy loading (só aloca quando usado):
|
|
11
|
+
* - query: Record<string, string> (getter lazy)
|
|
12
|
+
* - headers: Headers (getter que retorna req.headers)
|
|
13
|
+
* - body: Record<string, any> (getter lazy)
|
|
14
|
+
* - locals: Record<string, any> (getter lazy)
|
|
15
|
+
* - rawBody: ArrayBuffer (lazy)
|
|
16
|
+
*
|
|
17
|
+
* V8/JSC otimiza shape consistente. Propriedades lazy não quebram
|
|
18
|
+
* monomorfismo porque são getters, não props dinâmicas.
|
|
19
|
+
*/
|
|
2
20
|
export declare class Context {
|
|
3
|
-
query: Record<string, any>;
|
|
4
|
-
private _body;
|
|
5
|
-
rawBody?: ArrayBuffer;
|
|
6
|
-
param: Record<string, any>;
|
|
7
21
|
req: Request;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
private
|
|
22
|
+
param: Record<string, string>;
|
|
23
|
+
status: number;
|
|
24
|
+
private _queryString;
|
|
25
|
+
private _query;
|
|
26
|
+
private _locals;
|
|
27
|
+
private _body;
|
|
28
|
+
private _rawBody;
|
|
12
29
|
private _bodyParsed;
|
|
13
30
|
private constructor();
|
|
31
|
+
get headers(): Headers;
|
|
32
|
+
get query(): Record<string, string>;
|
|
33
|
+
set query(value: Record<string, string>);
|
|
34
|
+
get locals(): Record<string, any>;
|
|
35
|
+
set locals(value: Record<string, any>);
|
|
14
36
|
get body(): Record<string, any>;
|
|
15
37
|
set body(value: Record<string, any>);
|
|
38
|
+
get rawBody(): ArrayBuffer | undefined;
|
|
39
|
+
set rawBody(value: ArrayBuffer | undefined);
|
|
16
40
|
getBody(): Promise<Record<string, any>>;
|
|
17
41
|
isBodyParsed(): boolean;
|
|
18
|
-
static createFromRequest(url: any, request: Request, server: Server<any>): Promise<Context>;
|
|
19
|
-
static createFromRequestSync(url: any, request: Request, server: Server<any>): Context;
|
|
20
|
-
static createFromRequestWithBody(url: any, request: Request, server: Server<any>): Promise<Context>;
|
|
21
|
-
static createFromJob(job: any): Context;
|
|
22
|
-
private setQuery;
|
|
23
|
-
private setBody;
|
|
24
|
-
private setReq;
|
|
25
|
-
private setHeaders;
|
|
26
|
-
setParam(param: Record<string, any>): void;
|
|
27
42
|
setResponseStatus(status: number): void;
|
|
28
43
|
getResponseStatus(): number;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
setParam(param: Record<string, string>): void;
|
|
45
|
+
static createFromRequestSync(url: {
|
|
46
|
+
query?: string;
|
|
47
|
+
}, request: Request, server: Server<any>): Context;
|
|
48
|
+
static createFastContext(request: Request, params: Record<string, any>): Context;
|
|
49
|
+
static createFromRequest(url: {
|
|
50
|
+
query?: string;
|
|
51
|
+
}, request: Request, server: Server<any>): Promise<Context>;
|
|
52
|
+
static createFromJob(job: any): Context;
|
|
53
|
+
private parseQueryString;
|
|
54
|
+
private parseBody;
|
|
55
|
+
private parseJsonBody;
|
|
56
|
+
private parseFormDataBody;
|
|
57
|
+
private parseUrlEncodedBody;
|
|
36
58
|
}
|