( urlString: string, noProxy: string | undefined = getNoProxy(), )
| 86 | * @param noProxy NO_PROXY value (defaults to getNoProxy() for production use) |
| 87 | */ |
| 88 | export function shouldBypassProxy( |
| 89 | urlString: string, |
| 90 | noProxy: string | undefined = getNoProxy(), |
| 91 | ): boolean { |
| 92 | if (!noProxy) return false |
| 93 | |
| 94 | // Handle wildcard |
| 95 | if (noProxy === '*') return true |
| 96 | |
| 97 | try { |
| 98 | const url = new URL(urlString) |
| 99 | const hostname = url.hostname.toLowerCase() |
| 100 | const port = url.port || (url.protocol === 'https:' ? '443' : '80') |
| 101 | const hostWithPort = `${hostname}:${port}` |
| 102 | |
| 103 | // Split by comma or space and trim each entry |
| 104 | const noProxyList = noProxy.split(/[,\s]+/).filter(Boolean) |
| 105 | |
| 106 | return noProxyList.some(pattern => { |
| 107 | pattern = pattern.toLowerCase().trim() |
| 108 | |
| 109 | // Check for port-specific match |
| 110 | if (pattern.includes(':')) { |
| 111 | return hostWithPort === pattern |
| 112 | } |
| 113 | |
| 114 | // Check for domain suffix match (with or without leading dot) |
| 115 | if (pattern.startsWith('.')) { |
| 116 | // Pattern ".example.com" should match "sub.example.com" and "example.com" |
| 117 | // but NOT "notexample.com" |
| 118 | const suffix = pattern |
| 119 | return hostname === pattern.substring(1) || hostname.endsWith(suffix) |
| 120 | } |
| 121 | |
| 122 | // Check for exact hostname match or IP address |
| 123 | return hostname === pattern |
| 124 | }) |
| 125 | } catch { |
| 126 | // If URL parsing fails, don't bypass proxy |
| 127 | return false |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Create an HttpsProxyAgent with optional mTLS configuration |
no test coverage detected