1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
var assert = require('assert')
var url = require('url')
var request = require('request')
var once = require('once')
module.exports = fetch
function fetch (uri, params, cb) {
assert(typeof uri === 'string', 'must pass uri to request')
assert(params && typeof params === 'object', 'must pass params to request')
assert(typeof cb === 'function', 'must pass callback to request')
cb = once(cb)
var client = this
this.attempt(function (operation) {
makeRequest.call(client, uri, params, function (er, req) {
if (er) return cb(er)
req.once('error', retryOnError)
function retryOnError (er) {
if (operation.retry(er)) {
client.log.info('retry', 'will retry, error on last attempt: ' + er)
} else {
cb(er)
}
}
req.on('response', function (res) {
client.log.http('fetch', '' + res.statusCode, uri)
req.removeListener('error', retryOnError)
var er
var statusCode = res && res.statusCode
if (statusCode === 200) {
// Work around bug in node v0.10.0 where the CryptoStream
// gets stuck and never starts reading again.
res.resume()
if (process.version === 'v0.10.0') unstick(res)
req.once('error', function (er) {
res.emit('error', er)
})
return cb(null, res)
// Only retry on 408, 5xx or no `response`.
} else if (statusCode === 408) {
er = new Error('request timed out')
} else if (statusCode >= 500) {
er = new Error('server error ' + statusCode)
}
if (er && operation.retry(er)) {
client.log.info('retry', 'will retry, error on last attempt: ' + er)
} else {
cb(new Error('fetch failed with status code ' + statusCode))
}
})
})
})
}
function unstick (response) {
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)
}
function makeRequest (remote, params, cb) {
var parsed = url.parse(remote)
this.log.http('fetch', 'GET', parsed.href)
var headers = params.headers || {}
var er = this.authify(
params.auth && params.auth.alwaysAuth,
parsed,
headers,
params.auth
)
if (er) return cb(er)
var opts = this.initialize(
parsed,
'GET',
'application/x-tar, application/vnd.github+json; q=0.1',
headers
)
// always want to follow redirects for fetch
opts.followRedirect = true
cb(null, request(opts))
}
|