예제 #1
0
        private async Task <bool> ConditionalGetOrHeadIsValid(HttpContext httpContext)
        {
            _logger.LogInformation("Checking for conditional GET/HEAD.");

            if (httpContext.Request.Method != HttpMethod.Get.ToString() &&
                httpContext.Request.Method != HttpMethod.Head.ToString())
            {
                _logger.LogInformation("Not valid - method isn't GET or HEAD.");
                return(false);
            }

            // we should check ALL If-None-Match values (can be multiple eTags) (if available),
            // and the If-Modified-Since date (if available AND an eTag matches).  See issue #2 @Github.
            // So, this is a valid conditional GET/HEAD (304) if one of the ETags match and, if it's
            // available, the If-Modified-Since date is larger than what's saved.

            // if both headers are missing, we should
            // always return false - we don't need to check anything, and
            // can never return a 304 response
            if (!httpContext.Request.Headers.Keys.Contains(HeaderNames.IfNoneMatch) &&
                !httpContext.Request.Headers.Keys.Contains(HeaderNames.IfModifiedSince))
            {
                _logger.LogInformation("Not valid - no If-None-Match or If-Modified-Since headers.");
                return(false);
            }

            // generate the request key
            var storeKey = await _storeKeyGenerator.GenerateStoreKey(
                ConstructStoreKeyContext(httpContext.Request, _validationModelOptions));

            // find the validatorValue with this key in the store
            var validatorValue = await _store.GetAsync(storeKey);

            // if there is no validation value in the store, always
            // return false - we have nothing to compare to, and can
            // never return a 304 response
            if (validatorValue?.ETag == null)
            {
                _logger.LogInformation("No saved response found in store.");
                return(false);
            }

            if (httpContext.Request.Headers.Keys.Contains(HeaderNames.IfNoneMatch))
            {
                // check the ETags. If the Etag is present we should not check the If-Modified-Since header
                // see issue https://github.com/KevinDockx/HttpCacheHeaders/issues/82

                // cfr: "If none of the entity tags match, then the server MAY perform the requested method as if the
                // If-None-Match header field did not exist, but MUST also ignore any If-Modified-Since header field(s)
                // in the request. That is, if no entity tags match, then the server MUST NOT return a 304(Not Modified) response."

                return(CheckIfNoneMatchIsValid(httpContext, validatorValue));
            }

            _logger.LogInformation("No If-None-Match header, don't check ETag.");
            return(await CheckIfModifiedSinceIsValid(httpContext, validatorValue));
        }
예제 #2
0
        private async Task <bool> ConditionalGetOrHeadIsValid(HttpContext httpContext)
        {
            _logger.LogInformation("Checking for conditional GET/HEAD.");

            if (httpContext.Request.Method != HttpMethod.Get.ToString() &&
                httpContext.Request.Method != HttpMethod.Head.ToString())
            {
                _logger.LogInformation("Not valid - method isn't GET or HEAD.");
                return(false);
            }

            // we should check ALL If-None-Match values (can be multiple eTags) (if available),
            // and the If-Modified-Since date (if available AND an eTag matches).  See issue #2 @Github.
            // So, this is a valid conditional GET/HEAD (304) if one of the ETags match and, if it's
            // available, the If-Modified-Since date is larger than what's saved.

            // if both headers are missing, we should
            // always return false - we don't need to check anything, and
            // can never return a 304 response
            if (!httpContext.Request.Headers.Keys.Contains(HeaderNames.IfNoneMatch) &&
                !httpContext.Request.Headers.Keys.Contains(HeaderNames.IfModifiedSince))
            {
                _logger.LogInformation("Not valid - no If-None-Match or If-Modified-Since headers.");
                return(false);
            }

            // generate the request key
            var storeKey = await _storeKeyGenerator.GenerateStoreKey(
                ConstructStoreKeyContext(httpContext.Request, _validationModelOptions));

            // find the validatorValue with this key in the store
            var validatorValue = await _store.GetAsync(storeKey);

            // if there is no validation value in the store, always
            // return false - we have nothing to compare to, and can
            // never return a 304 response
            if (validatorValue?.ETag == null)
            {
                _logger.LogInformation("No saved response found in store.");
                return(false);
            }

            // check the ETags
            // return the combined result of all validators.
            return(CheckIfNoneMatchIsValid(httpContext, validatorValue) &&
                   await CheckIfModifiedSinceIsValid(httpContext, validatorValue));
        }
예제 #3
0
        // Key = generated from request URI & headers (if VaryBy is set, only use those headers)
        public async Task <EntityTagHeaderValue> GenerateETag(HttpContext context)
        {
            var storeKey          = (await _storeKeyGenerator.GenerateStoreKey(context)).ToString();
            var requestKeyAsBytes = Encoding.UTF8.GetBytes(storeKey);

            // combine both to generate an etag
            var combinedBytes = GetETagValue(requestKeyAsBytes);

            return(new ETag(_eTagType, combinedBytes).GetETag());
        }