import http from 'http'; import https from 'https'; import urlMod from 'url'; import { BaseClient, BaseResponse } from './base.js'; import { AbortError } from '../../utils.js'; class HttpResponse extends BaseResponse { /** * BaseResponse facade for node HTTP/HTTPS API Response * @param {http.ServerResponse} response */ constructor(response, dataPromise) { super(); this.response = response; this.dataPromise = dataPromise; } get status() { return this.response.statusCode; } getHeader(name) { return this.response.headers[name]; } async getData() { const data = await this.dataPromise; return data; } } export class HttpClient extends BaseClient { constructor(url) { super(url); this.parsedUrl = urlMod.parse(this.url); this.httpApi = (this.parsedUrl.protocol === 'http:' ? http : https); } constructRequest(headers, signal) { return new Promise((resolve, reject) => { const request = this.httpApi.get( { ...this.parsedUrl, headers, }, (response) => { const dataPromise = new Promise((resolveData) => { const chunks = []; // collect chunks response.on('data', (chunk) => { chunks.push(chunk); }); // concatenate all chunks and resolve the promise with the resulting buffer response.on('end', () => { const data = Buffer.concat(chunks).buffer; resolveData(data); }); response.on('error', reject); }); resolve(new HttpResponse(response, dataPromise)); }, ); request.on('error', reject); if (signal) { if (signal.aborted) { request.destroy(new AbortError('Request aborted')); } signal.addEventListener('abort', () => request.destroy(new AbortError('Request aborted'))); } }); } async request({ headers, signal } = {}) { const response = await this.constructRequest(headers, signal); return response; } }