Created
January 19, 2016 01:38
-
-
Save stormpython/f9a29894f6eb12cea217 to your computer and use it in GitHub Desktop.
HTTP Proxy Example using https-proxy-agent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { fromNode: fn } = require('bluebird'); | |
const { createWriteStream, unlinkSync } = require('fs'); | |
const Wreck = require('wreck'); | |
const HttpsProxyAgent = require('https-proxy-agent'); | |
const getProgressReporter = require('../progress_reporter'); | |
function sendRequest({ sourceUrl, timeout, proxy }) { | |
const maxRedirects = 11; //Because this one goes to 11. | |
sourceUrl = proxy ? sourceUrl.agent = new HttpsProxyAgent(proxy) : sourceUrl; | |
return fn(cb => { | |
const req = Wreck.request('GET', sourceUrl, { timeout, redirects: maxRedirects }, (err, resp) => { | |
if (err) { | |
if (err.code === 'ECONNREFUSED') { | |
err = new Error('ENOTFOUND'); | |
} | |
return cb(err); | |
} | |
if (resp.statusCode >= 400) { | |
return cb(new Error('ENOTFOUND')); | |
} | |
cb(null, { req, resp }); | |
}); | |
}); | |
} | |
function downloadResponse({ resp, targetPath, progressReporter }) { | |
return new Promise((resolve, reject) => { | |
const writeStream = createWriteStream(targetPath); | |
// if either stream errors, fail quickly | |
resp.on('error', reject); | |
writeStream.on('error', reject); | |
// report progress as we download | |
resp.on('data', (chunk) => { | |
progressReporter.progress(chunk.length); | |
}); | |
// write the download to the file system | |
resp.pipe(writeStream); | |
// when the write is done, we are done | |
writeStream.on('finish', resolve); | |
}); | |
} | |
function getArchiveTypeFromResponse(resp, sourceUrl) { | |
const contentType = (resp.headers['content-type'] || ''); | |
switch (contentType.toLowerCase()) { | |
case 'application/zip': return '.zip'; | |
case 'application/x-gzip': return '.tar.gz'; | |
default: | |
//If we can't infer the archive type from the content-type header, | |
//fall back to checking the extension in the url | |
if (/\.zip$/i.test(sourceUrl)) { | |
return '.zip'; | |
} | |
if (/\.tar\.gz$/i.test(sourceUrl)) { | |
return '.tar.gz'; | |
} | |
break; | |
} | |
} | |
/* | |
Responsible for managing http transfers | |
*/ | |
export default async function downloadUrl(logger, sourceUrl, targetPath, timeout) { | |
try { | |
const { req, resp } = await sendRequest({ sourceUrl, timeout }); | |
try { | |
let totalSize = parseFloat(resp.headers['content-length']) || 0; | |
const progressReporter = getProgressReporter(logger); | |
progressReporter.init(totalSize); | |
await downloadResponse({ resp, targetPath, progressReporter }); | |
progressReporter.complete(); | |
} catch (err) { | |
req.abort(); | |
throw err; | |
} | |
// all is well, return our archive type | |
const archiveType = getArchiveTypeFromResponse(resp, sourceUrl); | |
return { archiveType }; | |
} catch (err) { | |
if (err.message !== 'ENOTFOUND') { | |
logger.error(err); | |
} | |
throw err; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment