UNPKG

ruud

Version:
122 lines (98 loc) 2.79 kB
import { URL } from 'url'; import { protocols } from './util.js'; const DEFAULT_TIMEOUT = 5000; const postParameters = url => { // TODO! expand with { port, search, hash, username, password } const { protocol, hostname, pathname } = new URL(url); return { protocol, hostname, path: pathname }; }; const getProtocol = url => { const urlObject = new URL(url); return urlObject.protocol.replace(/[^a-zA-Z]/g, ''); }; const statusOk = code => Math.floor(code / 100) === 2; const parseResponse = (res, body, buffer) => { try { return buffer ? Buffer.concat(body) : /json/.test(res.headers['content-type']) ? JSON.parse(body) : body; } catch ({ message }) { return { error: message }; }; }; const fetch = (url = '', options = {}, streamHandler) => new Promise((resolve, reject) => { if (!url) { return reject({ error: 'url required' }); } if (globalThis.fetch) { // todo! use native fetch } const { method = 'GET', headers: inputHeaders = {}, body, silent, raw, buffer, } = options; const headers = Object.assign({ Accept: '*/*' }, inputHeaders); const fetchHandler = res => { if (raw) { return resolve(res); } !buffer && res.setEncoding('utf8'); let body = buffer ? [] : ''; res.on('error', ({ message }) => reject({ error: message })); res.on('data', chunk => buffer ? body.push(chunk) : body += chunk); res.on('end', () => resolve(parseResponse(res, body, buffer))); }; const handler = res => { if (/HEAD/i.test(method)) { return resolve(res); } if (!statusOk(res.statusCode)) { return silent ? resolve() : reject({ code: res.statusCode, error: res.statusMessage }); } streamHandler ? streamHandler(resolve, reject, res) : fetchHandler(res); }; const httpModule = protocols[getProtocol(url)]; const req = body ? httpModule.request(Object.assign(postParameters(url), { method, headers }), handler) : httpModule.get(url, { method, headers }, handler); if (body) { req.write(body); req.end(); } req.setTimeout(options.timeout || DEFAULT_TIMEOUT, reject); req.on('error', ({ message }) => resolve({ error: message })); }); const stream = (serverRes, url, options = {}) => fetch(url, options, (resolve, reject, res) => { if (options.buffer) { return resolve(res); } try { serverRes.setHeader('Content-Type', res.headers['content-type']); res.on('error', ({ message }) => reject({ error: message })); res.on('data', chunk => serverRes.write(chunk)); res.on('end', () => resolve(serverRes.end())); } catch ({ message }) { reject({ error: message }); } }); export { fetch, stream };