diff --git a/.gitignore b/.gitignore index 2554a1fc23..8bc217058d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ nuget.exe *.userprefs *DS_Store *.ncrunchsolution +*.*sdf +*.ipch \ No newline at end of file diff --git a/src/Microsoft.AspNet.Abstractions/HttpResponse.cs b/src/Microsoft.AspNet.Abstractions/HttpResponse.cs index de84899fda..8df6277482 100644 --- a/src/Microsoft.AspNet.Abstractions/HttpResponse.cs +++ b/src/Microsoft.AspNet.Abstractions/HttpResponse.cs @@ -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); } } diff --git a/src/Microsoft.AspNet.Abstractions/IResponseCookiesCollection.cs b/src/Microsoft.AspNet.Abstractions/IResponseCookiesCollection.cs new file mode 100644 index 0000000000..8e38bb92dd --- /dev/null +++ b/src/Microsoft.AspNet.Abstractions/IResponseCookiesCollection.cs @@ -0,0 +1,37 @@ + +namespace Microsoft.AspNet.Abstractions +{ + /// + /// A wrapper for the response Set-Cookie header + /// + public interface IResponseCookiesCollection + { + /// + /// Add a new cookie and value + /// + /// + /// + void Append(string key, string value); + + /// + /// Add a new cookie + /// + /// + /// + /// + void Append(string key, string value, CookieOptions options); + + /// + /// Sets an expired cookie + /// + /// + void Delete(string key); + + /// + /// Sets an expired cookie + /// + /// + /// + void Delete(string key, CookieOptions options); + } +} diff --git a/src/Microsoft.AspNet.PipelineCore/Collections/RequestCookieCollection.cs b/src/Microsoft.AspNet.PipelineCore/Collections/RequestCookieCollection.cs deleted file mode 100644 index 91b1577f28..0000000000 --- a/src/Microsoft.AspNet.PipelineCore/Collections/RequestCookieCollection.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Microsoft.AspNet.PipelineCore.Collections -{ - /// - /// A wrapper for the request Cookie header - /// - public class RequestCookieCollection : IEnumerable> - { - /// - /// Create a new wrapper - /// - /// - public RequestCookieCollection(IDictionary store) - { - if (store == null) - { - throw new ArgumentNullException("store"); - } - - Store = store; - } - - private IDictionary Store { get; set; } - - /// - /// Returns null rather than throwing KeyNotFoundException - /// - /// - /// - public string this[string key] - { - get - { - string value; - Store.TryGetValue(key, out value); - return value; - } - } - - /// - /// - /// - /// - public IEnumerator> GetEnumerator() - { - return Store.GetEnumerator(); - } - - /// - /// - /// - /// - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Microsoft.AspNet.PipelineCore/RequestCookiesCollection.cs b/src/Microsoft.AspNet.PipelineCore/Collections/RequestCookiesCollection.cs similarity index 97% rename from src/Microsoft.AspNet.PipelineCore/RequestCookiesCollection.cs rename to src/Microsoft.AspNet.PipelineCore/Collections/RequestCookiesCollection.cs index 0f84ea704f..40445bb31d 100644 --- a/src/Microsoft.AspNet.PipelineCore/RequestCookiesCollection.cs +++ b/src/Microsoft.AspNet.PipelineCore/Collections/RequestCookiesCollection.cs @@ -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 { diff --git a/src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookieCollection.cs b/src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookiesCollection.cs similarity index 96% rename from src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookieCollection.cs rename to src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookiesCollection.cs index 78703285cf..1a11469597 100644 --- a/src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookieCollection.cs +++ b/src/Microsoft.AspNet.PipelineCore/Collections/ResponseCookiesCollection.cs @@ -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 { /// /// A wrapper for the response Set-Cookie header /// - public class ResponseCookieCollection + public class ResponseCookiesCollection : IResponseCookiesCollection { /// /// Create a new wrapper /// /// - public ResponseCookieCollection(IHeaderDictionary headers) + public ResponseCookiesCollection(IHeaderDictionary headers) { if (headers == null) { diff --git a/src/Microsoft.AspNet.PipelineCore/DefaultCanHasRequestCookies.cs b/src/Microsoft.AspNet.PipelineCore/DefaultCanHasRequestCookies.cs index df33085763..b6071c4d41 100644 --- a/src/Microsoft.AspNet.PipelineCore/DefaultCanHasRequestCookies.cs +++ b/src/Microsoft.AspNet.PipelineCore/DefaultCanHasRequestCookies.cs @@ -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) { diff --git a/src/Microsoft.AspNet.PipelineCore/DefaultCanHasResponseCookies.cs b/src/Microsoft.AspNet.PipelineCore/DefaultCanHasResponseCookies.cs new file mode 100644 index 0000000000..ee176b7af9 --- /dev/null +++ b/src/Microsoft.AspNet.PipelineCore/DefaultCanHasResponseCookies.cs @@ -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 _request = FeatureReference.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; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs b/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs index c1ec42c5d0..4351f7a18d 100644 --- a/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs +++ b/src/Microsoft.AspNet.PipelineCore/DefaultHttpResponse.cs @@ -16,6 +16,7 @@ namespace Microsoft.AspNet.PipelineCore private readonly DefaultHttpContext _context; private readonly IFeatureCollection _features; private FeatureReference _response = FeatureReference.Default; + private FeatureReference _canHasCookies = FeatureReference.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); diff --git a/src/Microsoft.AspNet.PipelineCore/ICanHasResponseCookies.cs b/src/Microsoft.AspNet.PipelineCore/ICanHasResponseCookies.cs new file mode 100644 index 0000000000..23c73d4d2a --- /dev/null +++ b/src/Microsoft.AspNet.PipelineCore/ICanHasResponseCookies.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.PipelineCore.Collections; + +namespace Microsoft.AspNet.PipelineCore +{ + public interface ICanHasResponseCookies + { + IResponseCookiesCollection Cookies { get; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.PipelineCore/Infrastructure/Constants.cs b/src/Microsoft.AspNet.PipelineCore/Infrastructure/Constants.cs index 114ae660e3..cc92a10786 100644 --- a/src/Microsoft.AspNet.PipelineCore/Infrastructure/Constants.cs +++ b/src/Microsoft.AspNet.PipelineCore/Infrastructure/Constants.cs @@ -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"; }