You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					138 lines
				
				2.6 KiB
			
		
		
			
		
	
	
					138 lines
				
				2.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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
							 | 
						||
| 
								 | 
							
								}
							 |