Skip to content

Commit dbb18f4

Browse files
committed
deps: @npmcli/agent@2.1.0
1 parent 812aa6d commit dbb18f4

28 files changed

+1681
-686
lines changed

DEPENDENCIES.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ graph LR;
115115
npm-->npm-profile;
116116
npm-->npm-registry-fetch;
117117
npm-->npm-user-validate;
118+
npm-->npmcli-agent["@npmcli/agent"];
118119
npm-->npmcli-arborist["@npmcli/arborist"];
119120
npm-->npmcli-config["@npmcli/config"];
120121
npm-->npmcli-docs["@npmcli/docs"];
@@ -540,6 +541,7 @@ graph LR;
540541
npm-->npm-profile;
541542
npm-->npm-registry-fetch;
542543
npm-->npm-user-validate;
544+
npm-->npmcli-agent["@npmcli/agent"];
543545
npm-->npmcli-arborist["@npmcli/arborist"];
544546
npm-->npmcli-config["@npmcli/config"];
545547
npm-->npmcli-docs["@npmcli/docs"];
@@ -598,8 +600,10 @@ graph LR;
598600
npm-registry-fetch-->minizlib;
599601
npm-registry-fetch-->npm-package-arg;
600602
npm-registry-fetch-->proc-log;
603+
npmcli-agent-->http-proxy-agent;
604+
npmcli-agent-->https-proxy-agent;
601605
npmcli-agent-->lru-cache;
602-
npmcli-agent-->socks;
606+
npmcli-agent-->socks-proxy-agent;
603607
npmcli-arborist-->benchmark;
604608
npmcli-arborist-->bin-links;
605609
npmcli-arborist-->cacache;

node_modules/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
!/@npmcli/
2020
/@npmcli/*
2121
!/@npmcli/agent
22+
!/@npmcli/agent/node_modules/
23+
/@npmcli/agent/node_modules/*
24+
!/@npmcli/agent/node_modules/agent-base
25+
!/@npmcli/agent/node_modules/http-proxy-agent
26+
!/@npmcli/agent/node_modules/https-proxy-agent
27+
!/@npmcli/agent/node_modules/socks-proxy-agent
2228
!/@npmcli/disparity-colors
2329
!/@npmcli/fs
2430
!/@npmcli/git
+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
'use strict'
2+
3+
const http = require('http')
4+
const https = require('https')
5+
const net = require('net')
6+
const tls = require('tls')
7+
const { once } = require('events')
8+
const { createTimeout, abortRace, urlify, appendPort, cacheAgent } = require('./util')
9+
const { normalizeOptions, cacheOptions } = require('./options')
10+
const { getProxy, getProxyType, isSecureProxy, proxyCache } = require('./proxy.js')
11+
const Errors = require('./errors.js')
12+
13+
const createAgent = (base, name) => {
14+
const SECURE = base === https
15+
const SOCKET_TYPE = SECURE ? tls : net
16+
17+
const agent = class extends base.Agent {
18+
#options
19+
#timeouts
20+
#proxy
21+
#socket
22+
23+
constructor (_options) {
24+
const { timeouts, proxy, noProxy, ...options } = normalizeOptions(_options)
25+
26+
super(options)
27+
28+
this.#options = options
29+
this.#timeouts = timeouts
30+
this.#proxy = proxy ? { proxies: getProxyType(proxy), proxy: urlify(proxy), noProxy } : null
31+
}
32+
33+
get proxy () {
34+
return this.#proxy ? { url: this.#proxy.proxy } : {}
35+
}
36+
37+
#getProxy (options) {
38+
const proxy = this.#proxy
39+
? getProxy(appendPort(`${options.protocol}//${options.host}`, options.port), this.#proxy)
40+
: null
41+
42+
if (!proxy) {
43+
return
44+
}
45+
46+
const secure = isSecureProxy(proxy)
47+
48+
return cacheAgent({
49+
key: cacheOptions({
50+
...options,
51+
...this.#options,
52+
secure,
53+
timeouts: this.#timeouts,
54+
proxy,
55+
}),
56+
cache: proxyCache,
57+
secure,
58+
proxies: this.#proxy.proxies,
59+
}, proxy, this.#options)
60+
}
61+
62+
#setKeepAlive (socket) {
63+
socket.setKeepAlive(this.keepAlive, this.keepAliveMsecs)
64+
socket.setNoDelay(this.keepAlive)
65+
}
66+
67+
#setIdleTimeout (socket, options) {
68+
if (this.#timeouts.idle) {
69+
socket.setTimeout(this.#timeouts.idle, () => {
70+
socket.destroy(new Errors.IdleTimeoutError(options))
71+
})
72+
}
73+
}
74+
75+
async #proxyConnect (proxy, request, options) {
76+
// socks-proxy-agent accepts a dns lookup function
77+
options.lookup ??= this.#options.lookup
78+
79+
// all the proxy agents use this secureEndpoint option to determine
80+
// if the proxy should connect over tls or not. we can set it based
81+
// on if the HttpAgent or HttpsAgent is used.
82+
options.secureEndpoint = SECURE
83+
84+
const socket = await abortRace([
85+
(ac) => createTimeout(this.#timeouts.connection, ac).catch(() => {
86+
throw new Errors.ConnectionTimeoutError(options)
87+
}),
88+
(ac) => proxy.connect(request, options).then((s) => {
89+
this.#setKeepAlive(s)
90+
91+
const connectEvent = SECURE ? 'secureConnect' : 'connect'
92+
const connectingEvent = SECURE ? 'secureConnecting' : 'connecting'
93+
94+
if (!s[connectingEvent]) {
95+
return s
96+
}
97+
98+
return abortRace([
99+
() => once(s, 'error', ac).then((err) => {
100+
throw err
101+
}),
102+
() => once(s, connectEvent, ac).then(() => s),
103+
], ac)
104+
}),
105+
])
106+
107+
this.#setIdleTimeout(socket, options)
108+
109+
return socket
110+
}
111+
112+
async connect (request, options) {
113+
const proxy = this.#getProxy(options)
114+
if (proxy) {
115+
return this.#proxyConnect(proxy, request, options)
116+
}
117+
118+
const socket = SOCKET_TYPE.connect(options)
119+
120+
this.#setKeepAlive(socket)
121+
122+
await abortRace([
123+
(s) => createTimeout(this.#timeouts.connection, s).catch(() => {
124+
throw new Errors.ConnectionTimeoutError(options)
125+
}),
126+
(s) => once(socket, 'error', s).then((err) => {
127+
throw err
128+
}),
129+
(s) => once(socket, 'connect', s),
130+
])
131+
132+
this.#setIdleTimeout(socket, options)
133+
134+
return socket
135+
}
136+
137+
addRequest (request, options) {
138+
const proxy = this.#getProxy(options)
139+
// it would be better to call proxy.addRequest here but this causes the
140+
// http-proxy-agent to call its super.addRequest which causes the request
141+
// to be added to the agent twice. since we only support 3 agents
142+
// currently (see the required agents in proxy.js) we have manually
143+
// checked that the only public methods we need to call are called in the
144+
// next block. this could change in the future and presumably we would get
145+
// failing tests until we have properly called the necessary methods on
146+
// each of our proxy agents
147+
if (proxy?.setRequestProps) {
148+
proxy.setRequestProps(request, options)
149+
}
150+
151+
request.setHeader('connection', this.keepAlive ? 'keep-alive' : 'close')
152+
153+
const responseTimeout = createTimeout(this.#timeouts.response)
154+
if (responseTimeout) {
155+
request.once('finish', () => {
156+
responseTimeout.start(() => {
157+
request.destroy(new Errors.ResponseTimeoutError(request, this.proxy?.url))
158+
})
159+
})
160+
request.once('response', () => {
161+
responseTimeout.clear()
162+
})
163+
}
164+
165+
const transferTimeout = createTimeout(this.#timeouts.transfer)
166+
if (transferTimeout) {
167+
request.once('response', (res) => {
168+
transferTimeout.start(() => {
169+
res.destroy(new Errors.TransferTimeoutError(request, this.proxy?.url))
170+
})
171+
res.once('close', () => {
172+
transferTimeout.clear()
173+
})
174+
})
175+
}
176+
177+
return super.addRequest(request, options)
178+
}
179+
180+
createSocket (req, options, cb) {
181+
return Promise.resolve()
182+
.then(() => this.connect(req, options))
183+
.then((socket) => {
184+
this.#socket = socket
185+
return super.createSocket(req, options, cb)
186+
}, cb)
187+
}
188+
189+
createConnection () {
190+
return this.#socket
191+
}
192+
}
193+
194+
Object.defineProperty(agent, 'name', { value: name })
195+
return agent
196+
}
197+
198+
module.exports = {
199+
HttpAgent: createAgent(http, 'HttpAgent'),
200+
HttpsAgent: createAgent(https, 'HttpsAgent'),
201+
}

node_modules/@npmcli/agent/lib/dns.js

+35-33
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,51 @@
33
const { LRUCache } = require('lru-cache')
44
const dns = require('dns')
55

6-
const defaultOptions = exports.defaultOptions = {
7-
family: undefined,
8-
hints: dns.ADDRCONFIG,
9-
all: false,
10-
verbatim: undefined,
11-
}
12-
13-
const lookupCache = exports.lookupCache = new LRUCache({ max: 50 })
14-
156
// this is a factory so that each request can have its own opts (i.e. ttl)
167
// while still sharing the cache across all requests
17-
exports.getLookup = (dnsOptions) => {
18-
return (hostname, options, callback) => {
19-
if (typeof options === 'function') {
20-
callback = options
21-
options = null
22-
} else if (typeof options === 'number') {
23-
options = { family: options }
8+
const cache = new LRUCache({ max: 50 })
9+
10+
const getOptions = ({
11+
family = 0,
12+
hints = dns.ADDRCONFIG,
13+
all = false,
14+
verbatim = undefined,
15+
ttl = 5 * 60 * 1000,
16+
lookup = dns.lookup,
17+
}) => ({
18+
// hints and lookup are returned since both are top level properties to (net|tls).connect
19+
hints,
20+
lookup: (hostname, ...args) => {
21+
const callback = args.pop() // callback is always last arg
22+
const lookupOptions = args[0] ?? {}
23+
24+
const options = {
25+
family,
26+
hints,
27+
all,
28+
verbatim,
29+
...(typeof lookupOptions === 'number' ? { family: lookupOptions } : lookupOptions),
2430
}
2531

26-
options = { ...defaultOptions, ...options }
32+
const key = JSON.stringify({ hostname, ...options })
2733

28-
const key = JSON.stringify({
29-
hostname,
30-
family: options.family,
31-
hints: options.hints,
32-
all: options.all,
33-
verbatim: options.verbatim,
34-
})
35-
36-
if (lookupCache.has(key)) {
37-
const [address, family] = lookupCache.get(key)
38-
process.nextTick(callback, null, address, family)
39-
return
34+
if (cache.has(key)) {
35+
const cached = cache.get(key)
36+
return process.nextTick(callback, null, ...cached)
4037
}
4138

42-
dnsOptions.lookup(hostname, options, (err, address, family) => {
39+
lookup(hostname, options, (err, ...result) => {
4340
if (err) {
4441
return callback(err)
4542
}
4643

47-
lookupCache.set(key, [address, family], { ttl: dnsOptions.ttl })
48-
return callback(null, address, family)
44+
cache.set(key, result, { ttl })
45+
return callback(null, ...result)
4946
})
50-
}
47+
},
48+
})
49+
50+
module.exports = {
51+
cache,
52+
getOptions,
5153
}

0 commit comments

Comments
 (0)