Improve request and response cookie handling.

This commit is contained in:
Chris Ross 2014-03-18 10:21:12 -07:00
parent ca2ef860f5
commit ae9545a124
11 changed files with 103 additions and 66 deletions

2
.gitignore vendored
View File

@ -20,3 +20,5 @@ nuget.exe
*.userprefs
*DS_Store
*.ncrunchsolution
*.*sdf
*.ipch

View File

@ -15,6 +15,7 @@ namespace Microsoft.AspNet.Abstractions
public abstract long? ContentLength { get; set; }
public abstract string ContentType { get; set; }
public abstract IResponseCookiesCollection Cookies { get; }
public abstract Task WriteAsync(string data);
}
}

View File

@ -0,0 +1,37 @@

namespace Microsoft.AspNet.Abstractions
{
/// <summary>
/// A wrapper for the response Set-Cookie header
/// </summary>
public interface IResponseCookiesCollection
{
/// <summary>
/// Add a new cookie and value
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
void Append(string key, string value);
/// <summary>
/// Add a new cookie
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="options"></param>
void Append(string key, string value, CookieOptions options);
/// <summary>
/// Sets an expired cookie
/// </summary>
/// <param name="key"></param>
void Delete(string key);
/// <summary>
/// Sets an expired cookie
/// </summary>
/// <param name="key"></param>
/// <param name="options"></param>
void Delete(string key, CookieOptions options);
}
}

View File

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.PipelineCore.Collections
{
/// <summary>
/// A wrapper for the request Cookie header
/// </summary>
public class RequestCookieCollection : IEnumerable<KeyValuePair<string, string>>
{
/// <summary>
/// Create a new wrapper
/// </summary>
/// <param name="store"></param>
public RequestCookieCollection(IDictionary<string, string> store)
{
if (store == null)
{
throw new ArgumentNullException("store");
}
Store = store;
}
private IDictionary<string, string> Store { get; set; }
/// <summary>
/// Returns null rather than throwing KeyNotFoundException
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string this[string key]
{
get
{
string value;
Store.TryGetValue(key, out value);
return value;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return Store.GetEnumerator();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.PipelineCore.Infrastructure;
namespace Microsoft.AspNet.PipelineCore
namespace Microsoft.AspNet.PipelineCore.Collections
{
public class RequestCookiesCollection : IReadableStringCollection
{

View File

@ -3,20 +3,19 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Abstractions.Infrastructure;
using Microsoft.AspNet.Abstractions;
namespace Microsoft.AspNet.PipelineCore.Collections
namespace Microsoft.AspNet.Abstractions.Collections
{
/// <summary>
/// A wrapper for the response Set-Cookie header
/// </summary>
public class ResponseCookieCollection
public class ResponseCookiesCollection : IResponseCookiesCollection
{
/// <summary>
/// Create a new wrapper
/// </summary>
/// <param name="headers"></param>
public ResponseCookieCollection(IHeaderDictionary headers)
public ResponseCookiesCollection(IHeaderDictionary headers)
{
if (headers == null)
{

View File

@ -1,7 +1,9 @@
using System;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Abstractions.Infrastructure;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.HttpFeature;
using Microsoft.AspNet.PipelineCore.Collections;
using Microsoft.AspNet.PipelineCore.Infrastructure;
namespace Microsoft.AspNet.PipelineCore
@ -24,7 +26,7 @@ namespace Microsoft.AspNet.PipelineCore
get
{
var headers = _request.Fetch(_features).Headers;
string cookiesHeader = ParsingHelpers.GetHeader(headers, "Cookies") ?? "";
string cookiesHeader = ParsingHelpers.GetHeader(headers, Constants.Headers.Cookie) ?? "";
if (_cookiesCollection == null)
{

View File

@ -0,0 +1,35 @@
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Abstractions.Collections;
using Microsoft.AspNet.FeatureModel;
using Microsoft.AspNet.HttpFeature;
using Microsoft.AspNet.PipelineCore.Collections;
using Microsoft.AspNet.PipelineCore.Infrastructure;
namespace Microsoft.AspNet.PipelineCore
{
public class DefaultCanHasResponseCookies : ICanHasResponseCookies
{
private readonly IFeatureCollection _features;
private FeatureReference<IHttpResponseInformation> _request = FeatureReference<IHttpResponseInformation>.Default;
private IResponseCookiesCollection _cookiesCollection;
public DefaultCanHasResponseCookies(IFeatureCollection features)
{
_features = features;
}
public IResponseCookiesCollection Cookies
{
get
{
var headers = _request.Fetch(_features).Headers;
if (_cookiesCollection == null)
{
_cookiesCollection = new ResponseCookiesCollection(new HeaderDictionary(headers));
}
return _cookiesCollection;
}
}
}
}

View File

@ -16,6 +16,7 @@ namespace Microsoft.AspNet.PipelineCore
private readonly DefaultHttpContext _context;
private readonly IFeatureCollection _features;
private FeatureReference<IHttpResponseInformation> _response = FeatureReference<IHttpResponseInformation>.Default;
private FeatureReference<ICanHasResponseCookies> _canHasCookies = FeatureReference<ICanHasResponseCookies>.Default;
public DefaultHttpResponse(DefaultHttpContext context, IFeatureCollection features)
{
@ -28,6 +29,11 @@ namespace Microsoft.AspNet.PipelineCore
get { return _response.Fetch(_features); }
}
private ICanHasResponseCookies CanHasResponseCookies
{
get { return _canHasCookies.Fetch(_features) ?? _canHasCookies.Update(_features, new DefaultCanHasResponseCookies(_features)); }
}
public override HttpContext HttpContext { get { return _context; } }
public override int StatusCode
@ -79,6 +85,10 @@ namespace Microsoft.AspNet.PipelineCore
}
}
public override IResponseCookiesCollection Cookies
{
get { return CanHasResponseCookies.Cookies; }
}
public override Task WriteAsync(string data)
{
var bytes = Encoding.UTF8.GetBytes(data);

View File

@ -0,0 +1,10 @@
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.PipelineCore.Collections;
namespace Microsoft.AspNet.PipelineCore
{
public interface ICanHasResponseCookies
{
IResponseCookiesCollection Cookies { get; }
}
}

View File

@ -18,6 +18,7 @@ namespace Microsoft.AspNet.Abstractions.Infrastructure
internal const string ETag = "ETag";
internal const string Location = "Location";
internal const string ContentLength = "Content-Length";
internal const string Cookie = "Cookie";
internal const string SetCookie = "Set-Cookie";
internal const string Expires = "Expires";
}