React to string[] -> StringValues changes.

This commit is contained in:
Chris R 2015-08-28 12:59:00 -07:00
parent 40ca61b640
commit 803ec38073
9 changed files with 434 additions and 426 deletions

View File

@ -8,6 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Framework.Primitives;
// ReSharper disable AccessToModifiedClosure // ReSharper disable AccessToModifiedClosure
@ -55,13 +56,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public string Path { get; set; } public string Path { get; set; }
public string QueryString { get; set; } public string QueryString { get; set; }
public string HttpVersion { get; set; } public string HttpVersion { get; set; }
public IDictionary<string, string[]> RequestHeaders { get; set; } public IDictionary<string, StringValues> RequestHeaders { get; set; }
public MessageBody MessageBody { get; set; } public MessageBody MessageBody { get; set; }
public Stream RequestBody { get; set; } public Stream RequestBody { get; set; }
public int StatusCode { get; set; } public int StatusCode { get; set; }
public string ReasonPhrase { get; set; } public string ReasonPhrase { get; set; }
public IDictionary<string, string[]> ResponseHeaders { get; set; } public IDictionary<string, StringValues> ResponseHeaders { get; set; }
public Stream ResponseBody { get; set; } public Stream ResponseBody { get; set; }
public Stream DuplexStream { get; set; } public Stream DuplexStream { get; set; }
@ -357,7 +358,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
if (_responseStarted) return; if (_responseStarted) return;
string[] expect; StringValues expect;
if (HttpVersion.Equals("HTTP/1.1") && if (HttpVersion.Equals("HTTP/1.1") &&
RequestHeaders.TryGetValue("Expect", out expect) && RequestHeaders.TryGetValue("Expect", out expect) &&
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase)) (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
@ -444,7 +445,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private Tuple<ArraySegment<byte>, IDisposable> CreateResponseHeader( private Tuple<ArraySegment<byte>, IDisposable> CreateResponseHeader(
string status, string status,
bool appCompleted, bool appCompleted,
IEnumerable<KeyValuePair<string, string[]>> headers) IEnumerable<KeyValuePair<string, StringValues>> headers)
{ {
var writer = new MemoryPoolTextWriter(Memory); var writer = new MemoryPoolTextWriter(Memory);
writer.Write(HttpVersion); writer.Write(HttpVersion);

View File

@ -2,36 +2,34 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Framework.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public abstract class FrameHeaders : IDictionary<string, string[]> public abstract class FrameHeaders : IDictionary<string, StringValues>
{ {
protected Dictionary<string, string[]> MaybeUnknown; protected Dictionary<string, StringValues> MaybeUnknown;
protected Dictionary<string, string[]> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)); protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase));
protected static string[] AppendValue(string[] existing, string append) protected static StringValues AppendValue(StringValues existing, string append)
{ {
var appended = new string[existing.Length + 1]; return StringValues.Concat(existing, append);
Array.Copy(existing, appended, existing.Length);
appended[existing.Length] = append;
return appended;
} }
protected virtual int GetCountFast() protected virtual int GetCountFast()
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual string[] GetValueFast(string key) protected virtual StringValues GetValueFast(string key)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual bool TryGetValueFast(string key, out string[] value) protected virtual bool TryGetValueFast(string key, out StringValues value)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual void SetValueFast(string key, string[] value) protected virtual void SetValueFast(string key, StringValues value)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual void AddValueFast(string key, string[] value) protected virtual void AddValueFast(string key, StringValues value)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual bool RemoveFast(string key) protected virtual bool RemoveFast(string key)
@ -40,14 +38,14 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected virtual void ClearFast() protected virtual void ClearFast()
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex) protected virtual void CopyToFast(KeyValuePair<string, StringValues>[] array, int arrayIndex)
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
protected virtual IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast() protected virtual IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
{ throw new NotImplementedException(); } { throw new NotImplementedException(); }
string[] IDictionary<string, string[]>.this[string key] StringValues IDictionary<string, StringValues>.this[string key]
{ {
get get
{ {
@ -60,44 +58,44 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
} }
} }
int ICollection<KeyValuePair<string, string[]>>.Count => GetCountFast(); int ICollection<KeyValuePair<string, StringValues>>.Count => GetCountFast();
bool ICollection<KeyValuePair<string, string[]>>.IsReadOnly => false; bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => false;
ICollection<string> IDictionary<string, string[]>.Keys => ((IDictionary<string,string[]>)this).Select(x => x.Key).ToList(); ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(x => x.Key).ToList();
ICollection<string[]> IDictionary<string, string[]>.Values => ((IDictionary<string, string[]>)this).Select(x => x.Value).ToList(); ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(x => x.Value).ToList();
void ICollection<KeyValuePair<string, string[]>>.Add(KeyValuePair<string, string[]> item) void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item)
{ {
AddValueFast(item.Key, item.Value); AddValueFast(item.Key, item.Value);
} }
void IDictionary<string, string[]>.Add(string key, string[] value) void IDictionary<string, StringValues>.Add(string key, StringValues value)
{ {
AddValueFast(key, value); AddValueFast(key, value);
} }
void ICollection<KeyValuePair<string, string[]>>.Clear() void ICollection<KeyValuePair<string, StringValues>>.Clear()
{ {
ClearFast(); ClearFast();
} }
bool ICollection<KeyValuePair<string, string[]>>.Contains(KeyValuePair<string, string[]> item) bool ICollection<KeyValuePair<string, StringValues>>.Contains(KeyValuePair<string, StringValues> item)
{ {
string[] value; StringValues value;
return return
TryGetValueFast(item.Key, out value) && TryGetValueFast(item.Key, out value) &&
object.Equals(value, item.Value); object.Equals(value, item.Value);
} }
bool IDictionary<string, string[]>.ContainsKey(string key) bool IDictionary<string, StringValues>.ContainsKey(string key)
{ {
string[] value; StringValues value;
return TryGetValueFast(key, out value); return TryGetValueFast(key, out value);
} }
void ICollection<KeyValuePair<string, string[]>>.CopyTo(KeyValuePair<string, string[]>[] array, int arrayIndex) void ICollection<KeyValuePair<string, StringValues>>.CopyTo(KeyValuePair<string, StringValues>[] array, int arrayIndex)
{ {
CopyToFast(array, arrayIndex); CopyToFast(array, arrayIndex);
} }
@ -107,26 +105,26 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return GetEnumeratorFast(); return GetEnumeratorFast();
} }
IEnumerator<KeyValuePair<string, string[]>> IEnumerable<KeyValuePair<string, string[]>>.GetEnumerator() IEnumerator<KeyValuePair<string, StringValues>> IEnumerable<KeyValuePair<string, StringValues>>.GetEnumerator()
{ {
return GetEnumeratorFast(); return GetEnumeratorFast();
} }
bool ICollection<KeyValuePair<string, string[]>>.Remove(KeyValuePair<string, string[]> item) bool ICollection<KeyValuePair<string, StringValues>>.Remove(KeyValuePair<string, StringValues> item)
{ {
string[] value; StringValues value;
return return
TryGetValueFast(item.Key, out value) && TryGetValueFast(item.Key, out value) &&
object.Equals(value, item.Value) && object.Equals(value, item.Value) &&
RemoveFast(item.Key); RemoveFast(item.Key);
} }
bool IDictionary<string, string[]>.Remove(string key) bool IDictionary<string, StringValues>.Remove(string key)
{ {
return RemoveFast(key); return RemoveFast(key);
} }
bool IDictionary<string, string[]>.TryGetValue(string key, out string[] value) bool IDictionary<string, StringValues>.TryGetValue(string key, out StringValues value)
{ {
return TryGetValueFast(key, out value); return TryGetValueFast(key, out value);
} }
@ -139,33 +137,33 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return new Enumerator(this); return new Enumerator(this);
} }
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast() protected override IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
{ {
return GetEnumerator(); return GetEnumerator();
} }
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>> public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
{ {
FrameRequestHeaders _collection; FrameRequestHeaders _collection;
long _bits; long _bits;
int _state; int _state;
KeyValuePair<string, string[]> _current; KeyValuePair<string, StringValues> _current;
bool _hasUnknown; bool _hasUnknown;
Dictionary<string, string[]>.Enumerator _unknownEnumerator; Dictionary<string, StringValues>.Enumerator _unknownEnumerator;
internal Enumerator(FrameRequestHeaders collection) internal Enumerator(FrameRequestHeaders collection)
{ {
_collection = collection; _collection = collection;
_bits = collection._bits; _bits = collection._bits;
_state = 0; _state = 0;
_current = default(KeyValuePair<string, string[]>); _current = default(KeyValuePair<string, StringValues>);
_hasUnknown = collection.MaybeUnknown != null; _hasUnknown = collection.MaybeUnknown != null;
_unknownEnumerator = _hasUnknown _unknownEnumerator = _hasUnknown
? collection.MaybeUnknown.GetEnumerator() ? collection.MaybeUnknown.GetEnumerator()
: default(Dictionary<string, string[]>.Enumerator); : default(Dictionary<string, StringValues>.Enumerator);
} }
public KeyValuePair<string, string[]> Current => _current; public KeyValuePair<string, StringValues> Current => _current;
object IEnumerator.Current => _current; object IEnumerator.Current => _current;
@ -187,33 +185,33 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return new Enumerator(this); return new Enumerator(this);
} }
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast() protected override IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
{ {
return GetEnumerator(); return GetEnumerator();
} }
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>> public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
{ {
FrameResponseHeaders _collection; FrameResponseHeaders _collection;
long _bits; long _bits;
int _state; int _state;
KeyValuePair<string, string[]> _current; KeyValuePair<string, StringValues> _current;
bool _hasUnknown; bool _hasUnknown;
Dictionary<string, string[]>.Enumerator _unknownEnumerator; Dictionary<string, StringValues>.Enumerator _unknownEnumerator;
internal Enumerator(FrameResponseHeaders collection) internal Enumerator(FrameResponseHeaders collection)
{ {
_collection = collection; _collection = collection;
_bits = collection._bits; _bits = collection._bits;
_state = 0; _state = 0;
_current = default(KeyValuePair<string, string[]>); _current = default(KeyValuePair<string, StringValues>);
_hasUnknown = collection.MaybeUnknown != null; _hasUnknown = collection.MaybeUnknown != null;
_unknownEnumerator = _hasUnknown _unknownEnumerator = _hasUnknown
? collection.MaybeUnknown.GetEnumerator() ? collection.MaybeUnknown.GetEnumerator()
: default(Dictionary<string, string[]>.Enumerator); : default(Dictionary<string, StringValues>.Enumerator);
} }
public KeyValuePair<string, string[]> Current => _current; public KeyValuePair<string, StringValues> Current => _current;
object IEnumerator.Current => _current; object IEnumerator.Current => _current;

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Framework.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public static MessageBody For( public static MessageBody For(
string httpVersion, string httpVersion,
IDictionary<string, string[]> headers, IDictionary<string, StringValues> headers,
FrameContext context) FrameContext context)
{ {
// see also http://tools.ietf.org/html/rfc2616#section-4.4 // see also http://tools.ietf.org/html/rfc2616#section-4.4
@ -61,15 +62,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return new ForRemainingData(context); return new ForRemainingData(context);
} }
public static bool TryGet(IDictionary<string, string[]> headers, string name, out string value) public static bool TryGet(IDictionary<string, StringValues> headers, string name, out string value)
{ {
string[] values; StringValues values;
if (!headers.TryGetValue(name, out values) || values == null) if (!headers.TryGetValue(name, out values) || values == null)
{ {
value = null; value = null;
return false; return false;
} }
var count = values.Length; var count = values.Count;
if (count == 0) if (count == 0)
{ {
value = null; value = null;

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Framework.Primitives;
namespace Microsoft.AspNet.Server.Kestrel namespace Microsoft.AspNet.Server.Kestrel
{ {
@ -115,7 +116,7 @@ namespace Microsoft.AspNet.Server.Kestrel
} }
} }
IDictionary<string, string[]> IHttpRequestFeature.Headers IDictionary<string, StringValues> IHttpRequestFeature.Headers
{ {
get get
{ {
@ -167,7 +168,7 @@ namespace Microsoft.AspNet.Server.Kestrel
} }
} }
IDictionary<string, string[]> IHttpResponseFeature.Headers IDictionary<string, StringValues> IHttpResponseFeature.Headers
{ {
get get
{ {
@ -212,7 +213,7 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
string[] values; StringValues values;
if (_frame.RequestHeaders.TryGetValue("Connection", out values)) if (_frame.RequestHeaders.TryGetValue("Connection", out values))
{ {
return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1); return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1);
@ -225,10 +226,10 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
_frame.StatusCode = 101; _frame.StatusCode = 101;
_frame.ReasonPhrase = "Switching Protocols"; _frame.ReasonPhrase = "Switching Protocols";
_frame.ResponseHeaders["Connection"] = new string[] { "Upgrade" }; _frame.ResponseHeaders["Connection"] = "Upgrade";
if (!_frame.ResponseHeaders.ContainsKey("Upgrade")) if (!_frame.ResponseHeaders.ContainsKey("Upgrade"))
{ {
string[] values; StringValues values;
if (_frame.RequestHeaders.TryGetValue("Upgrade", out values)) if (_frame.RequestHeaders.TryGetValue("Upgrade", out values))
{ {
_frame.ResponseHeaders["Upgrade"] = values; _frame.ResponseHeaders["Upgrade"] = values;

View File

@ -1,7 +1,7 @@
using Microsoft.AspNet.Server.Kestrel.Http; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Framework.Primitives;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Server.KestrelTests namespace Microsoft.AspNet.Server.KestrelTests
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void InitialDictionaryIsEmpty() public void InitialDictionaryIsEmpty()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
Assert.Equal(0, headers.Count); Assert.Equal(0, headers.Count);
Assert.False(headers.IsReadOnly); Assert.False(headers.IsReadOnly);
@ -20,31 +20,31 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void SettingUnknownHeadersWorks() public void SettingUnknownHeadersWorks()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers["custom"] = new[] { "value" }; headers["custom"] = new[] { "value" };
Assert.NotNull(headers["custom"]); Assert.NotNull(headers["custom"]);
Assert.Equal(1, headers["custom"].Length); Assert.Equal(1, headers["custom"].Count);
Assert.Equal("value", headers["custom"][0]); Assert.Equal("value", headers["custom"][0]);
} }
[Fact] [Fact]
public void SettingKnownHeadersWorks() public void SettingKnownHeadersWorks()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers["host"] = new[] { "value" }; headers["host"] = new[] { "value" };
Assert.NotNull(headers["host"]); Assert.NotNull(headers["host"]);
Assert.Equal(1, headers["host"].Length); Assert.Equal(1, headers["host"].Count);
Assert.Equal("value", headers["host"][0]); Assert.Equal("value", headers["host"][0]);
} }
[Fact] [Fact]
public void KnownAndCustomHeaderCountAddedTogether() public void KnownAndCustomHeaderCountAddedTogether()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers["host"] = new[] { "value" }; headers["host"] = new[] { "value" };
headers["custom"] = new[] { "value" }; headers["custom"] = new[] { "value" };
@ -55,9 +55,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void TryGetValueWorksForKnownAndUnknownHeaders() public void TryGetValueWorksForKnownAndUnknownHeaders()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
string[] value; StringValues value;
Assert.False(headers.TryGetValue("host", out value)); Assert.False(headers.TryGetValue("host", out value));
Assert.False(headers.TryGetValue("custom", out value)); Assert.False(headers.TryGetValue("custom", out value));
@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void SameExceptionThrownForMissingKey() public void SameExceptionThrownForMissingKey()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
Assert.Throws<KeyNotFoundException>(() => headers["custom"]); Assert.Throws<KeyNotFoundException>(() => headers["custom"]);
Assert.Throws<KeyNotFoundException>(() => headers["host"]); Assert.Throws<KeyNotFoundException>(() => headers["host"]);
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void EntriesCanBeEnumerated() public void EntriesCanBeEnumerated()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
var v1 = new[] { "localhost" }; var v1 = new[] { "localhost" };
var v2 = new[] { "value" }; var v2 = new[] { "value" };
headers["host"] = v1; headers["host"] = v1;
@ -90,8 +90,8 @@ namespace Microsoft.AspNet.Server.KestrelTests
Assert.Equal( Assert.Equal(
new[] { new[] {
new KeyValuePair<string, string[]>("Host", v1), new KeyValuePair<string, StringValues>("Host", v1),
new KeyValuePair<string, string[]>("custom", v2), new KeyValuePair<string, StringValues>("custom", v2),
}, },
headers); headers);
} }
@ -99,9 +99,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void KeysAndValuesCanBeEnumerated() public void KeysAndValuesCanBeEnumerated()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
var v1 = new[] { "localhost" }; StringValues v1 = new[] { "localhost" };
var v2 = new[] { "value" }; StringValues v2 = new[] { "value" };
headers["host"] = v1; headers["host"] = v1;
headers["custom"] = v2; headers["custom"] = v2;
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
new[] { "Host", "custom" }, new[] { "Host", "custom" },
headers.Keys); headers.Keys);
Assert.Equal<string[]>( Assert.Equal<StringValues>(
new[] { v1, v2 }, new[] { v1, v2 },
headers.Values); headers.Values);
} }
@ -118,11 +118,11 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void ContainsAndContainsKeyWork() public void ContainsAndContainsKeyWork()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
var kv1 = new KeyValuePair<string, string[]>("host", new[] { "localhost" }); var kv1 = new KeyValuePair<string, StringValues>("host", new[] { "localhost" });
var kv2 = new KeyValuePair<string, string[]>("custom", new[] { "value" }); var kv2 = new KeyValuePair<string, StringValues>("custom", new[] { "value" });
var kv1b = new KeyValuePair<string, string[]>("host", new[] { "localhost" }); var kv1b = new KeyValuePair<string, StringValues>("host", new[] { "localhost" });
var kv2b = new KeyValuePair<string, string[]>("custom", new[] { "value" }); var kv2b = new KeyValuePair<string, StringValues>("custom", new[] { "value" });
Assert.False(headers.ContainsKey("host")); Assert.False(headers.ContainsKey("host"));
Assert.False(headers.ContainsKey("custom")); Assert.False(headers.ContainsKey("custom"));
@ -149,9 +149,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void AddWorksLikeSetAndThrowsIfKeyExists() public void AddWorksLikeSetAndThrowsIfKeyExists()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
string[] value; StringValues value;
Assert.False(headers.TryGetValue("host", out value)); Assert.False(headers.TryGetValue("host", out value));
Assert.False(headers.TryGetValue("custom", out value)); Assert.False(headers.TryGetValue("custom", out value));
@ -169,11 +169,11 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void ClearRemovesAllHeaders() public void ClearRemovesAllHeaders()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers.Add("host", new[] { "localhost" }); headers.Add("host", new[] { "localhost" });
headers.Add("custom", new[] { "value" }); headers.Add("custom", new[] { "value" });
string[] value; StringValues value;
Assert.Equal(2, headers.Count); Assert.Equal(2, headers.Count);
Assert.True(headers.TryGetValue("host", out value)); Assert.True(headers.TryGetValue("host", out value));
Assert.True(headers.TryGetValue("custom", out value)); Assert.True(headers.TryGetValue("custom", out value));
@ -188,11 +188,11 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void RemoveTakesHeadersOutOfDictionary() public void RemoveTakesHeadersOutOfDictionary()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers.Add("host", new[] { "localhost" }); headers.Add("host", new[] { "localhost" });
headers.Add("custom", new[] { "value" }); headers.Add("custom", new[] { "value" });
string[] value; StringValues value;
Assert.Equal(2, headers.Count); Assert.Equal(2, headers.Count);
Assert.True(headers.TryGetValue("host", out value)); Assert.True(headers.TryGetValue("host", out value));
Assert.True(headers.TryGetValue("custom", out value)); Assert.True(headers.TryGetValue("custom", out value));
@ -215,24 +215,24 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void CopyToMovesDataIntoArray() public void CopyToMovesDataIntoArray()
{ {
IDictionary<string, string[]> headers = new FrameRequestHeaders(); IDictionary<string, StringValues> headers = new FrameRequestHeaders();
headers.Add("host", new[] { "localhost" }); headers.Add("host", new[] { "localhost" });
headers.Add("custom", new[] { "value" }); headers.Add("custom", new[] { "value" });
var entries = new KeyValuePair<string, string[]>[4]; var entries = new KeyValuePair<string, StringValues>[4];
headers.CopyTo(entries, 1); headers.CopyTo(entries, 1);
Assert.Null(entries[0].Key); Assert.Null(entries[0].Key);
Assert.Null(entries[0].Value); Assert.Equal(new StringValues(), entries[0].Value);
Assert.Equal("Host", entries[1].Key); Assert.Equal("Host", entries[1].Key);
Assert.NotNull(entries[1].Value); Assert.Equal(new[] { "localhost" }, entries[1].Value);
Assert.Equal("custom", entries[2].Key); Assert.Equal("custom", entries[2].Key);
Assert.NotNull(entries[2].Value); Assert.Equal(new[] { "value" }, entries[2].Value);
Assert.Null(entries[3].Key); Assert.Null(entries[3].Key);
Assert.Null(entries[3].Value); Assert.Equal(new StringValues(), entries[0].Value);
} }
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Framework.Primitives;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Server.KestrelTests namespace Microsoft.AspNet.Server.KestrelTests
@ -13,19 +14,19 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void InitialDictionaryContainsServerAndDate() public void InitialDictionaryContainsServerAndDate()
{ {
IDictionary<string, string[]> headers = new FrameResponseHeaders(); IDictionary<string, StringValues> headers = new FrameResponseHeaders();
Assert.Equal(2, headers.Count); Assert.Equal(2, headers.Count);
string[] serverHeader; StringValues serverHeader;
Assert.True(headers.TryGetValue("Server", out serverHeader)); Assert.True(headers.TryGetValue("Server", out serverHeader));
Assert.Equal(1, serverHeader.Length); Assert.Equal(1, serverHeader.Count);
Assert.Equal("Kestrel", serverHeader[0]); Assert.Equal("Kestrel", serverHeader[0]);
string[] dateHeader; StringValues dateHeader;
DateTime date; DateTime date;
Assert.True(headers.TryGetValue("Date", out dateHeader)); Assert.True(headers.TryGetValue("Date", out dateHeader));
Assert.Equal(1, dateHeader.Length); Assert.Equal(1, dateHeader.Count);
Assert.True(DateTime.TryParse(dateHeader[0], out date)); Assert.True(DateTime.TryParse(dateHeader[0], out date));
Assert.True(DateTime.Now - date <= TimeSpan.FromMinutes(1)); Assert.True(DateTime.Now - date <= TimeSpan.FromMinutes(1));
@ -35,7 +36,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact] [Fact]
public void InitialEntriesCanBeCleared() public void InitialEntriesCanBeCleared()
{ {
IDictionary<string, string[]> headers = new FrameResponseHeaders(); IDictionary<string, StringValues> headers = new FrameResponseHeaders();
headers.Clear(); headers.Clear();

View File

@ -1,11 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Server.Kestrel.Http;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Framework.Primitives;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Server.KestrelTests namespace Microsoft.AspNet.Server.KestrelTests
@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
public void Http10ConnectionClose() public void Http10ConnectionClose()
{ {
var input = new TestInput(); var input = new TestInput();
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.FrameContext); var body = MessageBody.For("HTTP/1.0", new Dictionary<string, StringValues>(), input.FrameContext);
var stream = new FrameRequestStream(body); var stream = new FrameRequestStream(body);
input.Add("Hello", true); input.Add("Hello", true);
@ -38,7 +39,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
public async Task Http10ConnectionCloseAsync() public async Task Http10ConnectionCloseAsync()
{ {
var input = new TestInput(); var input = new TestInput();
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.FrameContext); var body = MessageBody.For("HTTP/1.0", new Dictionary<string, StringValues>(), input.FrameContext);
var stream = new FrameRequestStream(body); var stream = new FrameRequestStream(body);
input.Add("Hello", true); input.Add("Hello", true);

View File

@ -167,6 +167,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
return $@" return $@"
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Framework.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{{ {{
@ -174,8 +175,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{ {{
public FrameResponseHeaders() public FrameResponseHeaders()
{{ {{
_Server = new[] {{ ""Kestrel"" }}; _Server = ""Kestrel"";
_Date = new[] {{ DateTime.UtcNow.ToString(""r"") }}; _Date = DateTime.UtcNow.ToString(""r"");
_bits = { _bits = {
1L << responseHeaders.First(header => header.Name == "Server").Index | 1L << responseHeaders.First(header => header.Name == "Server").Index |
1L << responseHeaders.First(header => header.Name == "Date").Index 1L << responseHeaders.First(header => header.Name == "Date").Index
@ -187,7 +188,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{{ {{
long _bits = 0; long _bits = 0;
{Each(loop.Headers, header => @" {Each(loop.Headers, header => @"
string[] _" + header.Identifier + ";")} StringValues _" + header.Identifier + ";")}
protected override int GetCountFast() protected override int GetCountFast()
{{ {{
@ -201,7 +202,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return count; return count;
}} }}
protected override string[] GetValueFast(string key) protected override StringValues GetValueFast(string key)
{{ {{
switch(key.Length) switch(key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -228,7 +229,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return MaybeUnknown[key]; return MaybeUnknown[key];
}} }}
protected override bool TryGetValueFast(string key, out string[] value) protected override bool TryGetValueFast(string key, out StringValues value)
{{ {{
switch(key.Length) switch(key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -243,18 +244,18 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}} }}
else else
{{ {{
value = null; value = StringValues.Empty;
return false; return false;
}} }}
}} }}
")}}} ")}}}
break; break;
")}}} ")}}}
value = null; value = StringValues.Empty;
return MaybeUnknown?.TryGetValue(key, out value) ?? false; return MaybeUnknown?.TryGetValue(key, out value) ?? false;
}} }}
protected override void SetValueFast(string key, string[] value) protected override void SetValueFast(string key, StringValues value)
{{ {{
switch(key.Length) switch(key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -272,7 +273,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
Unknown[key] = value; Unknown[key] = value;
}} }}
protected override void AddValueFast(string key, string[] value) protected override void AddValueFast(string key, StringValues value)
{{ {{
switch(key.Length) switch(key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -324,7 +325,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
MaybeUnknown?.Clear(); MaybeUnknown?.Clear();
}} }}
protected override void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex) protected override void CopyToFast(KeyValuePair<string, StringValues>[] array, int arrayIndex)
{{ {{
if (arrayIndex < 0) if (arrayIndex < 0)
{{ {{
@ -339,11 +340,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
throw new ArgumentException(); throw new ArgumentException();
}} }}
array[arrayIndex] = new KeyValuePair<string, string[]>(""{header.Name}"", _{header.Identifier}); array[arrayIndex] = new KeyValuePair<string, StringValues>(""{header.Name}"", _{header.Identifier});
++arrayIndex; ++arrayIndex;
}} }}
")} ")}
((ICollection<KeyValuePair<string, string[]>>)MaybeUnknown)?.CopyTo(array, arrayIndex); ((ICollection<KeyValuePair<string, StringValues>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
}} }}
public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value)
@ -370,8 +371,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
break; break;
")}}}}} ")}}}}}
var key = System.Text.Encoding.ASCII.GetString(keyBytes, keyOffset, keyLength); var key = System.Text.Encoding.ASCII.GetString(keyBytes, keyOffset, keyLength);
string[] existing; StringValues existing;
Unknown[key] = Unknown.TryGetValue(key, out existing) ? AppendValue(existing, value) : new[] {{value}}; Unknown.TryGetValue(key, out existing);
Unknown[key] = AppendValue(existing, value);
}} }}
public partial struct Enumerator public partial struct Enumerator
@ -391,7 +393,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
state{header.Index}: state{header.Index}:
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
_current = new KeyValuePair<string, string[]>(""{header.Name}"", _collection._{header.Identifier}); _current = new KeyValuePair<string, StringValues>(""{header.Name}"", _collection._{header.Identifier});
_state = {header.Index + 1}; _state = {header.Index + 1};
return true; return true;
}} }}
@ -399,7 +401,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
state_default: state_default:
if (!_hasUnknown || !_unknownEnumerator.MoveNext()) if (!_hasUnknown || !_unknownEnumerator.MoveNext())
{{ {{
_current = default(KeyValuePair<string, string[]>); _current = default(KeyValuePair<string, StringValues>);
return false; return false;
}} }}
_current = _unknownEnumerator.Current; _current = _unknownEnumerator.Current;