Skip to content

Commit 93ea173

Browse files
committed
set 100-continue timeout to 6s minimum
1 parent 87fadbb commit 93ea173

File tree

2 files changed

+40
-21
lines changed

2 files changed

+40
-21
lines changed

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

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import EventEmitter from "events";
2-
import { describe, expect, test as it, vi } from "vitest";
2+
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";
33

44
import { writeRequestBody } from "./write-request-body";
55

@@ -60,24 +60,35 @@ describe(writeRequestBody.name, () => {
6060
}
6161
);
6262

63-
it("should send the body if the 100 Continue response is not received before the timeout", async () => {
64-
const httpRequest = Object.assign(new EventEmitter(), {
65-
end: vi.fn(),
66-
}) as any;
67-
const request = {
68-
headers: {
69-
expect: "100-continue",
70-
},
71-
body: Buffer.from("abcd"),
72-
method: "GET",
73-
hostname: "",
74-
protocol: "https:",
75-
path: "/",
76-
};
63+
describe("with fake timers", () => {
64+
beforeEach(() => {
65+
vi.useFakeTimers();
66+
});
7767

78-
const promise = writeRequestBody(httpRequest, request);
79-
expect(httpRequest.end).not.toHaveBeenCalled();
80-
await promise;
81-
expect(httpRequest.end).toHaveBeenCalled();
68+
afterEach(() => {
69+
vi.useRealTimers();
70+
});
71+
it("should send the body if the 100 Continue response is not received before the timeout", async () => {
72+
const httpRequest = Object.assign(new EventEmitter(), {
73+
end: vi.fn(),
74+
}) as any;
75+
const request = {
76+
headers: {
77+
expect: "100-continue",
78+
},
79+
body: Buffer.from("abcd"),
80+
method: "GET",
81+
hostname: "",
82+
protocol: "https:",
83+
path: "/",
84+
};
85+
86+
const promise = writeRequestBody(httpRequest, request, 12_000);
87+
expect(httpRequest.end).not.toHaveBeenCalled();
88+
vi.advanceTimersByTime(13000);
89+
await promise;
90+
91+
expect(httpRequest.end).toHaveBeenCalled();
92+
});
8293
});
8394
});

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { Readable } from "stream";
55

66
import { timing } from "./timing";
77

8-
const MIN_WAIT_TIME = 1000;
8+
const MIN_WAIT_TIME = 6_000;
99

1010
/**
1111
* This resolves when writeBody has been called.
1212
*
1313
* @param httpRequest - opened Node.js request.
1414
* @param request - container with the request body.
15-
* @param maxContinueTimeoutMs - maximum time to wait for the continue event. Minimum of 1000ms.
15+
* @param maxContinueTimeoutMs - time to wait for the continue event.
1616
*/
1717
export async function writeRequestBody(
1818
httpRequest: ClientRequest | ClientHttp2Stream,
@@ -28,6 +28,14 @@ export async function writeRequestBody(
2828
if (expect === "100-continue") {
2929
sendBody = await Promise.race<boolean>([
3030
new Promise((resolve) => {
31+
// If this resolves first (wins the race), it means that at least MIN_WAIT_TIME ms
32+
// elapsed and no continue, response, or error has happened.
33+
// The high default timeout is to give the server ample time to respond.
34+
// This is an unusual situation, and indicates the server may not be S3 actual
35+
// and did not correctly implement 100-continue event handling.
36+
// Strictly speaking, we should perhaps keep waiting up to the request timeout
37+
// and then throw an error, but we resolve true to allow the server to deal
38+
// with the request body.
3139
timeoutId = Number(timing.setTimeout(() => resolve(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
3240
}),
3341
new Promise((resolve) => {

0 commit comments

Comments
 (0)