166 lines
5.0 KiB
C#
166 lines
5.0 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
namespace Microsoft.Net.Http.Headers
|
|
{
|
|
public class RangeConditionHeaderValue
|
|
{
|
|
private static readonly HttpHeaderParser<RangeConditionHeaderValue> Parser
|
|
= new GenericHeaderParser<RangeConditionHeaderValue>(false, GetRangeConditionLength);
|
|
|
|
private DateTimeOffset? _lastModified;
|
|
private EntityTagHeaderValue _entityTag;
|
|
|
|
private RangeConditionHeaderValue()
|
|
{
|
|
// Used by the parser to create a new instance of this type.
|
|
}
|
|
|
|
public RangeConditionHeaderValue(DateTimeOffset lastModified)
|
|
{
|
|
_lastModified = lastModified;
|
|
}
|
|
|
|
public RangeConditionHeaderValue(EntityTagHeaderValue entityTag)
|
|
{
|
|
if (entityTag == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(entityTag));
|
|
}
|
|
|
|
_entityTag = entityTag;
|
|
}
|
|
|
|
public RangeConditionHeaderValue(string entityTag)
|
|
: this(new EntityTagHeaderValue(entityTag))
|
|
{
|
|
}
|
|
|
|
public DateTimeOffset? LastModified
|
|
{
|
|
get { return _lastModified; }
|
|
}
|
|
|
|
public EntityTagHeaderValue EntityTag
|
|
{
|
|
get { return _entityTag; }
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if (_entityTag == null)
|
|
{
|
|
return HttpRuleParser.DateToString(_lastModified.Value);
|
|
}
|
|
return _entityTag.ToString();
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
var other = obj as RangeConditionHeaderValue;
|
|
|
|
if (other == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_entityTag == null)
|
|
{
|
|
return (other._lastModified != null) && (_lastModified.Value == other._lastModified.Value);
|
|
}
|
|
|
|
return _entityTag.Equals(other._entityTag);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
if (_entityTag == null)
|
|
{
|
|
return _lastModified.Value.GetHashCode();
|
|
}
|
|
|
|
return _entityTag.GetHashCode();
|
|
}
|
|
|
|
public static RangeConditionHeaderValue Parse(string input)
|
|
{
|
|
var index = 0;
|
|
return Parser.ParseValue(input, ref index);
|
|
}
|
|
|
|
public static bool TryParse(string input, out RangeConditionHeaderValue parsedValue)
|
|
{
|
|
var index = 0;
|
|
return Parser.TryParseValue(input, ref index, out parsedValue);
|
|
}
|
|
|
|
private static int GetRangeConditionLength(string input, int startIndex, out RangeConditionHeaderValue parsedValue)
|
|
{
|
|
Contract.Requires(startIndex >= 0);
|
|
|
|
parsedValue = null;
|
|
|
|
// Make sure we have at least 2 characters
|
|
if (string.IsNullOrEmpty(input) || (startIndex + 1 >= input.Length))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
var current = startIndex;
|
|
|
|
// Caller must remove leading whitespaces.
|
|
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.
|
|
var firstChar = input[current];
|
|
var secondChar = input[current + 1];
|
|
|
|
if ((firstChar == '\"') || (((firstChar == 'w') || (firstChar == 'W')) && (secondChar == '/')))
|
|
{
|
|
// trailing whitespaces are removed by GetEntityTagLength()
|
|
var entityTagLength = EntityTagHeaderValue.GetEntityTagLength(input, current, out entityTag);
|
|
|
|
if (entityTagLength == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
current = 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 (!HttpRuleParser.TryStringToDate(input.Substring(current), out date))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// If we got a valid date, then the parser consumed the whole string (incl. trailing whitespaces).
|
|
current = input.Length;
|
|
}
|
|
|
|
parsedValue = new RangeConditionHeaderValue();
|
|
if (entityTag == null)
|
|
{
|
|
parsedValue._lastModified = date;
|
|
}
|
|
else
|
|
{
|
|
parsedValue._entityTag = entityTag;
|
|
}
|
|
|
|
return current - startIndex;
|
|
}
|
|
}
|
|
} |