Skip to content

Commit 160aeba

Browse files
authored
fix(node-http-handler): throw meaningful errors in H2 events (#2568)
1 parent 08c0342 commit 160aeba

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AbortController } from "@aws-sdk/abort-controller";
22
import { HttpRequest } from "@aws-sdk/protocol-http";
33
import { rejects } from "assert";
44
import http2, { constants, Http2Stream } from "http2";
5+
import { Duplex } from "stream";
56

67
import { NodeHttp2Handler } from "./node-http2-handler";
78
import { createMockHttp2Server, createResponseFunction, createResponseFunctionWithDelay } from "./server.mock";
@@ -375,6 +376,53 @@ describe(NodeHttp2Handler.name, () => {
375376
});
376377
});
377378

379+
it("will throw reasonable error when connection aborted abnormally", async () => {
380+
nodeH2Handler = new NodeHttp2Handler();
381+
// Create a session by sending a request.
382+
await nodeH2Handler.handle(new HttpRequest(getMockReqOptions()), {});
383+
const authority = `${protocol}//${hostname}:${port}`;
384+
// @ts-ignore: access private property
385+
const session: ClientHttp2Session = nodeH2Handler.sessionCache.get(authority)[0];
386+
const fakeStream = new Duplex();
387+
const fakeRstCode = 1;
388+
// @ts-ignore: fake result code
389+
fakeStream.rstCode = fakeRstCode;
390+
jest.spyOn(session, "request").mockImplementation(() => fakeStream);
391+
// @ts-ignore: access private property
392+
nodeH2Handler.sessionCache.set(`${protocol}//${hostname}:${port}`, [session]);
393+
// Delay response so that onabort is called earlier
394+
setTimeout(() => {
395+
fakeStream.emit("aborted");
396+
}, 0);
397+
398+
await expect(nodeH2Handler.handle(new HttpRequest({ ...getMockReqOptions() }), {})).rejects.toHaveProperty(
399+
"message",
400+
`HTTP/2 stream is abnormally aborted in mid-communication with result code ${fakeRstCode}.`
401+
);
402+
});
403+
404+
it("will throw reasonable error when frameError is thrown", async () => {
405+
nodeH2Handler = new NodeHttp2Handler();
406+
// Create a session by sending a request.
407+
await nodeH2Handler.handle(new HttpRequest(getMockReqOptions()), {});
408+
const authority = `${protocol}//${hostname}:${port}`;
409+
// @ts-ignore: access private property
410+
const session: ClientHttp2Session = nodeH2Handler.sessionCache.get(authority)[0];
411+
const fakeStream = new Duplex();
412+
jest.spyOn(session, "request").mockImplementation(() => fakeStream);
413+
// @ts-ignore: access private property
414+
nodeH2Handler.sessionCache.set(`${protocol}//${hostname}:${port}`, [session]);
415+
// Delay response so that onabort is called earlier
416+
setTimeout(() => {
417+
fakeStream.emit("frameError", "TYPE", "CODE", "ID");
418+
}, 0);
419+
420+
await expect(nodeH2Handler.handle(new HttpRequest({ ...getMockReqOptions() }), {})).rejects.toHaveProperty(
421+
"message",
422+
`Frame type id TYPE in stream id ID has failed with code CODE.`
423+
);
424+
});
425+
378426
describe("disableConcurrentStreams", () => {
379427
beforeEach(() => {
380428
nodeH2Handler = new NodeHttp2Handler({

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,13 @@ export class NodeHttp2Handler implements HttpHandler {
125125
}
126126

127127
// Set up handlers for errors
128-
req.on("frameError", reject);
128+
req.on("frameError", (type: number, code: number, id: number) => {
129+
reject(new Error(`Frame type id ${type} in stream id ${id} has failed with code ${code}.`));
130+
});
129131
req.on("error", reject);
130-
req.on("goaway", reject);
131-
req.on("aborted", reject);
132+
req.on("aborted", () => {
133+
reject(new Error(`HTTP/2 stream is abnormally aborted in mid-communication with result code ${req.rstCode}.`));
134+
});
132135

133136
// The HTTP/2 error code used when closing the stream can be retrieved using the
134137
// http2stream.rstCode property. If the code is any value other than NGHTTP2_NO_ERROR (0),

0 commit comments

Comments
 (0)