cdk-amazon-chime-resources
Version:

99 lines (98 loc) • 4.11 kB
JavaScript
import { HttpResponse } from "@aws-sdk/protocol-http";
import { buildQueryString } from "@aws-sdk/querystring-builder";
import { Agent as hAgent, request as hRequest } from "http";
import { Agent as hsAgent, request as hsRequest } from "https";
import { NODEJS_TIMEOUT_ERROR_CODES } from "./constants";
import { getTransformedHeaders } from "./get-transformed-headers";
import { writeRequestBody } from "./write-request-body";
export const DEFAULT_REQUEST_TIMEOUT = 0;
export class NodeHttpHandler {
constructor(options) {
this.metadata = { handlerProtocol: "http/1.1" };
this.configProvider = new Promise((resolve, reject) => {
if (typeof options === "function") {
options()
.then((_options) => {
resolve(this.resolveDefaultConfig(_options));
})
.catch(reject);
}
else {
resolve(this.resolveDefaultConfig(options));
}
});
}
resolveDefaultConfig(options) {
const { requestTimeout, connectionTimeout, socketTimeout, httpAgent, httpsAgent } = options || {};
const keepAlive = true;
const maxSockets = 50;
return {
connectionTimeout,
socketTimeout,
requestTimeout: requestTimeout ?? connectionTimeout ?? socketTimeout ?? DEFAULT_REQUEST_TIMEOUT,
httpAgent: httpAgent || new hAgent({ keepAlive, maxSockets }),
httpsAgent: httpsAgent || new hsAgent({ keepAlive, maxSockets }),
};
}
destroy() {
this.config?.httpAgent?.destroy();
this.config?.httpsAgent?.destroy();
}
async handle(request, { abortSignal } = {}) {
if (!this.config) {
this.config = await this.configProvider;
}
return new Promise((resolve, reject) => {
if (!this.config) {
throw new Error("Node HTTP request handler config is not resolved");
}
if (abortSignal?.aborted) {
const abortError = new Error("Request aborted");
abortError.name = "AbortError";
reject(abortError);
return;
}
const isSSL = request.protocol === "https:";
const queryString = buildQueryString(request.query || {});
const nodeHttpsOptions = {
headers: request.headers,
host: request.hostname,
method: request.method,
path: queryString ? `${request.path}?${queryString}` : request.path,
port: request.port,
agent: isSSL ? this.config.httpsAgent : this.config.httpAgent,
};
const requestFunc = isSSL ? hsRequest : hRequest;
const req = requestFunc(nodeHttpsOptions, (res) => {
const httpResponse = new HttpResponse({
statusCode: res.statusCode || -1,
headers: getTransformedHeaders(res.headers),
body: res,
});
resolve({ response: httpResponse });
});
req.on("error", (err) => {
if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
reject(Object.assign(err, { name: "TimeoutError" }));
}
else {
reject(err);
}
});
const timeout = this.config?.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
req.setTimeout(timeout, () => {
req.destroy();
reject(Object.assign(new Error(`Connection timed out after ${timeout} ms`), { name: "TimeoutError" }));
});
if (abortSignal) {
abortSignal.onabort = () => {
req.abort();
const abortError = new Error("Request aborted");
abortError.name = "AbortError";
reject(abortError);
};
}
writeRequestBody(req, request);
});
}
}