hfs
Version:
HTTP File Server
93 lines (92 loc) • 4.62 kB
JavaScript
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stream2string = void 0;
exports.httpString = httpString;
exports.httpWithBody = httpWithBody;
exports.httpStream = httpStream;
const node_url_1 = require("node:url");
const node_https_1 = __importDefault(require("node:https"));
const node_http_1 = __importDefault(require("node:http"));
const node_stream_1 = require("node:stream");
const lodash_1 = __importDefault(require("lodash"));
const consumers_1 = require("node:stream/consumers");
Object.defineProperty(exports, "stream2string", { enumerable: true, get: function () { return consumers_1.text; } });
async function httpString(url, options) {
return await (0, consumers_1.text)(await httpStream(url, options));
}
async function httpWithBody(url, options) {
const req = await httpStream(url, options);
return Object.assign(req, {
ok: lodash_1.default.inRange(req.statusCode, 200, 300),
body: req.statusCode ? await (0, consumers_1.buffer)(req) : undefined,
});
}
function httpStream(url, { body, jar, noRedirect, httpThrow, proxy, ...options } = {}) {
var _a;
const controller = new AbortController();
(_a = options.signal) !== null && _a !== void 0 ? _a : (options.signal = controller.signal);
return Object.assign(new Promise((resolve, reject) => {
var _a, _b, _c, _d;
var _e, _f, _g;
proxy !== null && proxy !== void 0 ? proxy : (proxy = httpStream.defaultProxy);
(_a = options.headers) !== null && _a !== void 0 ? _a : (options.headers = {});
if (body) {
options.method || (options.method = 'POST');
if (lodash_1.default.isPlainObject(body)) {
(_b = (_e = options.headers)['content-type']) !== null && _b !== void 0 ? _b : (_e['content-type'] = 'application/json');
body = JSON.stringify(body);
}
if (!(body instanceof node_stream_1.Readable))
(_c = (_f = options.headers)['content-length']) !== null && _c !== void 0 ? _c : (_f['content-length'] = Buffer.byteLength(body));
}
if (jar)
options.headers.cookie = lodash_1.default.map(jar, (v, k) => `${k}=${v}; `).join('')
+ (options.headers.cookie || ''); // preserve parameter
Object.assign(options, lodash_1.default.pick((0, node_url_1.parse)(proxy || url), ['hostname', 'port', 'path', 'protocol', 'auth']));
if (proxy) {
options.path = url;
(_d = (_g = options.headers).host) !== null && _d !== void 0 ? _d : (_g.host = (0, node_url_1.parse)(url).host || undefined);
}
const proto = options.protocol === 'https:' ? node_https_1.default : node_http_1.default;
const req = proto.request(options, res => {
var _a;
var _b;
console.debug("http responded", res.statusCode, "to", url);
if (jar)
for (const entry of res.headers['set-cookie'] || []) {
const [, k, v] = /(.+?)=([^;]+)/.exec(entry) || [];
if (!k)
continue;
if (v)
jar[k] = v;
else
delete jar[k];
}
if (!res.statusCode || (httpThrow !== null && httpThrow !== void 0 ? httpThrow : true) && res.statusCode >= 400)
return reject(new Error(String(res.statusCode), { cause: res }));
let r = res.headers.location;
if (r && !noRedirect) {
if (r.startsWith('/')) // relative
r = ((_a = /(.+)\b\/(\b|$)/.exec(url)) === null || _a === void 0 ? void 0 : _a[1]) + r;
const stack = ((_b = options)._stack || (_b._stack = []));
if (stack.length > 20 || stack.includes(r))
return reject(new Error('endless http redirection'));
stack.push(r);
return resolve(httpStream(r, options));
}
resolve(res);
}).on('error', e => {
reject(req.res || e);
});
if (body && body instanceof node_stream_1.Readable)
body.pipe(req).on('end', () => req.end());
else
req.end(body);
}), {
abort() { controller.abort(); }
});
}
;