|
|
|
/**
|
|
|
|
* 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
|
|
|
|
}
|