private bool CheckIfModifiedSinceIsValid(HttpContext httpContext, ValidationValue validationValue) { if (httpContext.Request.Headers.Keys.Contains(HeaderNames.IfModifiedSince)) { // if the LastModified date is smaller than the IfModifiedSince date, // we can return a 304 Not Modified (If there's also a matching ETag). // By adding an If-Modified-Since date // to a GET/HEAD request, the consumer is stating that (s)he only wants the resource // to be returned if if has been modified after that. var ifModifiedSinceValue = httpContext.Request.Headers[HeaderNames.IfModifiedSince].ToString(); _logger.LogInformation($"Checking If-Modified-Since: {ifModifiedSinceValue}"); if (DateTimeOffset.TryParseExact( ifModifiedSinceValue, "r", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AdjustToUniversal, out var parsedIfModifiedSince)) { return(validationValue.LastModified.CompareTo(parsedIfModifiedSince) <= 0); } // can only check if we can parse it. Invalid values must be ignored. _logger.LogInformation("Cannot parse If-Modified-Since value as date, header is ignored."); return(true); } // if there is no IfModifiedSince header, the check is valid. _logger.LogInformation("No If-Modified-Since header."); return(true); }
private bool CheckIfUnmodifiedSinceIsValid(HttpContext httpContext, ValidationValue validationValue) { // Either the ETag matches (or one of them), or there was no IfMatch header. // Continue with checking the IfUnModifiedSince header, if it exists. if (httpContext.Request.Headers.Keys.Contains(HeaderNames.IfUnmodifiedSince)) { // if the LastModified date is smaller than the IfUnmodifiedSince date, // the precondition is valid. var ifUnModifiedSinceValue = httpContext.Request.Headers[HeaderNames.IfUnmodifiedSince].ToString(); _logger.LogInformation($"Checking If-Unmodified-Since: {ifUnModifiedSinceValue}"); if (DateTimeOffset.TryParseExact( ifUnModifiedSinceValue, "r", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AdjustToUniversal, out var parsedIfUnModifiedSince)) { // If the LastModified date is smaller than the IfUnmodifiedSince date, // the precondition is valid. return(validationValue.LastModified.CompareTo(parsedIfUnModifiedSince) < 0); } // can only check if we can parse it. Invalid values must be ignored. _logger.LogInformation("Cannot parse If-Unmodified-Since value as date, header is ignored."); return(true); } // if there is no IfUnmodifiedSince header, the check is valid. _logger.LogInformation("No If-Unmodified-Since header."); return(true); }
private bool CheckIfMatchIsValid(HttpContext httpContext, ValidationValue validationValue) { if (!httpContext.Request.Headers.Keys.Contains(HeaderNames.IfMatch)) { // if there is no IfMatch header, the tag precondition is valid. _logger.LogInformation("No If-Match header, don't check ETag."); return(true); } _logger.LogInformation("Checking If-Match."); var ifMatchHeaderValue = httpContext.Request.Headers[HeaderNames.IfMatch].ToString().Trim(); _logger.LogInformation($"Checking If-Match: {ifMatchHeaderValue}."); // if the value is *, the check is valid. if (ifMatchHeaderValue == "*") { return(true); } // otherwise, check the actual ETag(s) var eTagsFromIfMatchHeader = ifMatchHeaderValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // check the ETag. If one of the ETags matches, the // ETag precondition is valid. // for concurrency checks, we use the strong // comparison function. if (eTagsFromIfMatchHeader.Any(eTag => ETagsMatch(validationValue.ETag, eTag.Trim(), true))) { _logger.LogInformation($"ETag valid: {validationValue.ETag}."); return(true); } // if there is an IfMatch header but none of the ETags match, // the precondition is already invalid. We don't have to // continue checking. _logger.LogInformation("Not valid. No match found for ETag."); return(false); }
private bool CheckIfNoneMatchIsValid(HttpContext httpContext, ValidationValue validationValue) { if (!httpContext.Request.Headers.Keys.Contains(HeaderNames.IfNoneMatch)) { // if there is no IfNoneMatch header, the tag precondition is valid. _logger.LogInformation("No If-None-Match header, don't check ETag."); return(true); } _logger.LogInformation("Checking If-None-Match."); var ifNoneMatchHeaderValue = httpContext.Request.Headers[HeaderNames.IfNoneMatch].ToString().Trim(); _logger.LogInformation($"Checking If-None-Match: {ifNoneMatchHeaderValue}."); // if the value is *, the check is valid. if (ifNoneMatchHeaderValue == "*") { return(true); } var eTagsFromIfNoneMatchHeader = ifNoneMatchHeaderValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // check the ETag. If one of the ETags matches, we're good to // go and can return a 304 Not Modified. // For conditional GET/HEAD, we use weak comparison. if (eTagsFromIfNoneMatchHeader.Any(eTag => ETagsMatch(validationValue.ETag, eTag.Trim(), false))) { _logger.LogInformation($"ETag valid: {validationValue.ETag}."); return(true); } // if there is an IfNoneMatch header, but none of the eTags match, we don't take the // If-Modified-Since headers into account. // // 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." _logger.LogInformation("Not valid. No match found for ETag."); return(false); }