Socket
Socket
Sign inDemoInstall

http-cache-semantics

Package Overview
Dependencies
0
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.0 to 3.1.0

fresh.jpg

29

index.js

@@ -8,2 +8,4 @@ 'use strict';

const hopByHopHeaders = {'connection':true, 'keep-alive':true, 'proxy-authenticate':true, 'proxy-authorization':true, 'te':true, 'trailers':true, 'transfer-encoding':true, 'upgrade':true};
function parseCacheControl(header) {

@@ -24,3 +26,3 @@ const cc = {};

function CachePolicy(req, res, {shared} = {}) {
function CachePolicy(req, res, {shared, cacheHeuristic} = {}) {
if (!res || !res.headers) {

@@ -35,2 +37,4 @@ throw Error("Response headers missing");

this._isShared = shared !== false;
this._cacheHeuristic = undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE
this._status = 'status' in res ? res.status : 200;

@@ -137,2 +141,19 @@ this._resHeaders = res.headers;

responseHeaders() {
const headers = {};
for(const name in this._resHeaders) {
if (hopByHopHeaders[name]) continue;
headers[name] = this._resHeaders[name];
}
// 9.1. Connection
if (this._resHeaders.connection) {
const tokens = this._resHeaders.connection.trim().split(/\s*,\s*/);
for(const name of tokens) {
delete headers[name];
}
}
headers.age = `${Math.round(this.age())}`;
return headers;
},
/**

@@ -211,3 +232,3 @@ * Value of the Date response header or current time if Date was demed invalid

if (isFinite(lastModified) && dateValue > lastModified) {
return (dateValue - lastModified) * 0.00001; // In absence of other information cache for 1% of item's age
return (dateValue - lastModified)/1000 * this._cacheHeuristic;
}

@@ -218,2 +239,6 @@ }

timeToLive() {
return Math.max(0, this.maxAge() - this.age())*1000;
},
stale() {

@@ -220,0 +245,0 @@ return this.maxAge() <= this.age();

2

package.json
{
"name": "http-cache-semantics",
"version": "3.0.0",
"version": "3.1.0",
"description": "Parses Cache-Control headers and friends",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -1,20 +0,29 @@

# HTTP cache semantics
# Can I cache this?
`CachePolicy` object that computes properties of a HTTP response, such as whether it's fresh or stale, and how long it can be cached for. Based on RFC 7234.
`CachePolicy` implements HTTP cache semantics. It can tell when responses can be reused from cache, taking into account [RFC 7234](http://httpwg.org/specs/rfc7234.html) rules for user agents and shared caches. It's aware of many tricky details such as the `Vary` header, proxy revalidation, authenticated responses.
## Usage
Cacheability of an HTTP response depends on how it was requested, so both `request` and `response` are required to create the policy.
```js
const cache = new CachePolicy(request, response, options);
const policy = new CachePolicy(request, response, options);
// Age counts from the time response has been created
const secondsFresh = cache.maxAge();
const secondsOld = cache.age();
if (!policy.storable()) {
// throw the response away, it's not usable at all
}
// Current state
const outOfDate = cache.stale();
if (policy.satisfiesWithoutRevalidation(newRequest)) {
// the previous `response` can be used to respond to the `newRequest`
}
```
Cacheability of response depends on how it was requested, so both request and response are required. Both are objects with `headers` property that is an object with lowercased header names as keys, e.g.
It may be surprising, but it's not enough for an HTTP response to be [fresh](#yo-fresh) to satisfy a request. It may need to match request headers specified in `Vary`. Even a matching fresh response may still not be usable if the new request restricted cacheability, etc.
The key method is `satisfiesWithoutRevalidation(newRequest)`, which checks whether the `newRequest` is compatible with the original request and whether all caching conditions are met.
### Constructor options
Request and response must have a `headers` property with all header names in lower case. `url`, `status` and `method` are optional (defaults are any URL, status `200`, and `GET` method).
```js

@@ -38,2 +47,3 @@ const request = {

shared: true,
cacheHeuristic: 0.1,
};

@@ -44,11 +54,17 @@ ```

`options.cacheHeuristic` is a fraction of response's age that is used as a fallback cache duration. The default is 0.1 (10%), e.g. if a file hasn't been modified for 100 days, it'll be cached for 100*0.1 = 10 days.
### `storable()`
Returns `true` if the response can be stored in a cache. If it's `false` then you MUST NOT store either the request or the response.
### `satisfiesWithoutRevalidation(request)`
If it returns `true`, then the given `request` matches the response this cache policy has been created with, and the existing response can be used without contacting the server.
If it returns `true`, then the given `request` matches the original response this cache policy has been created with, and the response can be reused without contacting the server. Note that the old response can't be returned without being updated, see `responseHeaders()`.
If it returns `false`, then the response may not be matching at all (e.g. it's different URL or method), or may require to be refreshed first.
If it returns `false`, then the response may not be matching at all (e.g. it's for a different URL or method), or may require to be refreshed first.
### `storable()`
### `responseHeaders()`
Returns `true` if the response can be stored in a cache. If it's `false` then you MUST NOT store either request or the response.
Returns updated, filtered set of response headers. Proxies MUST always remove hop-by-hop headers (such as `TE` and `Connection`) and update response age to avoid doubling cache time.

@@ -59,4 +75,12 @@ ### `stale()`

It generally means the response can't be used any more without revalidation with the server. However, there are exceptions, e.g. client can explicitly allow stale responses. A fresh response still may not be used if other conditions—such as `Vary`—are not satisfied.
It generally means the response can't be used any more without revalidation with the server. However, there are exceptions, e.g. a client can explicitly allow stale responses.
### `timeToLive()`
Returns number of *milliseconds* until the response becomes stale. After that time (when `timeToLive() <= 0`) the response won't be usable without revalidation.
# Yo, FRESH
![satisfiesWithoutRevalidation](fresh.jpg)
## Implemented

@@ -68,4 +92,4 @@

* `Age` response header
* `Vary` response header
* Default cacheability of statuses and methods
* Basic support for `Vary`

@@ -72,0 +96,0 @@ ## Unimplemented

@@ -64,7 +64,10 @@ 'use strict';

assert.equal(50*1000, cache.timeToLive());
assert(!cache.stale());
now += 48*1000;
assert.equal(2*1000, cache.timeToLive());
assert(!cache.stale());
now += 5*1000;
assert(cache.stale());
assert.equal(0, cache.timeToLive());
});

@@ -248,2 +251,33 @@

});
it('remove hop headers', function() {
let now = 10000;
class TimeTravellingPolicy extends CachePolicy {
now() {
return now;
}
}
const res = {headers:{
'te': 'deflate',
'date': 'now',
'custom': 'header',
'oompa': 'lumpa',
'connection': 'close, oompa, header',
'age': '10',
'cache-control': 'public, max-age=333',
}};
const cache = new TimeTravellingPolicy(req, res);
now += 1005;
const h = cache.responseHeaders();
assert(!h.connection);
assert(!h.te);
assert(!h.oompa);
assert.equal(h['cache-control'], 'public, max-age=333');
assert.equal(h.date, 'now', "date must stay the same for expires, age, etc");
assert.equal(h.custom, 'header');
assert.equal(h.age, '11');
assert.equal(res.headers.age, '10');
});
});
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc