RO Headers & rationalise exceptions

This commit is contained in:
Ben Adams 2016-02-13 03:35:26 +00:00
parent c293bbbd1a
commit 460dbb15c2
4 changed files with 308 additions and 849 deletions

View File

@ -656,8 +656,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
byte[] statusBytes, byte[] statusBytes,
bool appCompleted) bool appCompleted)
{ {
var end = SocketOutput.ProducingStart();
var responseHeaders = _frameHeaders.ResponseHeaders; var responseHeaders = _frameHeaders.ResponseHeaders;
responseHeaders.SetReadOnly();
var end = SocketOutput.ProducingStart();
if (_keepAlive) if (_keepAlive)
{ {
foreach (var connectionValue in responseHeaders.HeaderConnection) foreach (var connectionValue in responseHeaders.HeaderConnection)

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
public abstract class FrameHeaders : IHeaderDictionary public abstract class FrameHeaders : IHeaderDictionary
{ {
protected bool _isReadOnly;
protected Dictionary<string, StringValues> MaybeUnknown; protected Dictionary<string, StringValues> MaybeUnknown;
protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase)); protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase));
@ -26,6 +27,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
set set
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
SetValueFast(key, value); SetValueFast(key, value);
} }
} }
@ -38,20 +43,50 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
set set
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
SetValueFast(key, value); SetValueFast(key, value);
} }
} }
protected void ThrowReadOnlyException()
{
throw new InvalidOperationException("Headers are readonly, reponse has already started.");
}
protected void ThrowArgumentException()
{
throw new ArgumentException();
}
protected void ThrowKeyNotFoundException()
{
throw new KeyNotFoundException();
}
protected void ThrowDuplicateKeyException()
{
throw new ArgumentException("An item with the same key has already been added.");
}
int ICollection<KeyValuePair<string, StringValues>>.Count => GetCountFast(); int ICollection<KeyValuePair<string, StringValues>>.Count => GetCountFast();
bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => false; bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => _isReadOnly;
ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(pair => pair.Key).ToList(); ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(pair => pair.Key).ToList();
ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(pair => pair.Value).ToList(); ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(pair => pair.Value).ToList();
public void SetReadOnly()
{
_isReadOnly = true;
}
public void Reset() public void Reset()
{ {
_isReadOnly = false;
ClearFast(); ClearFast();
} }
@ -105,16 +140,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item) void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item)
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
AddValueFast(item.Key, item.Value); AddValueFast(item.Key, item.Value);
} }
void IDictionary<string, StringValues>.Add(string key, StringValues value) void IDictionary<string, StringValues>.Add(string key, StringValues value)
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
AddValueFast(key, value); AddValueFast(key, value);
} }
void ICollection<KeyValuePair<string, StringValues>>.Clear() void ICollection<KeyValuePair<string, StringValues>>.Clear()
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
ClearFast(); ClearFast();
} }
@ -158,6 +205,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
bool IDictionary<string, StringValues>.Remove(string key) bool IDictionary<string, StringValues>.Remove(string key)
{ {
if (_isReadOnly)
{
ThrowReadOnlyException();
}
return RemoveFast(key); return RemoveFast(key);
} }

View File

@ -263,7 +263,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}} }}
else else
{{ {{
throw new System.Collections.Generic.KeyNotFoundException(); ThrowKeyNotFoundException();
}} }}
}} }}
")}}} ")}}}
@ -271,7 +271,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
")}}} ")}}}
if (MaybeUnknown == null) if (MaybeUnknown == null)
{{ {{
throw new System.Collections.Generic.KeyNotFoundException(); ThrowKeyNotFoundException();
}} }}
return MaybeUnknown[key]; return MaybeUnknown[key];
}} }}
@ -328,7 +328,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{ {{
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
throw new ArgumentException(""An item with the same key has already been added.""); ThrowDuplicateKeyException();
}} }}
{header.SetBit()}; {header.SetBit()};
_{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@" _{header.Identifier} = value;{(header.EnhancedSetter == false ? "" : $@"
@ -377,14 +377,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{{ {{
if (arrayIndex < 0) if (arrayIndex < 0)
{{ {{
throw new ArgumentException(); ThrowArgumentException();
}} }}
{Each(loop.Headers, header => $@" {Each(loop.Headers, header => $@"
if ({header.TestBit()}) if ({header.TestBit()})
{{ {{
if (arrayIndex == array.Length) if (arrayIndex == array.Length)
{{ {{
throw new ArgumentException(); ThrowArgumentException();
}} }}
array[arrayIndex] = new KeyValuePair<string, StringValues>(""{header.Name}"", _{header.Identifier}); array[arrayIndex] = new KeyValuePair<string, StringValues>(""{header.Name}"", _{header.Identifier});
@ -415,6 +415,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}} }}
")} ")}
}}" : "")} }}" : "")}
{(loop.ClassName == "FrameRequestHeaders" ? $@"
public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value)
{{ {{
fixed (byte* ptr = &keyBytes[keyOffset]) fixed (byte* ptr = &keyBytes[keyOffset])
@ -449,7 +450,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
StringValues existing; StringValues existing;
Unknown.TryGetValue(key, out existing); Unknown.TryGetValue(key, out existing);
Unknown[key] = AppendValue(existing, value); Unknown[key] = AppendValue(existing, value);
}} }}" : "")}
public partial struct Enumerator public partial struct Enumerator
{{ {{
public bool MoveNext() public bool MoveNext()