proxy.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. 'use strict'
  2. const { HttpProxyAgent } = require('http-proxy-agent')
  3. const { HttpsProxyAgent } = require('https-proxy-agent')
  4. const { SocksProxyAgent } = require('socks-proxy-agent')
  5. const { LRUCache } = require('lru-cache')
  6. const { InvalidProxyProtocolError } = require('./errors.js')
  7. const PROXY_CACHE = new LRUCache({ max: 20 })
  8. const SOCKS_PROTOCOLS = new Set(SocksProxyAgent.protocols)
  9. const PROXY_ENV_KEYS = new Set(['https_proxy', 'http_proxy', 'proxy', 'no_proxy'])
  10. const PROXY_ENV = Object.entries(process.env).reduce((acc, [key, value]) => {
  11. key = key.toLowerCase()
  12. if (PROXY_ENV_KEYS.has(key)) {
  13. acc[key] = value
  14. }
  15. return acc
  16. }, {})
  17. const getProxyAgent = (url) => {
  18. url = new URL(url)
  19. const protocol = url.protocol.slice(0, -1)
  20. if (SOCKS_PROTOCOLS.has(protocol)) {
  21. return SocksProxyAgent
  22. }
  23. if (protocol === 'https' || protocol === 'http') {
  24. return [HttpProxyAgent, HttpsProxyAgent]
  25. }
  26. throw new InvalidProxyProtocolError(url)
  27. }
  28. const isNoProxy = (url, noProxy) => {
  29. if (typeof noProxy === 'string') {
  30. noProxy = noProxy.split(',').map((p) => p.trim()).filter(Boolean)
  31. }
  32. if (!noProxy || !noProxy.length) {
  33. return false
  34. }
  35. const hostSegments = url.hostname.split('.').reverse()
  36. return noProxy.some((no) => {
  37. const noSegments = no.split('.').filter(Boolean).reverse()
  38. if (!noSegments.length) {
  39. return false
  40. }
  41. for (let i = 0; i < noSegments.length; i++) {
  42. if (hostSegments[i] !== noSegments[i]) {
  43. return false
  44. }
  45. }
  46. return true
  47. })
  48. }
  49. const getProxy = (url, { proxy, noProxy }) => {
  50. url = new URL(url)
  51. if (!proxy) {
  52. proxy = url.protocol === 'https:'
  53. ? PROXY_ENV.https_proxy
  54. : PROXY_ENV.https_proxy || PROXY_ENV.http_proxy || PROXY_ENV.proxy
  55. }
  56. if (!noProxy) {
  57. noProxy = PROXY_ENV.no_proxy
  58. }
  59. if (!proxy || isNoProxy(url, noProxy)) {
  60. return null
  61. }
  62. return new URL(proxy)
  63. }
  64. module.exports = {
  65. getProxyAgent,
  66. getProxy,
  67. proxyCache: PROXY_CACHE,
  68. }