'use strict'; const fs = require('fs'); const path = require('path'); const url = require('url'); const caw = require('caw'); const contentDisposition = require('content-disposition'); const decompress = require('decompress'); const filenamify = require('filenamify'); const getStream = require('get-stream'); const got = require('got'); const makeDir = require('make-dir'); const pify = require('pify'); const pEvent = require('p-event'); const fileType = require('file-type'); const extName = require('ext-name'); const fsP = pify(fs); const filenameFromPath = res => path.basename(url.parse(res.requestUrl).pathname); const getExtFromMime = res => { const header = res.headers['content-type']; if (!header) { return null; } const exts = extName.mime(header); if (exts.length !== 1) { return null; } return exts[0].ext; }; const getFilename = (res, data) => { const header = res.headers['content-disposition']; if (header) { const parsed = contentDisposition.parse(header); if (parsed.parameters && parsed.parameters.filename) { return parsed.parameters.filename; } } let filename = filenameFromPath(res); if (!path.extname(filename)) { const ext = (fileType(data) || {}).ext || getExtFromMime(res); if (ext) { filename = `${filename}.${ext}`; } } return filename; }; module.exports = (uri, output, opts) => { if (typeof output === 'object') { opts = output; output = null; } let protocol = url.parse(uri).protocol; if (protocol) { protocol = protocol.slice(0, -1); } opts = Object.assign({ encoding: null, rejectUnauthorized: process.env.npm_config_strict_ssl !== 'false' }, opts); const agent = caw(opts.proxy, {protocol}); const stream = got.stream(uri, Object.assign({agent}, opts)); const promise = pEvent(stream, 'response').then(res => { const encoding = opts.encoding === null ? 'buffer' : opts.encoding; return Promise.all([getStream(stream, {encoding}), res]); }).then(result => { // TODO: Use destructuring when targeting Node.js 6 const data = result[0]; const res = result[1]; if (!output) { return opts.extract ? decompress(data, opts) : data; } const filename = opts.filename || filenamify(getFilename(res, data)); const outputFilepath = path.join(output, filename); if (opts.extract) { return decompress(data, path.dirname(outputFilepath), opts); } return makeDir(path.dirname(outputFilepath)) .then(() => fsP.writeFile(outputFilepath, data)) .then(() => data); }); stream.then = promise.then.bind(promise); stream.catch = promise.catch.bind(promise); return stream; };