894 lines
29 KiB
C#
894 lines
29 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Http;
|
|
using Microsoft.AspNet.Http.Infrastructure;
|
|
using Microsoft.AspNet.PipelineCore.Collections;
|
|
|
|
namespace Microsoft.AspNet.PipelineCore.Infrastructure
|
|
{
|
|
internal struct HeaderSegment : IEquatable<HeaderSegment>
|
|
{
|
|
private readonly StringSegment _formatting;
|
|
private readonly StringSegment _data;
|
|
|
|
// <summary>
|
|
// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
|
// </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
|
|
}
|
|
|
|
[System.CodeDom.Compiler.GeneratedCode("App_Packages", "")]
|
|
internal struct HeaderSegmentCollection : IEnumerable<HeaderSegment>, IEquatable<HeaderSegmentCollection>
|
|
{
|
|
private readonly string[] _headers;
|
|
|
|
public HeaderSegmentCollection(string[] headers)
|
|
{
|
|
_headers = headers;
|
|
}
|
|
|
|
#region Equality members
|
|
|
|
public bool Equals(HeaderSegmentCollection other)
|
|
{
|
|
return 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 (_headers != null ? _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 string[] _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;
|
|
|
|
private static readonly string[] NoHeaders = new string[0];
|
|
|
|
public Enumerator(string[] headers)
|
|
{
|
|
_headers = headers ?? NoHeaders;
|
|
_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.Length)
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.CodeDom.Compiler.GeneratedCode("App_Packages", "")]
|
|
internal struct StringSegment : IEquatable<StringSegment>
|
|
{
|
|
private readonly string _buffer;
|
|
private readonly int _offset;
|
|
private readonly int _count;
|
|
|
|
// <summary>
|
|
// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
|
// </summary>
|
|
public StringSegment(string buffer, int offset, int count)
|
|
{
|
|
_buffer = buffer;
|
|
_offset = offset;
|
|
_count = count;
|
|
}
|
|
|
|
public string Buffer
|
|
{
|
|
get { return _buffer; }
|
|
}
|
|
|
|
public int Offset
|
|
{
|
|
get { return _offset; }
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { return _count; }
|
|
}
|
|
|
|
public string Value
|
|
{
|
|
get { return _offset == -1 ? null : _buffer.Substring(_offset, _count); }
|
|
}
|
|
|
|
public bool HasValue
|
|
{
|
|
get { return _offset != -1 && _count != 0 && _buffer != null; }
|
|
}
|
|
|
|
#region Equality members
|
|
|
|
public bool Equals(StringSegment other)
|
|
{
|
|
return string.Equals(_buffer, other._buffer) && _offset == other._offset && _count == other._count;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (ReferenceEquals(null, obj))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return obj is StringSegment && Equals((StringSegment)obj);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int hashCode = (_buffer != null ? _buffer.GetHashCode() : 0);
|
|
hashCode = (hashCode * 397) ^ _offset;
|
|
hashCode = (hashCode * 397) ^ _count;
|
|
return hashCode;
|
|
}
|
|
}
|
|
|
|
public static bool operator ==(StringSegment left, StringSegment right)
|
|
{
|
|
return left.Equals(right);
|
|
}
|
|
|
|
public static bool operator !=(StringSegment left, StringSegment right)
|
|
{
|
|
return !left.Equals(right);
|
|
}
|
|
|
|
#endregion
|
|
|
|
public bool StartsWith(string text, StringComparison comparisonType)
|
|
{
|
|
if (text == null)
|
|
{
|
|
throw new ArgumentNullException("text");
|
|
}
|
|
int textLength = text.Length;
|
|
if (!HasValue || _count < textLength)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return string.Compare(_buffer, _offset, text, 0, textLength, comparisonType) == 0;
|
|
}
|
|
|
|
public bool EndsWith(string text, StringComparison comparisonType)
|
|
{
|
|
if (text == null)
|
|
{
|
|
throw new ArgumentNullException("text");
|
|
}
|
|
int textLength = text.Length;
|
|
if (!HasValue || _count < textLength)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return string.Compare(_buffer, _offset + _count - textLength, text, 0, textLength, comparisonType) == 0;
|
|
}
|
|
|
|
public bool Equals(string text, StringComparison comparisonType)
|
|
{
|
|
if (text == null)
|
|
{
|
|
throw new ArgumentNullException("text");
|
|
}
|
|
int textLength = text.Length;
|
|
if (!HasValue || _count != textLength)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return string.Compare(_buffer, _offset, text, 0, textLength, comparisonType) == 0;
|
|
}
|
|
|
|
public string Substring(int offset, int length)
|
|
{
|
|
return _buffer.Substring(_offset + offset, length);
|
|
}
|
|
|
|
public StringSegment Subsegment(int offset, int length)
|
|
{
|
|
return new StringSegment(_buffer, _offset + offset, length);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Value ?? string.Empty;
|
|
}
|
|
}
|
|
|
|
internal static partial class ParsingHelpers
|
|
{
|
|
private static readonly Action<string, string, object> AddCookieCallback = (name, value, state) =>
|
|
{
|
|
var dictionary = (IDictionary<string, string>)state;
|
|
if (!dictionary.ContainsKey(name))
|
|
{
|
|
dictionary.Add(name, value);
|
|
}
|
|
};
|
|
|
|
private static readonly char[] SemicolonAndComma = new[] { ';', ',' };
|
|
|
|
internal static T GetItem<T>(HttpRequest request, string key)
|
|
{
|
|
object value;
|
|
return request.HttpContext.Items.TryGetValue(key, out value) ? (T)value : default(T);
|
|
}
|
|
|
|
internal static void SetItem<T>(HttpRequest request, string key, T value)
|
|
{
|
|
request.HttpContext.Items[key] = value;
|
|
}
|
|
|
|
internal static IDictionary<string, string> GetCookies(HttpRequest request)
|
|
{
|
|
var cookies = GetItem<IDictionary<string, string>>(request, "Microsoft.Owin.Cookies#dictionary");
|
|
if (cookies == null)
|
|
{
|
|
cookies = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
SetItem(request, "Microsoft.Owin.Cookies#dictionary", cookies);
|
|
}
|
|
|
|
string text = GetHeader(request.Headers, "Cookie");
|
|
if (GetItem<string>(request, "Microsoft.Owin.Cookies#text") != text)
|
|
{
|
|
cookies.Clear();
|
|
ParseDelimited(text, SemicolonAndComma, AddCookieCallback, cookies);
|
|
SetItem(request, "Microsoft.Owin.Cookies#text", text);
|
|
}
|
|
return cookies;
|
|
}
|
|
|
|
internal static void ParseCookies(string cookiesHeader, IDictionary<string, string> cookiesCollection)
|
|
{
|
|
ParseDelimited(cookiesHeader, SemicolonAndComma, AddCookieCallback, cookiesCollection);
|
|
}
|
|
|
|
internal static void ParseDelimited(string text, char[] delimiters, Action<string, string, object> callback, object state)
|
|
{
|
|
int textLength = text.Length;
|
|
int equalIndex = text.IndexOf('=');
|
|
if (equalIndex == -1)
|
|
{
|
|
equalIndex = textLength;
|
|
}
|
|
int scanIndex = 0;
|
|
while (scanIndex < textLength)
|
|
{
|
|
int delimiterIndex = text.IndexOfAny(delimiters, scanIndex);
|
|
if (delimiterIndex == -1)
|
|
{
|
|
delimiterIndex = textLength;
|
|
}
|
|
if (equalIndex < delimiterIndex)
|
|
{
|
|
while (scanIndex != equalIndex && char.IsWhiteSpace(text[scanIndex]))
|
|
{
|
|
++scanIndex;
|
|
}
|
|
string name = text.Substring(scanIndex, equalIndex - scanIndex);
|
|
string value = text.Substring(equalIndex + 1, delimiterIndex - equalIndex - 1);
|
|
callback(
|
|
Uri.UnescapeDataString(name.Replace('+', ' ')),
|
|
Uri.UnescapeDataString(value.Replace('+', ' ')),
|
|
state);
|
|
equalIndex = text.IndexOf('=', delimiterIndex);
|
|
if (equalIndex == -1)
|
|
{
|
|
equalIndex = textLength;
|
|
}
|
|
}
|
|
scanIndex = delimiterIndex + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static partial class ParsingHelpers
|
|
{
|
|
public static string GetHeader(IDictionary<string, string[]> headers, string key)
|
|
{
|
|
string[] values = GetHeaderUnmodified(headers, key);
|
|
return values == null ? null : string.Join(",", values);
|
|
}
|
|
|
|
public static IEnumerable<string> GetHeaderSplit(IDictionary<string, string[]> headers, string key)
|
|
{
|
|
string[] values = GetHeaderUnmodified(headers, key);
|
|
return values == null ? null : GetHeaderSplitImplementation(values);
|
|
}
|
|
|
|
private static IEnumerable<string> GetHeaderSplitImplementation(string[] values)
|
|
{
|
|
foreach (var segment in new HeaderSegmentCollection(values))
|
|
{
|
|
if (segment.Data.HasValue)
|
|
{
|
|
yield return DeQuote(segment.Data.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string[] GetHeaderUnmodified(IDictionary<string, string[]> headers, string key)
|
|
{
|
|
if (headers == null)
|
|
{
|
|
throw new ArgumentNullException("headers");
|
|
}
|
|
string[] values;
|
|
return headers.TryGetValue(key, out values) ? values : null;
|
|
}
|
|
|
|
public static void SetHeader(IDictionary<string, string[]> headers, string key, string value)
|
|
{
|
|
if (headers == null)
|
|
{
|
|
throw new ArgumentNullException("headers");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
throw new ArgumentNullException("key");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
headers.Remove(key);
|
|
}
|
|
else
|
|
{
|
|
headers[key] = new[] { value };
|
|
}
|
|
}
|
|
|
|
public static void SetHeaderJoined(IDictionary<string, string[]> headers, string key, params string[] values)
|
|
{
|
|
if (headers == null)
|
|
{
|
|
throw new ArgumentNullException("headers");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
throw new ArgumentNullException("key");
|
|
}
|
|
if (values == null || values.Length == 0)
|
|
{
|
|
headers.Remove(key);
|
|
}
|
|
else
|
|
{
|
|
headers[key] = new[] { string.Join(",", values.Select(value => QuoteIfNeeded(value))) };
|
|
}
|
|
}
|
|
|
|
// Quote items that contain comas and are not already quoted.
|
|
private static string QuoteIfNeeded(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
// Ignore
|
|
}
|
|
else if (value.Contains(','))
|
|
{
|
|
if (value[0] != '"' || value[value.Length - 1] != '"')
|
|
{
|
|
value = '"' + value + '"';
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public static void SetHeaderUnmodified(IDictionary<string, string[]> headers, string key, params string[] values)
|
|
{
|
|
if (headers == null)
|
|
{
|
|
throw new ArgumentNullException("headers");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
throw new ArgumentNullException("key");
|
|
}
|
|
if (values == null || values.Length == 0)
|
|
{
|
|
headers.Remove(key);
|
|
}
|
|
else
|
|
{
|
|
headers[key] = values;
|
|
}
|
|
}
|
|
|
|
public static void SetHeaderUnmodified(IDictionary<string, string[]> headers, string key, IEnumerable<string> values)
|
|
{
|
|
if (headers == null)
|
|
{
|
|
throw new ArgumentNullException("headers");
|
|
}
|
|
headers[key] = values.ToArray();
|
|
}
|
|
|
|
public static void AppendHeader(IDictionary<string, string[]> headers, string key, string values)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(values))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string existing = GetHeader(headers, key);
|
|
if (existing == null)
|
|
{
|
|
SetHeader(headers, key, values);
|
|
}
|
|
else
|
|
{
|
|
headers[key] = new[] { existing + "," + values };
|
|
}
|
|
}
|
|
|
|
public static void AppendHeaderJoined(IDictionary<string, string[]> headers, string key, params string[] values)
|
|
{
|
|
if (values == null || values.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string existing = GetHeader(headers, key);
|
|
if (existing == null)
|
|
{
|
|
SetHeaderJoined(headers, key, values);
|
|
}
|
|
else
|
|
{
|
|
headers[key] = new[] { existing + "," + string.Join(",", values.Select(value => QuoteIfNeeded(value))) };
|
|
}
|
|
}
|
|
|
|
public static void AppendHeaderUnmodified(IDictionary<string, string[]> headers, string key, params string[] values)
|
|
{
|
|
if (values == null || values.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string[] existing = GetHeaderUnmodified(headers, key);
|
|
if (existing == null)
|
|
{
|
|
SetHeaderUnmodified(headers, key, values);
|
|
}
|
|
else
|
|
{
|
|
SetHeaderUnmodified(headers, key, existing.Concat(values));
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static partial class ParsingHelpers
|
|
{
|
|
private static readonly Action<string, string, object> AppendItemCallback = (name, value, state) =>
|
|
{
|
|
var dictionary = (IDictionary<string, List<String>>)state;
|
|
|
|
List<string> existing;
|
|
if (!dictionary.TryGetValue(name, out existing))
|
|
{
|
|
dictionary.Add(name, new List<string>(1) { value });
|
|
}
|
|
else
|
|
{
|
|
existing.Add(value);
|
|
}
|
|
};
|
|
|
|
private static readonly char[] AmpersandAndSemicolon = new[] { '&', ';' };
|
|
|
|
internal static IDictionary<string, string[]> GetQuery(string queryString)
|
|
{
|
|
if (!string.IsNullOrEmpty(queryString) && queryString[0] == '?')
|
|
{
|
|
queryString = queryString.Substring(1);
|
|
}
|
|
var accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
|
ParseDelimited(queryString, AmpersandAndSemicolon, AppendItemCallback, accumulator);
|
|
return accumulator.ToDictionary(
|
|
item => item.Key,
|
|
item => item.Value.ToArray(),
|
|
StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
internal static IFormCollection GetForm(string text)
|
|
{
|
|
IDictionary<string, string[]> form = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
|
var accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
|
ParseDelimited(text, new[] { '&' }, AppendItemCallback, accumulator);
|
|
foreach (var kv in accumulator)
|
|
{
|
|
form.Add(kv.Key, kv.Value.ToArray());
|
|
}
|
|
return new FormCollection(form);
|
|
}
|
|
|
|
internal static string GetJoinedValue(IDictionary<string, string[]> store, string key)
|
|
{
|
|
string[] values = GetUnmodifiedValues(store, key);
|
|
return values == null ? null : string.Join(",", values);
|
|
}
|
|
|
|
internal static string[] GetUnmodifiedValues(IDictionary<string, string[]> store, string key)
|
|
{
|
|
if (store == null)
|
|
{
|
|
throw new ArgumentNullException("store");
|
|
}
|
|
string[] values;
|
|
return store.TryGetValue(key, out values) ? values : null;
|
|
}
|
|
}
|
|
|
|
internal static partial class ParsingHelpers
|
|
{
|
|
//internal static string GetHost(HttpRequest request)
|
|
//{
|
|
// IHeaderDictionary headers = request.Headers;
|
|
|
|
// string host = GetHeader(headers, "Host");
|
|
// if (!string.IsNullOrWhiteSpace(host))
|
|
// {
|
|
// return host;
|
|
// }
|
|
|
|
// string localIpAddress = request.LocalIpAddress ?? "localhost";
|
|
// var localPort = request.Get<string>(OwinConstants.CommonKeys.LocalPort);
|
|
// return string.IsNullOrWhiteSpace(localPort) ? localIpAddress : (localIpAddress + ":" + localPort);
|
|
//}
|
|
|
|
public static long? GetContentLength(IHeaderDictionary headers)
|
|
{
|
|
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
|
|
long value;
|
|
string rawValue = headers.Get(Constants.Headers.ContentLength);
|
|
if (!string.IsNullOrWhiteSpace(rawValue) &&
|
|
long.TryParse(rawValue, styles, CultureInfo.InvariantCulture, out value))
|
|
{
|
|
return value;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void SetContentLength(IHeaderDictionary headers, long? value)
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
headers[Constants.Headers.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
else
|
|
{
|
|
headers.Remove(Constants.Headers.ContentLength);
|
|
}
|
|
}
|
|
}
|
|
}
|