aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/node-gyp/lib/download.js
diff options
context:
space:
mode:
authorpack <pack@packgekko.xyz>2026-08-09 10:37:07 +0000
committerpack <pack@packgekko.xyz>2026-08-09 10:37:07 +0000
commit55a4f1fc869e41aca748c63d3018f0448b1606e0 (patch)
treed132d1d01772b6d53faee3e63c534dea5706b78a /node_modules/node-gyp/lib/download.js
downloadcrud-55a4f1fc869e41aca748c63d3018f0448b1606e0.tar.gz
first commit
Diffstat (limited to 'node_modules/node-gyp/lib/download.js')
-rw-r--r--node_modules/node-gyp/lib/download.js86
1 files changed, 86 insertions, 0 deletions
diff --git a/node_modules/node-gyp/lib/download.js b/node_modules/node-gyp/lib/download.js
new file mode 100644
index 0000000..dfaca79
--- /dev/null
+++ b/node_modules/node-gyp/lib/download.js
@@ -0,0 +1,86 @@
+const { Readable } = require('stream')
+const { Agent, EnvHttpProxyAgent, RetryAgent, fetch } = require('undici')
+const { promises: fs } = require('graceful-fs')
+const log = require('./log')
+
+async function download (gyp, url) {
+ log.http('GET', url)
+
+ const requestOpts = {
+ headers: {
+ 'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`,
+ Connection: 'keep-alive'
+ },
+ dispatcher: await createDispatcher(gyp)
+ }
+
+ let res
+ try {
+ res = await fetch(url, requestOpts)
+ } catch (err) {
+ // Built-in fetch wraps low-level errors in "TypeError: fetch failed" with
+ // the underlying error on .cause. Callers inspect .code (e.g. ENOTFOUND).
+ if (err.cause) {
+ throw err.cause
+ }
+ throw err
+ }
+
+ log.http(res.status, res.url)
+
+ const body = res.body ? Readable.fromWeb(res.body) : Readable.from([])
+ return {
+ status: res.status,
+ url: res.url,
+ body,
+ text: async () => {
+ let data = ''
+ body.setEncoding('utf8')
+ for await (const chunk of body) {
+ data += chunk
+ }
+ return data
+ }
+ }
+}
+
+async function createDispatcher (gyp) {
+ const env = process.env
+ const hasProxyEnv = env.http_proxy || env.HTTP_PROXY || env.https_proxy || env.HTTPS_PROXY
+ if (!gyp.opts.proxy && !gyp.opts.cafile && !hasProxyEnv) {
+ return new RetryAgent(new Agent(), { maxRetries: 3 })
+ }
+
+ const opts = {}
+ if (gyp.opts.cafile) {
+ const ca = await readCAFile(gyp.opts.cafile)
+ // EnvHttpProxyAgent forwards opts to both its internal Agent (direct) and
+ // ProxyAgent (proxied). Agent reads TLS config from `connect`; ProxyAgent
+ // reads it from `requestTls` (origin) / `proxyTls` (proxy). Set all three
+ // so the custom CA is applied regardless of which path a request takes.
+ opts.connect = { ca }
+ opts.requestTls = { ca }
+ opts.proxyTls = { ca }
+ }
+ if (gyp.opts.proxy) {
+ opts.httpProxy = gyp.opts.proxy
+ opts.httpsProxy = gyp.opts.proxy
+ }
+ if (gyp.opts.noproxy) {
+ opts.noProxy = gyp.opts.noproxy
+ }
+ return new RetryAgent(new EnvHttpProxyAgent(opts), { maxRetries: 3 })
+}
+
+async function readCAFile (filename) {
+ // The CA file can contain multiple certificates so split on certificate
+ // boundaries. [\S\s]*? is used to match everything including newlines.
+ const ca = await fs.readFile(filename, 'utf8')
+ const re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g
+ return ca.match(re)
+}
+
+module.exports = {
+ download,
+ readCAFile
+}