'use strict'
var CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\s*?no-cache\s*?(?:,|$)/
module.exports = fresh
function fresh (reqHeaders, resHeaders) {
var modifiedSince = reqHeaders['if-modified-since']
var noneMatch = reqHeaders['if-none-match']
if (!modifiedSince && !noneMatch) {
return false
}
var cacheControl = reqHeaders['cache-control']
if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {
return false
}
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 (modifiedSince) {
var lastModified = resHeaders['last-modified']
var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince))
if (modifiedStale) {
return false
}
}
return true
}
function parseHttpDate (date) {
var timestamp = date && Date.parse(date)
return typeof timestamp === 'number'
? timestamp
: NaN
}
function parseTokenList (str) {
var end = 0
var list = []
var start = 0
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
}
}
list.push(str.substring(start, end))
return list
}