Skip to content

Commit e818783

Browse files
committed
#167: Update cookie APIs to use shared core.
1 parent 09d6ab0 commit e818783

File tree

4 files changed

+48
-153
lines changed

4 files changed

+48
-153
lines changed

src/Microsoft.AspNet.Http.Core/Collections/RequestCookiesCollection.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
using System;
55
using System.Collections;
66
using System.Collections.Generic;
7-
using Microsoft.AspNet.Http;
8-
using Microsoft.AspNet.Http.Core.Infrastructure;
7+
using Microsoft.Net.Http.Headers;
98

109
namespace Microsoft.AspNet.Http.Core.Collections
1110
{
@@ -73,12 +72,20 @@ public IList<string> GetValues(string key)
7372
return _dictionary.TryGetValue(key, out value) ? new[] { value } : null;
7473
}
7574

76-
private static readonly char[] SemicolonAndComma = { ';', ',' };
77-
78-
public void Reparse(string cookiesHeader)
75+
public void Reparse(IList<string> values)
7976
{
8077
_dictionary.Clear();
81-
ParsingHelpers.ParseDelimited(cookiesHeader, SemicolonAndComma, AddCookieCallback, _dictionary);
78+
79+
IList<CookieHeaderValue> cookies;
80+
if (CookieHeaderValue.TryParseList(values, out cookies))
81+
{
82+
foreach (var cookie in cookies)
83+
{
84+
var name = Uri.UnescapeDataString(cookie.Name.Replace('+', ' '));
85+
var value = Uri.UnescapeDataString(cookie.Value.Replace('+', ' '));
86+
_dictionary[name] = value;
87+
}
88+
}
8289
}
8390

8491
public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
@@ -93,14 +100,5 @@ IEnumerator IEnumerable.GetEnumerator()
93100
{
94101
return GetEnumerator();
95102
}
96-
97-
private static readonly Action<string, string, object> AddCookieCallback = (name, value, state) =>
98-
{
99-
var dictionary = (IDictionary<string, string>)state;
100-
if (!dictionary.ContainsKey(name))
101-
{
102-
dictionary.Add(name, value);
103-
}
104-
};
105103
}
106104
}

src/Microsoft.AspNet.Http.Core/Collections/ResponseCookies.cs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Globalization;
76
using System.Linq;
87
using Microsoft.Framework.Internal;
98
using Microsoft.Framework.WebEncoders;
@@ -34,7 +33,11 @@ public ResponseCookies([NotNull] IHeaderDictionary headers)
3433
/// <param name="value"></param>
3534
public void Append(string key, string value)
3635
{
37-
Headers.AppendValues(HeaderNames.SetCookie, UrlEncoder.Default.UrlEncode(key) + "=" + UrlEncoder.Default.UrlEncode(value) + "; path=/");
36+
Headers.AppendValues(HeaderNames.SetCookie,
37+
new SetCookieHeaderValue(
38+
UrlEncoder.Default.UrlEncode(key),
39+
UrlEncoder.Default.UrlEncode(value))
40+
{ Path = "/" }.ToString());
3841
}
3942

4043
/// <summary>
@@ -45,23 +48,17 @@ public void Append(string key, string value)
4548
/// <param name="options"></param>
4649
public void Append(string key, string value, [NotNull] CookieOptions options)
4750
{
48-
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
49-
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
50-
bool expiresHasValue = options.Expires.HasValue;
51-
52-
string setCookieValue = string.Concat(
53-
UrlEncoder.Default.UrlEncode(key),
54-
"=",
55-
UrlEncoder.Default.UrlEncode(value ?? string.Empty),
56-
!domainHasValue ? null : "; domain=",
57-
!domainHasValue ? null : options.Domain,
58-
!pathHasValue ? null : "; path=",
59-
!pathHasValue ? null : options.Path,
60-
!expiresHasValue ? null : "; expires=",
61-
!expiresHasValue ? null : options.Expires.Value.ToString("ddd, dd-MMM-yyyy HH:mm:ss ", CultureInfo.InvariantCulture) + "GMT",
62-
!options.Secure ? null : "; secure",
63-
!options.HttpOnly ? null : "; HttpOnly");
64-
Headers.AppendValues(HeaderNames.SetCookie, setCookieValue);
51+
Headers.AppendValues(HeaderNames.SetCookie,
52+
new SetCookieHeaderValue(
53+
UrlEncoder.Default.UrlEncode(key),
54+
UrlEncoder.Default.UrlEncode(value))
55+
{
56+
Domain = options.Domain,
57+
Path = options.Path,
58+
Expires = options.Expires,
59+
Secure = options.Secure,
60+
HttpOnly = options.HttpOnly,
61+
}.ToString());
6562
}
6663

6764
/// <summary>
@@ -70,9 +67,10 @@ public void Append(string key, string value, [NotNull] CookieOptions options)
7067
/// <param name="key"></param>
7168
public void Delete(string key)
7269
{
73-
Func<string, bool> predicate = value => value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase);
70+
var encodedKeyPlusEquals = UrlEncoder.Default.UrlEncode(key) + "=";
71+
Func<string, bool> predicate = value => value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase);
7472

75-
var deleteCookies = new[] { UrlEncoder.Default.UrlEncode(key) + "=; expires=Thu, 01-Jan-1970 00:00:00 GMT" };
73+
var deleteCookies = new[] { encodedKeyPlusEquals + "; expires=Thu, 01-Jan-1970 00:00:00 GMT" };
7674
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);
7775
if (existingValues == null || existingValues.Count == 0)
7876
{
@@ -91,25 +89,26 @@ public void Delete(string key)
9189
/// <param name="options"></param>
9290
public void Delete(string key, [NotNull] CookieOptions options)
9391
{
92+
var encodedKeyPlusEquals = UrlEncoder.Default.UrlEncode(key) + "=";
9493
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
9594
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
9695

9796
Func<string, bool> rejectPredicate;
9897
if (domainHasValue)
9998
{
10099
rejectPredicate = value =>
101-
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
100+
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
102101
value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
103102
}
104103
else if (pathHasValue)
105104
{
106105
rejectPredicate = value =>
107-
value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase) &&
106+
value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase) &&
108107
value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
109108
}
110109
else
111110
{
112-
rejectPredicate = value => value.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase);
111+
rejectPredicate = value => value.StartsWith(encodedKeyPlusEquals, StringComparison.OrdinalIgnoreCase);
113112
}
114113

115114
IList<string> existingValues = Headers.GetValues(HeaderNames.SetCookie);

src/Microsoft.AspNet.Http.Core/Infrastructure/ParsingHelpers.cs

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -496,71 +496,6 @@ public override string ToString()
496496

497497
internal static class ParsingHelpers
498498
{
499-
private static readonly Action<string, string, object> AddCookieCallback = (name, value, state) =>
500-
{
501-
var dictionary = (IDictionary<string, string>)state;
502-
if (!dictionary.ContainsKey(name))
503-
{
504-
dictionary.Add(name, value);
505-
}
506-
};
507-
508-
private static readonly char[] SemicolonAndComma = new[] { ';', ',' };
509-
510-
internal static T GetItem<T>(HttpRequest request, string key)
511-
{
512-
object value;
513-
return request.HttpContext.Items.TryGetValue(key, out value) ? (T)value : default(T);
514-
}
515-
516-
internal static void SetItem<T>(HttpRequest request, string key, T value)
517-
{
518-
request.HttpContext.Items[key] = value;
519-
}
520-
521-
internal static void ParseCookies(string cookiesHeader, IDictionary<string, string> cookiesCollection)
522-
{
523-
ParseDelimited(cookiesHeader, SemicolonAndComma, AddCookieCallback, cookiesCollection);
524-
}
525-
526-
internal static void ParseDelimited(string text, char[] delimiters, Action<string, string, object> callback, object state)
527-
{
528-
int textLength = text.Length;
529-
int equalIndex = text.IndexOf('=');
530-
if (equalIndex == -1)
531-
{
532-
equalIndex = textLength;
533-
}
534-
int scanIndex = 0;
535-
while (scanIndex < textLength)
536-
{
537-
int delimiterIndex = text.IndexOfAny(delimiters, scanIndex);
538-
if (delimiterIndex == -1)
539-
{
540-
delimiterIndex = textLength;
541-
}
542-
if (equalIndex < delimiterIndex)
543-
{
544-
while (scanIndex != equalIndex && char.IsWhiteSpace(text[scanIndex]))
545-
{
546-
++scanIndex;
547-
}
548-
string name = text.Substring(scanIndex, equalIndex - scanIndex);
549-
string value = text.Substring(equalIndex + 1, delimiterIndex - equalIndex - 1);
550-
callback(
551-
Uri.UnescapeDataString(name.Replace('+', ' ')),
552-
Uri.UnescapeDataString(value.Replace('+', ' ')),
553-
state);
554-
equalIndex = text.IndexOf('=', delimiterIndex);
555-
if (equalIndex == -1)
556-
{
557-
equalIndex = textLength;
558-
}
559-
}
560-
scanIndex = delimiterIndex + 1;
561-
}
562-
}
563-
564499
public static string GetHeader(IDictionary<string, string[]> headers, string key)
565500
{
566501
string[] values = GetHeaderUnmodified(headers, key);
@@ -729,48 +664,6 @@ public static void AppendHeaderUnmodified([NotNull] IDictionary<string, string[]
729664
}
730665
}
731666

732-
private static readonly Action<string, string, object> AppendItemCallback = (name, value, state) =>
733-
{
734-
var dictionary = (IDictionary<string, List<String>>)state;
735-
736-
List<string> existing;
737-
if (!dictionary.TryGetValue(name, out existing))
738-
{
739-
dictionary.Add(name, new List<string>(1) { value });
740-
}
741-
else
742-
{
743-
existing.Add(value);
744-
}
745-
};
746-
747-
internal static string GetJoinedValue(IDictionary<string, string[]> store, string key)
748-
{
749-
string[] values = GetUnmodifiedValues(store, key);
750-
return values == null ? null : string.Join(",", values);
751-
}
752-
753-
internal static string[] GetUnmodifiedValues([NotNull] IDictionary<string, string[]> store, string key)
754-
{
755-
string[] values;
756-
return store.TryGetValue(key, out values) ? values : null;
757-
}
758-
759-
//internal static string GetHost(HttpRequest request)
760-
//{
761-
// IHeaderDictionary headers = request.Headers;
762-
763-
// string host = GetHeader(headers, "Host");
764-
// if (!string.IsNullOrWhiteSpace(host))
765-
// {
766-
// return host;
767-
// }
768-
769-
// string localIpAddress = request.LocalIpAddress ?? "localhost";
770-
// var localPort = request.Get<string>(OwinConstants.CommonKeys.LocalPort);
771-
// return string.IsNullOrWhiteSpace(localPort) ? localIpAddress : (localIpAddress + ":" + localPort);
772-
//}
773-
774667
public static long? GetContentLength([NotNull] IHeaderDictionary headers)
775668
{
776669
const NumberStyles styles = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite;

src/Microsoft.AspNet.Http.Core/RequestCookiesFeature.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Linq;
67
using Microsoft.AspNet.FeatureModel;
78
using Microsoft.AspNet.Http.Core.Collections;
89
using Microsoft.AspNet.Http.Core.Infrastructure;
@@ -15,7 +16,7 @@ public class RequestCookiesFeature : IRequestCookiesFeature
1516
{
1617
private readonly IFeatureCollection _features;
1718
private readonly FeatureReference<IHttpRequestFeature> _request = FeatureReference<IHttpRequestFeature>.Default;
18-
private string _cookiesHeader;
19+
private string[] _cookieHeaders;
1920
private RequestCookiesCollection _cookiesCollection;
2021
private IReadableStringCollection _cookies;
2122

@@ -44,18 +45,22 @@ public IReadableStringCollection Cookies
4445
}
4546

4647
var headers = _request.Fetch(_features).Headers;
47-
string cookiesHeader = ParsingHelpers.GetHeader(headers, HeaderNames.Cookie) ?? string.Empty;
48+
string[] values;
49+
if (!headers.TryGetValue(HeaderNames.Cookie, out values))
50+
{
51+
values = new string[0];
52+
}
4853

4954
if (_cookiesCollection == null)
5055
{
56+
_cookieHeaders = values;
5157
_cookiesCollection = new RequestCookiesCollection();
52-
_cookiesCollection.Reparse(cookiesHeader);
53-
_cookiesHeader = cookiesHeader;
58+
_cookiesCollection.Reparse(values);
5459
}
55-
else if (!string.Equals(_cookiesHeader, cookiesHeader, StringComparison.Ordinal))
60+
else if (!Enumerable.SequenceEqual(_cookieHeaders, values, StringComparer.Ordinal))
5661
{
57-
_cookiesCollection.Reparse(cookiesHeader);
58-
_cookiesHeader = cookiesHeader;
62+
_cookieHeaders = values;
63+
_cookiesCollection.Reparse(values);
5964
}
6065

6166
return _cookiesCollection;

0 commit comments

Comments
 (0)