Skip to content

Commit f4e1a45

Browse files
fix(node-http-handler): skip sending body without waiting for a timeout on response, if "expect" request header with "100-continue" is provided (#1459)
* fix(node-http-handler): skip sending body without waiting for a timeout on response, if "expect" request header with "100-continue" is provided * fix(node-http-handler): skip sending body without waiting for a timeout on response, if "expect" request header with "100-continue" is provided * add unit tests --------- Co-authored-by: George Fu <[email protected]>
1 parent 430021a commit f4e1a45

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

.changeset/hungry-eels-accept.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/node-http-handler": patch
3+
---
4+
5+
skip sending body without waiting for a timeout on response, if "expect" request header with "100-continue" is provided
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import EventEmitter from "events";
2+
import { describe, expect, test as it, vi } from "vitest";
3+
4+
import { writeRequestBody } from "./write-request-body";
5+
6+
describe(writeRequestBody.name, () => {
7+
it("should wait for the continue event if request has expect=100-continue", async () => {
8+
const httpRequest = Object.assign(new EventEmitter(), {
9+
end: vi.fn(),
10+
}) as any;
11+
const request = {
12+
headers: {
13+
expect: "100-continue",
14+
},
15+
body: Buffer.from("abcd"),
16+
method: "GET",
17+
hostname: "",
18+
protocol: "https:",
19+
path: "/",
20+
};
21+
let done: (value?: unknown) => void;
22+
const promise = new Promise((r) => (done = r));
23+
setTimeout(async () => {
24+
httpRequest.emit("continue", {});
25+
done();
26+
}, 25);
27+
await writeRequestBody(httpRequest, request);
28+
expect(httpRequest.end).toHaveBeenCalled();
29+
await promise;
30+
});
31+
it(
32+
"should not send the body if the request is expect=100-continue" +
33+
"but a response is received before the continue event",
34+
async () => {
35+
const httpRequest = Object.assign(new EventEmitter(), {
36+
end: vi.fn(),
37+
}) as any;
38+
const request = {
39+
headers: {
40+
expect: "100-continue",
41+
},
42+
body: {
43+
pipe: vi.fn(),
44+
},
45+
method: "GET",
46+
hostname: "",
47+
protocol: "https:",
48+
path: "/",
49+
};
50+
let done: (value?: unknown) => void;
51+
const promise = new Promise((r) => (done = r));
52+
setTimeout(() => {
53+
httpRequest.emit("response", {});
54+
done();
55+
}, 25);
56+
await writeRequestBody(httpRequest, request);
57+
expect(request.body.pipe).not.toHaveBeenCalled();
58+
expect(httpRequest.end).not.toHaveBeenCalled();
59+
await promise;
60+
}
61+
);
62+
});

packages/node-http-handler/src/write-request-body.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,38 @@ export async function writeRequestBody(
2323
const expect = headers["Expect"] || headers["expect"];
2424

2525
let timeoutId = -1;
26-
let hasError = false;
26+
let sendBody = true;
2727

2828
if (expect === "100-continue") {
29-
await Promise.race<void>([
29+
sendBody = await Promise.race<boolean>([
3030
new Promise((resolve) => {
3131
timeoutId = Number(timing.setTimeout(resolve, Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
3232
}),
3333
new Promise((resolve) => {
3434
httpRequest.on("continue", () => {
3535
timing.clearTimeout(timeoutId);
36-
resolve();
36+
resolve(true);
37+
});
38+
httpRequest.on("response", () => {
39+
// if this handler is called, then response is
40+
// already received and there is no point in
41+
// sending body or waiting
42+
timing.clearTimeout(timeoutId);
43+
resolve(false);
3744
});
3845
httpRequest.on("error", () => {
39-
hasError = true;
4046
timing.clearTimeout(timeoutId);
4147
// this handler does not reject with the error
4248
// because there is already an error listener
4349
// on the request in node-http-handler
4450
// and node-http2-handler.
45-
resolve();
51+
resolve(false);
4652
});
4753
}),
4854
]);
4955
}
5056

51-
if (!hasError) {
57+
if (sendBody) {
5258
writeBody(httpRequest, request.body);
5359
}
5460
}

0 commit comments

Comments
 (0)