Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/commons/getProxyForUrl.ts
1028 views
1
import { URL } from 'url';
2
3
// logic from https://github.com/Rob--W/proxy-from-env
4
5
export function getProxyForUrl(url: string): URL {
6
const parsedUrl = new URL(url);
7
let protocol = parsedUrl.protocol;
8
let hostname = parsedUrl.host;
9
if (typeof hostname !== 'string' || !hostname || typeof protocol !== 'string') {
10
return null; // Don't proxy URLs without a valid scheme or host.
11
}
12
13
setProxyVars();
14
protocol = protocol.split(':', 1)[0];
15
// Stripping ports in this way instead of using parsedUrl.hostname to make
16
// sure that the brackets around IPv6 addresses are kept.
17
hostname = hostname.replace(/:\d*$/, '');
18
let parsedPort = parseInt(parsedUrl.port, 10) || 0;
19
if (!parsedPort) parsedPort = protocol === 'https:' ? 443 : 80;
20
if (!shouldProxy(hostname, parsedPort)) {
21
return null; // Don't proxy URLs that match NO_PROXY.
22
}
23
24
let proxy =
25
getEnv(`npm_config_${protocol}_proxy`) ||
26
getEnv(`${protocol}_proxy`) ||
27
getEnv('npm_config_proxy') ||
28
getEnv('all_proxy');
29
if (proxy && proxy.indexOf('://') === -1) {
30
// Missing scheme in proxy, default to the requested URL's scheme.
31
proxy = `${protocol}://${proxy}`;
32
}
33
if (!proxy) return null;
34
return new URL(proxy);
35
}
36
37
function shouldProxy(hostname: string, port: number): boolean {
38
const NO_PROXY = (getEnv('npm_config_no_proxy') || getEnv('no_proxy')).toLowerCase();
39
if (!NO_PROXY) {
40
return true; // Always proxy if NO_PROXY is not set.
41
}
42
if (NO_PROXY === '*') {
43
return false; // Never proxy if wildcard is set.
44
}
45
46
for (const proxy of NO_PROXY.split(/[,\s]/)) {
47
if (!proxy) continue;
48
const parsedProxy = proxy.match(/^(.+):(\d+)$/);
49
let parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy;
50
const parsedProxyPort = parsedProxy ? parseInt(parsedProxy[2], 10) : 0;
51
if (parsedProxyPort && parsedProxyPort !== port) {
52
continue;
53
}
54
55
if (!parsedProxyHostname.startsWith('.') && !parsedProxyHostname.startsWith('*')) {
56
// No wildcards, so stop proxying if there is an exact match.
57
if (hostname === parsedProxyHostname) {
58
return false;
59
}
60
}
61
62
if (parsedProxyHostname.startsWith('*')) {
63
// Remove leading wildcard.
64
parsedProxyHostname = parsedProxyHostname.slice(1);
65
}
66
// Stop proxying if the hostname ends with the no_proxy host.
67
if (!hostname.endsWith(parsedProxyHostname)) {
68
return false;
69
}
70
}
71
return true;
72
}
73
74
function getEnv(key: string): string {
75
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
76
}
77
78
function setProxyVars(): void {
79
// Override current environment proxy settings with npm configuration, if any.
80
const NPM_HTTPS_PROXY = process.env.npm_config_https_proxy || process.env.npm_config_proxy;
81
const NPM_HTTP_PROXY = process.env.npm_config_http_proxy || process.env.npm_config_proxy;
82
const NPM_NO_PROXY = process.env.npm_config_no_proxy;
83
84
if (NPM_HTTPS_PROXY) process.env.HTTPS_PROXY = NPM_HTTPS_PROXY;
85
if (NPM_HTTP_PROXY) process.env.HTTP_PROXY = NPM_HTTP_PROXY;
86
if (NPM_NO_PROXY) process.env.NO_PROXY = NPM_NO_PROXY;
87
}
88
89