UNPKG

camstreamerlib

Version:

Helper library for CamStreamer ACAP applications.

96 lines (95 loc) 3.86 kB
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')}`; } } }