| |
| |
| |
| |
| |
|
|
|
|
| '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) {
|
| if (noneMatch === '*') {
|
| return true
|
| }
|
| var etag = resHeaders.etag
|
|
|
| if (!etag) {
|
| return false
|
| }
|
|
|
| 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) {
|
| return true
|
| }
|
| }
|
|
|
| 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
|
| }
|
|
|