camstreamerlib
Version:
Helper library for CamStreamer ACAP applications.
96 lines (95 loc) • 3.86 kB
JavaScript
import { Digest } from './Digest';
import { Agent, fetch as undiciFetch, Request as UndiciRequest, } from 'undici';
export class HttpRequestSender {
agent;
authData;
constructor(agentOptions) {
this.agent = new Agent({
connect: { rejectUnauthorized: agentOptions?.rejectUnaurhorized, keepAlive: agentOptions?.keepAlive },
});
}
async sendRequest(options, postData) {
const stackHolder = { stack: '' };
Error.captureStackTrace(stackHolder, this.sendRequest);
try {
return await this.sendRequestWithAuth(options, postData);
}
catch (err) {
if (err instanceof Error) {
err.stack = `${err.stack}\nCaptured at:\n${stackHolder.stack}`;
}
throw err;
}
}
async sendRequestWithAuth(options, postData, wwwAuthenticateHeader) {
options.timeout ??= 10000;
const url = HttpRequestSender.getURL(options);
const authorization = this.getAuthorization(options, wwwAuthenticateHeader);
if (authorization !== undefined) {
options.headers ??= {};
options.headers['Authorization'] = authorization;
}
const req = new UndiciRequest(url, { body: postData, method: options.method, headers: options.headers });
const res = await undiciFetch(req, { signal: AbortSignal.timeout(options.timeout), dispatcher: this.agent });
if (!res.ok) {
this.invalidateAuthorization();
}
if (res.status === 401) {
const authenticateHeader = res.headers.get('www-authenticate');
if (authenticateHeader !== null &&
authenticateHeader.indexOf('Digest') !== -1 &&
wwwAuthenticateHeader === undefined) {
return this.sendRequestWithAuth(options, postData, authenticateHeader);
}
else {
return res;
}
}
else {
return res;
}
}
static getURL(options) {
const url = new URL(`${options.protocol}//${options.host}:${options.port}${options.path}`);
return url.toString();
}
getAuthorization(options, wwwAuthenticateHeader) {
if (options.user === undefined || options.pass === undefined) {
this.authData = undefined;
return;
}
if (this.authData &&
(this.authData.host !== options.host ||
this.authData.port !== options.port ||
this.authData.user !== options.user ||
this.authData.pass !== options.pass ||
(wwwAuthenticateHeader !== undefined && this.authData.wwwAuthenticateHeader !== wwwAuthenticateHeader))) {
this.authData = undefined;
}
if (this.authData === undefined) {
this.authData = {
host: options.host,
port: options.port,
user: options.user,
pass: options.pass,
wwwAuthenticateHeader,
digest: new Digest(),
};
}
return HttpRequestSender.getAuthHeader(options, this.authData);
}
invalidateAuthorization() {
this.authData = undefined;
}
static getAuthHeader(options, authData) {
if (options.user === undefined || options.pass === undefined) {
throw new Error('No credentials found');
}
if (authData.wwwAuthenticateHeader !== undefined && authData.wwwAuthenticateHeader.indexOf('Digest') !== -1) {
return authData.digest.getAuthHeader(options.user, options.pass, options.method ?? 'GET', options.path, authData.wwwAuthenticateHeader);
}
else {
return `Basic ${Buffer.from(`${options.user}:${options.pass}`).toString('base64')}`;
}
}
}