@c9up/ream 0.2.29 → 0.2.30
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 +5 -6
- package/dist/Codemods.d.ts +8 -0
- package/dist/Codemods.d.ts.map +1 -1
- package/dist/Codemods.js +29 -1
- package/dist/Codemods.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +17 -5
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +5 -0
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +12 -1
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +4 -4
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +38 -11
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/MultipartFile.d.ts +21 -15
- package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
- package/dist/bodyparser/MultipartFile.js +40 -58
- package/dist/bodyparser/MultipartFile.js.map +1 -1
- package/dist/bodyparser/parseSize.d.ts +7 -4
- package/dist/bodyparser/parseSize.d.ts.map +1 -1
- package/dist/bodyparser/parseSize.js +12 -17
- package/dist/bodyparser/parseSize.js.map +1 -1
- package/dist/bodyparser/qsParse.d.ts +10 -0
- package/dist/bodyparser/qsParse.d.ts.map +1 -1
- package/dist/bodyparser/qsParse.js +27 -12
- package/dist/bodyparser/qsParse.js.map +1 -1
- package/dist/console/prompts.d.ts.map +1 -1
- package/dist/console/prompts.js +3 -1
- package/dist/console/prompts.js.map +1 -1
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +61 -71
- package/dist/container/Container.js.map +1 -1
- package/dist/events/Emitter.d.ts +12 -0
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +36 -9
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/helix/helpers.d.ts.map +1 -1
- package/dist/events/helix/helpers.js +19 -9
- package/dist/events/helix/helpers.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +8 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +77 -11
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/helpers/MessageBuilder.d.ts +4 -2
- package/dist/helpers/MessageBuilder.d.ts.map +1 -1
- package/dist/helpers/MessageBuilder.js +4 -2
- package/dist/helpers/MessageBuilder.js.map +1 -1
- package/dist/helpers/errors.d.ts +11 -0
- package/dist/helpers/errors.d.ts.map +1 -0
- package/dist/helpers/errors.js +17 -0
- package/dist/helpers/errors.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts.map +1 -1
- package/dist/helpers/napi-loader.js +3 -2
- package/dist/helpers/napi-loader.js.map +1 -1
- package/dist/http/HttpContext.d.ts +20 -2
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +10 -4
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +4 -0
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +15 -29
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +7 -4
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +14 -6
- package/dist/http/Response.js.map +1 -1
- package/dist/http/permissions.d.ts +14 -8
- package/dist/http/permissions.d.ts.map +1 -1
- package/dist/http/permissions.js +26 -16
- package/dist/http/permissions.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.js +1 -1
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/native/generated.d.ts +16 -30
- package/dist/native/generated.d.ts.map +1 -1
- package/dist/profiler/Profiler.d.ts.map +1 -1
- package/dist/profiler/Profiler.js +4 -1
- package/dist/profiler/Profiler.js.map +1 -1
- package/dist/profiler/client.generated.d.ts +5 -0
- package/dist/profiler/client.generated.d.ts.map +1 -0
- package/dist/profiler/client.generated.js +6 -0
- package/dist/profiler/client.generated.js.map +1 -0
- package/dist/profiler/collectors.d.ts +92 -13
- package/dist/profiler/collectors.d.ts.map +1 -1
- package/dist/profiler/collectors.js +106 -19
- package/dist/profiler/collectors.js.map +1 -1
- package/dist/profiler/endpoint.d.ts +2 -1
- package/dist/profiler/endpoint.d.ts.map +1 -1
- package/dist/profiler/endpoint.js +25 -1
- package/dist/profiler/endpoint.js.map +1 -1
- package/dist/profiler/index.d.ts +8 -4
- package/dist/profiler/index.d.ts.map +1 -1
- package/dist/profiler/index.js +11 -4
- package/dist/profiler/index.js.map +1 -1
- package/dist/profiler/middleware.d.ts.map +1 -1
- package/dist/profiler/middleware.js +76 -10
- package/dist/profiler/middleware.js.map +1 -1
- package/dist/profiler/preview.d.ts +17 -0
- package/dist/profiler/preview.d.ts.map +1 -0
- package/dist/profiler/preview.js +100 -0
- package/dist/profiler/preview.js.map +1 -0
- package/dist/profiler/toolbar.d.ts +15 -23
- package/dist/profiler/toolbar.d.ts.map +1 -1
- package/dist/profiler/toolbar.js +25 -91
- package/dist/profiler/toolbar.js.map +1 -1
- package/dist/profiler/types.d.ts +6 -1
- package/dist/profiler/types.d.ts.map +1 -1
- package/dist/router/Router.d.ts +6 -0
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +115 -12
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcRouter.js +3 -3
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/Scheduler.js +1 -1
- package/dist/scheduler/Scheduler.js.map +1 -1
- package/dist/security/CookieSigner.d.ts.map +1 -1
- package/dist/security/CookieSigner.js +15 -5
- package/dist/security/CookieSigner.js.map +1 -1
- package/dist/security/SignedUrl.d.ts.map +1 -1
- package/dist/security/SignedUrl.js +10 -18
- package/dist/security/SignedUrl.js.map +1 -1
- package/dist/server/Server.d.ts +4 -1
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/nativeLimits.d.ts +9 -1
- package/dist/server/nativeLimits.d.ts.map +1 -1
- package/dist/server/nativeLimits.js +8 -0
- package/dist/server/nativeLimits.js.map +1 -1
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +13 -4
- package/dist/session/Session.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +14 -2
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/storage/StaticMiddleware.d.ts.map +1 -1
- package/dist/storage/StaticMiddleware.js +20 -9
- package/dist/storage/StaticMiddleware.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts.map +1 -1
- package/dist/testing/ApiResponse.js +7 -1
- package/dist/testing/ApiResponse.js.map +1 -1
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +16 -4
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.d.ts +1 -1
- package/dist/utils/Macroable.js +2 -2
- package/dist/utils/Macroable.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -2
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Codemods.ts +49 -3
- package/src/HttpKernel.ts +18 -7
- package/src/Ignitor.ts +21 -4
- package/src/bodyparser/BodyParserMiddleware.ts +42 -16
- package/src/bodyparser/MultipartFile.ts +46 -67
- package/src/bodyparser/parseSize.ts +17 -17
- package/src/bodyparser/qsParse.ts +28 -13
- package/src/console/prompts.ts +3 -1
- package/src/container/Container.ts +97 -81
- package/src/events/Emitter.ts +37 -10
- package/src/events/helix/helpers.ts +24 -19
- package/src/graphql/GraphQLEngine.ts +89 -13
- package/src/helpers/MessageBuilder.ts +4 -2
- package/src/helpers/errors.ts +16 -0
- package/src/helpers/napi-loader.ts +3 -2
- package/src/http/HttpContext.ts +20 -4
- package/src/http/RedirectBuilder.ts +3 -0
- package/src/http/Request.ts +15 -29
- package/src/http/Response.ts +15 -7
- package/src/http/permissions.ts +31 -15
- package/src/index.ts +2 -1
- package/src/middleware/Pipeline.ts +1 -1
- package/src/native/generated.ts +18 -42
- package/src/profiler/Profiler.ts +4 -1
- package/src/profiler/client/toolbar.css +595 -0
- package/src/profiler/client/toolbar.js +1299 -0
- package/src/profiler/client.generated.ts +7 -0
- package/src/profiler/collectors.ts +156 -19
- package/src/profiler/endpoint.ts +27 -1
- package/src/profiler/index.ts +17 -3
- package/src/profiler/middleware.ts +74 -9
- package/src/profiler/preview.ts +104 -0
- package/src/profiler/toolbar.ts +28 -91
- package/src/profiler/types.ts +6 -1
- package/src/router/Router.ts +136 -13
- package/src/rpc/RpcRouter.ts +4 -4
- package/src/scheduler/Scheduler.ts +1 -1
- package/src/security/CookieSigner.ts +13 -5
- package/src/security/SignedUrl.ts +12 -16
- package/src/server/Server.ts +4 -1
- package/src/server/nativeLimits.ts +18 -1
- package/src/session/Session.ts +13 -4
- package/src/session/drivers/MemoryDriver.ts +15 -2
- package/src/storage/StaticMiddleware.ts +18 -9
- package/src/testing/ApiResponse.ts +7 -1
- package/src/testing/TestClient.ts +14 -5
- package/src/utils/Macroable.ts +2 -2
- package/scripts/build-napi-types.mjs +0 -69
- package/scripts/copy-napi.mjs +0 -121
- package/scripts/generate-mime.mjs +0 -119
- package/scripts/generate-napi-types.mjs +0 -187
|
@@ -15,11 +15,11 @@ export interface BodyParserConfig {
|
|
|
15
15
|
*/
|
|
16
16
|
allowedMethods?: string[];
|
|
17
17
|
json?: {
|
|
18
|
-
limit?: string;
|
|
18
|
+
limit?: string | number;
|
|
19
19
|
types?: string[];
|
|
20
20
|
};
|
|
21
21
|
form?: {
|
|
22
|
-
limit?: string;
|
|
22
|
+
limit?: string | number;
|
|
23
23
|
types?: string[];
|
|
24
24
|
/**
|
|
25
25
|
* Turn `''` into `null`. AdonisJS defaults this to `true`, so an empty
|
|
@@ -33,12 +33,12 @@ export interface BodyParserConfig {
|
|
|
33
33
|
queryString?: QsParseOptions;
|
|
34
34
|
};
|
|
35
35
|
raw?: {
|
|
36
|
-
limit?: string;
|
|
36
|
+
limit?: string | number;
|
|
37
37
|
types?: string[];
|
|
38
38
|
};
|
|
39
39
|
multipart?: {
|
|
40
40
|
/** Total multipart body size cap (sum of all file sizes). Default: '20mb'. */
|
|
41
|
-
limit?: string;
|
|
41
|
+
limit?: string | number;
|
|
42
42
|
/**
|
|
43
43
|
* Maximum number of files per request. AdonisJS has no such option — it
|
|
44
44
|
* bounds a multipart body by total size and field count only, so ten
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BodyParserMiddleware.d.ts","sourceRoot":"","sources":["../../src/bodyparser/BodyParserMiddleware.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAGzD,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAEpE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,IAAI,CAAC,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"BodyParserMiddleware.d.ts","sourceRoot":"","sources":["../../src/bodyparser/BodyParserMiddleware.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAGzD,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAEpE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,IAAI,CAAC,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACvB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KACjB,CAAA;IACD,IAAI,CAAC,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACvB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;QAChB;;;;WAIG;QACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;QACnC,qEAAqE;QACrE,eAAe,CAAC,EAAE,OAAO,CAAA;QACzB,2EAA2E;QAC3E,WAAW,CAAC,EAAE,cAAc,CAAA;KAC7B,CAAA;IACD,GAAG,CAAC,EAAE;QACJ,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACvB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KACjB,CAAA;IACD,SAAS,CAAC,EAAE;QACV,8EAA8E;QAC9E,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACvB;;;;;WAKG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,6DAA6D;QAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KACjB,CAAA;CACF;AAwCD,MAAM,CAAC,OAAO,OAAO,oBAAoB;;gBAK3B,cAAc,GAAE,gBAAgB,GAAG,SAAqB;IA2B9D,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;CAsGzD"}
|
|
@@ -41,6 +41,8 @@ const DEFAULT_CONFIG = {
|
|
|
41
41
|
};
|
|
42
42
|
export default class BodyParserMiddleware {
|
|
43
43
|
#config;
|
|
44
|
+
/** Each section's limit in bytes, read once so a bad size fails at boot. */
|
|
45
|
+
#limits;
|
|
44
46
|
constructor(explicitConfig = undefined) {
|
|
45
47
|
// The default value is load-bearing: an OPTIONAL parameter still counts
|
|
46
48
|
// toward `Function.length`, and the container refuses to auto-construct a
|
|
@@ -60,6 +62,12 @@ export default class BodyParserMiddleware {
|
|
|
60
62
|
raw: { ...DEFAULT_CONFIG.raw, ...config?.raw },
|
|
61
63
|
multipart: { ...DEFAULT_CONFIG.multipart, ...config?.multipart },
|
|
62
64
|
};
|
|
65
|
+
this.#limits = {
|
|
66
|
+
json: parseSize(this.#config.json.limit),
|
|
67
|
+
form: parseSize(this.#config.form.limit),
|
|
68
|
+
raw: parseSize(this.#config.raw.limit),
|
|
69
|
+
multipart: parseSize(this.#config.multipart.limit),
|
|
70
|
+
};
|
|
63
71
|
}
|
|
64
72
|
async handle(ctx, next) {
|
|
65
73
|
// Only methods that are supposed to carry a body get one parsed
|
|
@@ -82,12 +90,13 @@ export default class BodyParserMiddleware {
|
|
|
82
90
|
// Size check. Thrown rather than written: the app's exception handler
|
|
83
91
|
// negotiates the response, so an HTML app gets an error page instead of a
|
|
84
92
|
// JSON envelope it never asked for — and can override the rendering.
|
|
85
|
-
if (Buffer.byteLength(rawBody, 'utf8') >
|
|
93
|
+
if (Buffer.byteLength(rawBody, 'utf8') > this.#getLimit(contentType)) {
|
|
86
94
|
throw entityTooLarge('request entity too large');
|
|
87
95
|
}
|
|
88
|
-
// JSON
|
|
96
|
+
// JSON — parsed here and only here, under one of `json.types`. A body
|
|
97
|
+
// with any other media type (or none) is never read as JSON.
|
|
89
98
|
if (matchesType(contentType, this.#config.json.types)) {
|
|
90
|
-
|
|
99
|
+
ctx.request.setParsedBody(parseJsonBody(rawBody));
|
|
91
100
|
}
|
|
92
101
|
// Form URL-encoded
|
|
93
102
|
if (matchesType(contentType, this.#config.form.types)) {
|
|
@@ -123,12 +132,12 @@ export default class BodyParserMiddleware {
|
|
|
123
132
|
}
|
|
124
133
|
#getLimit(contentType) {
|
|
125
134
|
if (matchesType(contentType, this.#config.json.types))
|
|
126
|
-
return this.#
|
|
135
|
+
return this.#limits.json;
|
|
127
136
|
if (matchesType(contentType, this.#config.form.types))
|
|
128
|
-
return this.#
|
|
137
|
+
return this.#limits.form;
|
|
129
138
|
if (matchesType(contentType, this.#config.multipart.types))
|
|
130
|
-
return this.#
|
|
131
|
-
return this.#
|
|
139
|
+
return this.#limits.multipart;
|
|
140
|
+
return this.#limits.raw;
|
|
132
141
|
}
|
|
133
142
|
/**
|
|
134
143
|
* Throws when the multipart payload exceeds a configured limit.
|
|
@@ -146,11 +155,30 @@ export default class BodyParserMiddleware {
|
|
|
146
155
|
throw entityTooLarge('Files length limit exceeded');
|
|
147
156
|
}
|
|
148
157
|
const totalBytes = files.reduce((sum, f) => sum + f.size, 0);
|
|
149
|
-
if (totalBytes >
|
|
158
|
+
if (totalBytes > this.#limits.multipart) {
|
|
150
159
|
throw entityTooLarge('request entity too large');
|
|
151
160
|
}
|
|
152
161
|
}
|
|
153
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* A JSON body as the request body: an object as is, any other JSON value under
|
|
165
|
+
* `_body` (the shape the raw-text parser uses), and `{}` for malformed JSON.
|
|
166
|
+
*/
|
|
167
|
+
function parseJsonBody(raw) {
|
|
168
|
+
if (raw.length === 0)
|
|
169
|
+
return {};
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(raw);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
178
|
+
return { ...parsed };
|
|
179
|
+
}
|
|
180
|
+
return { _body: parsed };
|
|
181
|
+
}
|
|
154
182
|
/** The one exception every body-size limit raises (AdonisJS parity). */
|
|
155
183
|
function entityTooLarge(message) {
|
|
156
184
|
return new Exception(message, { status: 413, code: 'E_REQUEST_ENTITY_TOO_LARGE' });
|
|
@@ -178,8 +206,7 @@ function matchesType(contentType, types) {
|
|
|
178
206
|
}
|
|
179
207
|
/**
|
|
180
208
|
* `enabled` was an atlas-era invention: AdonisJS has no such flag, and a parser
|
|
181
|
-
* is turned off by giving it no `types`.
|
|
182
|
-
* `Request` lazy-parses on first read regardless.
|
|
209
|
+
* is turned off by giving it no `types`.
|
|
183
210
|
*
|
|
184
211
|
* Silently ignoring a config key that used to mean something would re-enable a
|
|
185
212
|
* parser an app deliberately switched off, so it fails loudly with the
|
|
@@ -203,7 +230,7 @@ function assertNoEnabledFlag(config) {
|
|
|
203
230
|
if (multipart !== null && typeof multipart === 'object' && 'tmpDir' in multipart) {
|
|
204
231
|
throw new Error('[E_BODYPARSER_CONFIG] `multipart.tmpDir` is not supported — uploaded files are held in ' +
|
|
205
232
|
'memory and never written to a temporary directory. Choose the destination when you ' +
|
|
206
|
-
'store the file: `await file.
|
|
233
|
+
'store the file: `await file.move(directory)`.');
|
|
207
234
|
}
|
|
208
235
|
}
|
|
209
236
|
//# sourceMappingURL=BodyParserMiddleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BodyParserMiddleware.js","sourceRoot":"","sources":["../../src/bodyparser/BodyParserMiddleware.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAuB,MAAM,cAAc,CAAA;AAuDpE,MAAM,cAAc,GAA6B;IAC/C,4EAA4E;IAC5E,kCAAkC;IAClC,cAAc,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;IAClD,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;KACxD;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,CAAC,mCAAmC,CAAC;QAC5C,+EAA+E;QAC/E,gEAAgE;QAChE,yBAAyB,EAAE,IAAI;QAC/B,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,EAAE;KAChB;IACD,GAAG,EAAE;QACH,sEAAsE;QACtE,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,CAAC,QAAQ,CAAC;KAClB;IACD,SAAS,EAAE;QACT,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,CAAC,qBAAqB,CAAC;KAC/B;CACF,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAA0B;
|
|
1
|
+
{"version":3,"file":"BodyParserMiddleware.js","sourceRoot":"","sources":["../../src/bodyparser/BodyParserMiddleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
*/
|
|
19
19
|
export type MimeType = 'application' | 'audio' | 'example' | 'font' | 'image' | 'message' | 'model' | 'multipart' | 'text' | 'video';
|
|
20
20
|
import { Readable } from 'node:stream';
|
|
21
|
+
import { Macroable } from '../utils/Macroable.js';
|
|
21
22
|
export interface FileValidationOptions {
|
|
22
|
-
size
|
|
23
|
+
/** Largest accepted size: bytes, or a value such as `'2mb'` or `'1.5 mb'`. */
|
|
24
|
+
size?: string | number;
|
|
23
25
|
extnames?: string[];
|
|
24
26
|
}
|
|
25
|
-
export declare class MultipartFile {
|
|
27
|
+
export declare class MultipartFile extends Macroable {
|
|
26
28
|
#private;
|
|
27
29
|
/** Original filename from the client. */
|
|
28
30
|
readonly clientName: string;
|
|
@@ -82,6 +84,11 @@ export declare class MultipartFile {
|
|
|
82
84
|
filePath?: string;
|
|
83
85
|
/** The name it was written under, once it has been moved. */
|
|
84
86
|
fileName?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Free-form data about the file, for whoever moves it: a storage macro
|
|
89
|
+
* records the URL of the stored object here.
|
|
90
|
+
*/
|
|
91
|
+
meta: Record<string, unknown>;
|
|
85
92
|
/** File size in bytes. */
|
|
86
93
|
readonly size: number;
|
|
87
94
|
/** Raw file content as Buffer. */
|
|
@@ -140,14 +147,6 @@ export declare class MultipartFile {
|
|
|
140
147
|
*/
|
|
141
148
|
validate(options?: FileValidationOptions): boolean;
|
|
142
149
|
get isValid(): boolean;
|
|
143
|
-
/**
|
|
144
|
-
* Move file to a directory on disk. When `name` is supplied it must be
|
|
145
|
-
* a plain filename — no path separators, no `.`/`..` segments. The
|
|
146
|
-
* common footgun is passing the client-supplied `clientName` directly
|
|
147
|
-
* (`await file.moveToDisk('uploads', file.clientName)`); a malicious
|
|
148
|
-
* upload could otherwise traverse out of `directory` via `../../etc/...`.
|
|
149
|
-
*/
|
|
150
|
-
moveToDisk(directory: string, name?: string): Promise<string>;
|
|
151
150
|
/**
|
|
152
151
|
* Write the file into `location` (AdonisJS `move`).
|
|
153
152
|
*
|
|
@@ -156,10 +155,17 @@ export declare class MultipartFile {
|
|
|
156
155
|
* construction), so this writes the buffer. There is therefore no
|
|
157
156
|
* `E_MISSING_FILE_TMP_PATH`: there is no temporary file to be missing.
|
|
158
157
|
*
|
|
159
|
-
* `overwrite` defaults to true, as upstream.
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
158
|
+
* `overwrite` defaults to true, as upstream.
|
|
159
|
+
*
|
|
160
|
+
* NAMED DEVIATION — without `name`, upstream writes under `clientName`, a
|
|
161
|
+
* value the client chose; Ream generates a random name carrying the
|
|
162
|
+
* detected extension, so an upload neither picks its own path nor
|
|
163
|
+
* overwrites another one by sharing its name.
|
|
164
|
+
*
|
|
165
|
+
* A caller-supplied `name` must be a plain filename (no separator, no `.`
|
|
166
|
+
* or `..`): the common footgun is passing `file.clientName` straight
|
|
167
|
+
* through. The generated name is checked too, since its extension comes
|
|
168
|
+
* from the client's filename when the bytes are not recognised.
|
|
163
169
|
*/
|
|
164
170
|
move(location: string, options?: {
|
|
165
171
|
name?: string;
|
|
@@ -195,7 +201,7 @@ export declare function hydrateMultipartPayload(payload: {
|
|
|
195
201
|
contentB64: string;
|
|
196
202
|
}>;
|
|
197
203
|
}): {
|
|
198
|
-
fields: Record<string,
|
|
204
|
+
fields: Record<string, unknown>;
|
|
199
205
|
files: MultipartFile[];
|
|
200
206
|
};
|
|
201
207
|
//# sourceMappingURL=MultipartFile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultipartFile.d.ts","sourceRoot":"","sources":["../../src/bodyparser/MultipartFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,SAAS,GACT,OAAO,GACP,WAAW,GACX,MAAM,GACN,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"MultipartFile.d.ts","sourceRoot":"","sources":["../../src/bodyparser/MultipartFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,11 +19,19 @@ function isMimeType(value) {
|
|
|
19
19
|
*
|
|
20
20
|
* Like AdonisJS MultipartFile:
|
|
21
21
|
* const avatar = request.file('avatar', { size: '2mb', extnames: ['jpg', 'png'] })
|
|
22
|
-
* await avatar.
|
|
22
|
+
* await avatar.move(app.makePath('uploads'))
|
|
23
|
+
*
|
|
24
|
+
* Macroable: a package extends every upload at boot, the way a storage
|
|
25
|
+
* package adds `moveToDisk(key, disk?, options?)` to write it to a configured
|
|
26
|
+
* disk. `moveToDisk` is deliberately not defined here, so that macro owns it.
|
|
23
27
|
*/
|
|
24
28
|
import { randomBytes } from 'node:crypto';
|
|
25
29
|
import { Readable } from 'node:stream';
|
|
26
|
-
|
|
30
|
+
import { errorCode } from '../helpers/errors.js';
|
|
31
|
+
import { Macroable } from '../utils/Macroable.js';
|
|
32
|
+
import { parseSize } from './parseSize.js';
|
|
33
|
+
import { parseFormFields } from './qsParse.js';
|
|
34
|
+
export class MultipartFile extends Macroable {
|
|
27
35
|
/** Original filename from the client. */
|
|
28
36
|
clientName;
|
|
29
37
|
/**
|
|
@@ -105,6 +113,11 @@ export class MultipartFile {
|
|
|
105
113
|
filePath;
|
|
106
114
|
/** The name it was written under, once it has been moved. */
|
|
107
115
|
fileName;
|
|
116
|
+
/**
|
|
117
|
+
* Free-form data about the file, for whoever moves it: a storage macro
|
|
118
|
+
* records the URL of the stored object here.
|
|
119
|
+
*/
|
|
120
|
+
meta = {};
|
|
108
121
|
/** File size in bytes. */
|
|
109
122
|
size;
|
|
110
123
|
/** Raw file content as Buffer. */
|
|
@@ -126,6 +139,7 @@ export class MultipartFile {
|
|
|
126
139
|
/** Whether the magic-byte pass has run, however it turned out. */
|
|
127
140
|
#detectionRan = false;
|
|
128
141
|
constructor(options) {
|
|
142
|
+
super();
|
|
129
143
|
this.fieldName = options.fieldName;
|
|
130
144
|
this.clientName = options.clientName;
|
|
131
145
|
this.headers = { 'content-type': options.type };
|
|
@@ -201,8 +215,8 @@ export class MultipartFile {
|
|
|
201
215
|
* spells it.
|
|
202
216
|
*/
|
|
203
217
|
validate(options = this.#validationOptions) {
|
|
204
|
-
if (options.size) {
|
|
205
|
-
const maxBytes =
|
|
218
|
+
if (options.size !== undefined) {
|
|
219
|
+
const maxBytes = parseSize(options.size);
|
|
206
220
|
if (this.size > maxBytes) {
|
|
207
221
|
this.errors.push(`File size ${this.size} exceeds limit ${options.size}`);
|
|
208
222
|
}
|
|
@@ -243,33 +257,6 @@ export class MultipartFile {
|
|
|
243
257
|
get isValid() {
|
|
244
258
|
return this.errors.length === 0;
|
|
245
259
|
}
|
|
246
|
-
/**
|
|
247
|
-
* Move file to a directory on disk. When `name` is supplied it must be
|
|
248
|
-
* a plain filename — no path separators, no `.`/`..` segments. The
|
|
249
|
-
* common footgun is passing the client-supplied `clientName` directly
|
|
250
|
-
* (`await file.moveToDisk('uploads', file.clientName)`); a malicious
|
|
251
|
-
* upload could otherwise traverse out of `directory` via `../../etc/...`.
|
|
252
|
-
*/
|
|
253
|
-
async moveToDisk(directory, name) {
|
|
254
|
-
const { mkdirSync, writeFileSync } = await import('node:fs');
|
|
255
|
-
const { join } = await import('node:path');
|
|
256
|
-
if (name !== undefined && !isSafeFilename(name)) {
|
|
257
|
-
throw new Error(`MultipartFile.moveToDisk: 'name' must be a plain filename (no path separators, '.', or '..'). Got: ${JSON.stringify(name)}`);
|
|
258
|
-
}
|
|
259
|
-
mkdirSync(directory, { recursive: true });
|
|
260
|
-
const fileName = name ?? `${randomBytes(16).toString('hex')}.${this.extname}`;
|
|
261
|
-
// Defense-in-depth: the default branch interpolates `extname` (derived
|
|
262
|
-
// from attacker-controlled `clientName`) into the filename, bypassing
|
|
263
|
-
// the `name` guard above. Re-validate the synthesized fileName before
|
|
264
|
-
// join to reject a hostile extname (separators, NUL).
|
|
265
|
-
if (!isSafeFilename(fileName)) {
|
|
266
|
-
throw new Error(`MultipartFile.moveToDisk: derived filename '${fileName}' is unsafe (separator or invalid char in clientName-derived extname).`);
|
|
267
|
-
}
|
|
268
|
-
const filePath = join(directory, fileName);
|
|
269
|
-
writeFileSync(filePath, this.content);
|
|
270
|
-
this.markAsMoved(fileName, filePath);
|
|
271
|
-
return filePath;
|
|
272
|
-
}
|
|
273
260
|
/**
|
|
274
261
|
* Write the file into `location` (AdonisJS `move`).
|
|
275
262
|
*
|
|
@@ -278,17 +265,27 @@ export class MultipartFile {
|
|
|
278
265
|
* construction), so this writes the buffer. There is therefore no
|
|
279
266
|
* `E_MISSING_FILE_TMP_PATH`: there is no temporary file to be missing.
|
|
280
267
|
*
|
|
281
|
-
* `overwrite` defaults to true, as upstream.
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
268
|
+
* `overwrite` defaults to true, as upstream.
|
|
269
|
+
*
|
|
270
|
+
* NAMED DEVIATION — without `name`, upstream writes under `clientName`, a
|
|
271
|
+
* value the client chose; Ream generates a random name carrying the
|
|
272
|
+
* detected extension, so an upload neither picks its own path nor
|
|
273
|
+
* overwrites another one by sharing its name.
|
|
274
|
+
*
|
|
275
|
+
* A caller-supplied `name` must be a plain filename (no separator, no `.`
|
|
276
|
+
* or `..`): the common footgun is passing `file.clientName` straight
|
|
277
|
+
* through. The generated name is checked too, since its extension comes
|
|
278
|
+
* from the client's filename when the bytes are not recognised.
|
|
285
279
|
*/
|
|
286
280
|
async move(location, options) {
|
|
287
281
|
const { mkdir, writeFile } = await import('node:fs/promises');
|
|
288
282
|
const { join } = await import('node:path');
|
|
283
|
+
if (options?.name !== undefined && !isSafeFilename(options.name)) {
|
|
284
|
+
throw new Error(`MultipartFile.move: 'name' must be a plain filename (no path separators, '.', or '..'). Got: ${JSON.stringify(options.name)}`);
|
|
285
|
+
}
|
|
289
286
|
const name = options?.name ?? `${randomBytes(16).toString('hex')}.${this.extname || 'unknown'}`;
|
|
290
287
|
if (!isSafeFilename(name)) {
|
|
291
|
-
throw new Error(`MultipartFile.move:
|
|
288
|
+
throw new Error(`MultipartFile.move: the derived file name ${JSON.stringify(name)} is unsafe (a separator or NUL in the extension of the client's filename).`);
|
|
292
289
|
}
|
|
293
290
|
const filePath = join(location, name);
|
|
294
291
|
await mkdir(location, { recursive: true });
|
|
@@ -306,7 +303,7 @@ export class MultipartFile {
|
|
|
306
303
|
await writeFile(filePath, this.content, options?.overwrite === false ? { flag: 'wx' } : {});
|
|
307
304
|
}
|
|
308
305
|
catch (error) {
|
|
309
|
-
if (error
|
|
306
|
+
if (errorCode(error) === 'EEXIST') {
|
|
310
307
|
throw new Error(`"${name}" already exists at "${location}". Set "overwrite = true" to overwrite it`);
|
|
311
308
|
}
|
|
312
309
|
throw error;
|
|
@@ -342,23 +339,6 @@ function isSafeFilename(name) {
|
|
|
342
339
|
return false;
|
|
343
340
|
return true;
|
|
344
341
|
}
|
|
345
|
-
function parseFileSize(size) {
|
|
346
|
-
const match = size.match(/^(\d+)(kb|mb|gb)?$/i);
|
|
347
|
-
if (!match)
|
|
348
|
-
return 1024 * 1024;
|
|
349
|
-
const [, digits, unit] = match;
|
|
350
|
-
const num = parseInt(digits ?? '0', 10);
|
|
351
|
-
switch (unit?.toLowerCase()) {
|
|
352
|
-
case 'kb':
|
|
353
|
-
return num * 1024;
|
|
354
|
-
case 'mb':
|
|
355
|
-
return num * 1024 * 1024;
|
|
356
|
-
case 'gb':
|
|
357
|
-
return num * 1024 * 1024 * 1024;
|
|
358
|
-
default:
|
|
359
|
-
return num;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
342
|
/**
|
|
363
343
|
* Hydrate `MultipartFile` instances from the typed payload the Rust
|
|
364
344
|
* HyperServer attaches to the request. The wire-level parser (multer crate,
|
|
@@ -366,10 +346,12 @@ function parseFileSize(size) {
|
|
|
366
346
|
* parsing — JS just decodes the base64 envelope and wraps the result.
|
|
367
347
|
*/
|
|
368
348
|
export function hydrateMultipartPayload(payload) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
349
|
+
// Nested and collected exactly like a urlencoded body: `tags[]` repeated is
|
|
350
|
+
// an array, `user[name]` an object. Flat, a repeated name kept only its
|
|
351
|
+
// last value once a file input was added to the form.
|
|
352
|
+
// The multipart part count is already bounded natively (`maxFields`), so
|
|
353
|
+
// no parameter cap applies on top of it here.
|
|
354
|
+
const fields = parseFormFields(payload.fields, { parameterLimit: Number.POSITIVE_INFINITY });
|
|
373
355
|
const files = payload.files.map((f) => new MultipartFile({
|
|
374
356
|
fieldName: f.fieldName,
|
|
375
357
|
clientName: f.clientName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultipartFile.js","sourceRoot":"","sources":["../../src/bodyparser/MultipartFile.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAS;IACjC,aAAa;IACb,OAAO;IACP,SAAS;IACT,MAAM;IACN,OAAO;IACP,SAAS;IACT,OAAO;IACP,WAAW;IACX,MAAM;IACN,OAAO;CACR,CAAC,CAAA;AAEF,6DAA6D;AAC7D,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"MultipartFile.js","sourceRoot":"","sources":["../../src/bodyparser/MultipartFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Read a size limit (`'1mb'`, `'50 mb'`, `'1.5kb'`, `1024`) into bytes, with
|
|
3
|
+
* the `bytes` grammar every size option of the body parser accepts.
|
|
4
|
+
*
|
|
5
|
+
* Throws on anything it cannot read, or on a negative size. A silent fallback
|
|
6
|
+
* is what turned `limit: '50 mb'` into a 1 MB cap with no word: a limit the
|
|
7
|
+
* application did not set is worse than a boot that refuses to start.
|
|
5
8
|
*/
|
|
6
|
-
export declare function parseSize(size: string): number;
|
|
9
|
+
export declare function parseSize(size: string | number): number;
|
|
7
10
|
//# sourceMappingURL=parseSize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseSize.d.ts","sourceRoot":"","sources":["../../src/bodyparser/parseSize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parseSize.d.ts","sourceRoot":"","sources":["../../src/bodyparser/parseSize.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CASvD"}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
+
import { ReamError } from '../errors/ReamError.js';
|
|
2
|
+
import { parse } from '../helpers/bytes.js';
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* Read a size limit (`'1mb'`, `'50 mb'`, `'1.5kb'`, `1024`) into bytes, with
|
|
5
|
+
* the `bytes` grammar every size option of the body parser accepts.
|
|
6
|
+
*
|
|
7
|
+
* Throws on anything it cannot read, or on a negative size. A silent fallback
|
|
8
|
+
* is what turned `limit: '50 mb'` into a 1 MB cap with no word: a limit the
|
|
9
|
+
* application did not set is worse than a boot that refuses to start.
|
|
5
10
|
*/
|
|
6
11
|
export function parseSize(size) {
|
|
7
|
-
const
|
|
8
|
-
if (!
|
|
9
|
-
|
|
10
|
-
const [, digits, unit] = match;
|
|
11
|
-
const num = parseInt(digits ?? '0', 10);
|
|
12
|
-
switch (unit?.toLowerCase()) {
|
|
13
|
-
case 'kb':
|
|
14
|
-
return num * 1024;
|
|
15
|
-
case 'mb':
|
|
16
|
-
return num * 1024 * 1024;
|
|
17
|
-
case 'gb':
|
|
18
|
-
return num * 1024 * 1024 * 1024;
|
|
19
|
-
default:
|
|
20
|
-
return num;
|
|
12
|
+
const bytes = parse(size);
|
|
13
|
+
if (bytes === null || !Number.isFinite(bytes) || bytes < 0) {
|
|
14
|
+
throw new ReamError('E_BODYPARSER_INVALID_SIZE', `Cannot read the size ${JSON.stringify(size)}: expected a number of bytes or a value such as '512kb', '1.5mb' or '2 gb'.`);
|
|
21
15
|
}
|
|
16
|
+
return bytes;
|
|
22
17
|
}
|
|
23
18
|
//# sourceMappingURL=parseSize.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseSize.js","sourceRoot":"","sources":["../../src/bodyparser/parseSize.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"parseSize.js","sourceRoot":"","sources":["../../src/bodyparser/parseSize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAE3C;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,IAAqB;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CACjB,2BAA2B,EAC3B,wBAAwB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,6EAA6E,CAC1H,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -58,4 +58,14 @@ export interface QsParseOptions {
|
|
|
58
58
|
export declare function decodeFormComponent(value: string): string;
|
|
59
59
|
/** Parse a urlencoded body into a nested object. */
|
|
60
60
|
export declare function parseQueryString(body: string, options?: QsParseOptions): Record<string, unknown>;
|
|
61
|
+
/**
|
|
62
|
+
* Nest form fields that arrive as decoded name/value pairs — a multipart
|
|
63
|
+
* body's text parts — with the key grammar and the guards of a urlencoded
|
|
64
|
+
* body. A `<select multiple name="tags[]">` keeps every value, and
|
|
65
|
+
* `user[name]` nests, whether or not the form also carries a file input.
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseFormFields(fields: Iterable<{
|
|
68
|
+
name: string;
|
|
69
|
+
value: string;
|
|
70
|
+
}>, options?: QsParseOptions): Record<string, unknown>;
|
|
61
71
|
//# sourceMappingURL=qsParse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qsParse.d.ts","sourceRoot":"","sources":["../../src/bodyparser/qsParse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAC3C,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAyID;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"qsParse.d.ts","sourceRoot":"","sources":["../../src/bodyparser/qsParse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAC3C,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAyID;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EACjD,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAezB"}
|
|
@@ -170,29 +170,44 @@ export function decodeFormComponent(value) {
|
|
|
170
170
|
}
|
|
171
171
|
/** Parse a urlencoded body into a nested object. */
|
|
172
172
|
export function parseQueryString(body, options = {}) {
|
|
173
|
-
const depth = options.depth ?? DEFAULT_DEPTH;
|
|
174
|
-
const parameterLimit = options.parameterLimit ?? DEFAULT_PARAMETER_LIMIT;
|
|
175
|
-
const arrayLimit = options.arrayLimit ?? DEFAULT_ARRAY_LIMIT;
|
|
176
|
-
const result = {};
|
|
177
173
|
if (!body)
|
|
178
|
-
return
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
for (const pair of
|
|
174
|
+
return {};
|
|
175
|
+
const parameterLimit = options.parameterLimit ?? DEFAULT_PARAMETER_LIMIT;
|
|
176
|
+
const fields = [];
|
|
177
|
+
for (const pair of body.split('&')) {
|
|
182
178
|
if (!pair)
|
|
183
179
|
continue;
|
|
184
|
-
|
|
180
|
+
// Nothing past the limit is even decoded.
|
|
181
|
+
if (fields.length >= parameterLimit)
|
|
185
182
|
break;
|
|
186
183
|
const eqIdx = pair.indexOf('=');
|
|
187
184
|
const rawKey = eqIdx === -1 ? pair : pair.slice(0, eqIdx);
|
|
188
185
|
const rawValue = eqIdx === -1 ? '' : pair.slice(eqIdx + 1);
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
fields.push({ name: decodeFormComponent(rawKey), value: decodeFormComponent(rawValue) });
|
|
187
|
+
}
|
|
188
|
+
return parseFormFields(fields, options);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Nest form fields that arrive as decoded name/value pairs — a multipart
|
|
192
|
+
* body's text parts — with the key grammar and the guards of a urlencoded
|
|
193
|
+
* body. A `<select multiple name="tags[]">` keeps every value, and
|
|
194
|
+
* `user[name]` nests, whether or not the form also carries a file input.
|
|
195
|
+
*/
|
|
196
|
+
export function parseFormFields(fields, options = {}) {
|
|
197
|
+
const depth = options.depth ?? DEFAULT_DEPTH;
|
|
198
|
+
const parameterLimit = options.parameterLimit ?? DEFAULT_PARAMETER_LIMIT;
|
|
199
|
+
const arrayLimit = options.arrayLimit ?? DEFAULT_ARRAY_LIMIT;
|
|
200
|
+
const result = {};
|
|
201
|
+
let seen = 0;
|
|
202
|
+
for (const field of fields) {
|
|
203
|
+
if (++seen > parameterLimit)
|
|
204
|
+
break;
|
|
205
|
+
let value = field.value;
|
|
191
206
|
if (options.trimWhitespaces && typeof value === 'string')
|
|
192
207
|
value = value.trim();
|
|
193
208
|
if (options.convertEmptyStringsToNull && value === '')
|
|
194
209
|
value = null;
|
|
195
|
-
assign(result, splitKey(
|
|
210
|
+
assign(result, splitKey(field.name, depth, options.allowDots ?? true), value, arrayLimit);
|
|
196
211
|
}
|
|
197
212
|
return result;
|
|
198
213
|
}
|