(proxyUrl, targetHost, targetPort)
| 39 | } |
| 40 | |
| 41 | function connectThroughProxy(proxyUrl, targetHost, targetPort) { |
| 42 | return new Promise((resolve, reject) => { |
| 43 | const proxy = new URL(proxyUrl) |
| 44 | const isHttpsProxy = proxy.protocol === 'https:' |
| 45 | const connectOptions = { |
| 46 | hostname: proxy.hostname, |
| 47 | port: proxy.port || (isHttpsProxy ? 443 : 80), |
| 48 | method: 'CONNECT', |
| 49 | path: `${targetHost}:${targetPort}`, |
| 50 | headers: { |
| 51 | Host: `${targetHost}:${targetPort}`, |
| 52 | }, |
| 53 | } |
| 54 | |
| 55 | if (proxy.username || proxy.password) { |
| 56 | const auth = Buffer.from( |
| 57 | `${decodeURIComponent(proxy.username || '')}:${decodeURIComponent( |
| 58 | proxy.password || '', |
| 59 | )}`, |
| 60 | ).toString('base64') |
| 61 | connectOptions.headers['Proxy-Authorization'] = `Basic ${auth}` |
| 62 | } |
| 63 | |
| 64 | const transport = isHttpsProxy ? httpsModule : httpModule |
| 65 | const req = transport.request(connectOptions) |
| 66 | |
| 67 | req.on('connect', (res, socket) => { |
| 68 | if (res.statusCode === 200) { |
| 69 | resolve(socket) |
| 70 | return |
| 71 | } |
| 72 | |
| 73 | socket.destroy() |
| 74 | reject(new Error(`Proxy CONNECT failed with status ${res.statusCode}`)) |
| 75 | }) |
| 76 | |
| 77 | req.on('error', (error) => { |
| 78 | reject(new Error(`Proxy connection failed: ${error.message}`)) |
| 79 | }) |
| 80 | |
| 81 | req.setTimeout(requestTimeout, () => { |
| 82 | req.destroy() |
| 83 | reject(new Error('Proxy connection timeout.')) |
| 84 | }) |
| 85 | |
| 86 | req.end() |
| 87 | }) |
| 88 | } |
| 89 | |
| 90 | async function buildRequestOptions(url, options = {}) { |
| 91 | const parsedUrl = new URL(url) |
no test coverage detected