Skip to content

Commit ced80a6

Browse files
author
Nicolas Hansse
committed
fix(http): do not recreate agent for each request
1 parent 60f2a3d commit ced80a6

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

src/httpClient/httpURLConnectionClient.ts

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { ClientRequest, IncomingHttpHeaders, IncomingMessage, request as httpRequest } from "http";
21-
import { Agent, AgentOptions, request as httpsRequest } from "https";
21+
import { Agent, AgentOptions, globalAgent, request as httpsRequest } from "https";
2222
import { HttpsProxyAgent } from "https-proxy-agent";
2323

2424
import * as fs from "fs";
@@ -37,7 +37,7 @@ import checkServerIdentity from "../helpers/checkServerIdentity";
3737
class HttpURLConnectionClient implements ClientInterface {
3838
private static CHARSET = "utf-8";
3939
public proxy?: AgentOptions;
40-
private agentOptions!: AgentOptions;
40+
private agents: Record<string, Agent> = {};
4141

4242
/**
4343
* Sends an HTTP request to the specified endpoint with the provided JSON payload and configuration.
@@ -64,9 +64,7 @@ class HttpURLConnectionClient implements ClientInterface {
6464
requestOptions.headers ??= {};
6565
requestOptions.timeout = config.connectionTimeoutMillis;
6666

67-
if (config.certificatePath) {
68-
this.installCertificateVerifier(config.certificatePath);
69-
}
67+
const agent = this.selectAgent(config.certificatePath);
7068

7169
const apiKey = config.apiKey;
7270

@@ -85,12 +83,12 @@ class HttpURLConnectionClient implements ClientInterface {
8583

8684
requestOptions.headers[ApiConstants.CONTENT_TYPE] = ApiConstants.APPLICATION_JSON_TYPE;
8785

88-
const httpConnection: ClientRequest = this.createRequest(endpoint, requestOptions, config.applicationName);
86+
const httpConnection: ClientRequest = this.createRequest(endpoint, requestOptions, agent, config.applicationName);
8987
return this.doRequest(httpConnection, json);
9088
}
9189

9290
// create Request object
93-
private createRequest(endpoint: string, requestOptions: IRequest.Options, applicationName?: string): ClientRequest {
91+
private createRequest(endpoint: string, requestOptions: IRequest.Options, agent: Agent, applicationName?: string): ClientRequest {
9492
if (!requestOptions.headers) {
9593
requestOptions.headers = {};
9694
}
@@ -114,7 +112,7 @@ class HttpURLConnectionClient implements ClientInterface {
114112
const { host, port, ...options } = this.proxy;
115113
requestOptions.agent = new HttpsProxyAgent({ host, port: port || 443, ...options });
116114
} else {
117-
requestOptions.agent = new Agent(this.agentOptions);
115+
requestOptions.agent = agent;
118116
}
119117

120118
requestOptions.headers["Cache-Control"] = "no-cache";
@@ -255,27 +253,6 @@ class HttpURLConnectionClient implements ClientInterface {
255253
});
256254
}
257255

258-
private installCertificateVerifier(terminalCertificatePath: string): void | Promise<HttpClientException> {
259-
try {
260-
if (terminalCertificatePath == "unencrypted") {
261-
this.agentOptions = {
262-
rejectUnauthorized: false
263-
};
264-
} else {
265-
const certificateInput = fs.readFileSync(terminalCertificatePath);
266-
this.agentOptions = {
267-
ca: certificateInput,
268-
checkServerIdentity,
269-
};
270-
}
271-
272-
} catch (e) {
273-
const message = e instanceof Error ? e.message : "undefined";
274-
return Promise.reject(new HttpClientException({ message: `Error loading certificate from path: ${message}` }));
275-
}
276-
277-
}
278-
279256
private verifyLocation(location: string): boolean {
280257
try {
281258
const url = new URL(location);
@@ -286,6 +263,40 @@ class HttpURLConnectionClient implements ClientInterface {
286263
return false;
287264
}
288265
}
266+
267+
private selectAgent(terminalCertificatePath?: string): Agent {
268+
if (!terminalCertificatePath) return globalAgent;
269+
270+
if (this.agents[terminalCertificatePath])
271+
return this.agents[terminalCertificatePath];
272+
273+
if (terminalCertificatePath == "unencrypted") {
274+
this.agents["unencrypted"] = new Agent({
275+
keepAlive: true,
276+
scheduling: "lifo",
277+
timeout: 5000,
278+
rejectUnauthorized: false,
279+
});
280+
return this.agents["unencrypted"];
281+
} else {
282+
try {
283+
const certificateInput = fs.readFileSync(terminalCertificatePath);
284+
this.agents[terminalCertificatePath] = new Agent({
285+
keepAlive: true,
286+
scheduling: "lifo",
287+
timeout: 5000,
288+
ca: certificateInput,
289+
checkServerIdentity,
290+
});
291+
return this.agents[terminalCertificatePath];
292+
} catch (e) {
293+
const message = e instanceof Error ? e.message : "undefined";
294+
throw new HttpClientException({
295+
message: `Error loading certificate from path: ${message}`,
296+
});
297+
}
298+
}
299+
}
289300
}
290301

291302

0 commit comments

Comments
 (0)