Skip to content

Commit

Permalink
feat: attempt to use smaller function set of fetch
Browse files Browse the repository at this point in the history
Make-fetch-happen uses minipass-fetch, disregarding caching, this goes
back to supporting the proxy ourselves.
  • Loading branch information
imatlopez committed Sep 14, 2020
1 parent 607bac5 commit 65093f1
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 6 deletions.
9 changes: 8 additions & 1 deletion lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const stream = require('stream')
const crypto = require('crypto')
const log = require('npmlog')
const semver = require('semver')
const fetch = require('make-fetch-happen')
const fetch = require('minipass-fetch')
const getProxyFromURI = require('./proxy')
const processRelease = require('./process-release')
const win = process.platform === 'win32'
const streamPipeline = util.promisify(stream.pipeline)
Expand Down Expand Up @@ -351,6 +352,12 @@ async function download (gyp, url) {
requestOpts.ca = await readCAFile(cafile)
}

const proxyAgent = getProxyFromURI(gyp, url, requestOpts.ca)
if (proxyAgent) {
log.verbose('download', `using proxy url: "${proxyAgent.proxy.host}:${proxyAgent.proxy.port}"`)
requestOpts.agent = proxyAgent
}

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

Expand Down
104 changes: 104 additions & 0 deletions lib/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict'
// Taken from https://github.com/request/request/blob/212570b/lib/getProxyFromURI.js

const url = require('url')
const HttpProxyAgent = require('http-proxy-agent')
const HttpsProxyAgent = require('https-proxy-agent')

function formatHostname (hostname) {
// canonicalize the hostname, so that 'oogle.com' won't match 'google.com'
return hostname.replace(/^\.*/, '.').toLowerCase()
}

function parseNoProxyZone (zone) {
zone = zone.trim().toLowerCase()

const zoneParts = zone.split(':', 2)
const zoneHost = formatHostname(zoneParts[0])
const zonePort = zoneParts[1]
const hasPort = zone.indexOf(':') > -1

return { hostname: zoneHost, port: zonePort, hasPort: hasPort }
}

function uriInNoProxy (uri, noProxy) {
const port = uri.port || (uri.protocol === 'https:' ? '443' : '80')
const hostname = formatHostname(uri.hostname)
const noProxyList = noProxy.split(',')

// iterate through the noProxyList until it finds a match.
return noProxyList.map(parseNoProxyZone).some(function (noProxyZone) {
const isMatchedAt = hostname.indexOf(noProxyZone.hostname)
const hostnameMatched = (
isMatchedAt > -1 &&
(isMatchedAt === hostname.length - noProxyZone.hostname.length)
)

if (noProxyZone.hasPort) {
return (port === noProxyZone.port) && hostnameMatched
}

return hostnameMatched
})
}

function getProxyFromURI (gyp, uri, ca) {
// If a string URI/URL was given, parse it into a URL object
if (typeof uri === 'string') {
// eslint-disable-next-line
uri = new url.URL(uri)
}

// Decide the proper request proxy to use based on the request URI object and the
// environmental variables (NO_PROXY, HTTP_PROXY, etc.)
// respect NO_PROXY environment variables (see: https://lynx.invisible-island.net/lynx2.8.7/breakout/lynx_help/keystrokes/environments.html)

const noProxy = gyp.opts.noproxy ||
process.env.NO_PROXY ||
process.env.no_proxy || ''

// if the noProxy is a wildcard then return null

if (noProxy === '*') {
return null
}

// if the noProxy is not empty and the uri is found return null

if (noProxy !== '' && uriInNoProxy(uri, noProxy)) {
return null
}

// Check for HTTP or HTTPS Proxy in environment Else default to null

if (uri.protocol === 'http:') {
let pxuri = gyp.opts.proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy || null

if (pxuri) {
pxuri = new url.URL(pxuri)
return new HttpProxyAgent({ host: pxuri.hostname, port: pxuri.port, ca })
}
}

if (uri.protocol === 'https:') {
let pxuri = gyp.opts.proxy ||
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy || null

if (pxuri) {
pxuri = new url.URL(pxuri)
return new HttpsProxyAgent({ host: pxuri.host, port: pxuri.port, ca })
}
}

// if none of that works, return null
// (What uri protocol are you using then?)

return null
}

module.exports = getProxyFromURI
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"env-paths": "^2.2.0",
"glob": "^7.1.4",
"graceful-fs": "^4.2.3",
"make-fetch-happen": "^8.0.9",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"minipass-fetch": "^1.3.1",
"nopt": "^4.0.3",
"npmlog": "^4.1.2",
"rimraf": "^2.6.3",
Expand Down
9 changes: 5 additions & 4 deletions test/test-download.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const log = require('npmlog')

log.level = 'warn'

test('download over http', (t) => {
test('download over http', async (t) => {
t.plan(2)

const server = http.createServer((req, res) => {
Expand Down Expand Up @@ -73,7 +73,7 @@ test('download over https with custom ca', async (t) => {
}))
})

test('download over http with proxy', (t) => {
test('download over http with proxy', async (t) => {
t.plan(2)

const server = http.createServer((_, res) => {
Expand All @@ -93,7 +93,8 @@ test('download over http with proxy', (t) => {
pserver.listen(port + 1, host, async () => {
const gyp = {
opts: {
proxy: `http://${host}:${port + 1}`
proxy: `http://${host}:${port + 1}`,
noproxy: 'bad'
},
version: '42'
}
Expand All @@ -105,7 +106,7 @@ test('download over http with proxy', (t) => {
}))
})

test('download over http with noproxy', (t) => {
test('download over http with noproxy', async (t) => {
t.plan(2)

const server = http.createServer((req, res) => {
Expand Down

0 comments on commit 65093f1

Please sign in to comment.