#167: Update cookie APIs to use shared core.

This commit is contained in:
Chris Ross 2015-04-10 12:06:09 -07:00
parent 09d6ab03bc
commit e818783ba4
4 changed files with 48 additions and 153 deletions

View File

@ -4,8 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core.Infrastructure;
using Microsoft.Net.Http.Headers;
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;
}
private static readonly char[] SemicolonAndComma = { ';', ',' };
public void Reparse(string cookiesHeader)
public void Reparse(IList<string> values)
{
_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()
@ -93,14 +100,5 @@ namespace Microsoft.AspNet.Http.Core.Collections
{
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);
}
};
}
}

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
@ -34,7 +33,11 @@ namespace Microsoft.AspNet.Http.Core.Collections
/// <param name="value"></param>
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>
@ -45,23 +48,17 @@ namespace Microsoft.AspNet.Http.Core.Collections
/// <param name="options"></param>
public void Append(string key, string value, [NotNull] CookieOptions options)
{
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
bool expiresHasValue = options.Expires.HasValue;
string setCookieValue = string.Concat(
UrlEncoder.Default.UrlEncode(key),
"=",
UrlEncoder.Default.UrlEncode(value ?? string.Empty),
!domainHasValue ? null : "; domain=",
!domainHasValue ? null : options.Domain,
!pathHasValue ? null : "; path=",
!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);
Headers.AppendValues(HeaderNames.SetCookie,
new SetCookieHeaderValue(
UrlEncoder.Default.UrlEncode(key),
UrlEncoder.Default.UrlEncode(value))
{
Domain = options.Domain,
Path = options.Path,
Expires = options.Expires,
Secure = options.Secure,
HttpOnly = options.HttpOnly,
}.ToString());
}
/// <summary>
@ -70,9 +67,10 @@ namespace Microsoft.AspNet.Http.Core.Collections
/// <param name="key"></param>
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);
if (existingValues == null || existingValues.Count == 0)
{
@ -91,6 +89,7 @@ namespace Microsoft.AspNet.Http.Core.Collections
/// <param name="options"></param>
public void Delete(string key, [NotNull] CookieOptions options)
{
var encodedKeyPlusEquals = UrlEncoder.Default.UrlEncode(key) + "=";
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
@ -98,18 +97,18 @@ namespace Microsoft.AspNet.Http.Core.Collections
if (domainHasValue)
{
rejectPredicate = value =>
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
}
else if (pathHasValue)
{
rejectPredicate = value =>
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
}
else
{
rejectPredicate = value => value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase);
rejectPredicate = value => value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase);
}
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);

View File

@ -496,71 +496,6 @@ namespace Microsoft.AspNet.Http.Core.Infrastructure
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)
{
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)
{
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.Http.Core.Collections;
using Microsoft.AspNet.Http.Core.Infrastructure;
@ -15,7 +16,7 @@ namespace Microsoft.AspNet.Http.Core
{
private readonly IFeatureCollection _features;
private readonly FeatureReference<IHttpRequestFeature> _request = FeatureReference<IHttpRequestFeature>.Default;
private string _cookiesHeader;
private string[] _cookieHeaders;
private RequestCookiesCollection _cookiesCollection;
private IReadableStringCollection _cookies;
@ -44,18 +45,22 @@ namespace Microsoft.AspNet.Http.Core
}
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)
{
_cookieHeaders = values;
_cookiesCollection = new RequestCookiesCollection();
_cookiesCollection.Reparse(cookiesHeader);
_cookiesHeader = cookiesHeader;
_cookiesCollection.Reparse(values);
}
else if (!string.Equals(_cookiesHeader, cookiesHeader, StringComparison.Ordinal))
else if (!Enumerable.SequenceEqual(_cookieHeaders, values, StringComparer.Ordinal))
{
_cookiesCollection.Reparse(cookiesHeader);
_cookiesHeader = cookiesHeader;
_cookieHeaders = values;
_cookiesCollection.Reparse(values);
}
return _cookiesCollection;