Skip to content

Commit 9c6cde8

Browse files
AllanZhengYPtrivikr
authored andcommitted
fix: support custom agent in node http handler (#489)
* feat(node-http-handler): support custom agent * fix: supply httpHandlerOptions with client.send() instead of httpOptions * feat: remove Browser&Node handler options interface from types package Because these interfaces are constructor interface for individual http handler, they only need to be exposed from its own http handler package
1 parent 8a3bcce commit 9c6cde8

File tree

8 files changed

+94
-90
lines changed

8 files changed

+94
-90
lines changed

Diff for: clients/client-rds-data/RdsDataServiceClient.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import {
5555
Client as SmithyClient,
5656
SmithyResolvedConfiguration
5757
} from "@aws-sdk/smithy-client";
58-
import { HttpOptions as __HttpOptions } from "@aws-sdk/types";
58+
import { HttpHandlerOptions as __HttpHandlerOptions } from "@aws-sdk/types";
5959

6060
export type ServiceInputTypes =
6161
| RollbackTransactionRequest
@@ -158,7 +158,7 @@ export type RdsDataServiceConfig = RDSDataRuntimeDependencies &
158158
UserAgentInputConfig;
159159

160160
export type RdsDataServiceResolvedConfig = SmithyResolvedConfiguration<
161-
__HttpOptions
161+
__HttpHandlerOptions
162162
> &
163163
Required<RDSDataRuntimeDependencies> &
164164
AwsAuthResolvedConfig &
@@ -168,7 +168,7 @@ export type RdsDataServiceResolvedConfig = SmithyResolvedConfiguration<
168168
UserAgentResolvedConfig;
169169

170170
export class RdsDataService extends SmithyClient<
171-
__HttpOptions,
171+
__HttpHandlerOptions,
172172
ServiceInputTypes,
173173
ServiceOutputTypes,
174174
RdsDataServiceResolvedConfig

Diff for: clients/client-rds-data/commands/ExecuteStatementCommand.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from "@aws-sdk/smithy-client";
22
import { getSerdePlugin } from "@aws-sdk/middleware-serde";
33
import {
4-
HttpOptions,
4+
HttpHandlerOptions as __HttpHandlerOptions,
55
Handler,
66
HandlerExecutionContext,
77
FinalizeHandlerArguments,
@@ -32,7 +32,7 @@ export class ExecuteStatementCommand extends Command<
3232
resolveMiddleware(
3333
clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
3434
configuration: RdsDataServiceResolvedConfig,
35-
options?: HttpOptions
35+
options?: __HttpHandlerOptions
3636
): Handler<ExecuteStatementRequest, ExecuteStatementResponse> {
3737
const { requestHandler } = configuration;
3838

Diff for: packages/fetch-http-handler/src/fetch-http-handler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HttpOptions, HeaderBag, HttpHandlerOptions } from "@aws-sdk/types";
1+
import { HeaderBag, HttpHandlerOptions } from "@aws-sdk/types";
22
import { HttpHandler, HttpRequest, HttpResponse } from "@aws-sdk/protocol-http";
33
import { requestTimeout } from "./request-timeout";
44
import { buildQueryString } from "@aws-sdk/querystring-builder";
@@ -8,7 +8,7 @@ declare var AbortController: any;
88
/**
99
* Represents the http options that can be passed to a browser http client.
1010
*/
11-
export interface BrowserHttpOptions extends HttpOptions {
11+
export interface BrowserHttpOptions {
1212
/**
1313
* The number of milliseconds a request can take before being automatically
1414
* terminated.

Diff for: packages/node-http-handler/src/node-http-handler.spec.ts

+28-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ import {
1414
import { AddressInfo } from "net";
1515

1616
describe("NodeHttpHandler", () => {
17+
describe("constructor", () => {
18+
it("can set httpAgent and httpsAgent", () => {
19+
let maxSockets = Math.round(Math.random() * 50);
20+
let nodeHttpHandler = new NodeHttpHandler({
21+
httpAgent: new http.Agent({ maxSockets })
22+
});
23+
expect((nodeHttpHandler as any).httpAgent.maxSockets).toEqual(maxSockets);
24+
maxSockets = Math.round(Math.random() * 50);
25+
nodeHttpHandler = new NodeHttpHandler({
26+
httpsAgent: new https.Agent({ maxSockets })
27+
});
28+
expect((nodeHttpHandler as any).httpsAgent.maxSockets).toEqual(
29+
maxSockets
30+
);
31+
});
32+
});
1733
describe("http", () => {
1834
const mockHttpServer: HttpServer = createMockHttpServer().listen(54321);
1935

@@ -89,15 +105,15 @@ describe("NodeHttpHandler", () => {
89105
);
90106
const nodeHttpHandler = new NodeHttpHandler();
91107
92-
let response = await nodeHttpHandler.handle(
93-
{
108+
let { response } = await nodeHttpHandler.handle(
109+
new HttpRequest({
94110
hostname: "localhost",
95111
method: "GET",
96-
port: (mockHttpServer.address() as AddressInfo).port,
112+
port: (mockHttpsServer.address() as AddressInfo).port,
97113
protocol: "https:",
98114
path: "/",
99115
headers: {}
100-
},
116+
}),
101117
{}
102118
);
103119
@@ -124,16 +140,16 @@ describe("NodeHttpHandler", () => {
124140
});
125141
126142
const nodeHttpHandler = new NodeHttpHandler();
127-
let response = await nodeHttpHandler.handle(
128-
{
143+
let { response } = await nodeHttpHandler.handle(
144+
new HttpRequest({
129145
hostname: "localhost",
130146
method: "PUT",
131-
port: (mockHttpServer.address() as AddressInfo).port,
147+
port: (mockHttpsServer.address() as AddressInfo).port,
132148
protocol: "https:",
133149
path: "/",
134150
headers: {},
135151
body
136-
},
152+
}),
137153
{}
138154
);
139155
@@ -214,16 +230,16 @@ describe("NodeHttpHandler", () => {
214230
);
215231
const nodeHttpHandler = new NodeHttpHandler();
216232
217-
let response = await nodeHttpHandler.handle(
218-
{
233+
let { response } = await nodeHttpHandler.handle(
234+
new HttpRequest({
219235
hostname: "localhost",
220236
method: "PUT",
221-
port: (mockHttpServer.address() as AddressInfo).port,
237+
port: (mockHttpsServer.address() as AddressInfo).port,
222238
protocol: "https:",
223239
path: "/",
224240
headers: {},
225241
body
226-
},
242+
}),
227243
{}
228244
);
229245

Diff for: packages/node-http-handler/src/node-http-handler.ts

+37-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,50 @@
11
import * as https from "https";
22
import * as http from "http";
33
import { buildQueryString } from "@aws-sdk/querystring-builder";
4-
import { HttpOptions, NodeHttpOptions } from "@aws-sdk/types";
4+
import { HttpHandlerOptions } from "@aws-sdk/types";
55
import { HttpHandler, HttpRequest, HttpResponse } from "@aws-sdk/protocol-http";
66
import { setConnectionTimeout } from "./set-connection-timeout";
77
import { setSocketTimeout } from "./set-socket-timeout";
88
import { writeRequestBody } from "./write-request-body";
99
import { getTransformedHeaders } from "./get-transformed-headers";
1010

11+
/**
12+
* Represents the http options that can be passed to a node http client.
13+
*/
14+
export interface NodeHttpOptions {
15+
/**
16+
* The maximum time in milliseconds that the connection phase of a request
17+
* may take before the connection attempt is abandoned.
18+
*/
19+
connectionTimeout?: number;
20+
21+
/**
22+
* The maximum time in milliseconds that a socket may remain idle before it
23+
* is closed.
24+
*/
25+
socketTimeout?: number;
26+
27+
httpAgent?: http.Agent;
28+
httpsAgent?: https.Agent;
29+
}
30+
1131
export class NodeHttpHandler implements HttpHandler {
1232
private readonly httpAgent: http.Agent;
1333
private readonly httpsAgent: https.Agent;
34+
private readonly connectionTimeout?: number;
35+
private readonly socketTimeout?: number;
1436

15-
constructor(private readonly httpOptions: NodeHttpOptions = {}) {
16-
const { keepAlive = true } = httpOptions;
17-
this.httpAgent = new http.Agent({ keepAlive });
18-
this.httpsAgent = new https.Agent({ keepAlive });
37+
constructor({
38+
connectionTimeout,
39+
socketTimeout,
40+
httpAgent,
41+
httpsAgent
42+
}: NodeHttpOptions = {}) {
43+
this.connectionTimeout = connectionTimeout;
44+
this.socketTimeout = socketTimeout;
45+
const keepAlive = true;
46+
this.httpAgent = httpAgent || new http.Agent({ keepAlive });
47+
this.httpsAgent = httpsAgent || new https.Agent({ keepAlive });
1948
}
2049

2150
destroy(): void {
@@ -25,7 +54,7 @@ export class NodeHttpHandler implements HttpHandler {
2554

2655
handle(
2756
request: HttpRequest,
28-
{ abortSignal }: HttpOptions
57+
{ abortSignal }: HttpHandlerOptions
2958
): Promise<{ response: HttpResponse }> {
3059
return new Promise((resolve, reject) => {
3160
// if the request was already aborted, prevent doing extra work
@@ -61,8 +90,8 @@ export class NodeHttpHandler implements HttpHandler {
6190
req.on("error", reject);
6291

6392
// wire-up any timeout logic
64-
setConnectionTimeout(req, reject, this.httpOptions.connectionTimeout);
65-
setSocketTimeout(req, reject, this.httpOptions.socketTimeout);
93+
setConnectionTimeout(req, reject, this.connectionTimeout);
94+
setSocketTimeout(req, reject, this.socketTimeout);
6695

6796
// wire-up abort logic
6897
if (abortSignal) {

Diff for: packages/node-http-handler/src/node-http2-handler.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
import { connect, constants, ClientHttp2Session } from "http2";
22

33
import { buildQueryString } from "@aws-sdk/querystring-builder";
4-
import { HttpOptions, NodeHttp2Options } from "@aws-sdk/types";
4+
import { HttpHandlerOptions } from "@aws-sdk/types";
55
import { HttpHandler, HttpRequest, HttpResponse } from "@aws-sdk/protocol-http";
66

77
import { writeRequestBody } from "./write-request-body";
88
import { getTransformedHeaders } from "./get-transformed-headers";
99

10+
/**
11+
* Represents the http2 options that can be passed to a node http2 client.
12+
*/
13+
export interface NodeHttp2Options {
14+
/**
15+
* The maximum time in milliseconds that a stream may remain idle before it
16+
* is closed.
17+
*/
18+
requestTimeout?: number;
19+
20+
/**
21+
* The maximum time in milliseconds that a session or socket may remain idle
22+
* before it is closed.
23+
* https://nodejs.org/docs/latest-v12.x/api/http2.html#http2_http2session_and_sockets
24+
*/
25+
sessionTimeout?: number;
26+
}
27+
1028
export class NodeHttp2Handler implements HttpHandler {
1129
private readonly connectionPool: Map<string, ClientHttp2Session>;
1230

@@ -23,7 +41,7 @@ export class NodeHttp2Handler implements HttpHandler {
2341

2442
handle(
2543
request: HttpRequest,
26-
{ abortSignal }: HttpOptions
44+
{ abortSignal }: HttpHandlerOptions
2745
): Promise<{ response: HttpResponse }> {
2846
return new Promise((resolve, reject) => {
2947
// if the request was already aborted, prevent doing extra work

Diff for: packages/protocol-http/src/httpHandler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { HttpRequest } from "./httpRequest";
22
import { HttpResponse } from "./httpResponse";
3-
import { RequestHandler, HttpOptions } from "@aws-sdk/types";
3+
import { RequestHandler, HttpHandlerOptions } from "@aws-sdk/types";
44

55
export type HttpHandler = RequestHandler<
66
HttpRequest,
77
HttpResponse,
8-
HttpOptions
8+
HttpHandlerOptions
99
>;

Diff for: packages/types/src/http.ts

-59
Original file line numberDiff line numberDiff line change
@@ -100,62 +100,3 @@ export interface ResolvedHttpResponse extends HttpResponse {
100100
export interface HttpHandlerOptions {
101101
abortSignal?: AbortSignal;
102102
}
103-
104-
/**
105-
* Represents the http options that can be shared across environments.
106-
*/
107-
export type HttpOptions = BrowserHttpOptions &
108-
NodeHttpOptions & { abortSignal?: AbortSignal };
109-
110-
/**
111-
* Represents the http options that can be passed to a browser http client.
112-
*/
113-
export interface BrowserHttpOptions {
114-
/**
115-
* The number of milliseconds a request can take before being automatically
116-
* terminated.
117-
*/
118-
requestTimeout?: number;
119-
}
120-
121-
/**
122-
* Represents the http options that can be passed to a node http client.
123-
*/
124-
export interface NodeHttpOptions {
125-
/**
126-
* The maximum time in milliseconds that the connection phase of a request
127-
* may take before the connection attempt is abandoned.
128-
*/
129-
connectionTimeout?: number;
130-
131-
/**
132-
* Whether sockets should be kept open even when there are no outstanding
133-
* requests so that future requests can forgo having to reestablish a TCP or
134-
* TLS connection.
135-
*/
136-
keepAlive?: boolean;
137-
138-
/**
139-
* The maximum time in milliseconds that a socket may remain idle before it
140-
* is closed.
141-
*/
142-
socketTimeout?: number;
143-
}
144-
145-
/**
146-
* Represents the http2 options that can be passed to a node http2 client.
147-
*/
148-
export interface NodeHttp2Options extends HttpOptions {
149-
/**
150-
* The maximum time in milliseconds that a stream may remain idle before it
151-
* is closed.
152-
*/
153-
requestTimeout?: number;
154-
155-
/**
156-
* The maximum time in milliseconds that a session or socket may remain idle
157-
* before it is closed.
158-
* https://nodejs.org/docs/latest-v12.x/api/http2.html#http2_http2session_and_sockets
159-
*/
160-
sessionTimeout?: number;
161-
}

0 commit comments

Comments
 (0)