Skip to content

Commit

Permalink
refactor: replace uriToHost with nerf-dart
Browse files Browse the repository at this point in the history
  • Loading branch information
nachoaldamav committed Jan 18, 2024
1 parent 739962b commit b8b6bdb
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 92 deletions.
189 changes: 98 additions & 91 deletions network/agent/agent.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,114 @@
import { URL } from 'url'
import HttpAgent from 'agentkeepalive'
import LRU from 'lru-cache'
import { getProxyAgent, ProxyAgentOptions } from '@pnpm/network.proxy-agent'
import { URL } from "url";
import HttpAgent from "agentkeepalive";
import LRU from "lru-cache";
import nerfDart from "nerf-dart";
import { getProxyAgent, ProxyAgentOptions } from "@pnpm/network.proxy-agent";

const HttpsAgent = HttpAgent.HttpsAgent
const HttpsAgent = HttpAgent.HttpsAgent;

const DEFAULT_MAX_SOCKETS = 50
const DEFAULT_MAX_SOCKETS = 50;

const AGENT_CACHE = new LRU({ max: 50 })
const AGENT_CACHE = new LRU({ max: 50 });

export type AgentOptions = ProxyAgentOptions & {
noProxy?: boolean | string
}

function uriToHost (uri: string) {
const parsedUri = new URL(uri)
const port = parsedUri.port
const hostname = parsedUri.hostname
let url = `//${hostname}`
if (port) {
url += `:${port}`
}
return `${url}/`
}
noProxy?: boolean | string;
};

export function getAgent (uri: string, opts: AgentOptions) {
if ((opts.httpProxy || opts.httpsProxy) && !checkNoProxy(uri, opts)) {
const proxyAgent = getProxyAgent(uri, opts)
if (proxyAgent) return proxyAgent
}
return getNonProxyAgent(uri, opts)
export function getAgent(uri: string, opts: AgentOptions) {
if ((opts.httpProxy || opts.httpsProxy) && !checkNoProxy(uri, opts)) {
const proxyAgent = getProxyAgent(uri, opts);
if (proxyAgent) return proxyAgent;
}
return getNonProxyAgent(uri, opts);
}

function getNonProxyAgent (uri: string, opts: AgentOptions) {
const parsedUri = new URL(uri)
const host = uriToHost(uri)
const isHttps = parsedUri.protocol === 'https:'
function getNonProxyAgent(uri: string, opts: AgentOptions) {
const parsedUri = new URL(uri);
const host = nerfDart(uri);
const isHttps = parsedUri.protocol === "https:";

const clientCertificates = opts.clientCertificates?.[host] ?? null
const clientCertificates = opts.clientCertificates?.[host] ?? null;

/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
const key = [
`https:${isHttps.toString()}`,
`local-address:${opts.localAddress ?? '>no-local-address<'}`,
`strict-ssl:${isHttps ? Boolean(opts.strictSsl).toString() : '>no-strict-ssl<'}`,
`ca:${(isHttps && clientCertificates?.ca || opts.ca?.toString()) || '>no-ca<'}`,
`cert:${(isHttps && clientCertificates?.cert || opts.cert?.toString()) || '>no-cert<'}`,
`key:${(isHttps && clientCertificates?.key || opts.key) || '>no-key<'}`,
].join(':')
/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
const key = [
`https:${isHttps.toString()}`,
`local-address:${opts.localAddress ?? ">no-local-address<"}`,
`strict-ssl:${
isHttps ? Boolean(opts.strictSsl).toString() : ">no-strict-ssl<"
}`,
`ca:${
(isHttps && clientCertificates?.ca) || opts.ca?.toString() || ">no-ca<"
}`,
`cert:${
(isHttps && clientCertificates?.cert) ||
opts.cert?.toString() ||
">no-cert<"
}`,
`key:${(isHttps && clientCertificates?.key) || opts.key || ">no-key<"}`,
].join(":");
/* eslint-enable @typescript-eslint/prefer-nullish-coalescing */

if (AGENT_CACHE.peek(key)) {
return AGENT_CACHE.get(key)
}
if (AGENT_CACHE.peek(key)) {
return AGENT_CACHE.get(key);
}

// If opts.timeout is zero, set the agentTimeout to zero as well. A timeout
// of zero disables the timeout behavior (OS limits still apply). Else, if
// opts.timeout is a non-zero value, set it to timeout + 1, to ensure that
// the node-fetch-npm timeout will always fire first, giving us more
// consistent errors.
const agentTimeout = typeof opts.timeout !== 'number' || opts.timeout === 0 ? 0 : opts.timeout + 1
// If opts.timeout is zero, set the agentTimeout to zero as well. A timeout
// of zero disables the timeout behavior (OS limits still apply). Else, if
// opts.timeout is a non-zero value, set it to timeout + 1, to ensure that
// the node-fetch-npm timeout will always fire first, giving us more
// consistent errors.
const agentTimeout =
typeof opts.timeout !== "number" || opts.timeout === 0
? 0
: opts.timeout + 1;

// NOTE: localAddress is passed to the agent here even though it is an
// undocumented option of the agent's constructor.
//
// This works because all options of the agent are merged with
// all options of the request:
// https://github.com/nodejs/node/blob/350a95b89faab526de852d417bbb8a3ac823c325/lib/_http_agent.js#L254
const agent = isHttps
? new HttpsAgent({
ca: clientCertificates?.ca || opts.ca,
cert: clientCertificates?.cert || opts.cert,
key: clientCertificates?.key || opts.key,
localAddress: opts.localAddress,
maxSockets: opts.maxSockets ?? DEFAULT_MAX_SOCKETS,
rejectUnauthorized: opts.strictSsl,
timeout: agentTimeout,
} as any) // eslint-disable-line @typescript-eslint/no-explicit-any
: new HttpAgent({
localAddress: opts.localAddress,
maxSockets: opts.maxSockets ?? DEFAULT_MAX_SOCKETS,
timeout: agentTimeout,
} as any) // eslint-disable-line @typescript-eslint/no-explicit-any
AGENT_CACHE.set(key, agent)
return agent
// NOTE: localAddress is passed to the agent here even though it is an
// undocumented option of the agent's constructor.
//
// This works because all options of the agent are merged with
// all options of the request:
// https://github.com/nodejs/node/blob/350a95b89faab526de852d417bbb8a3ac823c325/lib/_http_agent.js#L254
const agent = isHttps
? new HttpsAgent({
ca: clientCertificates?.ca || opts.ca,
cert: clientCertificates?.cert || opts.cert,
key: clientCertificates?.key || opts.key,
localAddress: opts.localAddress,
maxSockets: opts.maxSockets ?? DEFAULT_MAX_SOCKETS,
rejectUnauthorized: opts.strictSsl,
timeout: agentTimeout,
} as any) // eslint-disable-line @typescript-eslint/no-explicit-any
: new HttpAgent({
localAddress: opts.localAddress,
maxSockets: opts.maxSockets ?? DEFAULT_MAX_SOCKETS,
timeout: agentTimeout,
} as any); // eslint-disable-line @typescript-eslint/no-explicit-any
AGENT_CACHE.set(key, agent);
return agent;
}

function checkNoProxy (uri: string, opts: { noProxy?: boolean | string }) {
const host = new URL(uri).hostname.split('.').filter(x => x).reverse()
if (typeof opts.noProxy === 'string') {
const noproxyArr = opts.noProxy.split(/\s*,\s*/g)
return noproxyArr.some(no => {
const noParts = no.split('.').filter(x => x).reverse()
if (noParts.length === 0) {
return false
}
for (let i = 0; i < noParts.length; i++) {
if (host[i] !== noParts[i]) {
return false
}
}
return true
})
}
return opts.noProxy
function checkNoProxy(uri: string, opts: { noProxy?: boolean | string }) {
const host = new URL(uri).hostname
.split(".")
.filter((x) => x)
.reverse();
if (typeof opts.noProxy === "string") {
const noproxyArr = opts.noProxy.split(/\s*,\s*/g);
return noproxyArr.some((no) => {
const noParts = no
.split(".")
.filter((x) => x)
.reverse();
if (noParts.length === 0) {
return false;
}
for (let i = 0; i < noParts.length; i++) {
if (host[i] !== noParts[i]) {
return false;
}
}
return true;
});
}
return opts.noProxy;
}
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion workspace.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"http-proxy-agent": "5.0.0",
"https-proxy-agent": "5.0.1",
"lru-cache": "7.10.1",
"nerf-dart": "^1.0.0",
"node-fetch": "2.6.7",
"proxy": "1.0.2",
"safe-execa": "0.1.1",
Expand Down Expand Up @@ -92,4 +93,4 @@
}
}
}
}
}

0 comments on commit b8b6bdb

Please sign in to comment.