| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 | /*! * fresh * Copyright(c) 2012 TJ Holowaychuk * Copyright(c) 2016-2017 Douglas Christopher Wilson * MIT Licensed */'use strict'/** * RegExp to check for no-cache token in Cache-Control. * @private */var CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\s*?no-cache\s*?(?:,|$)//** * Module exports. * @public */module.exports = fresh/** * Check freshness of the response using request and response headers. * * @param {Object} reqHeaders * @param {Object} resHeaders * @return {Boolean} * @public */function fresh (reqHeaders, resHeaders) {  // fields  var modifiedSince = reqHeaders['if-modified-since']  var noneMatch = reqHeaders['if-none-match']  // unconditional request  if (!modifiedSince && !noneMatch) {    return false  }  // Always return stale when Cache-Control: no-cache  // to support end-to-end reload requests  // https://tools.ietf.org/html/rfc2616#section-14.9.4  var cacheControl = reqHeaders['cache-control']  if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {    return false  }  // if-none-match  if (noneMatch && noneMatch !== '*') {    var etag = resHeaders['etag']    if (!etag) {      return false    }    var etagStale = true    var matches = parseTokenList(noneMatch)    for (var i = 0; i < matches.length; i++) {      var match = matches[i]      if (match === etag || match === 'W/' + etag || 'W/' + match === etag) {        etagStale = false        break      }    }    if (etagStale) {      return false    }  }  // if-modified-since  if (modifiedSince) {    var lastModified = resHeaders['last-modified']    var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince))    if (modifiedStale) {      return false    }  }  return true}/** * Parse an HTTP Date into a number. * * @param {string} date * @private */function parseHttpDate (date) {  var timestamp = date && Date.parse(date)  // istanbul ignore next: guard against date.js Date.parse patching  return typeof timestamp === 'number'    ? timestamp    : NaN}/** * Parse a HTTP token list. * * @param {string} str * @private */function parseTokenList (str) {  var end = 0  var list = []  var start = 0  // gather tokens  for (var i = 0, len = str.length; i < len; i++) {    switch (str.charCodeAt(i)) {      case 0x20: /*   */        if (start === end) {          start = end = i + 1        }        break      case 0x2c: /* , */        list.push(str.substring(start, end))        start = end = i + 1        break      default:        end = i + 1        break    }  }  // final token  list.push(str.substring(start, end))  return list}
 |