#167: Update cookie APIs to use shared core.
This commit is contained in:
parent
09d6ab03bc
commit
e818783ba4
|
|
@ -4,8 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Microsoft.AspNet.Http.Core.Infrastructure;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Http.Core.Collections
|
namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
{
|
{
|
||||||
|
|
@ -73,12 +72,20 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
return _dictionary.TryGetValue(key, out value) ? new[] { value } : null;
|
return _dictionary.TryGetValue(key, out value) ? new[] { value } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly char[] SemicolonAndComma = { ';', ',' };
|
public void Reparse(IList<string> values)
|
||||||
|
|
||||||
public void Reparse(string cookiesHeader)
|
|
||||||
{
|
{
|
||||||
_dictionary.Clear();
|
_dictionary.Clear();
|
||||||
ParsingHelpers.ParseDelimited(cookiesHeader, SemicolonAndComma, AddCookieCallback, _dictionary);
|
|
||||||
|
IList<CookieHeaderValue> cookies;
|
||||||
|
if (CookieHeaderValue.TryParseList(values, out cookies))
|
||||||
|
{
|
||||||
|
foreach (var cookie in cookies)
|
||||||
|
{
|
||||||
|
var name = Uri.UnescapeDataString(cookie.Name.Replace('+', ' '));
|
||||||
|
var value = Uri.UnescapeDataString(cookie.Value.Replace('+', ' '));
|
||||||
|
_dictionary[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
|
public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
|
||||||
|
|
@ -93,14 +100,5 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
using Microsoft.Framework.WebEncoders;
|
using Microsoft.Framework.WebEncoders;
|
||||||
|
|
@ -34,7 +33,11 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public void Append(string key, string value)
|
public void Append(string key, string value)
|
||||||
{
|
{
|
||||||
Headers.AppendValues(HeaderNames.SetCookie, UrlEncoder.Default.UrlEncode(key) + "=" + UrlEncoder.Default.UrlEncode(value) + "; path=/");
|
Headers.AppendValues(HeaderNames.SetCookie,
|
||||||
|
new SetCookieHeaderValue(
|
||||||
|
UrlEncoder.Default.UrlEncode(key),
|
||||||
|
UrlEncoder.Default.UrlEncode(value))
|
||||||
|
{ Path = "/" }.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -45,23 +48,17 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
public void Append(string key, string value, [NotNull] CookieOptions options)
|
public void Append(string key, string value, [NotNull] CookieOptions options)
|
||||||
{
|
{
|
||||||
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
Headers.AppendValues(HeaderNames.SetCookie,
|
||||||
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
|
new SetCookieHeaderValue(
|
||||||
bool expiresHasValue = options.Expires.HasValue;
|
UrlEncoder.Default.UrlEncode(key),
|
||||||
|
UrlEncoder.Default.UrlEncode(value))
|
||||||
string setCookieValue = string.Concat(
|
{
|
||||||
UrlEncoder.Default.UrlEncode(key),
|
Domain = options.Domain,
|
||||||
"=",
|
Path = options.Path,
|
||||||
UrlEncoder.Default.UrlEncode(value ?? string.Empty),
|
Expires = options.Expires,
|
||||||
!domainHasValue ? null : "; domain=",
|
Secure = options.Secure,
|
||||||
!domainHasValue ? null : options.Domain,
|
HttpOnly = options.HttpOnly,
|
||||||
!pathHasValue ? null : "; path=",
|
}.ToString());
|
||||||
!pathHasValue ? null : options.Path,
|
|
||||||
!expiresHasValue ? null : "; expires=",
|
|
||||||
!expiresHasValue ? null : options.Expires.Value.ToString("ddd, dd-MMM-yyyy HH:mm:ss ", CultureInfo.InvariantCulture) + "GMT",
|
|
||||||
!options.Secure ? null : "; secure",
|
|
||||||
!options.HttpOnly ? null : "; HttpOnly");
|
|
||||||
Headers.AppendValues(HeaderNames.SetCookie, setCookieValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -70,9 +67,10 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
public void Delete(string key)
|
public void Delete(string key)
|
||||||
{
|
{
|
||||||
Func<string, bool> predicate = value => value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase);
|
var encodedKeyPlusEquals = UrlEncoder.Default.UrlEncode(key) + "=";
|
||||||
|
Func<string, bool> predicate = value => value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var deleteCookies = new[] { UrlEncoder.Default.UrlEncode(key) + "=; expires=Thu, 01-Jan-1970 00:00:00 GMT" };
|
var deleteCookies = new[] { encodedKeyPlusEquals + "; expires=Thu, 01-Jan-1970 00:00:00 GMT" };
|
||||||
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);
|
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);
|
||||||
if (existingValues == null || existingValues.Count == 0)
|
if (existingValues == null || existingValues.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -91,6 +89,7 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
public void Delete(string key, [NotNull] CookieOptions options)
|
public void Delete(string key, [NotNull] CookieOptions options)
|
||||||
{
|
{
|
||||||
|
var encodedKeyPlusEquals = UrlEncoder.Default.UrlEncode(key) + "=";
|
||||||
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
||||||
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
|
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
|
||||||
|
|
||||||
|
|
@ -98,18 +97,18 @@ namespace Microsoft.AspNet.Http.Core.Collections
|
||||||
if (domainHasValue)
|
if (domainHasValue)
|
||||||
{
|
{
|
||||||
rejectPredicate = value =>
|
rejectPredicate = value =>
|
||||||
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
|
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
|
||||||
value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
|
value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
}
|
}
|
||||||
else if (pathHasValue)
|
else if (pathHasValue)
|
||||||
{
|
{
|
||||||
rejectPredicate = value =>
|
rejectPredicate = value =>
|
||||||
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
|
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
|
||||||
value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
|
value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rejectPredicate = value => value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase);
|
rejectPredicate = value => value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);
|
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);
|
||||||
|
|
|
||||||
|
|
@ -496,71 +496,6 @@ namespace Microsoft.AspNet.Http.Core.Infrastructure
|
||||||
|
|
||||||
internal static class ParsingHelpers
|
internal static 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 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetHeader(IDictionary<string, string[]> headers, string key)
|
public static string GetHeader(IDictionary<string, string[]> headers, string key)
|
||||||
{
|
{
|
||||||
string[] values = GetHeaderUnmodified(headers, key);
|
string[] values = GetHeaderUnmodified(headers, key);
|
||||||
|
|
@ -729,48 +664,6 @@ namespace Microsoft.AspNet.Http.Core.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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([NotNull] IDictionary<string, string[]> store, string key)
|
|
||||||
{
|
|
||||||
string[] values;
|
|
||||||
return store.TryGetValue(key, out values) ? values : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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([NotNull] IHeaderDictionary headers)
|
public static long? GetContentLength([NotNull] IHeaderDictionary headers)
|
||||||
{
|
{
|
||||||
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
|
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNet.FeatureModel;
|
using Microsoft.AspNet.FeatureModel;
|
||||||
using Microsoft.AspNet.Http.Core.Collections;
|
using Microsoft.AspNet.Http.Core.Collections;
|
||||||
using Microsoft.AspNet.Http.Core.Infrastructure;
|
using Microsoft.AspNet.Http.Core.Infrastructure;
|
||||||
|
|
@ -15,7 +16,7 @@ namespace Microsoft.AspNet.Http.Core
|
||||||
{
|
{
|
||||||
private readonly IFeatureCollection _features;
|
private readonly IFeatureCollection _features;
|
||||||
private readonly FeatureReference<IHttpRequestFeature> _request = FeatureReference<IHttpRequestFeature>.Default;
|
private readonly FeatureReference<IHttpRequestFeature> _request = FeatureReference<IHttpRequestFeature>.Default;
|
||||||
private string _cookiesHeader;
|
private string[] _cookieHeaders;
|
||||||
private RequestCookiesCollection _cookiesCollection;
|
private RequestCookiesCollection _cookiesCollection;
|
||||||
private IReadableStringCollection _cookies;
|
private IReadableStringCollection _cookies;
|
||||||
|
|
||||||
|
|
@ -44,18 +45,22 @@ namespace Microsoft.AspNet.Http.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
var headers = _request.Fetch(_features).Headers;
|
var headers = _request.Fetch(_features).Headers;
|
||||||
string cookiesHeader = ParsingHelpers.GetHeader(headers, HeaderNames.Cookie) ?? string.Empty;
|
string[] values;
|
||||||
|
if (!headers.TryGetValue(HeaderNames.Cookie, out values))
|
||||||
|
{
|
||||||
|
values = new string[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (_cookiesCollection == null)
|
if (_cookiesCollection == null)
|
||||||
{
|
{
|
||||||
|
_cookieHeaders = values;
|
||||||
_cookiesCollection = new RequestCookiesCollection();
|
_cookiesCollection = new RequestCookiesCollection();
|
||||||
_cookiesCollection.Reparse(cookiesHeader);
|
_cookiesCollection.Reparse(values);
|
||||||
_cookiesHeader = cookiesHeader;
|
|
||||||
}
|
}
|
||||||
else if (!string.Equals(_cookiesHeader, cookiesHeader, StringComparison.Ordinal))
|
else if (!Enumerable.SequenceEqual(_cookieHeaders, values, StringComparer.Ordinal))
|
||||||
{
|
{
|
||||||
_cookiesCollection.Reparse(cookiesHeader);
|
_cookieHeaders = values;
|
||||||
_cookiesHeader = cookiesHeader;
|
_cookiesCollection.Reparse(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _cookiesCollection;
|
return _cookiesCollection;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue