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 | ||
|  | } |