diff --git a/v1/pcs/stored_endpoint.js b/v1/pcs/stored_endpoint.js index 5981aba3..e55575d2 100644 --- a/v1/pcs/stored_endpoint.js +++ b/v1/pcs/stored_endpoint.js @@ -3,6 +3,27 @@ const HyperSwitch = require('hyperswitch'); const URI = HyperSwitch.URI; const mwUtils = require('../../lib/mwUtil'); +const uuidUtils = require('../../lib/uuidUtils'); + +/** + * Checks whether the content has been modified since the timestamp + * in `if-unmodified-since` header of the request + * @param {Object} req the request + * @param {Object} res the response + * @return {boolean} true if content has beed modified + */ +function isModifiedSince(req, res) { + try { + if (req.headers['if-unmodified-since']) { + const jobTime = Date.parse(req.headers['if-unmodified-since']); + const revInfo = mwUtils.parseETag(res.headers.etag); + return revInfo && uuidUtils.getDate(revInfo.tid) >= jobTime; + } + } catch (e) { + // Ignore errors from date parsing + } + return false; +} class PCSEndpoint { constructor(options) { @@ -35,22 +56,23 @@ class PCSEndpoint { }); } - if (mwUtils.isNoCacheRequest(req)) { - return this._fetchFromPCSAndStore(hyper, req) - .tap((res) => { - this._injectCacheControl.bind(this)(res); - hyper.metrics.endTiming([ - 'pcs_getContent_latency', - 'pcs_getContent_latency_no_cache', - `pcs_getContent_latency_${rp.domain}` - ], startTime); - }); - } - return hyper.get({ uri: new URI([rp.domain, 'sys', 'key_value', this._options.name, rp.title]) }) .then((res) => { + if (mwUtils.isNoCacheRequest(req)) { + if (!isModifiedSince(req, res)) { + throw new HyperSwitch.HTTPError({ + status: 412, + body: { + type: 'precondition_failed', + detail: 'The precondition failed' + } + }); + } + return this._fetchFromPCS(hyper, req); + } + if (!rp.revision || `${mwUtils.parseETag(res.headers.etag).rev}` === `${rp.revision}`) { return res;