From 5f209411a8b833df80879515f1e82e6f24ad0b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kornel=20Lesi=C5=84ski?= Date: Sun, 5 Jun 2016 13:37:36 +0100 Subject: [PATCH] JSON roundtrippin --- README.md | 4 ++++ index.js | 47 +++++++++++++++++++++++++++++++++++++++++++- test/requesttest.js | 5 +++++ test/responsetest.js | 10 ++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ade36dc..8b27494 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,10 @@ It generally means the response can't be used any more without revalidation with Returns number of *milliseconds* until the response becomes stale. After that time (when `timeToLive() <= 0`) the response won't be usable without revalidation. +### `toObject()`/`fromObject(json)` + +Chances are you'll want to store the `CachePolicy` object along with the cached response. `obj = policy.toObject()` gives a plain JSON-serializable object. `policy = CachePolicy.fromObject(obj)` creates an instance from it. + # Yo, FRESH ![satisfiesWithoutRevalidation](fresh.jpg) diff --git a/index.js b/index.js index d0ee20e..8c391d7 100644 --- a/index.js +++ b/index.js @@ -23,7 +23,12 @@ function parseCacheControl(header) { } module.exports = class CachePolicy { - constructor(req, res, {shared, cacheHeuristic} = {}) { + constructor(req, res, {shared, cacheHeuristic, _fromObject} = {}) { + if (_fromObject) { + this._fromObject(_fromObject); + return; + } + if (!res || !res.headers) { throw Error("Response headers missing"); } @@ -240,4 +245,44 @@ module.exports = class CachePolicy { stale() { return this.maxAge() <= this.age(); } + + static fromObject(obj) { + return new this(undefined, undefined, {_fromObject:obj}); + } + + _fromObject(obj) { + if (this._responseTime) throw Error("Reinitialized"); + if (!obj || obj.v !== 1) throw Error("Invalid serialization"); + + this._responseTime = obj.t; + this._isShared = obj.sh; + this._cacheHeuristic = obj.ch; + this._status = obj.st; + this._resHeaders = obj.resh; + this._rescc = obj.rescc; + this._method = obj.m; + this._url = obj.u; + this._host = obj.h; + this._noAuthorization = obj.a; + this._reqHeaders = obj.reqh; + this._reqcc = obj.reqcc; + } + + toObject() { + return { + v:1, + t: this._responseTime, + sh: this._isShared, + ch: this._cacheHeuristic, + st: this._status, + resh: this._resHeaders, + rescc: this._rescc, + m: this._method, + u: this._url, + h: this._host, + a: this._noAuthorization, + reqh: this._reqHeaders, + reqcc: this._reqcc, + }; + } }; diff --git a/test/requesttest.js b/test/requesttest.js index e3072a3..f668556 100644 --- a/test/requesttest.js +++ b/test/requesttest.js @@ -35,6 +35,11 @@ describe('Request properties', function() { const cache = new CachePolicy({method:'GET',headers:{'authorization': 'test'}}, {headers:{'cache-control':'max-age=0,s-maxage=12'}}); assert(!cache.stale()); assert(cache.storable()); + + const cache2 = CachePolicy.fromObject(JSON.parse(JSON.stringify(cache.toObject()))); + assert(cache2 instanceof CachePolicy); + assert(!cache2.stale()); + assert(cache2.storable()); }); it('Private auth is OK', function() { diff --git a/test/responsetest.js b/test/responsetest.js index cbd92c2..cc9054e 100644 --- a/test/responsetest.js +++ b/test/responsetest.js @@ -21,6 +21,11 @@ describe('Response headers', function() { const cache = new CachePolicy(req, {headers:{'cache-control': ',,,,max-age = 456 ,'}}); assert(!cache.stale()); assert.equal(cache.maxAge(), 456); + + const cache2 = CachePolicy.fromObject(JSON.parse(JSON.stringify(cache.toObject()))); + assert(cache2 instanceof CachePolicy); + assert(!cache2.stale()); + assert.equal(cache2.maxAge(), 456); }); it('quoted syntax', function() { @@ -277,5 +282,10 @@ describe('Response headers', function() { assert.equal(h.custom, 'header'); assert.equal(h.age, '11'); assert.equal(res.headers.age, '10'); + + const cache2 = TimeTravellingPolicy.fromObject(JSON.parse(JSON.stringify(cache.toObject()))); + assert(cache2 instanceof TimeTravellingPolicy); + const h2 = cache2.responseHeaders(); + assert.deepEqual(h, h2); }); });