Skip to content

Commit 590e5ed

Browse files
committed
fix(node-http-handler): shift http1 expect 100-continue requests to isolated http Agents
1 parent 8af2d33 commit 590e5ed

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed
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+
shfit http1 calls with expect 100-continue header to isolated http Agents

packages/node-http-handler/src/node-http-handler.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,34 @@ describe("NodeHttpHandler", () => {
261261
await nodeHttpHandler.handle(httpRequest as any);
262262
expect(vi.mocked(hRequest as any).mock.calls[0][0]?.host).toEqual("host");
263263
});
264+
265+
it("creates a new http(s) Agent if the request has expect: 100-continue header", async () => {
266+
const nodeHttpHandler = new NodeHttpHandler({});
267+
{
268+
const httpRequest = {
269+
protocol: "http:",
270+
hostname: "[host]",
271+
path: "/some/path",
272+
headers: {
273+
expect: "100-continue",
274+
},
275+
};
276+
await nodeHttpHandler.handle(httpRequest as any);
277+
expect(vi.mocked(hRequest as any).mock.calls[0][0]?.agent).not.toBe(
278+
(nodeHttpHandler as any).config.httpAgent
279+
);
280+
}
281+
{
282+
const httpRequest = {
283+
protocol: "http:",
284+
hostname: "[host]",
285+
path: "/some/path",
286+
headers: {},
287+
};
288+
await nodeHttpHandler.handle(httpRequest as any);
289+
expect(vi.mocked(hRequest as any).mock.calls[1][0]?.agent).toBe((nodeHttpHandler as any).config.httpAgent);
290+
}
291+
});
264292
});
265293
});
266294

packages/node-http-handler/src/node-http-handler.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,19 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
203203

204204
// determine which http(s) client to use
205205
const isSSL = request.protocol === "https:";
206-
const agent = isSSL ? this.config.httpsAgent : this.config.httpAgent;
206+
207+
const headers = request.headers ?? {};
208+
const expectContinue = (headers.Expect ?? headers.expect) === "100-continue";
209+
210+
let agent = isSSL ? this.config.httpsAgent : this.config.httpAgent;
211+
if (expectContinue) {
212+
// Because awaiting 100-continue desynchronizes the request and request body transmission,
213+
// such requests must be offloaded to a separate Agent instance.
214+
// Additional logic will exist on the client using this handler to determine whether to add the header at all.
215+
216+
// hAgent also has options, but not in the type system.
217+
agent = new (isSSL ? hsAgent : hAgent)((agent as hsAgent).options);
218+
}
207219

208220
// If the request is taking a long time, check socket usage and potentially warn.
209221
// This warning will be cancelled if the request resolves.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function writeRequestBody(
2020
maxContinueTimeoutMs = MIN_WAIT_TIME
2121
): Promise<void> {
2222
const headers = request.headers ?? {};
23-
const expect = headers["Expect"] || headers["expect"];
23+
const expect = headers.Expect || headers.expect;
2424

2525
let timeoutId = -1;
2626
let sendBody = true;

0 commit comments

Comments
 (0)