blob: e92b68d14a136945c55bc8276fdbaff6c256f0c4 [file] [log] [blame]
/**
* Fetch an HTTP url to a local file.
**/
var request = require("request")
, fs = require("graceful-fs")
, npm = require("../npm.js")
, url = require("url")
, log = require("npmlog")
, path = require("path")
, mkdir = require("mkdirp")
, chownr = require("chownr")
, regHost
, once = require("once")
module.exports = fetch
function fetch (remote, local, headers, cb) {
if (typeof cb !== "function") cb = headers, headers = {}
cb = once(cb)
log.verbose("fetch", "to=", local)
mkdir(path.dirname(local), function (er, made) {
if (er) return cb(er)
fetch_(remote, local, headers, cb)
})
}
function fetch_ (remote, local, headers, cb) {
var fstr = fs.createWriteStream(local, { mode : npm.modes.file })
var response = null
fstr.on("error", function (er) {
cb(er)
fstr.destroy()
})
var req = makeRequest(remote, fstr, headers)
req.on("response", function (res) {
log.http(res.statusCode, remote)
response = res
response.resume()
// Work around bug in node v0.10.0 where the CryptoStream
// gets stuck and never starts reading again.
if (process.version === "v0.10.0") {
response.resume = function (orig) { return function() {
var ret = orig.apply(response, arguments)
if (response.socket.encrypted)
response.socket.encrypted.read(0)
return ret
}}(response.resume)
}
})
fstr.on("close", function () {
var er
if (response && response.statusCode && response.statusCode >= 400) {
er = new Error(response.statusCode + " "
+ require("http").STATUS_CODES[response.statusCode])
}
cb(er, response)
})
}
function makeRequest (remote, fstr, headers) {
remote = url.parse(remote)
log.http("GET", remote.href)
regHost = regHost || url.parse(npm.config.get("registry")).host
if (remote.host === regHost && npm.config.get("always-auth")) {
remote.auth = new Buffer( npm.config.get("_auth")
, "base64" ).toString("utf8")
if (!remote.auth) return fstr.emit("error", new Error(
"Auth required and none provided. Please run 'npm adduser'"))
}
var proxy
if (remote.protocol !== "https:" || !(proxy = npm.config.get("https-proxy"))) {
proxy = npm.config.get("proxy")
}
var opts = { url: remote
, proxy: proxy
, strictSSL: npm.config.get("strict-ssl")
, rejectUnauthorized: npm.config.get("strict-ssl")
, ca: remote.host === regHost ? npm.config.get("ca") : undefined
, headers: { "user-agent": npm.config.get("user-agent") }}
var req = request(opts)
req.on("error", function (er) {
fstr.emit("error", er)
})
req.pipe(fstr)
return req
}