Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

make-fetch-happen

Package Overview
Dependencies
Maintainers
1
Versions
109
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

make-fetch-happen - npm Package Compare versions

Comparing version 2.0.4 to 2.1.0

10

CHANGELOG.md

@@ -5,2 +5,12 @@ # Change Log

<a name="2.1.0"></a>
# [2.1.0](https://github.com/zkat/make-fetch-happen/compare/v2.0.4...v2.1.0) (2017-04-09)
### Features
* **cache:** cache now obeys Age and a variety of other things (#13) ([7b9652d](https://github.com/zkat/make-fetch-happen/commit/7b9652d))
<a name="2.0.4"></a>

@@ -7,0 +17,0 @@ ## [2.0.4](https://github.com/zkat/make-fetch-happen/compare/v2.0.3...v2.0.4) (2017-04-09)

149

index.js
'use strict'
let Cache
const CachePolicy = require('http-cache-semantics')
const fetch = require('node-fetch')

@@ -97,6 +98,6 @@ const LRU = require('lru-cache')

}
if (res && opts.cache === 'default' && !isStale(res)) {
if (res && opts.cache === 'default' && !isStale(req, res)) {
return res
} else if (res && (opts.cache === 'default' || opts.cache === 'no-cache')) {
return condFetch(uri, res, opts)
return condFetch(req, res, opts)
} else if (res && (

@@ -116,3 +117,3 @@ opts.cache === 'force-cache' || opts.cache === 'only-if-cached'

// Missing cache entry, or mode is default (if stale), reload, no-store
return remoteFetch(uri, opts)
return remoteFetch(req.url, opts)
}

@@ -125,90 +126,82 @@ })

// https://tools.ietf.org/html/rfc7234#section-4.2
function isStale (res) {
if (!res) { return null }
const ctrl = res.headers.get('Cache-Control') || ''
if (ctrl.match(/must-revalidate/i)) {
return true
function adaptHeaders (headers) {
const newHs = {}
for (let k of headers.keys()) {
newHs[k] = headers.get(k)
}
if (ctrl.match(/immutable/i)) {
return false
}
const maxAge = freshnessLifetime(res)
const currentAge = (new Date() - new Date(res.headers.get('Date') || new Date())) / 1000
return maxAge <= currentAge
return newHs
}
// https://tools.ietf.org/html/rfc7234#section-4.2.1
function freshnessLifetime (res) {
const cacheControl = res.headers.get('Cache-Control') || ''
const pragma = res.headers.get('Pragma') || ''
const maxAgeMatch = cacheControl.match(/(?:s-maxage|max-age)\s*=\s*(\d+)/i)
const noCacheMatch = (
cacheControl.match(/no-cache/i) ||
pragma.match(/no-cache/i)
)
if (noCacheMatch) {
// no-cache requires revalidation on every request
return 0
} else if (maxAgeMatch) {
return +maxAgeMatch[1]
} else if (res.headers.get('Expires')) {
const expireDate = new Date(res.headers.get('Expires'))
const resDate = new Date(res.headers.get('Date') || new Date())
return (expireDate - resDate) / 1000
} else {
return heuristicFreshness(res)
function makePolicy (req, res) {
const _req = {
url: req.url,
method: req.method,
headers: adaptHeaders(req.headers)
}
const _res = {
status: res.status,
headers: adaptHeaders(res.headers)
}
return new CachePolicy(_req, _res)
}
// https://tools.ietf.org/html/rfc7234#section-4.2.2
function heuristicFreshness (res) {
const lastMod = res.headers.get('Last-Modified')
const date = new Date(res.headers.get('Date') || new Date())
!res.headers.get('Warning') && setWarning(
res, 113, 'Used heuristics to calculate cache freshness'
)
if (lastMod) {
const age = (date - new Date(lastMod)) / 1000
return Math.min(age * 0.1, 300)
} else {
return 300
// https://tools.ietf.org/html/rfc7234#section-4.2
function isStale (req, res) {
if (!res) { return null }
const _req = {
url: req.url,
method: req.method,
headers: adaptHeaders(req.headers)
}
const bool = !makePolicy(req, res).satisfiesWithoutRevalidation(_req)
return bool
}
function condFetch (uri, cachedRes, opts) {
const ctrl = cachedRes.headers.get('cache-control') || ''
const newHeaders = {}
function mustRevalidate (res) {
return (res.headers.get('cache-control') || '').match(/must-revalidate/i)
}
function condFetch (req, cachedRes, opts) {
let newHeaders = {}
Object.keys(opts.headers || {}).forEach(k => {
newHeaders[k] = opts.headers[k]
})
if (cachedRes.headers.get('etag')) {
const condHeader = opts.method !== 'GET'
? 'if-match'
: 'if-none-match'
newHeaders[condHeader] = cachedRes.headers.get('etag')
const policy = makePolicy(req, cachedRes)
const _req = {
url: req.url,
method: req.method,
headers: newHeaders
}
if (cachedRes.headers.get('last-modified')) {
const condHeader = opts.method !== 'GET' && opts.method !== 'HEAD'
? 'if-unmodified-since'
: 'if-modified-since'
newHeaders[condHeader] = cachedRes.headers.get('last-modified')
}
opts.headers = newHeaders
if (isStale(cachedRes)) {
setWarning(cachedRes, 110, 'Local cached response stale')
}
return remoteFetch(uri, opts).then(condRes => {
opts.headers = policy.revalidationHeaders(_req)
return remoteFetch(req.url, opts).then(condRes => {
const revaled = policy.revalidatedPolicy(_req, {
status: condRes.status,
headers: adaptHeaders(condRes.headers)
})
if (condRes.status === 304) {
condRes.body = cachedRes.body
condRes.headers.set('Warning', cachedRes.headers.get('Warning'))
} else if (condRes.status >= 500 && !ctrl.match(/must-revalidate/i)) {
return opts.cacheManager.put(req, condRes, opts).then(newRes => {
newRes.headers = new fetch.Headers(revaled.policy.responseHeaders())
if (revaled.modified) {
setWarning(newRes, 110, 'Revalidation failed even with 304 response. Using stale body with new headers.')
} else {
setWarning(newRes, 110, 'Local cached response stale')
}
return newRes
})
} else if (
condRes.status >= 500 &&
!mustRevalidate(cachedRes)
) {
setWarning(
cachedRes, 111, `Revalidation failed. Returning stale response`
cachedRes, 111, `Revalidation failed with status ${condRes.status}. Returning stale response`
)
return cachedRes
} else {
return condRes
}
return condRes
}).then(res => {
return res
}).catch(err => {
if (ctrl.match(/must-revalidate/i)) {
if (mustRevalidate(cachedRes)) {
throw err

@@ -222,5 +215,5 @@ } else {

function setWarning (reqOrRes, code, message, host) {
function setWarning (reqOrRes, code, message, host, append) {
host = host || 'localhost'
reqOrRes.headers.set(
reqOrRes.headers[append ? 'append' : 'set'](
'Warning',

@@ -237,3 +230,3 @@ `${code} ${host} ${

const agent = getAgent(uri, opts)
const headers = {
let headers = {
'connection': agent ? 'keep-alive' : 'close',

@@ -247,2 +240,3 @@ 'user-agent': `${pkg.name}/${pkg.version} (+https://npm.im/${pkg.name})`

}
headers = new fetch.Headers(headers)
const reqOpts = {

@@ -277,10 +271,9 @@ agent,

}
const cacheCtrl = res.headers.get('cache-control') || ''
if (
(req.method === 'GET' || req.method === 'HEAD') &&
opts.cacheManager &&
!cacheCtrl.match(/no-store/i) &&
opts.cache !== 'no-store' &&
(req.method === 'GET' || req.method === 'HEAD') &&
makePolicy(req, res).storable() &&
// No other statuses should be stored!
(res.status === 200 || res.status === 304)
res.status === 200
) {

@@ -287,0 +280,0 @@ return opts.cacheManager.put(req, res, opts)

{
"name": "make-fetch-happen",
"version": "2.0.4",
"version": "2.1.0",
"description": "Opinionated, caching, retrying fetch client",

@@ -45,2 +45,3 @@ "main": "index.js",

"https-proxy-agent": "^1.0.0",
"http-cache-semantics": "^3.7.3",
"lru-cache": "^4.0.2",

@@ -47,0 +48,0 @@ "mississippi": "^1.2.0",

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc