3 * Copyright(c) 2012 TJ Holowaychuk
4 * Copyright(c) 2016-2017 Douglas Christopher Wilson
11 * RegExp to check for no-cache token in Cache-Control.
15 var CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\s*?no-cache\s*?(?:,|$)/
22 module.exports = fresh
25 * Check freshness of the response using request and response headers.
27 * @param {Object} reqHeaders
28 * @param {Object} resHeaders
33 function fresh (reqHeaders, resHeaders) {
35 var modifiedSince = reqHeaders['if-modified-since']
36 var noneMatch = reqHeaders['if-none-match']
38 // unconditional request
39 if (!modifiedSince && !noneMatch) {
43 // Always return stale when Cache-Control: no-cache
44 // to support end-to-end reload requests
45 // https://tools.ietf.org/html/rfc2616#section-14.9.4
46 var cacheControl = reqHeaders['cache-control']
47 if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) {
52 if (noneMatch && noneMatch !== '*') {
53 var etag = resHeaders['etag']
60 var matches = parseTokenList(noneMatch)
61 for (var i = 0; i < matches.length; i++) {
62 var match = matches[i]
63 if (match === etag || match === 'W/' + etag || 'W/' + match === etag) {
76 var lastModified = resHeaders['last-modified']
77 var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince))
88 * Parse an HTTP Date into a number.
90 * @param {string} date
94 function parseHttpDate (date) {
95 var timestamp = date && Date.parse(date)
97 // istanbul ignore next: guard against date.js Date.parse patching
98 return typeof timestamp === 'number'
104 * Parse a HTTP token list.
106 * @param {string} str
110 function parseTokenList (str) {
116 for (var i = 0, len = str.length; i < len; i++) {
117 switch (str.charCodeAt(i)) {
124 list.push(str.substring(start, end))
134 list.push(str.substring(start, end))