/ cloudformation-templates / node_modules / aws-cdk / node_modules / pac-proxy-agent / dist / agent.js
agent.js
1 "use strict"; 2 var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 return new (P || (P = Promise))(function (resolve, reject) { 5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 }); 10 }; 11 var __importDefault = (this && this.__importDefault) || function (mod) { 12 return (mod && mod.__esModule) ? mod : { "default": mod }; 13 }; 14 Object.defineProperty(exports, "__esModule", { value: true }); 15 const net_1 = __importDefault(require("net")); 16 const tls_1 = __importDefault(require("tls")); 17 const once_1 = __importDefault(require("@tootallnate/once")); 18 const crypto_1 = __importDefault(require("crypto")); 19 const get_uri_1 = __importDefault(require("get-uri")); 20 const debug_1 = __importDefault(require("debug")); 21 const raw_body_1 = __importDefault(require("raw-body")); 22 const url_1 = require("url"); 23 const http_proxy_agent_1 = require("http-proxy-agent"); 24 const https_proxy_agent_1 = require("https-proxy-agent"); 25 const socks_proxy_agent_1 = require("socks-proxy-agent"); 26 const pac_resolver_1 = __importDefault(require("pac-resolver")); 27 const agent_base_1 = require("agent-base"); 28 const debug = debug_1.default('pac-proxy-agent'); 29 /** 30 * The `PacProxyAgent` class. 31 * 32 * A few different "protocol" modes are supported (supported protocols are 33 * backed by the `get-uri` module): 34 * 35 * - "pac+data", "data" - refers to an embedded "data:" URI 36 * - "pac+file", "file" - refers to a local file 37 * - "pac+ftp", "ftp" - refers to a file located on an FTP server 38 * - "pac+http", "http" - refers to an HTTP endpoint 39 * - "pac+https", "https" - refers to an HTTPS endpoint 40 * 41 * @api public 42 */ 43 class PacProxyAgent extends agent_base_1.Agent { 44 constructor(uri, opts = {}) { 45 super(opts); 46 this.clearResolverPromise = () => { 47 this.resolverPromise = undefined; 48 }; 49 debug('Creating PacProxyAgent with URI %o and options %o', uri, opts); 50 // Strip the "pac+" prefix 51 this.uri = uri.replace(/^pac\+/i, ''); 52 this.opts = Object.assign({}, opts); 53 this.cache = undefined; 54 this.resolver = undefined; 55 this.resolverHash = ''; 56 this.resolverPromise = undefined; 57 // For `PacResolver` 58 if (!this.opts.filename) { 59 this.opts.filename = uri; 60 } 61 } 62 /** 63 * Loads the PAC proxy file from the source if necessary, and returns 64 * a generated `FindProxyForURL()` resolver function to use. 65 * 66 * @api private 67 */ 68 getResolver() { 69 if (!this.resolverPromise) { 70 this.resolverPromise = this.loadResolver(); 71 this.resolverPromise.then(this.clearResolverPromise, this.clearResolverPromise); 72 } 73 return this.resolverPromise; 74 } 75 loadResolver() { 76 return __awaiter(this, void 0, void 0, function* () { 77 try { 78 // (Re)load the contents of the PAC file URI 79 const code = yield this.loadPacFile(); 80 // Create a sha1 hash of the JS code 81 const hash = crypto_1.default 82 .createHash('sha1') 83 .update(code) 84 .digest('hex'); 85 if (this.resolver && this.resolverHash === hash) { 86 debug('Same sha1 hash for code - contents have not changed, reusing previous proxy resolver'); 87 return this.resolver; 88 } 89 // Cache the resolver 90 debug('Creating new proxy resolver instance'); 91 this.resolver = pac_resolver_1.default(code, this.opts); 92 // Store that sha1 hash for future comparison purposes 93 this.resolverHash = hash; 94 return this.resolver; 95 } 96 catch (err) { 97 if (this.resolver && err.code === 'ENOTMODIFIED') { 98 debug('Got ENOTMODIFIED response, reusing previous proxy resolver'); 99 return this.resolver; 100 } 101 throw err; 102 } 103 }); 104 } 105 /** 106 * Loads the contents of the PAC proxy file. 107 * 108 * @api private 109 */ 110 loadPacFile() { 111 return __awaiter(this, void 0, void 0, function* () { 112 debug('Loading PAC file: %o', this.uri); 113 const rs = yield get_uri_1.default(this.uri, { cache: this.cache }); 114 debug('Got `Readable` instance for URI'); 115 this.cache = rs; 116 const buf = yield raw_body_1.default(rs); 117 debug('Read %o byte PAC file from URI', buf.length); 118 return buf.toString('utf8'); 119 }); 120 } 121 /** 122 * Called when the node-core HTTP client library is creating a new HTTP request. 123 * 124 * @api protected 125 */ 126 callback(req, opts) { 127 return __awaiter(this, void 0, void 0, function* () { 128 const { secureEndpoint } = opts; 129 // First, get a generated `FindProxyForURL()` function, 130 // either cached or retrieved from the source 131 const resolver = yield this.getResolver(); 132 // Calculate the `url` parameter 133 const defaultPort = secureEndpoint ? 443 : 80; 134 let path = req.path; 135 let search = null; 136 const firstQuestion = path.indexOf('?'); 137 if (firstQuestion !== -1) { 138 search = path.substring(firstQuestion); 139 path = path.substring(0, firstQuestion); 140 } 141 const urlOpts = Object.assign(Object.assign({}, opts), { protocol: secureEndpoint ? 'https:' : 'http:', pathname: path, search, 142 // need to use `hostname` instead of `host` otherwise `port` is ignored 143 hostname: opts.host, host: null, href: null, 144 // set `port` to null when it is the protocol default port (80 / 443) 145 port: defaultPort === opts.port ? null : opts.port }); 146 const url = url_1.format(urlOpts); 147 debug('url: %o', url); 148 let result = yield resolver(url); 149 // Default to "DIRECT" if a falsey value was returned (or nothing) 150 if (!result) { 151 result = 'DIRECT'; 152 } 153 const proxies = String(result) 154 .trim() 155 .split(/\s*;\s*/g) 156 .filter(Boolean); 157 if (this.opts.fallbackToDirect && !proxies.includes('DIRECT')) { 158 proxies.push('DIRECT'); 159 } 160 for (const proxy of proxies) { 161 let agent = null; 162 let socket = null; 163 const [type, target] = proxy.split(/\s+/); 164 debug('Attempting to use proxy: %o', proxy); 165 if (type === 'DIRECT') { 166 // Direct connection to the destination endpoint 167 socket = secureEndpoint ? tls_1.default.connect(opts) : net_1.default.connect(opts); 168 } 169 else if (type === 'SOCKS' || type === 'SOCKS5') { 170 // Use a SOCKSv5h proxy 171 agent = new socks_proxy_agent_1.SocksProxyAgent(`socks://${target}`); 172 } 173 else if (type === 'SOCKS4') { 174 // Use a SOCKSv4a proxy 175 agent = new socks_proxy_agent_1.SocksProxyAgent(`socks4a://${target}`); 176 } 177 else if (type === 'PROXY' || 178 type === 'HTTP' || 179 type === 'HTTPS') { 180 // Use an HTTP or HTTPS proxy 181 // http://dev.chromium.org/developers/design-documents/secure-web-proxy 182 const proxyURL = `${type === 'HTTPS' ? 'https' : 'http'}://${target}`; 183 const proxyOpts = Object.assign(Object.assign({}, this.opts), url_1.parse(proxyURL)); 184 if (secureEndpoint) { 185 agent = new https_proxy_agent_1.HttpsProxyAgent(proxyOpts); 186 } 187 else { 188 agent = new http_proxy_agent_1.HttpProxyAgent(proxyOpts); 189 } 190 } 191 try { 192 if (socket) { 193 // "DIRECT" connection, wait for connection confirmation 194 yield once_1.default(socket, 'connect'); 195 req.emit('proxy', { proxy, socket }); 196 return socket; 197 } 198 if (agent) { 199 const s = yield agent.callback(req, opts); 200 req.emit('proxy', { proxy, socket: s }); 201 return s; 202 } 203 throw new Error(`Could not determine proxy type for: ${proxy}`); 204 } 205 catch (err) { 206 debug('Got error for proxy %o: %o', proxy, err); 207 req.emit('proxy', { proxy, error: err }); 208 } 209 } 210 throw new Error(`Failed to establish a socket connection to proxies: ${JSON.stringify(proxies)}`); 211 }); 212 } 213 } 214 exports.default = PacProxyAgent; 215 //# sourceMappingURL=agent.js.map