Remove duplication of parsing helper

This commit is contained in:
John Luo 2017-05-18 11:20:26 -07:00
parent 07470d41b1
commit 9313a02aa8
4 changed files with 5 additions and 412 deletions

View File

@ -6,13 +6,13 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Http.Internal
{
internal struct HeaderSegment : IEquatable<HeaderSegment>
public struct HeaderSegment : IEquatable<HeaderSegment>
{
private readonly StringSegment _formatting;
private readonly StringSegment _data;
// <summary>
// Initializes a new instance of the <see cref="HeaderSegment/> structure.
// Initializes a new instance of the <see cref="HeaderSegment"/> structure.
// </summary>
public HeaderSegment(StringSegment formatting, StringSegment data)
{

View File

@ -8,7 +8,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Http.Internal
{
internal struct HeaderSegmentCollection : IEnumerable<HeaderSegment>, IEquatable<HeaderSegmentCollection>
public struct HeaderSegmentCollection : IEnumerable<HeaderSegment>, IEquatable<HeaderSegmentCollection>
{
private readonly StringValues _headers;
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Http.Internal
return GetEnumerator();
}
internal struct Enumerator : IEnumerator<HeaderSegment>
public struct Enumerator : IEnumerator<HeaderSegment>
{
private readonly StringValues _headers;
private int _index;

View File

@ -8,7 +8,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Http.Internal
{
internal static class ParsingHelpers
public static class ParsingHelpers
{
public static StringValues GetHeader(IHeaderDictionary headers, string key)
{

View File

@ -1,407 +0,0 @@
// 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.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http.Internal
{
internal struct HeaderSegment : IEquatable<HeaderSegment>
{
private readonly StringSegment _formatting;
private readonly StringSegment _data;
// <summary>
// Initializes a new instance of the <see cref="HeaderSegment"/> structure.
// </summary>
public HeaderSegment(StringSegment formatting, StringSegment data)
{
_formatting = formatting;
_data = data;
}
public StringSegment Formatting
{
get { return _formatting; }
}
public StringSegment Data
{
get { return _data; }
}
#region Equality members
public bool Equals(HeaderSegment other)
{
return _formatting.Equals(other._formatting) && _data.Equals(other._data);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is HeaderSegment && Equals((HeaderSegment)obj);
}
public override int GetHashCode()
{
unchecked
{
return (_formatting.GetHashCode() * 397) ^ _data.GetHashCode();
}
}
public static bool operator ==(HeaderSegment left, HeaderSegment right)
{
return left.Equals(right);
}
public static bool operator !=(HeaderSegment left, HeaderSegment right)
{
return !left.Equals(right);
}
#endregion
}
internal struct HeaderSegmentCollection : IEnumerable<HeaderSegment>, IEquatable<HeaderSegmentCollection>
{
private readonly StringValues _headers;
public HeaderSegmentCollection(StringValues headers)
{
_headers = headers;
}
#region Equality members
public bool Equals(HeaderSegmentCollection other)
{
return StringValues.Equals(_headers, other._headers);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is HeaderSegmentCollection && Equals((HeaderSegmentCollection)obj);
}
public override int GetHashCode()
{
return (!StringValues.IsNullOrEmpty(_headers) ? _headers.GetHashCode() : 0);
}
public static bool operator ==(HeaderSegmentCollection left, HeaderSegmentCollection right)
{
return left.Equals(right);
}
public static bool operator !=(HeaderSegmentCollection left, HeaderSegmentCollection right)
{
return !left.Equals(right);
}
#endregion
public Enumerator GetEnumerator()
{
return new Enumerator(_headers);
}
IEnumerator<HeaderSegment> IEnumerable<HeaderSegment>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal struct Enumerator : IEnumerator<HeaderSegment>
{
private readonly StringValues _headers;
private int _index;
private string _header;
private int _headerLength;
private int _offset;
private int _leadingStart;
private int _leadingEnd;
private int _valueStart;
private int _valueEnd;
private int _trailingStart;
private Mode _mode;
public Enumerator(StringValues headers)
{
_headers = headers;
_header = string.Empty;
_headerLength = -1;
_index = -1;
_offset = -1;
_leadingStart = -1;
_leadingEnd = -1;
_valueStart = -1;
_valueEnd = -1;
_trailingStart = -1;
_mode = Mode.Leading;
}
private enum Mode
{
Leading,
Value,
ValueQuoted,
Trailing,
Produce,
}
private enum Attr
{
Value,
Quote,
Delimiter,
Whitespace
}
public HeaderSegment Current
{
get
{
return new HeaderSegment(
new StringSegment(_header, _leadingStart, _leadingEnd - _leadingStart),
new StringSegment(_header, _valueStart, _valueEnd - _valueStart));
}
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
}
public bool MoveNext()
{
while (true)
{
if (_mode == Mode.Produce)
{
_leadingStart = _trailingStart;
_leadingEnd = -1;
_valueStart = -1;
_valueEnd = -1;
_trailingStart = -1;
if (_offset == _headerLength &&
_leadingStart != -1 &&
_leadingStart != _offset)
{
// Also produce trailing whitespace
_leadingEnd = _offset;
return true;
}
_mode = Mode.Leading;
}
// if end of a string
if (_offset == _headerLength)
{
++_index;
_offset = -1;
_leadingStart = 0;
_leadingEnd = -1;
_valueStart = -1;
_valueEnd = -1;
_trailingStart = -1;
// if that was the last string
if (_index == _headers.Count)
{
// no more move nexts
return false;
}
// grab the next string
_header = _headers[_index] ?? string.Empty;
_headerLength = _header.Length;
}
while (true)
{
++_offset;
char ch = _offset == _headerLength ? (char)0 : _header[_offset];
// todo - array of attrs
Attr attr = char.IsWhiteSpace(ch) ? Attr.Whitespace : ch == '\"' ? Attr.Quote : (ch == ',' || ch == (char)0) ? Attr.Delimiter : Attr.Value;
switch (_mode)
{
case Mode.Leading:
switch (attr)
{
case Attr.Delimiter:
_leadingEnd = _offset;
_mode = Mode.Produce;
break;
case Attr.Quote:
_leadingEnd = _offset;
_valueStart = _offset;
_mode = Mode.ValueQuoted;
break;
case Attr.Value:
_leadingEnd = _offset;
_valueStart = _offset;
_mode = Mode.Value;
break;
case Attr.Whitespace:
// more
break;
}
break;
case Mode.Value:
switch (attr)
{
case Attr.Quote:
_mode = Mode.ValueQuoted;
break;
case Attr.Delimiter:
_valueEnd = _offset;
_trailingStart = _offset;
_mode = Mode.Produce;
break;
case Attr.Value:
// more
break;
case Attr.Whitespace:
_valueEnd = _offset;
_trailingStart = _offset;
_mode = Mode.Trailing;
break;
}
break;
case Mode.ValueQuoted:
switch (attr)
{
case Attr.Quote:
_mode = Mode.Value;
break;
case Attr.Delimiter:
if (ch == (char)0)
{
_valueEnd = _offset;
_trailingStart = _offset;
_mode = Mode.Produce;
}
break;
case Attr.Value:
case Attr.Whitespace:
// more
break;
}
break;
case Mode.Trailing:
switch (attr)
{
case Attr.Delimiter:
_mode = Mode.Produce;
break;
case Attr.Quote:
// back into value
_trailingStart = -1;
_valueEnd = -1;
_mode = Mode.ValueQuoted;
break;
case Attr.Value:
// back into value
_trailingStart = -1;
_valueEnd = -1;
_mode = Mode.Value;
break;
case Attr.Whitespace:
// more
break;
}
break;
}
if (_mode == Mode.Produce)
{
return true;
}
}
}
}
public void Reset()
{
_index = 0;
_offset = 0;
_leadingStart = 0;
_leadingEnd = 0;
_valueStart = 0;
_valueEnd = 0;
}
}
}
internal static class ParsingHelpers
{
public static StringValues GetHeaderSplit(IHeaderDictionary headers, string key)
{
var values = GetHeaderUnmodified(headers, key);
return new StringValues(GetHeaderSplitImplementation(values).ToArray());
}
private static IEnumerable<string> GetHeaderSplitImplementation(StringValues values)
{
foreach (var segment in new HeaderSegmentCollection(values))
{
if (segment.Data.HasValue)
{
yield return DeQuote(segment.Data.Value);
}
}
}
public static StringValues GetHeaderUnmodified(IHeaderDictionary headers, string key)
{
if (headers == null)
{
throw new ArgumentNullException(nameof(headers));
}
StringValues values;
return headers.TryGetValue(key, out values) ? values : StringValues.Empty;
}
private static string DeQuote(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
// Ignore
}
else if (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
}
return value;
}
}
}