@rdfc/http-utils-processor-ts
Version:
HTTP util functions to be used within RDF-Connect
114 lines (113 loc) • 3.8 kB
JavaScript
import { HttpUtilsError } from "./error.js";
import { timeout } from "./util/timeout.js";
import { statusCodeAccepted } from "./util/status.js";
import { parseHeaders } from "./util/headers.js";
import { Auth } from "./auth/index.js";
import { cronify } from "./util/cronify.js";
import { getLoggerFor } from "./util/logUtil.js";
const logger = getLoggerFor("httpFetch");
class HttpFetchArgs {
method = "GET";
headers = [];
acceptStatusCodes = ["200-300"];
closeOnEnd = true;
bodyCanBeEmpty = false;
timeOutMilliseconds = null;
auth = null;
cron = null;
runOnInit = false;
errorsAreFatal = true;
outputAsBuffer = false;
constructor(partial) {
Object.assign(this, partial);
if (!partial.bodyCanBeEmpty && partial.method == "HEAD") {
throw HttpUtilsError.illegalParameters("Cannot use HEAD method with bodyCanBeEmpty set to false");
}
if (partial.closeOnEnd && partial.cron) {
throw HttpUtilsError.illegalParameters("Cannot close stream when using cron.");
}
if (this.acceptStatusCodes.length === 0) {
this.acceptStatusCodes.push("200-300");
}
statusCodeAccepted(0, this.acceptStatusCodes);
}
getAuth() {
return this.auth ? Auth.from(this.auth) : null;
}
}
export async function httpFetch(url, writer, options = {}) {
url = (Array.isArray(url) ? url : [url]);
const args = new HttpFetchArgs(options);
const auth = args.getAuth();
const headers = parseHeaders(args.headers);
const requests = url.map((x) => {
return new Request(x, {
method: options.method,
headers,
});
});
const executeRequest = async (req) => {
logger.debug(`Executing request to '${req.url}'...`);
if (auth) {
await auth.authorize(req);
}
const fetchPromise = fetch(req).catch((err) => {
throw HttpUtilsError.genericFetchError(err);
});
const res = await timeout(args.timeOutMilliseconds, fetchPromise).catch((err) => {
if (err === "timeout") {
throw HttpUtilsError.timeOutError(args.timeOutMilliseconds);
}
else {
throw err;
}
});
if (!statusCodeAccepted(res.status, args.acceptStatusCodes)) {
if (res.status === 401 && auth) {
throw HttpUtilsError.credentialIssue();
}
else if (res.status === 401) {
throw HttpUtilsError.unauthorizedError();
}
else {
throw HttpUtilsError.statusCodeNotAccepted(res.status);
}
}
if (!res.body) {
if (!args.bodyCanBeEmpty) {
throw HttpUtilsError.noBodyInResponse();
}
if (!args.cron && args.closeOnEnd) {
await writer.end();
}
return;
}
try {
const body = args.outputAsBuffer
? Buffer.from(await res.arrayBuffer())
: await res.text();
await writer.push(body);
}
catch (e) {
console.error(e);
}
};
let executeAllRequests = async () => {
const promises = requests.map(executeRequest).map((promise) => promise.catch((err) => {
if (args.errorsAreFatal) {
throw err;
}
else {
console.error(err);
}
}));
await Promise.all(promises);
if (args.closeOnEnd) {
await writer.end();
}
};
if (args.cron) {
executeAllRequests = cronify(executeAllRequests, args.cron, args.runOnInit);
}
return executeAllRequests;
}