Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ jobs:
with:
node-version: 22.x
- name: Update npm
run: npm install npm@latest -g
run: |
npm install npm@~11.10.0 -g # Workaround for https://github.com/npm/cli/issues/9151
npm install npm@latest -g
- name: Install Dependencies
run: npm install
- name: Pack
Expand Down
4 changes: 2 additions & 2 deletions gyp/pylib/gyp/simple_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def deepcopy(x):
return _deepcopy_dispatch[type(x)](x)
except KeyError:
raise Error(
"Unsupported type %s for deepcopy. Use copy.deepcopy "
+ "or expand simple_copy support." % type(x)
f"Unsupported type {type(x)} for deepcopy. Use copy.deepcopy "
+ "or expand simple_copy support."
)


Expand Down
56 changes: 48 additions & 8 deletions lib/download.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const fetch = require('make-fetch-happen')
const { Readable } = require('stream')
const { EnvHttpProxyAgent } = require('undici')
const { promises: fs } = require('graceful-fs')
const log = require('./log')

Expand All @@ -10,19 +11,58 @@ async function download (gyp, url) {
'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`,
Connection: 'keep-alive'
},
proxy: gyp.opts.proxy,
noProxy: gyp.opts.noproxy
dispatcher: await createDispatcher(gyp)
}

const cafile = gyp.opts.cafile
if (cafile) {
requestOpts.ca = await readCAFile(cafile)
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
}

const res = await fetch(url, requestOpts)
log.http(res.status, res.url)

return res
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) {
Comment thread
gengjiawen marked this conversation as resolved.
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 undefined
}

const opts = {}
if (gyp.opts.cafile) {
opts.connect = { ca: await readCAFile(gyp.opts.cafile) }
}
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 EnvHttpProxyAgent(opts)
}

async function readCAFile (filename) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
"env-paths": "^2.2.0",
"exponential-backoff": "^3.1.1",
"graceful-fs": "^4.2.6",
"make-fetch-happen": "^15.0.0",
"nopt": "^9.0.0",
"proc-log": "^6.0.0",
"semver": "^7.3.5",
"tar": "^7.5.4",
"tinyglobby": "^0.2.12",
"undici": "^6.25.0",
"which": "^6.0.0"
},
"engines": {
Expand Down
31 changes: 24 additions & 7 deletions test/test-download.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const fs = require('fs/promises')
const path = require('path')
const http = require('http')
const https = require('https')
const net = require('net')
const install = require('../lib/install')
const { download, readCAFile } = require('../lib/download')
const { FULL_TEST, devDir, platformTimeout } = require('./common')
Expand Down Expand Up @@ -69,13 +70,24 @@ describe('download', function () {
})

it('download over http with proxy', async function () {
const server = http.createServer((_, res) => {
const server = http.createServer((req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('ok')
})

const pserver = http.createServer((req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('proxy ok')
let proxyUsed = false
const pserver = http.createServer()
pserver.on('connect', (req, clientSocket, head) => {
proxyUsed = true
const [targetHost, targetPort] = req.url.split(':')
const serverSocket = net.connect(targetPort, targetHost, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n')
serverSocket.write(head)
serverSocket.pipe(clientSocket)
clientSocket.pipe(serverSocket)
})
Comment thread
MarshallOfSound marked this conversation as resolved.
clientSocket.on('error', () => serverSocket.destroy())
serverSocket.on('error', () => clientSocket.destroy())
})

after(() => Promise.all([
Expand All @@ -96,7 +108,8 @@ describe('download', function () {
}
const url = `http://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'proxy ok')
assert.strictEqual(await res.text(), 'ok')
assert.strictEqual(proxyUsed, true)
})

it('download over http with noproxy', async function () {
Expand All @@ -105,8 +118,11 @@ describe('download', function () {
res.end('ok')
})

const pserver = http.createServer((_, res) => {
res.end('proxy ok')
let proxyUsed = false
const pserver = http.createServer()
pserver.on('connect', (_, socket) => {
proxyUsed = true
socket.destroy()
})

after(() => Promise.all([
Expand All @@ -128,6 +144,7 @@ describe('download', function () {
const url = `http://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'ok')
assert.strictEqual(proxyUsed, false)
})

it('download with missing cafile', async function () {
Expand Down
Loading