| File: System\Net\Http\Headers\RangeConditionHeaderValue.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Http\src\System.Net.Http.csproj (System.Net.Http) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class RangeConditionHeaderValue : ICloneable { // Exactly one of date and entityTag will be set. private readonly DateTimeOffset _date; private readonly EntityTagHeaderValue? _entityTag; public DateTimeOffset? Date => _entityTag is null ? _date : null; public EntityTagHeaderValue? EntityTag => _entityTag; public RangeConditionHeaderValue(DateTimeOffset date) { _date = date; } public RangeConditionHeaderValue(EntityTagHeaderValue entityTag) { ArgumentNullException.ThrowIfNull(entityTag); _entityTag = entityTag; } public RangeConditionHeaderValue(string entityTag) : this(new EntityTagHeaderValue(entityTag)) { } private RangeConditionHeaderValue(RangeConditionHeaderValue source) { Debug.Assert(source != null); _entityTag = source._entityTag; _date = source._date; } public override string ToString() => _entityTag?.ToString() ?? _date.ToString("r"); public override bool Equals([NotNullWhen(true)] object? obj) => obj is RangeConditionHeaderValue other && (_entityTag is null ? other._entityTag is null : _entityTag.Equals(other._entityTag)) && _date == other._date; public override int GetHashCode() => _entityTag?.GetHashCode() ?? _date.GetHashCode(); public static RangeConditionHeaderValue Parse(string input) { int index = 0; return (RangeConditionHeaderValue)GenericHeaderParser.RangeConditionParser.ParseValue( input, null, ref index); } public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out RangeConditionHeaderValue? parsedValue) { int index = 0; parsedValue = null; if (GenericHeaderParser.RangeConditionParser.TryParseValue(input, null, ref index, out object? output)) { parsedValue = (RangeConditionHeaderValue)output!; return true; } return false; } internal static int GetRangeConditionLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); parsedValue = null; // Make sure we have at least 2 characters if (string.IsNullOrEmpty(input) || (startIndex + 1 >= input.Length)) { return 0; } int current = startIndex; // Caller must remove leading whitespace. DateTimeOffset date = DateTimeOffset.MinValue; EntityTagHeaderValue? entityTag = null; // Entity tags are quoted strings optionally preceded by "W/". By looking at the first two character we // can determine whether the string is en entity tag or a date. char firstChar = input[current]; char secondChar = input[current + 1]; if ((firstChar == '\"') || (((firstChar == 'w') || (firstChar == 'W')) && (secondChar == '/'))) { // trailing whitespace is removed by GetEntityTagLength() int entityTagLength = EntityTagHeaderValue.GetEntityTagLength(input, current, out entityTag); if (entityTagLength == 0) { return 0; } current += entityTagLength; // RangeConditionHeaderValue only allows 1 value. There must be no delimiter/other chars after an // entity tag. if (current != input.Length) { return 0; } } else { if (!HttpDateParser.TryParse(input.AsSpan(current), out date)) { return 0; } // If we got a valid date, then the parser consumed the whole string (incl. trailing whitespace). current = input.Length; } if (entityTag == null) { parsedValue = new RangeConditionHeaderValue(date); } else { parsedValue = new RangeConditionHeaderValue(entityTag); } return current - startIndex; } object ICloneable.Clone() { return new RangeConditionHeaderValue(this); } } }