Socket
Socket
Sign inDemoInstall

make-fetch-happen

Package Overview
Dependencies
16
Maintainers
6
Versions
105
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 9.1.0 to 10.0.0

33

lib/agent.js

@@ -53,7 +53,9 @@ 'use strict'

if (isLambda && !pxuri)
if (isLambda && !pxuri) {
return lambdaAgent
}
if (AGENT_CACHE.peek(key))
if (AGENT_CACHE.peek(key)) {
return AGENT_CACHE.get(key)
}

@@ -90,12 +92,15 @@ if (pxuri) {

let noproxy = (opts.noProxy || getProcessEnv('no_proxy'))
if (typeof noproxy === 'string')
if (typeof noproxy === 'string') {
noproxy = noproxy.split(/\s*,\s*/g)
}
return noproxy && noproxy.some(no => {
const noParts = no.split('.').filter(x => x).reverse()
if (!noParts.length)
if (!noParts.length) {
return false
}
for (let i = 0; i < noParts.length; i++) {
if (host[i] !== noParts[i])
if (host[i] !== noParts[i]) {
return false
}
}

@@ -109,4 +114,5 @@ return true

function getProcessEnv (env) {
if (!env)
if (!env) {
return
}

@@ -120,4 +126,5 @@ let value

process.env[e.toLowerCase()]
if (typeof value !== 'undefined')
if (typeof value !== 'undefined') {
break
}
}

@@ -148,4 +155,5 @@ }

)
if (!proxy)
if (!proxy) {
return null
}

@@ -185,9 +193,10 @@ const parsedProxy = (typeof proxy === 'string') ? new url.URL(proxy) : proxy

if (proxyUrl.protocol === 'http:' || proxyUrl.protocol === 'https:') {
if (!isHttps)
if (!isHttps) {
return new HttpProxyAgent(popts)
else
} else {
return new HttpsProxyAgent(popts)
} else if (proxyUrl.protocol.startsWith('socks'))
}
} else if (proxyUrl.protocol.startsWith('socks')) {
return new SocksProxyAgent(popts)
else {
} else {
throw Object.assign(

@@ -194,0 +203,0 @@ new Error(`unsupported proxy protocol: '${proxyUrl.protocol}'`),

@@ -55,11 +55,18 @@ const { Request, Response } = require('minipass-fetch')

resHeaders: {},
// options on which we must match the request and vary the response
options: {
compress: options.compress != null ? options.compress : request.compress,
},
}
// only save the status if it's not a 200 or 304
if (response.status !== 200 && response.status !== 304)
if (response.status !== 200 && response.status !== 304) {
metadata.status = response.status
}
for (const name of KEEP_REQUEST_HEADERS) {
if (request.headers.has(name))
if (request.headers.has(name)) {
metadata.reqHeaders[name] = request.headers.get(name)
}
}

@@ -71,4 +78,5 @@

const parsedUrl = new url.URL(request.url)
if (host && parsedUrl.host !== host)
if (host && parsedUrl.host !== host) {
metadata.reqHeaders.host = host
}

@@ -87,5 +95,5 @@ // if the response has a vary header, make sure

for (const name of varyHeaders) {
// explicitly ignore accept-encoding here
if (name !== 'accept-encoding' && request.headers.has(name))
if (request.headers.has(name)) {
metadata.reqHeaders[name] = request.headers.get(name)
}
}

@@ -96,15 +104,7 @@ }

for (const name of KEEP_RESPONSE_HEADERS) {
if (response.headers.has(name))
if (response.headers.has(name)) {
metadata.resHeaders[name] = response.headers.get(name)
}
}
// we only store accept-encoding and content-encoding if the user
// has disabled automatic compression and decompression in minipass-fetch
// since if it's enabled (the default) then the content will have
// already been decompressed making the header a lie
if (options.compress === false) {
metadata.reqHeaders['accept-encoding'] = request.headers.get('accept-encoding')
metadata.resHeaders['content-encoding'] = response.headers.get('content-encoding')
}
return metadata

@@ -128,4 +128,5 @@ }

this.entry.metadata.time = this.entry.metadata.time || this.entry.time
} else
} else {
this.key = cacheKey(request)
}

@@ -151,5 +152,13 @@ this.options = options

validateEntry: (entry) => {
// clean out entries with a buggy content-encoding value
if (entry.metadata &&
entry.metadata.resHeaders &&
entry.metadata.resHeaders['content-encoding'] === null) {
return false
}
// if an integrity is null, it needs to have a status specified
if (entry.integrity === null)
if (entry.integrity === null) {
return !!(entry.metadata && entry.metadata.status)
}

@@ -167,4 +176,5 @@ return true

// create a brand new request no matter what.
if (options.cache === 'reload')
if (options.cache === 'reload') {
return
}

@@ -204,2 +214,3 @@ // find the specific entry that satisfies the request

headers: this.entry.metadata.reqHeaders,
...this.entry.metadata.options,
})

@@ -246,3 +257,7 @@ }

// cache status header and return it untouched
if (this.request.method !== 'GET' || ![200, 301, 308].includes(this.response.status) || !this.policy.storable()) {
if (
this.request.method !== 'GET' ||
![200, 301, 308].includes(this.response.status) ||
!this.policy.storable()
) {
this.response.headers.set('x-local-cache-status', 'skip')

@@ -288,3 +303,4 @@ return this.response

// TODO if the cache write fails, log a warning but return the response anyway
cacache.put(this.options.cachePath, this.key, data, cacheOpts).then(cacheWriteResolve, cacheWriteReject)
cacache.put(this.options.cachePath, this.key, data, cacheOpts)
.then(cacheWriteResolve, cacheWriteReject)
})

@@ -318,4 +334,5 @@ body.unshift(collector)

})
} else
} else {
await cacache.index.insert(this.options.cachePath, this.key, null, cacheOpts)
}

@@ -361,9 +378,15 @@ // note: we do not set the x-local-cache-hash header because we do not know

try {
const content = await cacache.get.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
const content = await cacache.get.byDigest(
this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
)
body.end(content)
} catch (err) {
if (err.code === 'EINTEGRITY')
await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
if (err.code === 'EINTEGRITY') {
await cacache.rm.content(
this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
)
}
if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') {
await CacheEntry.invalidate(this.request, this.options)
}
body.emit('error', err)

@@ -374,9 +397,15 @@ }

onResume = () => {
const cacheStream = cacache.get.stream.byDigest(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
const cacheStream = cacache.get.stream.byDigest(
this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
)
cacheStream.on('error', async (err) => {
cacheStream.pause()
if (err.code === 'EINTEGRITY')
await cacache.rm.content(this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize })
if (err.code === 'ENOENT' || err.code === 'EINTEGRITY')
if (err.code === 'EINTEGRITY') {
await cacache.rm.content(
this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize }
)
}
if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') {
await CacheEntry.invalidate(this.request, this.options)
}
body.emit('error', err)

@@ -431,4 +460,5 @@ cacheStream.resume()

// of 'must-revalidate'
if (!this.policy.mustRevalidate)
if (!this.policy.mustRevalidate) {
return this.respond(request.method, options, 'stale')
}

@@ -446,4 +476,8 @@ throw err

for (const name of KEEP_RESPONSE_HEADERS) {
if (!hasOwnProperty(metadata.resHeaders, name) && hasOwnProperty(this.entry.metadata.resHeaders, name))
if (
!hasOwnProperty(metadata.resHeaders, name) &&
hasOwnProperty(this.entry.metadata.resHeaders, name)
) {
metadata.resHeaders[name] = this.entry.metadata.resHeaders[name]
}
}

@@ -450,0 +484,0 @@

class NotCachedError extends Error {
constructor (url) {
/* eslint-disable-next-line max-len */
super(`request to ${url} failed: cache mode is 'only-if-cached' but no cached response is available.`)

@@ -4,0 +5,0 @@ this.code = 'ENOTCACHED'

@@ -11,4 +11,5 @@ const { NotCachedError } = require('./errors.js')

// no cached result, if the cache mode is 'only-if-cached' that's a failure
if (options.cache === 'only-if-cached')
if (options.cache === 'only-if-cached') {
throw new NotCachedError(request.url)
}

@@ -23,4 +24,5 @@ // otherwise, we make a request, store it and return it

// mode is 'no-cache' then we send the revalidation request no matter what
if (options.cache === 'no-cache')
if (options.cache === 'no-cache') {
return entry.revalidate(request, options)
}

@@ -33,4 +35,5 @@ // if the cached entry is not stale, or if the cache mode is 'force-cache' or

options.cache === 'only-if-cached' ||
!_needsRevalidation)
!_needsRevalidation) {
return entry.respond(request.method, options, _needsRevalidation ? 'stale' : 'hit')
}

@@ -42,4 +45,5 @@ // if we got here, the cache entry is stale so revalidate it

cacheFetch.invalidate = async (request, options) => {
if (!options.cachePath)
if (!options.cachePath) {
return
}

@@ -46,0 +50,0 @@ return CacheEntry.invalidate(request, options)

@@ -5,15 +5,2 @@ const CacheSemantics = require('http-cache-semantics')

// HACK: negotiator lazy loads several of its own modules
// as a micro optimization. we need to be sure that they're
// in memory as soon as possible at startup so that we do
// not try to lazy load them after the directory has been
// retired during a self update of the npm CLI, we do this
// by calling all of the methods that trigger a lazy load
// on a fake instance.
const preloadNegotiator = new Negotiator({ headers: {} })
preloadNegotiator.charsets()
preloadNegotiator.encodings()
preloadNegotiator.languages()
preloadNegotiator.mediaTypes()
// options passed to http-cache-semantics constructor

@@ -35,2 +22,3 @@ const policyOptions = {

headers: {},
compress: request.compress,
}

@@ -79,12 +67,15 @@

// no cachePath means no caching
if (!options.cachePath)
if (!options.cachePath) {
return false
}
// user explicitly asked not to cache
if (options.cache === 'no-store')
if (options.cache === 'no-store') {
return false
}
// we only cache GET and HEAD requests
if (!['GET', 'HEAD'].includes(request.method))
if (!['GET', 'HEAD'].includes(request.method)) {
return false
}

@@ -100,19 +91,28 @@ // otherwise, let http-cache-semantics make the decision

const _req = requestObject(request)
if (this.request.headers.host !== _req.headers.host)
if (this.request.headers.host !== _req.headers.host) {
return false
}
if (this.request.compress !== _req.compress) {
return false
}
const negotiatorA = new Negotiator(this.request)
const negotiatorB = new Negotiator(_req)
if (JSON.stringify(negotiatorA.mediaTypes()) !== JSON.stringify(negotiatorB.mediaTypes()))
if (JSON.stringify(negotiatorA.mediaTypes()) !== JSON.stringify(negotiatorB.mediaTypes())) {
return false
}
if (JSON.stringify(negotiatorA.languages()) !== JSON.stringify(negotiatorB.languages()))
if (JSON.stringify(negotiatorA.languages()) !== JSON.stringify(negotiatorB.languages())) {
return false
}
if (JSON.stringify(negotiatorA.encodings()) !== JSON.stringify(negotiatorB.encodings()))
if (JSON.stringify(negotiatorA.encodings()) !== JSON.stringify(negotiatorB.encodings())) {
return false
}
if (this.options.integrity)
if (this.options.integrity) {
return ssri.parse(this.options.integrity).match(this.entry.integrity)
}

@@ -119,0 +119,0 @@ return true

@@ -16,16 +16,24 @@ 'use strict'

const canFollowRedirect = (request, response, options) => {
if (!isRedirect(response.status))
if (!isRedirect(response.status)) {
return false
}
if (options.redirect === 'manual')
if (options.redirect === 'manual') {
return false
}
if (options.redirect === 'error')
throw new FetchError(`redirect mode is set to error: ${request.url}`, 'no-redirect', { code: 'ENOREDIRECT' })
if (options.redirect === 'error') {
throw new FetchError(`redirect mode is set to error: ${request.url}`,
'no-redirect', { code: 'ENOREDIRECT' })
}
if (!response.headers.has('location'))
throw new FetchError(`redirect location header missing for: ${request.url}`, 'no-location', { code: 'EINVALIDREDIRECT' })
if (!response.headers.has('location')) {
throw new FetchError(`redirect location header missing for: ${request.url}`,
'no-location', { code: 'EINVALIDREDIRECT' })
}
if (request.counter >= request.follow)
throw new FetchError(`maximum redirect reached at: ${request.url}`, 'max-redirect', { code: 'EMAXREDIRECT' })
if (request.counter >= request.follow) {
throw new FetchError(`maximum redirect reached at: ${request.url}`,
'max-redirect', { code: 'EMAXREDIRECT' })
}

@@ -43,12 +51,15 @@ return true

// Comment below is used under the following license:
// Copyright (c) 2010-2012 Mikeal Rogers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an "AS
// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language
// governing permissions and limitations under the License.
/**
* @license
* Copyright (c) 2010-2012 Mikeal Rogers
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS
* IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

@@ -58,8 +69,13 @@ // Remove authorization if changing hostnames (but not if just

// https://github.com/request/request/blob/b12a6245/lib/redirect.js#L134-L138
if (new url.URL(request.url).hostname !== redirectUrl.hostname)
if (new url.URL(request.url).hostname !== redirectUrl.hostname) {
request.headers.delete('authorization')
request.headers.delete('cookie')
}
// for POST request with 301/302 response, or any request with 303 response,
// use GET when following redirect
if (response.status === 303 || (request.method === 'POST' && [301, 302].includes(response.status))) {
if (
response.status === 303 ||
(request.method === 'POST' && [301, 302].includes(response.status))
) {
_opts.method = 'GET'

@@ -93,7 +109,9 @@ _opts.body = null

response.status >= 200 &&
response.status <= 399)
response.status <= 399) {
await cache.invalidate(request, options)
}
if (!canFollowRedirect(request, response, options))
if (!canFollowRedirect(request, response, options)) {
return response
}

@@ -100,0 +118,0 @@ const redirect = getRedirect(request, response, options)

@@ -10,18 +10,20 @@ const conditionalHeaders = [

const configureOptions = (opts) => {
const {strictSSL, ...options} = { ...opts }
const { strictSSL, ...options } = { ...opts }
options.method = options.method ? options.method.toUpperCase() : 'GET'
options.rejectUnauthorized = strictSSL !== false
if (!options.retry)
if (!options.retry) {
options.retry = { retries: 0 }
else if (typeof options.retry === 'string') {
} else if (typeof options.retry === 'string') {
const retries = parseInt(options.retry, 10)
if (isFinite(retries))
if (isFinite(retries)) {
options.retry = { retries }
else
} else {
options.retry = { retries: 0 }
} else if (typeof options.retry === 'number')
}
} else if (typeof options.retry === 'number') {
options.retry = { retries: options.retry }
else
} else {
options.retry = { retries: 0, ...options.retry }
}

@@ -33,4 +35,5 @@ options.cache = options.cache || 'default'

})
if (hasConditionalHeader)
if (hasConditionalHeader) {
options.cache = 'no-store'
}
}

@@ -40,4 +43,5 @@

// cachePath is not we should copy it to the new field
if (options.cacheManager && !options.cachePath)
if (options.cacheManager && !options.cachePath) {
options.cachePath = options.cacheManager
}

@@ -44,0 +48,0 @@ return options

@@ -32,7 +32,9 @@ const Minipass = require('minipass')

const agent = getAgent(request.url, options)
if (!request.headers.has('connection'))
if (!request.headers.has('connection')) {
request.headers.set('connection', agent ? 'keep-alive' : 'close')
}
if (!request.headers.has('user-agent'))
if (!request.headers.has('user-agent')) {
request.headers.set('user-agent', USER_AGENT)
}

@@ -68,4 +70,5 @@ // keep our own options since we're overriding the agent

if (isRetriable) {
if (typeof options.onRetry === 'function')
if (typeof options.onRetry === 'function') {
options.onRetry(res)
}

@@ -87,7 +90,9 @@ return retryHandler(res)

if (req.method === 'POST' || isRetryError)
if (req.method === 'POST' || isRetryError) {
throw err
}
if (typeof options.onRetry === 'function')
if (typeof options.onRetry === 'function') {
options.onRetry(err)
}

@@ -98,4 +103,5 @@ return retryHandler(err)

// don't reject for http errors, just return them
if (err.status >= 400 && err.type !== 'system')
if (err.status >= 400 && err.type !== 'system') {
return err
}

@@ -102,0 +108,0 @@ throw err

{
"name": "make-fetch-happen",
"version": "9.1.0",
"version": "10.0.0",
"description": "Opinionated, caching, retrying fetch client",
"main": "lib/index.js",
"files": [
"bin",
"lib"
],
"scripts": {
"preversion": "npm t",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push --follow-tags",
"prepublishOnly": "git push origin --follow-tags",
"test": "tap",
"posttest": "npm run lint",
"eslint": "eslint",
"lint": "npm run eslint -- lib test",
"lintfix": "npm run lint -- --fix"
"lint": "eslint '**/*.js'",
"lintfix": "npm run lint -- --fix",
"postlint": "npm-template-check",
"snap": "tap"
},

@@ -29,7 +32,3 @@ "repository": "https://github.com/npm/make-fetch-happen",

],
"author": {
"name": "Kat Marchán",
"email": "kzm@zkat.tech",
"twitter": "maybekatz"
},
"author": "GitHub Inc.",
"license": "ISC",

@@ -40,3 +39,3 @@ "dependencies": {

"http-cache-semantics": "^4.1.0",
"http-proxy-agent": "^4.0.1",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",

@@ -50,3 +49,3 @@ "is-lambda": "^1.0.1",

"minipass-pipeline": "^1.2.4",
"negotiator": "^0.6.2",
"negotiator": "^0.6.3",
"promise-retry": "^2.0.1",

@@ -57,10 +56,7 @@ "socks-proxy-agent": "^6.0.0",

"devDependencies": {
"eslint": "^7.26.0",
"eslint-plugin-import": "^2.23.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"@npmcli/template-oss": "^2.5.1",
"eslint": "^8.7.0",
"mkdirp": "^1.0.4",
"nock": "^13.0.11",
"npmlog": "^5.0.0",
"npmlog": "^6.0.0",
"require-inject": "^1.4.2",

@@ -73,3 +69,3 @@ "rimraf": "^3.0.2",

"engines": {
"node": ">= 10"
"node": "^12.13.0 || ^14.15.0 || >=16"
},

@@ -80,3 +76,6 @@ "tap": {

"check-coverage": true
},
"templateOSS": {
"version": "2.5.1"
}
}

@@ -390,7 +390,1 @@ # make-fetch-happen

```
### <a name="wow"></a> Message From Our Sponsors
![](stop.gif)
![](happening.gif)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc