Skip to content

Commit

Permalink
deps: @npmcli/agent@2.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Aug 30, 2023
1 parent 812aa6d commit dbb18f4
Show file tree
Hide file tree
Showing 28 changed files with 1,681 additions and 686 deletions.
6 changes: 5 additions & 1 deletion DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ graph LR;
npm-->npm-profile;
npm-->npm-registry-fetch;
npm-->npm-user-validate;
npm-->npmcli-agent["@npmcli/agent"];
npm-->npmcli-arborist["@npmcli/arborist"];
npm-->npmcli-config["@npmcli/config"];
npm-->npmcli-docs["@npmcli/docs"];
Expand Down Expand Up @@ -540,6 +541,7 @@ graph LR;
npm-->npm-profile;
npm-->npm-registry-fetch;
npm-->npm-user-validate;
npm-->npmcli-agent["@npmcli/agent"];
npm-->npmcli-arborist["@npmcli/arborist"];
npm-->npmcli-config["@npmcli/config"];
npm-->npmcli-docs["@npmcli/docs"];
Expand Down Expand Up @@ -598,8 +600,10 @@ graph LR;
npm-registry-fetch-->minizlib;
npm-registry-fetch-->npm-package-arg;
npm-registry-fetch-->proc-log;
npmcli-agent-->http-proxy-agent;
npmcli-agent-->https-proxy-agent;
npmcli-agent-->lru-cache;
npmcli-agent-->socks;
npmcli-agent-->socks-proxy-agent;
npmcli-arborist-->benchmark;
npmcli-arborist-->bin-links;
npmcli-arborist-->cacache;
Expand Down
6 changes: 6 additions & 0 deletions node_modules/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
!/@npmcli/
/@npmcli/*
!/@npmcli/agent
!/@npmcli/agent/node_modules/
/@npmcli/agent/node_modules/*
!/@npmcli/agent/node_modules/agent-base
!/@npmcli/agent/node_modules/http-proxy-agent
!/@npmcli/agent/node_modules/https-proxy-agent
!/@npmcli/agent/node_modules/socks-proxy-agent
!/@npmcli/disparity-colors
!/@npmcli/fs
!/@npmcli/git
Expand Down
201 changes: 201 additions & 0 deletions node_modules/@npmcli/agent/lib/agents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
'use strict'

const http = require('http')
const https = require('https')
const net = require('net')
const tls = require('tls')
const { once } = require('events')
const { createTimeout, abortRace, urlify, appendPort, cacheAgent } = require('./util')
const { normalizeOptions, cacheOptions } = require('./options')
const { getProxy, getProxyType, isSecureProxy, proxyCache } = require('./proxy.js')
const Errors = require('./errors.js')

const createAgent = (base, name) => {
const SECURE = base === https
const SOCKET_TYPE = SECURE ? tls : net

const agent = class extends base.Agent {
#options
#timeouts
#proxy
#socket

constructor (_options) {
const { timeouts, proxy, noProxy, ...options } = normalizeOptions(_options)

super(options)

this.#options = options
this.#timeouts = timeouts
this.#proxy = proxy ? { proxies: getProxyType(proxy), proxy: urlify(proxy), noProxy } : null
}

get proxy () {
return this.#proxy ? { url: this.#proxy.proxy } : {}
}

#getProxy (options) {
const proxy = this.#proxy
? getProxy(appendPort(`${options.protocol}//${options.host}`, options.port), this.#proxy)
: null

if (!proxy) {
return
}

const secure = isSecureProxy(proxy)

return cacheAgent({
key: cacheOptions({
...options,
...this.#options,
secure,
timeouts: this.#timeouts,
proxy,
}),
cache: proxyCache,
secure,
proxies: this.#proxy.proxies,
}, proxy, this.#options)
}

#setKeepAlive (socket) {
socket.setKeepAlive(this.keepAlive, this.keepAliveMsecs)
socket.setNoDelay(this.keepAlive)
}

#setIdleTimeout (socket, options) {
if (this.#timeouts.idle) {
socket.setTimeout(this.#timeouts.idle, () => {
socket.destroy(new Errors.IdleTimeoutError(options))
})
}
}

async #proxyConnect (proxy, request, options) {
// socks-proxy-agent accepts a dns lookup function
options.lookup ??= this.#options.lookup

// all the proxy agents use this secureEndpoint option to determine
// if the proxy should connect over tls or not. we can set it based
// on if the HttpAgent or HttpsAgent is used.
options.secureEndpoint = SECURE

const socket = await abortRace([
(ac) => createTimeout(this.#timeouts.connection, ac).catch(() => {
throw new Errors.ConnectionTimeoutError(options)
}),
(ac) => proxy.connect(request, options).then((s) => {
this.#setKeepAlive(s)

const connectEvent = SECURE ? 'secureConnect' : 'connect'
const connectingEvent = SECURE ? 'secureConnecting' : 'connecting'

if (!s[connectingEvent]) {
return s
}

return abortRace([
() => once(s, 'error', ac).then((err) => {
throw err
}),
() => once(s, connectEvent, ac).then(() => s),
], ac)
}),
])

this.#setIdleTimeout(socket, options)

return socket
}

async connect (request, options) {
const proxy = this.#getProxy(options)
if (proxy) {
return this.#proxyConnect(proxy, request, options)
}

const socket = SOCKET_TYPE.connect(options)

this.#setKeepAlive(socket)

await abortRace([
(s) => createTimeout(this.#timeouts.connection, s).catch(() => {
throw new Errors.ConnectionTimeoutError(options)
}),
(s) => once(socket, 'error', s).then((err) => {
throw err
}),
(s) => once(socket, 'connect', s),
])

this.#setIdleTimeout(socket, options)

return socket
}

addRequest (request, options) {
const proxy = this.#getProxy(options)
// it would be better to call proxy.addRequest here but this causes the
// http-proxy-agent to call its super.addRequest which causes the request
// to be added to the agent twice. since we only support 3 agents
// currently (see the required agents in proxy.js) we have manually
// checked that the only public methods we need to call are called in the
// next block. this could change in the future and presumably we would get
// failing tests until we have properly called the necessary methods on
// each of our proxy agents
if (proxy?.setRequestProps) {
proxy.setRequestProps(request, options)
}

request.setHeader('connection', this.keepAlive ? 'keep-alive' : 'close')

const responseTimeout = createTimeout(this.#timeouts.response)
if (responseTimeout) {
request.once('finish', () => {
responseTimeout.start(() => {
request.destroy(new Errors.ResponseTimeoutError(request, this.proxy?.url))
})
})
request.once('response', () => {
responseTimeout.clear()
})
}

const transferTimeout = createTimeout(this.#timeouts.transfer)
if (transferTimeout) {
request.once('response', (res) => {
transferTimeout.start(() => {
res.destroy(new Errors.TransferTimeoutError(request, this.proxy?.url))
})
res.once('close', () => {
transferTimeout.clear()
})
})
}

return super.addRequest(request, options)
}

createSocket (req, options, cb) {
return Promise.resolve()
.then(() => this.connect(req, options))
.then((socket) => {
this.#socket = socket
return super.createSocket(req, options, cb)
}, cb)
}

createConnection () {
return this.#socket
}
}

Object.defineProperty(agent, 'name', { value: name })
return agent
}

module.exports = {
HttpAgent: createAgent(http, 'HttpAgent'),
HttpsAgent: createAgent(https, 'HttpsAgent'),
}
68 changes: 35 additions & 33 deletions node_modules/@npmcli/agent/lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,51 @@
const { LRUCache } = require('lru-cache')
const dns = require('dns')

const defaultOptions = exports.defaultOptions = {
family: undefined,
hints: dns.ADDRCONFIG,
all: false,
verbatim: undefined,
}

const lookupCache = exports.lookupCache = new LRUCache({ max: 50 })

// this is a factory so that each request can have its own opts (i.e. ttl)
// while still sharing the cache across all requests
exports.getLookup = (dnsOptions) => {
return (hostname, options, callback) => {
if (typeof options === 'function') {
callback = options
options = null
} else if (typeof options === 'number') {
options = { family: options }
const cache = new LRUCache({ max: 50 })

const getOptions = ({
family = 0,
hints = dns.ADDRCONFIG,
all = false,
verbatim = undefined,
ttl = 5 * 60 * 1000,
lookup = dns.lookup,
}) => ({
// hints and lookup are returned since both are top level properties to (net|tls).connect
hints,
lookup: (hostname, ...args) => {
const callback = args.pop() // callback is always last arg
const lookupOptions = args[0] ?? {}

const options = {
family,
hints,
all,
verbatim,
...(typeof lookupOptions === 'number' ? { family: lookupOptions } : lookupOptions),
}

options = { ...defaultOptions, ...options }
const key = JSON.stringify({ hostname, ...options })

const key = JSON.stringify({
hostname,
family: options.family,
hints: options.hints,
all: options.all,
verbatim: options.verbatim,
})

if (lookupCache.has(key)) {
const [address, family] = lookupCache.get(key)
process.nextTick(callback, null, address, family)
return
if (cache.has(key)) {
const cached = cache.get(key)
return process.nextTick(callback, null, ...cached)
}

dnsOptions.lookup(hostname, options, (err, address, family) => {
lookup(hostname, options, (err, ...result) => {
if (err) {
return callback(err)
}

lookupCache.set(key, [address, family], { ttl: dnsOptions.ttl })
return callback(null, address, family)
cache.set(key, result, { ttl })
return callback(null, ...result)
})
}
},
})

module.exports = {
cache,
getOptions,
}
Loading

0 comments on commit dbb18f4

Please sign in to comment.