Skip to content

Commit ef566f3

Browse files
committed
Simplify error handling within the function processRequest.
1 parent f1ffd27 commit ef566f3

File tree

3 files changed

+22
-24
lines changed

3 files changed

+22
-24
lines changed

changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
- Updated the [`busboy`](https://npm.im/busboy) dependency to v1, fixing [#311](https://github.com/jaydenseric/graphql-upload/issues/311).
88
- This important update addresses the vulnerability [CVE-2022-24434](https://nvd.nist.gov/vuln/detail/CVE-2022-24434) ([GHSA-wm7h-9275-46v2](https://github.com/advisories/GHSA-wm7h-9275-46v2)).
9-
- It now emits an error on a file upload stream if the request disconnects partway through, which is different to the error that used to come from [`graphql-upload`](https://npm.im/graphql-upload).
109
- Some error messages have changed.
1110
- Temporarily until [mscdex/busboy#297](https://github.com/mscdex/busboy/issues/297) is fixed upstream, for the function `processRequest` and the middleware `graphqlUploadExpress` and `graphqlUploadKoa` the option `maxFileSize` is actually 1 byte less than the amount specified.
1211

1312
### Patch
1413

1514
- Updated the [`typescript`](https://npm.im/typescript) dev dependency.
1615
- In the function `processRequest` use the `on` method instead of `once` to listen for `error` events on the [`busboy`](https://npm.im/busboy) parser, as in edge cases the same parser could have multiple `error` events and all must be handled to prevent the Node.js process exiting with an error.
16+
- Simplified error handling within the function `processRequest`.
1717
- Added a test for the function `processRequest` with a maliciously malformed multipart request.
1818

1919
## 14.0.0

processRequest.js

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ function processRequest(
4242
/** @type {Error} */
4343
let exitError;
4444

45-
/** @type {import("stream").Readable} */
46-
let lastFileStream;
47-
4845
/**
4946
* @type {{ [key: string]: unknown } | Array<
5047
* { [key: string]: unknown }
@@ -76,27 +73,20 @@ function processRequest(
7673
/**
7774
* Exits request processing with an error. Successive calls have no effect.
7875
* @param {Error} error Error instance.
76+
* @param {boolean} [isParserError] Is the error from the parser.
7977
*/
80-
const exit = (error) => {
78+
function exit(error, isParserError = false) {
8179
if (exitError) return;
8280

8381
exitError = error;
8482

85-
reject(exitError);
86-
87-
parser.destroy();
88-
89-
if (
90-
lastFileStream &&
91-
!lastFileStream.readableEnded &&
92-
!lastFileStream.destroyed
93-
)
94-
lastFileStream.destroy(exitError);
95-
9683
if (map)
9784
for (const upload of map.values())
9885
if (!upload.file) upload.reject(exitError);
9986

87+
// If the error came from the parser, don’t cause it to be emitted again.
88+
isParserError ? parser.destroy() : parser.destroy(exitError);
89+
10090
request.unpipe(parser);
10191

10292
// With a sufficiently large request body, subsequent events in the same
@@ -106,7 +96,9 @@ function processRequest(
10696
setImmediate(() => {
10797
request.resume();
10898
});
109-
};
99+
100+
reject(exitError);
101+
}
110102

111103
parser.on("field", (fieldName, value, { valueTruncated }) => {
112104
if (valueTruncated)
@@ -228,8 +220,6 @@ function processRequest(
228220
parser.on(
229221
"file",
230222
(fieldName, stream, { filename, encoding, mimeType: mimetype }) => {
231-
lastFileStream = stream;
232-
233223
if (!map) {
234224
ignoreStream(stream);
235225
return exit(
@@ -331,7 +321,9 @@ function processRequest(
331321
// could have multiple `error` events and all must be handled to prevent the
332322
// Node.js process exiting with an error. One edge case is if there is a
333323
// malformed part header as well as an unexpected end of the form.
334-
parser.on("error", exit);
324+
parser.on("error", (/** @type {Error} */ error) => {
325+
exit(error, true);
326+
});
335327

336328
response.once("close", () => {
337329
released = true;

processRequest.test.mjs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,11 @@ export default (tests) => {
789789
stream.once("error", reject).once("end", resolve).resume();
790790
}),
791791
{
792-
name: "Error",
793-
message: "Unexpected end of file",
792+
name: "BadRequestError",
793+
message:
794+
"Request disconnected during file upload stream parsing.",
795+
status: 499,
796+
expose: true,
794797
}
795798
);
796799
};
@@ -931,8 +934,11 @@ export default (tests) => {
931934
strictEqual(upload.mimetype, "text/plain");
932935
strictEqual(upload.encoding, "7bit");
933936
throws(() => upload.createReadStream(), {
934-
name: "Error",
935-
message: "Unexpected end of file",
937+
name: "BadRequestError",
938+
message:
939+
"Request disconnected during file upload stream parsing.",
940+
status: 499,
941+
expose: true,
936942
});
937943
};
938944

0 commit comments

Comments
 (0)