public CachingHandler(ICacheStore cacheStore) { _cacheStore = cacheStore; VaryHeaderStore = new InMemoryVaryHeaderStore(); DefaultVaryHeaders = new string[]{"Accept"}; }
public CachingHandler(ICacheStore cacheStore) { _cacheStore = cacheStore; UseConditionalPut = true; VaryHeaderStore = new InMemoryVaryHeaderStore(); DefaultVaryHeaders = new string[]{"Accept"}; ResponseValidator = (response) => { // 13.4 //Unless specifically constrained by a cache-control (section 14.9) directive, a caching system MAY always store // a successful response (see section 13.8) as a cache entry, MAY return it without validation if it // is fresh, and MAY return it after successful validation. If there is neither a cache validator nor an // explicit expiration time associated with a response, we do not expect it to be cached, but certain caches MAY violate this expectation // (for example, when little or no network connectivity is available). if (!response.StatusCode.IsIn(_cacheableStatuses)) return ResponseValidationResult.NotCacheable; if (!response.IsSuccessStatusCode || response.Headers.CacheControl == null || response.Headers.CacheControl.NoStore || response.Headers.CacheControl.NoCache) return ResponseValidationResult.NotCacheable; response.Headers.Date = response.Headers.Date ?? DateTimeOffset.UtcNow; // this also helps in cache creation var dateTimeOffset = response.Headers.Date; if(response.Content == null) return ResponseValidationResult.NotCacheable; if (response.Headers.CacheControl.MaxAge == null && response.Headers.CacheControl.SharedMaxAge == null && response.Content.Headers.Expires == null) return ResponseValidationResult.NotCacheable; if (response.Content.Headers.Expires != null && response.Content.Headers.Expires < DateTimeOffset.UtcNow) return response.Headers.CacheControl.MustRevalidate ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; if (response.Headers.CacheControl.MaxAge != null && DateTimeOffset.UtcNow > response.Headers.Date.Value.Add(response.Headers.CacheControl.MaxAge.Value)) return response.Headers.CacheControl.MustRevalidate ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; if (response.Headers.CacheControl.SharedMaxAge != null && DateTimeOffset.UtcNow > response.Headers.Date.Value.Add(response.Headers.CacheControl.SharedMaxAge.Value)) return response.Headers.CacheControl.MustRevalidate ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; return ResponseValidationResult.OK; }; _ignoreRequestRules = (request) => { if (!request.Method.IsIn(HttpMethod.Get, HttpMethod.Put)) return true; // client can tell CachingHandler not to do caching for a particular request if(request.Headers.CacheControl!=null) { if (request.Headers.CacheControl.NoCache || request.Headers.CacheControl.NoStore) return true; } return false; }; ResponseStoragePreparationRules = (response) => { // 14.9.3 // If a response includes both an Expires header and a max-age directive, // the max-age directive overrides the Expires header, even if the Expires header is more restrictive. if(response.Content.Headers.Expires!=null && (response.Headers.CacheControl.MaxAge != null || response.Headers.CacheControl.SharedMaxAge!=null)) { response.Content.Headers.Expires = null; } }; }
public CachingHandler(ICacheStore cacheStore) { _cacheStore = cacheStore; UseConditionalPut = true; MustRevalidateByDefault = true; VaryHeaderStore = new InMemoryVaryHeaderStore(); DefaultVaryHeaders = new string[]{"Accept"}; ResponseValidator = (response) => { // 13.4 //Unless specifically constrained by a cache-control (section 14.9) directive, a caching system MAY always store // a successful response (see section 13.8) as a cache entry, MAY return it without validation if it // is fresh, and MAY return it after successful validation. If there is neither a cache validator nor an // explicit expiration time associated with a response, we do not expect it to be cached, but certain caches MAY violate this expectation // (for example, when little or no network connectivity is available). // 14.9.1 // If the no-cache directive does not specify a field-name, then a cache MUST NOT use the response to satisfy a subsequent request without // successful revalidation with the origin server. This allows an origin server to prevent caching // even by caches that have been configured to return stale responses to client requests. //If the no-cache directive does specify one or more field-names, then a cache MAY use the response // to satisfy a subsequent request, subject to any other restrictions on caching. However, the specified // field-name(s) MUST NOT be sent in the response to a subsequent request without successful revalidation // with the origin server. This allows an origin server to prevent the re-use of certain header fields in a response, while still allowing caching of the rest of the response. if (!response.StatusCode.IsIn(_cacheableStatuses)) return ResponseValidationResult.NotCacheable; if (!response.IsSuccessStatusCode || response.Headers.CacheControl == null || response.Headers.CacheControl.NoStore) // || response.Headers.CacheControl.NoCache was removed. See issue return ResponseValidationResult.NotCacheable; response.Headers.Date = response.Headers.Date ?? DateTimeOffset.UtcNow; // this also helps in cache creation var dateTimeOffset = response.Headers.Date; if(response.Content == null) return ResponseValidationResult.NotCacheable; if (response.Headers.CacheControl.MaxAge == null && response.Headers.CacheControl.SharedMaxAge == null && response.Content.Headers.Expires == null) return ResponseValidationResult.NotCacheable; if(response.Headers.CacheControl.NoCache) return ResponseValidationResult.MustRevalidate; // here we use if (response.Content.Headers.Expires != null && response.Content.Headers.Expires < DateTimeOffset.UtcNow) return response.Headers.CacheControl.ShouldRevalidate(MustRevalidateByDefault) ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; if (response.Headers.CacheControl.MaxAge != null && DateTimeOffset.UtcNow > response.Headers.Date.Value.Add(response.Headers.CacheControl.MaxAge.Value)) return response.Headers.CacheControl.ShouldRevalidate(MustRevalidateByDefault) ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; if (response.Headers.CacheControl.SharedMaxAge != null && DateTimeOffset.UtcNow > response.Headers.Date.Value.Add(response.Headers.CacheControl.SharedMaxAge.Value)) return response.Headers.CacheControl.ShouldRevalidate(MustRevalidateByDefault) ? ResponseValidationResult.MustRevalidate : ResponseValidationResult.Stale; return ResponseValidationResult.OK; }; _ignoreRequestRules = (request) => { if (!request.Method.IsIn(HttpMethod.Get, HttpMethod.Put)) return true; // client can tell CachingHandler not to do caching for a particular request if(request.Headers.CacheControl!=null) { if (request.Headers.CacheControl.NoStore) return true; } return false; }; ResponseStoragePreparationRules = (response) => { // 14.9.3 // If a response includes both an Expires header and a max-age directive, // the max-age directive overrides the Expires header, even if the Expires header is more restrictive. if(response.Content.Headers.Expires!=null && (response.Headers.CacheControl.MaxAge != null || response.Headers.CacheControl.SharedMaxAge!=null)) { response.Content.Headers.Expires = null; } }; }