diff --git a/src/Microsoft.AspNet.Server.Kestrel/Filter/SocketInputStream.cs b/src/Microsoft.AspNet.Server.Kestrel/Filter/SocketInputStream.cs index 26b513faa..d6cc5748f 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Filter/SocketInputStream.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Filter/SocketInputStream.cs @@ -74,11 +74,7 @@ public override void SetLength(long value) public override void Write(byte[] buffer, int offset, int count) { - var inputBuffer = _socketInput.IncomingStart(count); - - Buffer.BlockCopy(buffer, offset, inputBuffer.Data.Array, inputBuffer.Data.Offset, count); - - _socketInput.IncomingComplete(count, error: null); + _socketInput.IncomingData(buffer, offset, count); } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token) @@ -90,7 +86,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati protected override void Dispose(bool disposing) { // Close _socketInput with a fake zero-length write that will result in a zero-length read. - _socketInput.IncomingComplete(0, error: null); + _socketInput.IncomingData(null, 0, 0); base.Dispose(disposing); } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs b/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs index cbcb99f3a..f5c9795af 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs @@ -51,11 +51,11 @@ public void ProducingComplete(MemoryPoolIterator2 end) var returnBlock = block; block = block.Next; - returnBlock.Pool?.Return(returnBlock); + returnBlock.Pool.Return(returnBlock); } _outputStream.Write(end.Block.Array, end.Block.Data.Offset, end.Index - end.Block.Data.Offset); - end.Block.Pool?.Return(end.Block); + end.Block.Pool.Return(end.Block); } } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs index 89b9db55e..d56d92613 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs @@ -140,11 +140,11 @@ private static Libuv.uv_buf_t AllocCallback(UvStreamHandle handle, int suggested private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize) { - var result = _rawSocketInput.IncomingStart(2048); + var result = _rawSocketInput.IncomingRawStart(); return handle.Libuv.buf_init( - result.DataPtr, - result.Data.Count); + result.Pin + result.End, + result.BlockEndOffset - result.End); } private static void ReadCallback(UvStreamHandle handle, int status, object state) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index a69c5fc0d..a5d6ec3c4 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Linq; @@ -40,11 +41,11 @@ public abstract partial class Frame : FrameContext, IFrameControl private static readonly byte[] _bytesDate = Encoding.ASCII.GetBytes("Date: "); private static readonly byte[] _bytesEndHeaders = Encoding.ASCII.GetBytes("\r\n\r\n"); - private static readonly Vector _vectorCRs = new Vector((byte)'\r'); - private static readonly Vector _vectorColons = new Vector((byte)':'); - private static readonly Vector _vectorSpaces = new Vector((byte)' '); - private static readonly Vector _vectorQuestionMarks = new Vector((byte)'?'); - private static readonly Vector _vectorPercentages = new Vector((byte)'%'); + private static Vector _vectorCRs = new Vector((byte)'\r'); + private static Vector _vectorColons = new Vector((byte)':'); + private static Vector _vectorSpaces = new Vector((byte)' '); + private static Vector _vectorQuestionMarks = new Vector((byte)'?'); + private static Vector _vectorPercentages = new Vector((byte)'%'); private readonly object _onStartingSync = new Object(); private readonly object _onCompletedSync = new Object(); @@ -427,7 +428,7 @@ public void Write(ArraySegment data) } else { - SocketOutput.Write(data, immediate: true); + SocketOutput.Write(data, immediate: !SocketInput.IsCompleted); } } @@ -448,7 +449,7 @@ public Task WriteAsync(ArraySegment data, CancellationToken cancellationTo } else { - return SocketOutput.WriteAsync(data, immediate: true, cancellationToken: cancellationToken); + return SocketOutput.WriteAsync(data, immediate: !SocketInput.IsCompleted, cancellationToken: cancellationToken); } } @@ -466,39 +467,40 @@ public async Task WriteAsyncAwaited(ArraySegment data, CancellationToken c } else { - await SocketOutput.WriteAsync(data, immediate: true, cancellationToken: cancellationToken); + await SocketOutput.WriteAsync(data, immediate: !SocketInput.IsCompleted, cancellationToken: cancellationToken); } } private void WriteChunked(ArraySegment data) { - SocketOutput.Write(BeginChunkBytes(data.Count), immediate: false); + var tenByteBuffer = ArrayPool.Shared.Rent(10); + SocketOutput.Write(BeginChunkBytes(data.Count, tenByteBuffer), immediate: false); + ArrayPool.Shared.Return(tenByteBuffer); SocketOutput.Write(data, immediate: false); SocketOutput.Write(_endChunkBytes, immediate: true); } private async Task WriteChunkedAsync(ArraySegment data, CancellationToken cancellationToken) { - await SocketOutput.WriteAsync(BeginChunkBytes(data.Count), immediate: false, cancellationToken: cancellationToken); + var tenByteBuffer = ArrayPool.Shared.Rent(10); + await SocketOutput.WriteAsync(BeginChunkBytes(data.Count, tenByteBuffer), immediate: false, cancellationToken: cancellationToken); + ArrayPool.Shared.Return(tenByteBuffer); await SocketOutput.WriteAsync(data, immediate: false, cancellationToken: cancellationToken); await SocketOutput.WriteAsync(_endChunkBytes, immediate: true, cancellationToken: cancellationToken); } - public static ArraySegment BeginChunkBytes(int dataCount) + public static ArraySegment BeginChunkBytes(int dataCount, byte[] tenByteBuffer) { - var bytes = new byte[10] - { - _hex[((dataCount >> 0x1c) & 0x0f)], - _hex[((dataCount >> 0x18) & 0x0f)], - _hex[((dataCount >> 0x14) & 0x0f)], - _hex[((dataCount >> 0x10) & 0x0f)], - _hex[((dataCount >> 0x0c) & 0x0f)], - _hex[((dataCount >> 0x08) & 0x0f)], - _hex[((dataCount >> 0x04) & 0x0f)], - _hex[((dataCount >> 0x00) & 0x0f)], - (byte)'\r', - (byte)'\n', - }; + tenByteBuffer[0] = _hex[((dataCount >> 0x1c) & 0x0f)]; + tenByteBuffer[1] = _hex[((dataCount >> 0x18) & 0x0f)]; + tenByteBuffer[2] = _hex[((dataCount >> 0x14) & 0x0f)]; + tenByteBuffer[3] = _hex[((dataCount >> 0x10) & 0x0f)]; + tenByteBuffer[4] = _hex[((dataCount >> 0x0c) & 0x0f)]; + tenByteBuffer[5] = _hex[((dataCount >> 0x08) & 0x0f)]; + tenByteBuffer[6] = _hex[((dataCount >> 0x04) & 0x0f)]; + tenByteBuffer[7] = _hex[((dataCount >> 0x00) & 0x0f)]; + tenByteBuffer[8] = (byte)'\r'; + tenByteBuffer[9] = (byte)'\n'; // Determine the most-significant non-zero nibble int total, shift; @@ -510,7 +512,7 @@ public static ArraySegment BeginChunkBytes(int dataCount) total |= (dataCount > 0x000f) ? 0x04 : 0x00; var offset = 7 - (total >> 2); - return new ArraySegment(bytes, offset, 10 - offset); + return new ArraySegment(tenByteBuffer, offset, 10 - offset); } private void WriteChunkedResponseSuffix() @@ -533,7 +535,7 @@ public void ProduceContinue() RequestHeaders.TryGetValue("Expect", out expect) && (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase)) { - SocketOutput.Write(_continueBytes); + SocketOutput.Write(_continueBytes, immediate: true); } } @@ -613,7 +615,7 @@ protected Task ProduceEnd() private async Task ProduceEndAwaited() { - await ProduceStart(immediate: true, appCompleted: true); + await ProduceStart(immediate: !SocketInput.IsCompleted, appCompleted: true); WriteSuffix(); } @@ -640,14 +642,13 @@ private Task CreateResponseHeader( { var begin = SocketOutput.ProducingStart(); var end = begin; - if (_keepAlive) + if (_keepAlive && _responseHeaders.HasConnection) { - foreach (var connectionValue in _responseHeaders.HeaderConnection) + var connection = _responseHeaders.HeaderConnection.ToString(); + + if (connection.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1) { - if (connectionValue.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1) - { - _keepAlive = false; - } + _keepAlive = false; } } @@ -711,7 +712,7 @@ protected bool TakeStartLine(SocketInput input) try { var begin = scan; - if (scan.Seek(_vectorSpaces) == -1) + if (scan.Seek(ref _vectorSpaces) == -1) { return false; } @@ -726,11 +727,11 @@ protected bool TakeStartLine(SocketInput input) begin = scan; var needDecode = false; - var chFound = scan.Seek(_vectorSpaces, _vectorQuestionMarks, _vectorPercentages); + var chFound = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks, ref _vectorPercentages); if (chFound == '%') { needDecode = true; - chFound = scan.Seek(_vectorSpaces, _vectorQuestionMarks); + chFound = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks); } var pathBegin = begin; @@ -740,7 +741,7 @@ protected bool TakeStartLine(SocketInput input) if (chFound == '?') { begin = scan; - if (scan.Seek(_vectorSpaces) != ' ') + if (scan.Seek(ref _vectorSpaces) != ' ') { return false; } @@ -749,7 +750,7 @@ protected bool TakeStartLine(SocketInput input) scan.Take(); begin = scan; - if (scan.Seek(_vectorCRs) == -1) + if (scan.Seek(ref _vectorCRs) == -1) { return false; } @@ -834,6 +835,7 @@ private bool RequestUrlStartsWithPathBase(string requestUrl, out bool caseMatche public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders) { + MemoryPoolIterator2 endName; var scan = input.ConsumingStart(); var consumed = scan; try @@ -843,8 +845,15 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req while (!scan.IsEnd) { var beginName = scan; - scan.Seek(_vectorColons, _vectorCRs); - var endName = scan; + if (scan.Peek() == '\r' || scan.SeekCommonHeader()) + { + endName = scan; + } + else + { + scan.Seek(ref _vectorColons, ref _vectorCRs); + endName = scan; + } chFirst = scan.Take(); var beginValue = scan; @@ -894,7 +903,7 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req var wrapping = false; while (!scan.IsEnd) { - if (scan.Seek(_vectorCRs) == -1) + if (scan.Seek(ref _vectorCRs) == -1) { // no "\r" in sight, burn used bytes and go back to await more data return false; @@ -922,7 +931,8 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req continue; } - var name = beginName.GetArraySegment(endName); + byte[] rentedBuffer; + var name = beginName.GetArraySegment(endName, out rentedBuffer); var value = beginValue.GetAsciiString(endValue); if (wrapping) { @@ -931,6 +941,10 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req consumed = scan; requestHeaders.Append(name.Array, name.Offset, name.Count, value); + if (rentedBuffer != null) + { + ArrayPool.Shared.Return(rentedBuffer); + } break; } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameHeaders.Generated.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameHeaders.Generated.cs index 16c80b398..c89aeed10 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameHeaders.Generated.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameHeaders.Generated.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Text; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Primitives; @@ -56,6 +55,7 @@ public partial class FrameRequestHeaders private StringValues _UserAgent; + public StringValues HeaderCacheControl { get @@ -721,13 +721,13 @@ protected override StringValues GetValueFast(string key) { switch(key.Length) { - case 13: + case 4: { - if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1L) != 0)) + if (((_bits & 268435456L) != 0)) { - return _CacheControl; + return _Host; } else { @@ -735,11 +735,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 131072L) != 0)) + if (((_bits & 134217728L) != 0)) { - return _ContentRange; + return _From; } else { @@ -747,23 +747,27 @@ protected override StringValues GetValueFast(string key) } } - if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 524288L) != 0)) + if (((_bits & 4L) != 0)) { - return _LastModified; + return _Date; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - - if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 5: + { + if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16777216L) != 0)) + if (((_bits & 137438953472L) != 0)) { - return _Authorization; + return _Range; } else { @@ -771,11 +775,11 @@ protected override StringValues GetValueFast(string key) } } - if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2147483648L) != 0)) + if (((_bits & 1024L) != 0)) { - return _IfNoneMatch; + return _Allow; } else { @@ -785,13 +789,13 @@ protected override StringValues GetValueFast(string key) } break; - case 10: + case 6: { - if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2L) != 0)) + if (((_bits & 16L) != 0)) { - return _Connection; + return _Pragma; } else { @@ -799,11 +803,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8L) != 0)) + if (((_bits & 67108864L) != 0)) { - return _KeepAlive; + return _Expect; } else { @@ -811,11 +815,23 @@ protected override StringValues GetValueFast(string key) } } - if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1099511627776L) != 0)) + if (((_bits & 33554432L) != 0)) { - return _UserAgent; + return _Cookie; + } + else + { + throw new System.Collections.Generic.KeyNotFoundException(); + } + } + + if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1048576L) != 0)) + { + return _Accept; } else { @@ -825,13 +841,13 @@ protected override StringValues GetValueFast(string key) } break; - case 4: + case 7: { - if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4L) != 0)) + if (((_bits & 512L) != 0)) { - return _Date; + return _Warning; } else { @@ -839,11 +855,11 @@ protected override StringValues GetValueFast(string key) } } - if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 134217728L) != 0)) + if (((_bits & 128L) != 0)) { - return _From; + return _Upgrade; } else { @@ -851,27 +867,23 @@ protected override StringValues GetValueFast(string key) } } - if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 268435456L) != 0)) + if (((_bits & 32L) != 0)) { - return _Host; + return _Trailer; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - } - break; - - case 6: - { - if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16L) != 0)) + if (((_bits & 68719476736L) != 0)) { - return _Pragma; + return _Referer; } else { @@ -879,23 +891,27 @@ protected override StringValues GetValueFast(string key) } } - if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1048576L) != 0)) + if (((_bits & 262144L) != 0)) { - return _Accept; + return _Expires; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - - if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 8: + { + if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 33554432L) != 0)) + if (((_bits & 4294967296L) != 0)) { - return _Cookie; + return _IfRange; } else { @@ -903,11 +919,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 67108864L) != 0)) + if (((_bits & 536870912L) != 0)) { - return _Expect; + return _IfMatch; } else { @@ -917,25 +933,29 @@ protected override StringValues GetValueFast(string key) } break; - case 7: + case 9: { - if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32L) != 0)) + if (((_bits & 549755813888L) != 0)) { - return _Trailer; + return _Translate; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - - if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 10: + { + if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 128L) != 0)) + if (((_bits & 1099511627776L) != 0)) { - return _Upgrade; + return _UserAgent; } else { @@ -943,11 +963,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 512L) != 0)) + if (((_bits & 8L) != 0)) { - return _Warning; + return _KeepAlive; } else { @@ -955,23 +975,27 @@ protected override StringValues GetValueFast(string key) } } - if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 262144L) != 0)) + if (((_bits & 2L) != 0)) { - return _Expires; + return _Connection; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - - if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 11: + { + if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 68719476736L) != 0)) + if (((_bits & 65536L) != 0)) { - return _Referer; + return _ContentMD5; } else { @@ -981,13 +1005,13 @@ protected override StringValues GetValueFast(string key) } break; - case 17: + case 12: { - if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 64L) != 0)) + if (((_bits & 17179869184L) != 0)) { - return _TransferEncoding; + return _MaxForwards; } else { @@ -995,11 +1019,11 @@ protected override StringValues GetValueFast(string key) } } - if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1073741824L) != 0)) + if (((_bits & 4096L) != 0)) { - return _IfModifiedSince; + return _ContentType; } else { @@ -1009,29 +1033,25 @@ protected override StringValues GetValueFast(string key) } break; - case 3: + case 13: { - if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 256L) != 0)) + if (((_bits & 524288L) != 0)) { - return _Via; + return _LastModified; } else { throw new System.Collections.Generic.KeyNotFoundException(); } } - } - break; - - case 5: - { - if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1024L) != 0)) + if (((_bits & 2147483648L) != 0)) { - return _Allow; + return _IfNoneMatch; } else { @@ -1039,11 +1059,35 @@ protected override StringValues GetValueFast(string key) } } - if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 137438953472L) != 0)) + if (((_bits & 131072L) != 0)) { - return _Range; + return _ContentRange; + } + else + { + throw new System.Collections.Generic.KeyNotFoundException(); + } + } + + if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1L) != 0)) + { + return _CacheControl; + } + else + { + throw new System.Collections.Generic.KeyNotFoundException(); + } + } + + if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 16777216L) != 0)) + { + return _Authorization; } else { @@ -1081,13 +1125,13 @@ protected override StringValues GetValueFast(string key) } break; - case 12: + case 15: { - if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4096L) != 0)) + if (((_bits & 8388608L) != 0)) { - return _ContentType; + return _AcceptLanguage; } else { @@ -1095,11 +1139,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 17179869184L) != 0)) + if (((_bits & 4194304L) != 0)) { - return _MaxForwards; + return _AcceptEncoding; } else { @@ -1111,11 +1155,11 @@ protected override StringValues GetValueFast(string key) case 16: { - if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8192L) != 0)) + if (((_bits & 32768L) != 0)) { - return _ContentEncoding; + return _ContentLocation; } else { @@ -1135,27 +1179,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 32768L) != 0)) - { - return _ContentLocation; - } - else - { - throw new System.Collections.Generic.KeyNotFoundException(); - } - } - } - break; - - case 11: - { - if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 65536L) != 0)) + if (((_bits & 8192L) != 0)) { - return _ContentMD5; + return _ContentEncoding; } else { @@ -1165,13 +1193,13 @@ protected override StringValues GetValueFast(string key) } break; - case 15: + case 17: { - if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4194304L) != 0)) + if (((_bits & 64L) != 0)) { - return _AcceptEncoding; + return _TransferEncoding; } else { @@ -1179,11 +1207,11 @@ protected override StringValues GetValueFast(string key) } } - if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8388608L) != 0)) + if (((_bits & 1073741824L) != 0)) { - return _AcceptLanguage; + return _IfModifiedSince; } else { @@ -1193,13 +1221,13 @@ protected override StringValues GetValueFast(string key) } break; - case 8: + case 19: { - if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 536870912L) != 0)) + if (((_bits & 34359738368L) != 0)) { - return _IfMatch; + return _ProxyAuthorization; } else { @@ -1207,22 +1235,6 @@ protected override StringValues GetValueFast(string key) } } - if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 4294967296L) != 0)) - { - return _IfRange; - } - else - { - throw new System.Collections.Generic.KeyNotFoundException(); - } - } - } - break; - - case 19: - { if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { if (((_bits & 8589934592L) != 0)) @@ -1234,18 +1246,6 @@ protected override StringValues GetValueFast(string key) throw new System.Collections.Generic.KeyNotFoundException(); } } - - if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 34359738368L) != 0)) - { - return _ProxyAuthorization; - } - else - { - throw new System.Collections.Generic.KeyNotFoundException(); - } - } } break; @@ -1265,13 +1265,13 @@ protected override StringValues GetValueFast(string key) } break; - case 9: + case 3: { - if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 549755813888L) != 0)) + if (((_bits & 256L) != 0)) { - return _Translate; + return _Via; } else { @@ -1291,13 +1291,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) { switch(key.Length) { - case 13: + case 4: { - if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1L) != 0)) + if (((_bits & 268435456L) != 0)) { - value = _CacheControl; + value = _Host; return true; } else @@ -1307,11 +1307,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 131072L) != 0)) + if (((_bits & 134217728L) != 0)) { - value = _ContentRange; + value = _From; return true; } else @@ -1321,11 +1321,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 524288L) != 0)) + if (((_bits & 4L) != 0)) { - value = _LastModified; + value = _Date; return true; } else @@ -1334,12 +1334,16 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - - if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 5: + { + if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16777216L) != 0)) + if (((_bits & 137438953472L) != 0)) { - value = _Authorization; + value = _Range; return true; } else @@ -1349,11 +1353,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2147483648L) != 0)) + if (((_bits & 1024L) != 0)) { - value = _IfNoneMatch; + value = _Allow; return true; } else @@ -1365,13 +1369,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 10: + case 6: { - if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2L) != 0)) + if (((_bits & 16L) != 0)) { - value = _Connection; + value = _Pragma; return true; } else @@ -1381,11 +1385,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8L) != 0)) + if (((_bits & 67108864L) != 0)) { - value = _KeepAlive; + value = _Expect; return true; } else @@ -1395,11 +1399,25 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1099511627776L) != 0)) + if (((_bits & 33554432L) != 0)) { - value = _UserAgent; + value = _Cookie; + return true; + } + else + { + value = StringValues.Empty; + return false; + } + } + + if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1048576L) != 0)) + { + value = _Accept; return true; } else @@ -1411,13 +1429,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 4: + case 7: { - if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4L) != 0)) + if (((_bits & 512L) != 0)) { - value = _Date; + value = _Warning; return true; } else @@ -1427,11 +1445,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 134217728L) != 0)) + if (((_bits & 128L) != 0)) { - value = _From; + value = _Upgrade; return true; } else @@ -1441,11 +1459,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 268435456L) != 0)) + if (((_bits & 32L) != 0)) { - value = _Host; + value = _Trailer; return true; } else @@ -1454,16 +1472,12 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - } - break; - - case 6: - { - if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16L) != 0)) + if (((_bits & 68719476736L) != 0)) { - value = _Pragma; + value = _Referer; return true; } else @@ -1473,11 +1487,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1048576L) != 0)) + if (((_bits & 262144L) != 0)) { - value = _Accept; + value = _Expires; return true; } else @@ -1486,12 +1500,16 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - - if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 8: + { + if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 33554432L) != 0)) + if (((_bits & 4294967296L) != 0)) { - value = _Cookie; + value = _IfRange; return true; } else @@ -1501,11 +1519,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 67108864L) != 0)) + if (((_bits & 536870912L) != 0)) { - value = _Expect; + value = _IfMatch; return true; } else @@ -1517,13 +1535,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 7: + case 9: { - if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32L) != 0)) + if (((_bits & 549755813888L) != 0)) { - value = _Trailer; + value = _Translate; return true; } else @@ -1532,12 +1550,16 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - - if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 10: + { + if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 128L) != 0)) + if (((_bits & 1099511627776L) != 0)) { - value = _Upgrade; + value = _UserAgent; return true; } else @@ -1547,11 +1569,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 512L) != 0)) + if (((_bits & 8L) != 0)) { - value = _Warning; + value = _KeepAlive; return true; } else @@ -1561,11 +1583,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 262144L) != 0)) + if (((_bits & 2L) != 0)) { - value = _Expires; + value = _Connection; return true; } else @@ -1574,12 +1596,16 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - - if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 11: + { + if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 68719476736L) != 0)) + if (((_bits & 65536L) != 0)) { - value = _Referer; + value = _ContentMD5; return true; } else @@ -1591,13 +1617,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 17: + case 12: { - if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 64L) != 0)) + if (((_bits & 17179869184L) != 0)) { - value = _TransferEncoding; + value = _MaxForwards; return true; } else @@ -1607,11 +1633,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1073741824L) != 0)) + if (((_bits & 4096L) != 0)) { - value = _IfModifiedSince; + value = _ContentType; return true; } else @@ -1623,13 +1649,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 3: + case 13: { - if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 256L) != 0)) + if (((_bits & 524288L) != 0)) { - value = _Via; + value = _LastModified; return true; } else @@ -1638,16 +1664,12 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - } - break; - - case 5: - { - if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1024L) != 0)) + if (((_bits & 2147483648L) != 0)) { - value = _Allow; + value = _IfNoneMatch; return true; } else @@ -1657,11 +1679,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 137438953472L) != 0)) + if (((_bits & 131072L) != 0)) { - value = _Range; + value = _ContentRange; return true; } else @@ -1670,16 +1692,12 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - } - break; - - case 14: - { - if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2048L) != 0)) + if (((_bits & 1L) != 0)) { - value = _ContentLength; + value = _CacheControl; return true; } else @@ -1689,11 +1707,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2097152L) != 0)) + if (((_bits & 16777216L) != 0)) { - value = _AcceptCharset; + value = _Authorization; return true; } else @@ -1705,13 +1723,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 12: + case 14: { - if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4096L) != 0)) + if (((_bits & 2048L) != 0)) { - value = _ContentType; + value = _ContentLength; return true; } else @@ -1721,11 +1739,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 17179869184L) != 0)) + if (((_bits & 2097152L) != 0)) { - value = _MaxForwards; + value = _AcceptCharset; return true; } else @@ -1737,27 +1755,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 16: + case 15: { - if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 8192L) != 0)) - { - value = _ContentEncoding; - return true; - } - else - { - value = StringValues.Empty; - return false; - } - } - - if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16384L) != 0)) + if (((_bits & 8388608L) != 0)) { - value = _ContentLanguage; + value = _AcceptLanguage; return true; } else @@ -1767,11 +1771,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32768L) != 0)) + if (((_bits & 4194304L) != 0)) { - value = _ContentLocation; + value = _AcceptEncoding; return true; } else @@ -1783,13 +1787,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 11: + case 16: { - if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 65536L) != 0)) + if (((_bits & 32768L) != 0)) { - value = _ContentMD5; + value = _ContentLocation; return true; } else @@ -1798,16 +1802,12 @@ protected override bool TryGetValueFast(string key, out StringValues value) return false; } } - } - break; - - case 15: - { - if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4194304L) != 0)) + if (((_bits & 16384L) != 0)) { - value = _AcceptEncoding; + value = _ContentLanguage; return true; } else @@ -1817,11 +1817,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8388608L) != 0)) + if (((_bits & 8192L) != 0)) { - value = _AcceptLanguage; + value = _ContentEncoding; return true; } else @@ -1833,13 +1833,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 8: + case 17: { - if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 536870912L) != 0)) + if (((_bits & 64L) != 0)) { - value = _IfMatch; + value = _TransferEncoding; return true; } else @@ -1849,11 +1849,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4294967296L) != 0)) + if (((_bits & 1073741824L) != 0)) { - value = _IfRange; + value = _IfModifiedSince; return true; } else @@ -1867,11 +1867,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) case 19: { - if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8589934592L) != 0)) + if (((_bits & 34359738368L) != 0)) { - value = _IfUnmodifiedSince; + value = _ProxyAuthorization; return true; } else @@ -1881,11 +1881,11 @@ protected override bool TryGetValueFast(string key, out StringValues value) } } - if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 34359738368L) != 0)) + if (((_bits & 8589934592L) != 0)) { - value = _ProxyAuthorization; + value = _IfUnmodifiedSince; return true; } else @@ -1915,13 +1915,13 @@ protected override bool TryGetValueFast(string key, out StringValues value) } break; - case 9: + case 3: { - if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 549755813888L) != 0)) + if (((_bits & 256L) != 0)) { - value = _Translate; + value = _Via; return true; } else @@ -1940,90 +1940,44 @@ protected override void SetValueFast(string key, StringValues value) { switch(key.Length) { - case 13: - { - if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 1L; - _CacheControl = value; - return; - } - - if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 131072L; - _ContentRange = value; - return; - } - - if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 524288L; - _LastModified = value; - return; - } - - if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 16777216L; - _Authorization = value; - return; - } - - if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 2147483648L; - _IfNoneMatch = value; - return; - } - } - break; - - case 10: + case 4: { - if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 2L; - _Connection = value; + _bits |= 268435456L; + _Host = value; return; } - if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 8L; - _KeepAlive = value; + _bits |= 134217728L; + _From = value; return; } - if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 1099511627776L; - _UserAgent = value; + _bits |= 4L; + _Date = value; return; } } break; - case 4: + case 5: { - if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 4L; - _Date = value; - return; - } - - if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 134217728L; - _From = value; + _bits |= 137438953472L; + _Range = value; return; } - if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 268435456L; - _Host = value; + _bits |= 1024L; + _Allow = value; return; } } @@ -2038,10 +1992,10 @@ protected override void SetValueFast(string key, StringValues value) return; } - if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 1048576L; - _Accept = value; + _bits |= 67108864L; + _Expect = value; return; } @@ -2052,10 +2006,10 @@ protected override void SetValueFast(string key, StringValues value) return; } - if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 67108864L; - _Expect = value; + _bits |= 1048576L; + _Accept = value; return; } } @@ -2063,10 +2017,10 @@ protected override void SetValueFast(string key, StringValues value) case 7: { - if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 32L; - _Trailer = value; + _bits |= 512L; + _Warning = value; return; } @@ -2077,89 +2031,89 @@ protected override void SetValueFast(string key, StringValues value) return; } - if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 512L; - _Warning = value; + _bits |= 32L; + _Trailer = value; return; } - if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 262144L; - _Expires = value; + _bits |= 68719476736L; + _Referer = value; return; } - if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 68719476736L; - _Referer = value; + _bits |= 262144L; + _Expires = value; return; } } break; - case 17: + case 8: { - if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 64L; - _TransferEncoding = value; + _bits |= 4294967296L; + _IfRange = value; return; } - if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 1073741824L; - _IfModifiedSince = value; + _bits |= 536870912L; + _IfMatch = value; return; } } break; - case 3: + case 9: { - if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 256L; - _Via = value; + _bits |= 549755813888L; + _Translate = value; return; } } break; - case 5: + case 10: { - if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 1024L; - _Allow = value; + _bits |= 1099511627776L; + _UserAgent = value; return; } - if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 137438953472L; - _Range = value; + _bits |= 8L; + _KeepAlive = value; + return; + } + + if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 2L; + _Connection = value; return; } } break; - case 14: + case 11: { - if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - _bits |= 2048L; - _ContentLength = value; - return; - } - - if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 2097152L; - _AcceptCharset = value; + _bits |= 65536L; + _ContentMD5 = value; return; } } @@ -2167,53 +2121,74 @@ protected override void SetValueFast(string key, StringValues value) case 12: { - if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 4096L; - _ContentType = value; + _bits |= 17179869184L; + _MaxForwards = value; return; } - if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 17179869184L; - _MaxForwards = value; + _bits |= 4096L; + _ContentType = value; return; } } break; - case 16: + case 13: { - if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 8192L; - _ContentEncoding = value; + _bits |= 524288L; + _LastModified = value; return; } - if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 16384L; - _ContentLanguage = value; + _bits |= 2147483648L; + _IfNoneMatch = value; return; } - if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 32768L; - _ContentLocation = value; + _bits |= 131072L; + _ContentRange = value; + return; + } + + if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 1L; + _CacheControl = value; + return; + } + + if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 16777216L; + _Authorization = value; return; } } break; - case 11: + case 14: { - if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 65536L; - _ContentMD5 = value; + _bits |= 2048L; + _ContentLength = value; + return; + } + + if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 2097152L; + _AcceptCharset = value; return; } } @@ -2221,35 +2196,60 @@ protected override void SetValueFast(string key, StringValues value) case 15: { + if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 8388608L; + _AcceptLanguage = value; + return; + } + if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { _bits |= 4194304L; _AcceptEncoding = value; return; } + } + break; + + case 16: + { + if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 32768L; + _ContentLocation = value; + return; + } - if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 8388608L; - _AcceptLanguage = value; + _bits |= 16384L; + _ContentLanguage = value; + return; + } + + if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + _bits |= 8192L; + _ContentEncoding = value; return; } } break; - case 8: + case 17: { - if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 536870912L; - _IfMatch = value; + _bits |= 64L; + _TransferEncoding = value; return; } - if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 4294967296L; - _IfRange = value; + _bits |= 1073741824L; + _IfModifiedSince = value; return; } } @@ -2257,17 +2257,17 @@ protected override void SetValueFast(string key, StringValues value) case 19: { - if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 8589934592L; - _IfUnmodifiedSince = value; + _bits |= 34359738368L; + _ProxyAuthorization = value; return; } - if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 34359738368L; - _ProxyAuthorization = value; + _bits |= 8589934592L; + _IfUnmodifiedSince = value; return; } } @@ -2284,12 +2284,12 @@ protected override void SetValueFast(string key, StringValues value) } break; - case 9: + case 3: { - if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) { - _bits |= 549755813888L; - _Translate = value; + _bits |= 256L; + _Via = value; return; } } @@ -2301,308 +2301,349 @@ protected override void AddValueFast(string key, StringValues value) { switch(key.Length) { - case 13: + case 4: { - if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1L) != 0)) + if (((_bits & 268435456L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 1L; - _CacheControl = value; + _bits |= 268435456L; + _Host = value; return; } - if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 131072L) != 0)) + if (((_bits & 134217728L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 131072L; - _ContentRange = value; + _bits |= 134217728L; + _From = value; return; } - if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 524288L) != 0)) + if (((_bits & 4L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 524288L; - _LastModified = value; + _bits |= 4L; + _Date = value; return; } - - if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 5: + { + if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16777216L) != 0)) + if (((_bits & 137438953472L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 16777216L; - _Authorization = value; + _bits |= 137438953472L; + _Range = value; return; } - if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2147483648L) != 0)) + if (((_bits & 1024L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 2147483648L; - _IfNoneMatch = value; + _bits |= 1024L; + _Allow = value; return; } } break; - case 10: + case 6: { - if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2L) != 0)) + if (((_bits & 16L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 2L; - _Connection = value; - return; + _bits |= 16L; + _Pragma = value; + return; } - if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8L) != 0)) + if (((_bits & 67108864L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 8L; - _KeepAlive = value; + _bits |= 67108864L; + _Expect = value; return; } - if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1099511627776L) != 0)) + if (((_bits & 33554432L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 1099511627776L; - _UserAgent = value; + _bits |= 33554432L; + _Cookie = value; + return; + } + + if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1048576L) != 0)) + { + throw new ArgumentException("An item with the same key has already been added."); + } + _bits |= 1048576L; + _Accept = value; return; } } break; - case 4: + case 7: { - if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4L) != 0)) + if (((_bits & 512L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 4L; - _Date = value; + _bits |= 512L; + _Warning = value; return; } - if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 134217728L) != 0)) + if (((_bits & 128L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 134217728L; - _From = value; + _bits |= 128L; + _Upgrade = value; return; } - if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 268435456L) != 0)) + if (((_bits & 32L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 268435456L; - _Host = value; + _bits |= 32L; + _Trailer = value; return; } - } - break; - - case 6: - { - if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16L) != 0)) + if (((_bits & 68719476736L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 16L; - _Pragma = value; + _bits |= 68719476736L; + _Referer = value; return; } - if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1048576L) != 0)) + if (((_bits & 262144L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 1048576L; - _Accept = value; + _bits |= 262144L; + _Expires = value; return; } - - if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 8: + { + if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 33554432L) != 0)) + if (((_bits & 4294967296L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 33554432L; - _Cookie = value; + _bits |= 4294967296L; + _IfRange = value; return; } - if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 67108864L) != 0)) + if (((_bits & 536870912L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 67108864L; - _Expect = value; + _bits |= 536870912L; + _IfMatch = value; return; } } break; - case 7: + case 9: { - if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32L) != 0)) + if (((_bits & 549755813888L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 32L; - _Trailer = value; + _bits |= 549755813888L; + _Translate = value; return; } - - if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 10: + { + if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 128L) != 0)) + if (((_bits & 1099511627776L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 128L; - _Upgrade = value; + _bits |= 1099511627776L; + _UserAgent = value; return; } - if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 512L) != 0)) + if (((_bits & 8L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 512L; - _Warning = value; + _bits |= 8L; + _KeepAlive = value; return; } - if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 262144L) != 0)) + if (((_bits & 2L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 262144L; - _Expires = value; + _bits |= 2L; + _Connection = value; return; } - - if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 11: + { + if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 68719476736L) != 0)) + if (((_bits & 65536L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 68719476736L; - _Referer = value; + _bits |= 65536L; + _ContentMD5 = value; return; } } break; - case 17: + case 12: { - if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 64L) != 0)) + if (((_bits & 17179869184L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 64L; - _TransferEncoding = value; + _bits |= 17179869184L; + _MaxForwards = value; return; } - if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1073741824L) != 0)) + if (((_bits & 4096L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 1073741824L; - _IfModifiedSince = value; + _bits |= 4096L; + _ContentType = value; return; } } break; - case 3: + case 13: { - if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 256L) != 0)) + if (((_bits & 524288L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 256L; - _Via = value; + _bits |= 524288L; + _LastModified = value; return; } - } - break; - - case 5: - { - if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1024L) != 0)) + if (((_bits & 2147483648L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 1024L; - _Allow = value; + _bits |= 2147483648L; + _IfNoneMatch = value; return; } - if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 137438953472L) != 0)) + if (((_bits & 131072L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 137438953472L; - _Range = value; + _bits |= 131072L; + _ContentRange = value; + return; + } + + if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1L) != 0)) + { + throw new ArgumentException("An item with the same key has already been added."); + } + _bits |= 1L; + _CacheControl = value; + return; + } + + if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 16777216L) != 0)) + { + throw new ArgumentException("An item with the same key has already been added."); + } + _bits |= 16777216L; + _Authorization = value; return; } } @@ -2634,27 +2675,27 @@ protected override void AddValueFast(string key, StringValues value) } break; - case 12: + case 15: { - if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4096L) != 0)) + if (((_bits & 8388608L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 4096L; - _ContentType = value; + _bits |= 8388608L; + _AcceptLanguage = value; return; } - if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 17179869184L) != 0)) + if (((_bits & 4194304L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 17179869184L; - _MaxForwards = value; + _bits |= 4194304L; + _AcceptEncoding = value; return; } } @@ -2662,14 +2703,14 @@ protected override void AddValueFast(string key, StringValues value) case 16: { - if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8192L) != 0)) + if (((_bits & 32768L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 8192L; - _ContentEncoding = value; + _bits |= 32768L; + _ContentLocation = value; return; } @@ -2684,88 +2725,58 @@ protected override void AddValueFast(string key, StringValues value) return; } - if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32768L) != 0)) + if (((_bits & 8192L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 32768L; - _ContentLocation = value; - return; - } - } - break; - - case 11: - { - if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 65536L) != 0)) - { - throw new ArgumentException("An item with the same key has already been added."); - } - _bits |= 65536L; - _ContentMD5 = value; + _bits |= 8192L; + _ContentEncoding = value; return; } } break; - case 15: + case 17: { - if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4194304L) != 0)) + if (((_bits & 64L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 4194304L; - _AcceptEncoding = value; + _bits |= 64L; + _TransferEncoding = value; return; } - if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8388608L) != 0)) + if (((_bits & 1073741824L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 8388608L; - _AcceptLanguage = value; + _bits |= 1073741824L; + _IfModifiedSince = value; return; } } break; - case 8: + case 19: { - if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 536870912L) != 0)) + if (((_bits & 34359738368L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 536870912L; - _IfMatch = value; + _bits |= 34359738368L; + _ProxyAuthorization = value; return; } - if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 4294967296L) != 0)) - { - throw new ArgumentException("An item with the same key has already been added."); - } - _bits |= 4294967296L; - _IfRange = value; - return; - } - } - break; - - case 19: - { if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { if (((_bits & 8589934592L) != 0)) @@ -2776,17 +2787,6 @@ protected override void AddValueFast(string key, StringValues value) _IfUnmodifiedSince = value; return; } - - if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 34359738368L) != 0)) - { - throw new ArgumentException("An item with the same key has already been added."); - } - _bits |= 34359738368L; - _ProxyAuthorization = value; - return; - } } break; @@ -2805,16 +2805,16 @@ protected override void AddValueFast(string key, StringValues value) } break; - case 9: + case 3: { - if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 549755813888L) != 0)) + if (((_bits & 256L) != 0)) { throw new ArgumentException("An item with the same key has already been added."); } - _bits |= 549755813888L; - _Translate = value; + _bits |= 256L; + _Via = value; return; } } @@ -2826,14 +2826,14 @@ protected override bool RemoveFast(string key) { switch(key.Length) { - case 13: + case 4: { - if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1L) != 0)) + if (((_bits & 268435456L) != 0)) { - _bits &= ~1L; - _CacheControl = StringValues.Empty; + _bits &= ~268435456L; + _Host = StringValues.Empty; return true; } else @@ -2842,12 +2842,12 @@ protected override bool RemoveFast(string key) } } - if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 131072L) != 0)) + if (((_bits & 134217728L) != 0)) { - _bits &= ~131072L; - _ContentRange = StringValues.Empty; + _bits &= ~134217728L; + _From = StringValues.Empty; return true; } else @@ -2856,12 +2856,12 @@ protected override bool RemoveFast(string key) } } - if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 524288L) != 0)) + if (((_bits & 4L) != 0)) { - _bits &= ~524288L; - _LastModified = StringValues.Empty; + _bits &= ~4L; + _Date = StringValues.Empty; return true; } else @@ -2869,13 +2869,17 @@ protected override bool RemoveFast(string key) return false; } } - - if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 5: + { + if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16777216L) != 0)) + if (((_bits & 137438953472L) != 0)) { - _bits &= ~16777216L; - _Authorization = StringValues.Empty; + _bits &= ~137438953472L; + _Range = StringValues.Empty; return true; } else @@ -2884,12 +2888,12 @@ protected override bool RemoveFast(string key) } } - if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2147483648L) != 0)) + if (((_bits & 1024L) != 0)) { - _bits &= ~2147483648L; - _IfNoneMatch = StringValues.Empty; + _bits &= ~1024L; + _Allow = StringValues.Empty; return true; } else @@ -2900,14 +2904,14 @@ protected override bool RemoveFast(string key) } break; - case 10: + case 6: { - if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2L) != 0)) + if (((_bits & 16L) != 0)) { - _bits &= ~2L; - _Connection = StringValues.Empty; + _bits &= ~16L; + _Pragma = StringValues.Empty; return true; } else @@ -2916,12 +2920,12 @@ protected override bool RemoveFast(string key) } } - if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8L) != 0)) + if (((_bits & 67108864L) != 0)) { - _bits &= ~8L; - _KeepAlive = StringValues.Empty; + _bits &= ~67108864L; + _Expect = StringValues.Empty; return true; } else @@ -2930,12 +2934,26 @@ protected override bool RemoveFast(string key) } } - if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1099511627776L) != 0)) + if (((_bits & 33554432L) != 0)) { - _bits &= ~1099511627776L; - _UserAgent = StringValues.Empty; + _bits &= ~33554432L; + _Cookie = StringValues.Empty; + return true; + } + else + { + return false; + } + } + + if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1048576L) != 0)) + { + _bits &= ~1048576L; + _Accept = StringValues.Empty; return true; } else @@ -2946,14 +2964,14 @@ protected override bool RemoveFast(string key) } break; - case 4: + case 7: { - if ("Date".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4L) != 0)) + if (((_bits & 512L) != 0)) { - _bits &= ~4L; - _Date = StringValues.Empty; + _bits &= ~512L; + _Warning = StringValues.Empty; return true; } else @@ -2962,12 +2980,12 @@ protected override bool RemoveFast(string key) } } - if ("From".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 134217728L) != 0)) + if (((_bits & 128L) != 0)) { - _bits &= ~134217728L; - _From = StringValues.Empty; + _bits &= ~128L; + _Upgrade = StringValues.Empty; return true; } else @@ -2976,12 +2994,12 @@ protected override bool RemoveFast(string key) } } - if ("Host".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 268435456L) != 0)) + if (((_bits & 32L) != 0)) { - _bits &= ~268435456L; - _Host = StringValues.Empty; + _bits &= ~32L; + _Trailer = StringValues.Empty; return true; } else @@ -2989,17 +3007,13 @@ protected override bool RemoveFast(string key) return false; } } - } - break; - - case 6: - { - if ("Pragma".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16L) != 0)) + if (((_bits & 68719476736L) != 0)) { - _bits &= ~16L; - _Pragma = StringValues.Empty; + _bits &= ~68719476736L; + _Referer = StringValues.Empty; return true; } else @@ -3008,12 +3022,12 @@ protected override bool RemoveFast(string key) } } - if ("Accept".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1048576L) != 0)) + if (((_bits & 262144L) != 0)) { - _bits &= ~1048576L; - _Accept = StringValues.Empty; + _bits &= ~262144L; + _Expires = StringValues.Empty; return true; } else @@ -3021,13 +3035,17 @@ protected override bool RemoveFast(string key) return false; } } - - if ("Cookie".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 8: + { + if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 33554432L) != 0)) + if (((_bits & 4294967296L) != 0)) { - _bits &= ~33554432L; - _Cookie = StringValues.Empty; + _bits &= ~4294967296L; + _IfRange = StringValues.Empty; return true; } else @@ -3036,12 +3054,12 @@ protected override bool RemoveFast(string key) } } - if ("Expect".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 67108864L) != 0)) + if (((_bits & 536870912L) != 0)) { - _bits &= ~67108864L; - _Expect = StringValues.Empty; + _bits &= ~536870912L; + _IfMatch = StringValues.Empty; return true; } else @@ -3052,14 +3070,14 @@ protected override bool RemoveFast(string key) } break; - case 7: + case 9: { - if ("Trailer".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32L) != 0)) + if (((_bits & 549755813888L) != 0)) { - _bits &= ~32L; - _Trailer = StringValues.Empty; + _bits &= ~549755813888L; + _Translate = StringValues.Empty; return true; } else @@ -3067,13 +3085,17 @@ protected override bool RemoveFast(string key) return false; } } - - if ("Upgrade".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 128L) != 0)) - { - _bits &= ~128L; - _Upgrade = StringValues.Empty; + } + break; + + case 10: + { + if ("User-Agent".Equals(key, StringComparison.OrdinalIgnoreCase)) + { + if (((_bits & 1099511627776L) != 0)) + { + _bits &= ~1099511627776L; + _UserAgent = StringValues.Empty; return true; } else @@ -3082,12 +3104,12 @@ protected override bool RemoveFast(string key) } } - if ("Warning".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Keep-Alive".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 512L) != 0)) + if (((_bits & 8L) != 0)) { - _bits &= ~512L; - _Warning = StringValues.Empty; + _bits &= ~8L; + _KeepAlive = StringValues.Empty; return true; } else @@ -3096,12 +3118,12 @@ protected override bool RemoveFast(string key) } } - if ("Expires".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 262144L) != 0)) + if (((_bits & 2L) != 0)) { - _bits &= ~262144L; - _Expires = StringValues.Empty; + _bits &= ~2L; + _Connection = StringValues.Empty; return true; } else @@ -3109,13 +3131,17 @@ protected override bool RemoveFast(string key) return false; } } - - if ("Referer".Equals(key, StringComparison.OrdinalIgnoreCase)) + } + break; + + case 11: + { + if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 68719476736L) != 0)) + if (((_bits & 65536L) != 0)) { - _bits &= ~68719476736L; - _Referer = StringValues.Empty; + _bits &= ~65536L; + _ContentMD5 = StringValues.Empty; return true; } else @@ -3126,14 +3152,14 @@ protected override bool RemoveFast(string key) } break; - case 17: + case 12: { - if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 64L) != 0)) + if (((_bits & 17179869184L) != 0)) { - _bits &= ~64L; - _TransferEncoding = StringValues.Empty; + _bits &= ~17179869184L; + _MaxForwards = StringValues.Empty; return true; } else @@ -3142,12 +3168,12 @@ protected override bool RemoveFast(string key) } } - if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1073741824L) != 0)) + if (((_bits & 4096L) != 0)) { - _bits &= ~1073741824L; - _IfModifiedSince = StringValues.Empty; + _bits &= ~4096L; + _ContentType = StringValues.Empty; return true; } else @@ -3158,14 +3184,14 @@ protected override bool RemoveFast(string key) } break; - case 3: + case 13: { - if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Last-Modified".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 256L) != 0)) + if (((_bits & 524288L) != 0)) { - _bits &= ~256L; - _Via = StringValues.Empty; + _bits &= ~524288L; + _LastModified = StringValues.Empty; return true; } else @@ -3173,17 +3199,13 @@ protected override bool RemoveFast(string key) return false; } } - } - break; - - case 5: - { - if ("Allow".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("If-None-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 1024L) != 0)) + if (((_bits & 2147483648L) != 0)) { - _bits &= ~1024L; - _Allow = StringValues.Empty; + _bits &= ~2147483648L; + _IfNoneMatch = StringValues.Empty; return true; } else @@ -3192,12 +3214,12 @@ protected override bool RemoveFast(string key) } } - if ("Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 137438953472L) != 0)) + if (((_bits & 131072L) != 0)) { - _bits &= ~137438953472L; - _Range = StringValues.Empty; + _bits &= ~131072L; + _ContentRange = StringValues.Empty; return true; } else @@ -3205,17 +3227,13 @@ protected override bool RemoveFast(string key) return false; } } - } - break; - - case 14: - { - if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Cache-Control".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2048L) != 0)) + if (((_bits & 1L) != 0)) { - _bits &= ~2048L; - _ContentLength = StringValues.Empty; + _bits &= ~1L; + _CacheControl = StringValues.Empty; return true; } else @@ -3224,12 +3242,12 @@ protected override bool RemoveFast(string key) } } - if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 2097152L) != 0)) + if (((_bits & 16777216L) != 0)) { - _bits &= ~2097152L; - _AcceptCharset = StringValues.Empty; + _bits &= ~16777216L; + _Authorization = StringValues.Empty; return true; } else @@ -3240,14 +3258,14 @@ protected override bool RemoveFast(string key) } break; - case 12: + case 14: { - if ("Content-Type".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Length".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4096L) != 0)) + if (((_bits & 2048L) != 0)) { - _bits &= ~4096L; - _ContentType = StringValues.Empty; + _bits &= ~2048L; + _ContentLength = StringValues.Empty; return true; } else @@ -3256,12 +3274,12 @@ protected override bool RemoveFast(string key) } } - if ("Max-Forwards".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Charset".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 17179869184L) != 0)) + if (((_bits & 2097152L) != 0)) { - _bits &= ~17179869184L; - _MaxForwards = StringValues.Empty; + _bits &= ~2097152L; + _AcceptCharset = StringValues.Empty; return true; } else @@ -3272,28 +3290,14 @@ protected override bool RemoveFast(string key) } break; - case 16: + case 15: { - if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) - { - if (((_bits & 8192L) != 0)) - { - _bits &= ~8192L; - _ContentEncoding = StringValues.Empty; - return true; - } - else - { - return false; - } - } - - if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 16384L) != 0)) + if (((_bits & 8388608L) != 0)) { - _bits &= ~16384L; - _ContentLanguage = StringValues.Empty; + _bits &= ~8388608L; + _AcceptLanguage = StringValues.Empty; return true; } else @@ -3302,12 +3306,12 @@ protected override bool RemoveFast(string key) } } - if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 32768L) != 0)) + if (((_bits & 4194304L) != 0)) { - _bits &= ~32768L; - _ContentLocation = StringValues.Empty; + _bits &= ~4194304L; + _AcceptEncoding = StringValues.Empty; return true; } else @@ -3318,14 +3322,14 @@ protected override bool RemoveFast(string key) } break; - case 11: + case 16: { - if ("Content-MD5".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Location".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 65536L) != 0)) + if (((_bits & 32768L) != 0)) { - _bits &= ~65536L; - _ContentMD5 = StringValues.Empty; + _bits &= ~32768L; + _ContentLocation = StringValues.Empty; return true; } else @@ -3333,17 +3337,13 @@ protected override bool RemoveFast(string key) return false; } } - } - break; - - case 15: - { - if ("Accept-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) + + if ("Content-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4194304L) != 0)) + if (((_bits & 16384L) != 0)) { - _bits &= ~4194304L; - _AcceptEncoding = StringValues.Empty; + _bits &= ~16384L; + _ContentLanguage = StringValues.Empty; return true; } else @@ -3352,12 +3352,12 @@ protected override bool RemoveFast(string key) } } - if ("Accept-Language".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Content-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8388608L) != 0)) + if (((_bits & 8192L) != 0)) { - _bits &= ~8388608L; - _AcceptLanguage = StringValues.Empty; + _bits &= ~8192L; + _ContentEncoding = StringValues.Empty; return true; } else @@ -3368,14 +3368,14 @@ protected override bool RemoveFast(string key) } break; - case 8: + case 17: { - if ("If-Match".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Transfer-Encoding".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 536870912L) != 0)) + if (((_bits & 64L) != 0)) { - _bits &= ~536870912L; - _IfMatch = StringValues.Empty; + _bits &= ~64L; + _TransferEncoding = StringValues.Empty; return true; } else @@ -3384,12 +3384,12 @@ protected override bool RemoveFast(string key) } } - if ("If-Range".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Modified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 4294967296L) != 0)) + if (((_bits & 1073741824L) != 0)) { - _bits &= ~4294967296L; - _IfRange = StringValues.Empty; + _bits &= ~1073741824L; + _IfModifiedSince = StringValues.Empty; return true; } else @@ -3402,12 +3402,12 @@ protected override bool RemoveFast(string key) case 19: { - if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 8589934592L) != 0)) + if (((_bits & 34359738368L) != 0)) { - _bits &= ~8589934592L; - _IfUnmodifiedSince = StringValues.Empty; + _bits &= ~34359738368L; + _ProxyAuthorization = StringValues.Empty; return true; } else @@ -3416,12 +3416,12 @@ protected override bool RemoveFast(string key) } } - if ("Proxy-Authorization".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("If-Unmodified-Since".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 34359738368L) != 0)) + if (((_bits & 8589934592L) != 0)) { - _bits &= ~34359738368L; - _ProxyAuthorization = StringValues.Empty; + _bits &= ~8589934592L; + _IfUnmodifiedSince = StringValues.Empty; return true; } else @@ -3450,14 +3450,14 @@ protected override bool RemoveFast(string key) } break; - case 9: + case 3: { - if ("Translate".Equals(key, StringComparison.OrdinalIgnoreCase)) + if ("Via".Equals(key, StringComparison.OrdinalIgnoreCase)) { - if (((_bits & 549755813888L) != 0)) + if (((_bits & 256L) != 0)) { - _bits &= ~549755813888L; - _Translate = StringValues.Empty; + _bits &= ~256L; + _Via = StringValues.Empty; return true; } else @@ -3936,134 +3936,46 @@ protected override void CopyToFast(KeyValuePair[] array, i ((ICollection>)MaybeUnknown)?.CopyTo(array, arrayIndex); } +#if DOTNET5_4 || DNXCORE50 + +#else +#endif public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) { fixed(byte* ptr = keyBytes) { var pUB = ptr + keyOffset; var pUL = (ulong*)pUB; var pUI = (uint*)pUB; var pUS = (ushort*)pUB; switch(keyLength) { - case 13: + case 4: { - if ((((pUL[0] & 16131893727263186911uL) == 5711458528024281411uL) && ((pUI[2] & 3755991007u) == 1330795598u) && ((pUB[12] & 223u) == 76u))) + if ((((pUI[0] & 3755991007u) == 1414745928u))) { - if (((_bits & 1L) != 0)) + if (((_bits & 268435456L) != 0)) { - _CacheControl = AppendValue(_CacheControl, value); + _Host = AppendValue(_Host, value); } else { - _bits |= 1L; - _CacheControl = new StringValues(value); + _bits |= 268435456L; + _Host = new StringValues(value); } return; } - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196310866u) && ((pUB[12] & 223u) == 69u))) + if ((((pUI[0] & 3755991007u) == 1297044038u))) { - if (((_bits & 131072L) != 0)) - { - _ContentRange = AppendValue(_ContentRange, value); - } - else - { - _bits |= 131072L; - _ContentRange = new StringValues(value); - } - return; - } - - if ((((pUL[0] & 16131858680330051551uL) == 4922237774822850892uL) && ((pUI[2] & 3755991007u) == 1162430025u) && ((pUB[12] & 223u) == 68u))) - { - if (((_bits & 524288L) != 0)) - { - _LastModified = AppendValue(_LastModified, value); - } - else - { - _bits |= 524288L; - _LastModified = new StringValues(value); - } - return; - } - - if ((((pUL[0] & 16131858542891098079uL) == 6505821637182772545uL) && ((pUI[2] & 3755991007u) == 1330205761u) && ((pUB[12] & 223u) == 78u))) - { - if (((_bits & 16777216L) != 0)) - { - _Authorization = AppendValue(_Authorization, value); - } - else - { - _bits |= 16777216L; - _Authorization = new StringValues(value); - } - return; - } - - if ((((pUL[0] & 18437701552106889183uL) == 3262099607620765257uL) && ((pUI[2] & 3755991007u) == 1129595213u) && ((pUB[12] & 223u) == 72u))) - { - if (((_bits & 2147483648L) != 0)) - { - _IfNoneMatch = AppendValue(_IfNoneMatch, value); - } - else - { - _bits |= 2147483648L; - _IfNoneMatch = new StringValues(value); - } - return; - } - } - break; - - case 10: - { - if ((((pUL[0] & 16131858542891098079uL) == 5283922227757993795uL) && ((pUS[4] & 57311u) == 20047u))) - { - if (((_bits & 2L) != 0)) - { - _Connection = AppendValue(_Connection, value); - } - else - { - _bits |= 2L; - _Connection = new StringValues(value); - } - return; - } - - if ((((pUL[0] & 16131858680330051551uL) == 5281668125874799947uL) && ((pUS[4] & 57311u) == 17750u))) - { - if (((_bits & 8L) != 0)) + if (((_bits & 134217728L) != 0)) { - _KeepAlive = AppendValue(_KeepAlive, value); + _From = AppendValue(_From, value); } else { - _bits |= 8L; - _KeepAlive = new StringValues(value); + _bits |= 134217728L; + _From = new StringValues(value); } return; } - if ((((pUL[0] & 16131858680330051551uL) == 4992030374873092949uL) && ((pUS[4] & 57311u) == 21582u))) - { - if (((_bits & 1099511627776L) != 0)) - { - _UserAgent = AppendValue(_UserAgent, value); - } - else - { - _bits |= 1099511627776L; - _UserAgent = new StringValues(value); - } - return; - } - } - break; - - case 4: - { if ((((pUI[0] & 3755991007u) == 1163149636u))) { if (((_bits & 4L) != 0)) @@ -4077,31 +3989,35 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string } return; } - - if ((((pUI[0] & 3755991007u) == 1297044038u))) + } + break; + + case 5: + { + if ((((pUI[0] & 3755991007u) == 1196310866u) && ((pUB[4] & 223u) == 69u))) { - if (((_bits & 134217728L) != 0)) + if (((_bits & 137438953472L) != 0)) { - _From = AppendValue(_From, value); + _Range = AppendValue(_Range, value); } else { - _bits |= 134217728L; - _From = new StringValues(value); + _bits |= 137438953472L; + _Range = new StringValues(value); } return; } - if ((((pUI[0] & 3755991007u) == 1414745928u))) + if ((((pUI[0] & 3755991007u) == 1330400321u) && ((pUB[4] & 223u) == 87u))) { - if (((_bits & 268435456L) != 0)) + if (((_bits & 1024L) != 0)) { - _Host = AppendValue(_Host, value); + _Allow = AppendValue(_Allow, value); } else { - _bits |= 268435456L; - _Host = new StringValues(value); + _bits |= 1024L; + _Allow = new StringValues(value); } return; } @@ -4124,16 +4040,16 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string return; } - if ((((pUI[0] & 3755991007u) == 1162036033u) && ((pUS[2] & 57311u) == 21584u))) + if ((((pUI[0] & 3755991007u) == 1162893381u) && ((pUS[2] & 57311u) == 21571u))) { - if (((_bits & 1048576L) != 0)) + if (((_bits & 67108864L) != 0)) { - _Accept = AppendValue(_Accept, value); + _Expect = AppendValue(_Expect, value); } else { - _bits |= 1048576L; - _Accept = new StringValues(value); + _bits |= 67108864L; + _Expect = new StringValues(value); } return; } @@ -4152,16 +4068,16 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string return; } - if ((((pUI[0] & 3755991007u) == 1162893381u) && ((pUS[2] & 57311u) == 21571u))) + if ((((pUI[0] & 3755991007u) == 1162036033u) && ((pUS[2] & 57311u) == 21584u))) { - if (((_bits & 67108864L) != 0)) + if (((_bits & 1048576L) != 0)) { - _Expect = AppendValue(_Expect, value); + _Accept = AppendValue(_Accept, value); } else { - _bits |= 67108864L; - _Expect = new StringValues(value); + _bits |= 1048576L; + _Accept = new StringValues(value); } return; } @@ -4170,16 +4086,16 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string case 7: { - if ((((pUI[0] & 3755991007u) == 1229017684u) && ((pUS[2] & 57311u) == 17740u) && ((pUB[6] & 223u) == 82u))) + if ((((pUI[0] & 3755991007u) == 1314013527u) && ((pUS[2] & 57311u) == 20041u) && ((pUB[6] & 223u) == 71u))) { - if (((_bits & 32L) != 0)) + if (((_bits & 512L) != 0)) { - _Trailer = AppendValue(_Trailer, value); + _Warning = AppendValue(_Warning, value); } else { - _bits |= 32L; - _Trailer = new StringValues(value); + _bits |= 512L; + _Warning = new StringValues(value); } return; } @@ -4198,158 +4114,158 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string return; } - if ((((pUI[0] & 3755991007u) == 1314013527u) && ((pUS[2] & 57311u) == 20041u) && ((pUB[6] & 223u) == 71u))) + if ((((pUI[0] & 3755991007u) == 1229017684u) && ((pUS[2] & 57311u) == 17740u) && ((pUB[6] & 223u) == 82u))) { - if (((_bits & 512L) != 0)) + if (((_bits & 32L) != 0)) { - _Warning = AppendValue(_Warning, value); + _Trailer = AppendValue(_Trailer, value); } else { - _bits |= 512L; - _Warning = new StringValues(value); + _bits |= 32L; + _Trailer = new StringValues(value); } return; } - if ((((pUI[0] & 3755991007u) == 1230002245u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 83u))) + if ((((pUI[0] & 3755991007u) == 1162233170u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 82u))) { - if (((_bits & 262144L) != 0)) + if (((_bits & 68719476736L) != 0)) { - _Expires = AppendValue(_Expires, value); + _Referer = AppendValue(_Referer, value); } else { - _bits |= 262144L; - _Expires = new StringValues(value); + _bits |= 68719476736L; + _Referer = new StringValues(value); } return; } - if ((((pUI[0] & 3755991007u) == 1162233170u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 82u))) + if ((((pUI[0] & 3755991007u) == 1230002245u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 83u))) { - if (((_bits & 68719476736L) != 0)) + if (((_bits & 262144L) != 0)) { - _Referer = AppendValue(_Referer, value); + _Expires = AppendValue(_Expires, value); } else { - _bits |= 68719476736L; - _Referer = new StringValues(value); + _bits |= 262144L; + _Expires = new StringValues(value); } return; } } break; - case 17: + case 8: { - if ((((pUL[0] & 16131858542891098079uL) == 5928221808112259668uL) && ((pUL[1] & 16131858542891098111uL) == 5641115115480565037uL) && ((pUB[16] & 223u) == 71u))) + if ((((pUL[0] & 16131858542893195231uL) == 4992044754422023753uL))) { - if (((_bits & 64L) != 0)) + if (((_bits & 4294967296L) != 0)) { - _TransferEncoding = AppendValue(_TransferEncoding, value); + _IfRange = AppendValue(_IfRange, value); } else { - _bits |= 64L; - _TransferEncoding = new StringValues(value); + _bits |= 4294967296L; + _IfRange = new StringValues(value); } return; } - if ((((pUL[0] & 16131858542893195231uL) == 5064654363342751305uL) && ((pUL[1] & 16131858543427968991uL) == 4849894470315165001uL) && ((pUB[16] & 223u) == 69u))) + if ((((pUL[0] & 16131858542893195231uL) == 5207098233614845513uL))) { - if (((_bits & 1073741824L) != 0)) + if (((_bits & 536870912L) != 0)) { - _IfModifiedSince = AppendValue(_IfModifiedSince, value); + _IfMatch = AppendValue(_IfMatch, value); } else { - _bits |= 1073741824L; - _IfModifiedSince = new StringValues(value); + _bits |= 536870912L; + _IfMatch = new StringValues(value); } return; } } break; - case 3: + case 9: { - if ((((pUS[0] & 57311u) == 18774u) && ((pUB[2] & 223u) == 65u))) + if ((((pUL[0] & 16131858542891098079uL) == 6071217693351039572uL) && ((pUB[8] & 223u) == 69u))) { - if (((_bits & 256L) != 0)) + if (((_bits & 549755813888L) != 0)) { - _Via = AppendValue(_Via, value); + _Translate = AppendValue(_Translate, value); } else { - _bits |= 256L; - _Via = new StringValues(value); + _bits |= 549755813888L; + _Translate = new StringValues(value); } return; } } break; - case 5: + case 10: { - if ((((pUI[0] & 3755991007u) == 1330400321u) && ((pUB[4] & 223u) == 87u))) + if ((((pUL[0] & 16131858680330051551uL) == 4992030374873092949uL) && ((pUS[4] & 57311u) == 21582u))) { - if (((_bits & 1024L) != 0)) + if (((_bits & 1099511627776L) != 0)) { - _Allow = AppendValue(_Allow, value); + _UserAgent = AppendValue(_UserAgent, value); } else { - _bits |= 1024L; - _Allow = new StringValues(value); + _bits |= 1099511627776L; + _UserAgent = new StringValues(value); } return; } - if ((((pUI[0] & 3755991007u) == 1196310866u) && ((pUB[4] & 223u) == 69u))) + if ((((pUL[0] & 16131858680330051551uL) == 5281668125874799947uL) && ((pUS[4] & 57311u) == 17750u))) { - if (((_bits & 137438953472L) != 0)) + if (((_bits & 8L) != 0)) { - _Range = AppendValue(_Range, value); + _KeepAlive = AppendValue(_KeepAlive, value); } else { - _bits |= 137438953472L; - _Range = new StringValues(value); + _bits |= 8L; + _KeepAlive = new StringValues(value); } return; } - } - break; - - case 14: - { - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196311884u) && ((pUS[6] & 57311u) == 18516u))) + + if ((((pUL[0] & 16131858542891098079uL) == 5283922227757993795uL) && ((pUS[4] & 57311u) == 20047u))) { - if (((_bits & 2048L) != 0)) + if (((_bits & 2L) != 0)) { - _ContentLength = AppendValue(_ContentLength, value); + _Connection = AppendValue(_Connection, value); } else { - _bits |= 2048L; - _ContentLength = new StringValues(value); + _bits |= 2L; + _Connection = new StringValues(value); } return; } - - if ((((pUL[0] & 16140865742145839071uL) == 4840617878229304129uL) && ((pUI[2] & 3755991007u) == 1397899592u) && ((pUS[6] & 57311u) == 21573u))) + } + break; + + case 11: + { + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUS[4] & 57311u) == 17485u) && ((pUB[10] & 255u) == 53u))) { - if (((_bits & 2097152L) != 0)) + if (((_bits & 65536L) != 0)) { - _AcceptCharset = AppendValue(_AcceptCharset, value); + _ContentMD5 = AppendValue(_ContentMD5, value); } else { - _bits |= 2097152L; - _AcceptCharset = new StringValues(value); + _bits |= 65536L; + _ContentMD5 = new StringValues(value); } return; } @@ -4358,6 +4274,20 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string case 12: { + if ((((pUL[0] & 16131858543427968991uL) == 6292178792217067853uL) && ((pUI[2] & 3755991007u) == 1396986433u))) + { + if (((_bits & 17179869184L) != 0)) + { + _MaxForwards = AppendValue(_MaxForwards, value); + } + else + { + _bits |= 17179869184L; + _MaxForwards = new StringValues(value); + } + return; + } + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1162893652u))) { if (((_bits & 4096L) != 0)) @@ -4371,81 +4301,109 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string } return; } + } + break; + + case 13: + { + if ((((pUL[0] & 16131858680330051551uL) == 4922237774822850892uL) && ((pUI[2] & 3755991007u) == 1162430025u) && ((pUB[12] & 223u) == 68u))) + { + if (((_bits & 524288L) != 0)) + { + _LastModified = AppendValue(_LastModified, value); + } + else + { + _bits |= 524288L; + _LastModified = new StringValues(value); + } + return; + } - if ((((pUL[0] & 16131858543427968991uL) == 6292178792217067853uL) && ((pUI[2] & 3755991007u) == 1396986433u))) + if ((((pUL[0] & 18437701552106889183uL) == 3262099607620765257uL) && ((pUI[2] & 3755991007u) == 1129595213u) && ((pUB[12] & 223u) == 72u))) { - if (((_bits & 17179869184L) != 0)) + if (((_bits & 2147483648L) != 0)) { - _MaxForwards = AppendValue(_MaxForwards, value); + _IfNoneMatch = AppendValue(_IfNoneMatch, value); } else { - _bits |= 17179869184L; - _MaxForwards = new StringValues(value); + _bits |= 2147483648L; + _IfNoneMatch = new StringValues(value); } return; } - } - break; - - case 16: - { - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5138124782612729413uL))) + + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196310866u) && ((pUB[12] & 223u) == 69u))) { - if (((_bits & 8192L) != 0)) + if (((_bits & 131072L) != 0)) { - _ContentEncoding = AppendValue(_ContentEncoding, value); + _ContentRange = AppendValue(_ContentRange, value); } else { - _bits |= 8192L; - _ContentEncoding = new StringValues(value); + _bits |= 131072L; + _ContentRange = new StringValues(value); } return; } - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 4992030546487820620uL))) + if ((((pUL[0] & 16131893727263186911uL) == 5711458528024281411uL) && ((pUI[2] & 3755991007u) == 1330795598u) && ((pUB[12] & 223u) == 76u))) { - if (((_bits & 16384L) != 0)) + if (((_bits & 1L) != 0)) { - _ContentLanguage = AppendValue(_ContentLanguage, value); + _CacheControl = AppendValue(_CacheControl, value); } else { - _bits |= 16384L; - _ContentLanguage = new StringValues(value); + _bits |= 1L; + _CacheControl = new StringValues(value); } return; } - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5642809484339531596uL))) + if ((((pUL[0] & 16131858542891098079uL) == 6505821637182772545uL) && ((pUI[2] & 3755991007u) == 1330205761u) && ((pUB[12] & 223u) == 78u))) { - if (((_bits & 32768L) != 0)) + if (((_bits & 16777216L) != 0)) { - _ContentLocation = AppendValue(_ContentLocation, value); + _Authorization = AppendValue(_Authorization, value); } else { - _bits |= 32768L; - _ContentLocation = new StringValues(value); + _bits |= 16777216L; + _Authorization = new StringValues(value); } return; } } break; - case 11: + case 14: { - if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUS[4] & 57311u) == 17485u) && ((pUB[10] & 255u) == 53u))) + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196311884u) && ((pUS[6] & 57311u) == 18516u))) { - if (((_bits & 65536L) != 0)) + if (((_bits & 2048L) != 0)) { - _ContentMD5 = AppendValue(_ContentMD5, value); + _ContentLength = AppendValue(_ContentLength, value); } else { - _bits |= 65536L; - _ContentMD5 = new StringValues(value); + _bits |= 2048L; + _ContentLength = new StringValues(value); + } + return; + } + + if ((((pUL[0] & 16140865742145839071uL) == 4840617878229304129uL) && ((pUI[2] & 3755991007u) == 1397899592u) && ((pUS[6] & 57311u) == 21573u))) + { + if (((_bits & 2097152L) != 0)) + { + _AcceptCharset = AppendValue(_AcceptCharset, value); + } + else + { + _bits |= 2097152L; + _AcceptCharset = new StringValues(value); } return; } @@ -4454,6 +4412,20 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string case 15: { + if ((((pUL[0] & 16140865742145839071uL) == 5489136224570655553uL) && ((pUI[2] & 3755991007u) == 1430736449u) && ((pUS[6] & 57311u) == 18241u) && ((pUB[14] & 223u) == 69u))) + { + if (((_bits & 8388608L) != 0)) + { + _AcceptLanguage = AppendValue(_AcceptLanguage, value); + } + else + { + _bits |= 8388608L; + _AcceptLanguage = new StringValues(value); + } + return; + } + if ((((pUL[0] & 16140865742145839071uL) == 4984733066305160001uL) && ((pUI[2] & 3755991007u) == 1146045262u) && ((pUS[6] & 57311u) == 20041u) && ((pUB[14] & 223u) == 71u))) { if (((_bits & 4194304L) != 0)) @@ -4467,49 +4439,81 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string } return; } + } + break; + + case 16: + { + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5642809484339531596uL))) + { + if (((_bits & 32768L) != 0)) + { + _ContentLocation = AppendValue(_ContentLocation, value); + } + else + { + _bits |= 32768L; + _ContentLocation = new StringValues(value); + } + return; + } - if ((((pUL[0] & 16140865742145839071uL) == 5489136224570655553uL) && ((pUI[2] & 3755991007u) == 1430736449u) && ((pUS[6] & 57311u) == 18241u) && ((pUB[14] & 223u) == 69u))) + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 4992030546487820620uL))) { - if (((_bits & 8388608L) != 0)) + if (((_bits & 16384L) != 0)) { - _AcceptLanguage = AppendValue(_AcceptLanguage, value); + _ContentLanguage = AppendValue(_ContentLanguage, value); } else { - _bits |= 8388608L; - _AcceptLanguage = new StringValues(value); + _bits |= 16384L; + _ContentLanguage = new StringValues(value); + } + return; + } + + if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5138124782612729413uL))) + { + if (((_bits & 8192L) != 0)) + { + _ContentEncoding = AppendValue(_ContentEncoding, value); + } + else + { + _bits |= 8192L; + _ContentEncoding = new StringValues(value); } return; } } break; - case 8: + case 17: { - if ((((pUL[0] & 16131858542893195231uL) == 5207098233614845513uL))) + if ((((pUL[0] & 16131858542891098079uL) == 5928221808112259668uL) && ((pUL[1] & 16131858542891098111uL) == 5641115115480565037uL) && ((pUB[16] & 223u) == 71u))) { - if (((_bits & 536870912L) != 0)) + if (((_bits & 64L) != 0)) { - _IfMatch = AppendValue(_IfMatch, value); + _TransferEncoding = AppendValue(_TransferEncoding, value); } else { - _bits |= 536870912L; - _IfMatch = new StringValues(value); + _bits |= 64L; + _TransferEncoding = new StringValues(value); } return; } - if ((((pUL[0] & 16131858542893195231uL) == 4992044754422023753uL))) + if ((((pUL[0] & 16131858542893195231uL) == 5064654363342751305uL) && ((pUL[1] & 16131858543427968991uL) == 4849894470315165001uL) && ((pUB[16] & 223u) == 69u))) { - if (((_bits & 4294967296L) != 0)) + if (((_bits & 1073741824L) != 0)) { - _IfRange = AppendValue(_IfRange, value); + _IfModifiedSince = AppendValue(_IfModifiedSince, value); } else { - _bits |= 4294967296L; - _IfRange = new StringValues(value); + _bits |= 1073741824L; + _IfModifiedSince = new StringValues(value); } return; } @@ -4518,30 +4522,30 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string case 19: { - if ((((pUL[0] & 16131858542893195231uL) == 4922237916571059785uL) && ((pUL[1] & 16131893727263186911uL) == 5283616559079179849uL) && ((pUS[8] & 57311u) == 17230u) && ((pUB[18] & 223u) == 69u))) + if ((((pUL[0] & 16131893727263186911uL) == 6143241228466999888uL) && ((pUL[1] & 16131858542891098079uL) == 6071233043632179284uL) && ((pUS[8] & 57311u) == 20297u) && ((pUB[18] & 223u) == 78u))) { - if (((_bits & 8589934592L) != 0)) + if (((_bits & 34359738368L) != 0)) { - _IfUnmodifiedSince = AppendValue(_IfUnmodifiedSince, value); + _ProxyAuthorization = AppendValue(_ProxyAuthorization, value); } else { - _bits |= 8589934592L; - _IfUnmodifiedSince = new StringValues(value); + _bits |= 34359738368L; + _ProxyAuthorization = new StringValues(value); } return; } - if ((((pUL[0] & 16131893727263186911uL) == 6143241228466999888uL) && ((pUL[1] & 16131858542891098079uL) == 6071233043632179284uL) && ((pUS[8] & 57311u) == 20297u) && ((pUB[18] & 223u) == 78u))) + if ((((pUL[0] & 16131858542893195231uL) == 4922237916571059785uL) && ((pUL[1] & 16131893727263186911uL) == 5283616559079179849uL) && ((pUS[8] & 57311u) == 17230u) && ((pUB[18] & 223u) == 69u))) { - if (((_bits & 34359738368L) != 0)) + if (((_bits & 8589934592L) != 0)) { - _ProxyAuthorization = AppendValue(_ProxyAuthorization, value); + _IfUnmodifiedSince = AppendValue(_IfUnmodifiedSince, value); } else { - _bits |= 34359738368L; - _ProxyAuthorization = new StringValues(value); + _bits |= 8589934592L; + _IfUnmodifiedSince = new StringValues(value); } return; } @@ -4566,18 +4570,18 @@ public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string } break; - case 9: + case 3: { - if ((((pUL[0] & 16131858542891098079uL) == 6071217693351039572uL) && ((pUB[8] & 223u) == 69u))) + if ((((pUS[0] & 57311u) == 18774u) && ((pUB[2] & 223u) == 65u))) { - if (((_bits & 549755813888L) != 0)) + if (((_bits & 256L) != 0)) { - _Translate = AppendValue(_Translate, value); + _Via = AppendValue(_Via, value); } else { - _bits |= 549755813888L; - _Translate = new StringValues(value); + _bits |= 256L; + _Via = new StringValues(value); } return; } @@ -5109,6 +5113,10 @@ public partial class FrameResponseHeaders private byte[] _rawContentLength; private byte[] _rawServer; + public bool HasConnection => ((_bits & 2L) != 0); + public bool HasTransferEncoding => ((_bits & 64L) != 0); + public bool HasContentLength => ((_bits & 2048L) != 0); + public StringValues HeaderCacheControl { get @@ -8024,391 +8032,1547 @@ protected override void CopyToFast(KeyValuePair[] array, i ((ICollection>)MaybeUnknown)?.CopyTo(array, arrayIndex); } +#if DOTNET5_4 || DNXCORE50 - protected void CopyToFast(ref MemoryPoolIterator2 output) + protected unsafe void CopyToFast(ref MemoryPoolIterator2 output) { + fixed (byte* pHeaderBytes = _headerBytes) + { if (((_bits & 1L) != 0)) { - foreach(var value in _CacheControl) - { - if (value != null) + if (_CacheControl.Count == 1) { - output.CopyFrom(_headerBytes, 0, 17); - output.CopyFromAscii(value); + var value = _CacheControl[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 0, 17); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _CacheControl) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 0, 17); + output.CopyFromAscii(value); + } + } } - } } if (((_bits & 2L) != 0)) { if (_rawConnection != null) { - output.CopyFrom(_rawConnection, 0, _rawConnection.Length); - } else - foreach(var value in _Connection) - { - if (value != null) + fixed (byte* pRawConnection = _rawConnection) { - output.CopyFrom(_headerBytes, 17, 14); - output.CopyFromAscii(value); + output.CopyFrom(pRawConnection, _rawConnection.Length); } - } - } - - if (((_bits & 4L) != 0)) - { - if (_rawDate != null) + } + else { - output.CopyFrom(_rawDate, 0, _rawDate.Length); - } else - foreach(var value in _Date) + if (_Connection.Count == 1) + { + var value = _Connection[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 17, 14); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Connection) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 17, 14); + output.CopyFromAscii(value); + } + } + } + } + } + + if (((_bits & 4L) != 0)) + { + if (_rawDate != null) { - if (value != null) + fixed (byte* pRawDate = _rawDate) { - output.CopyFrom(_headerBytes, 31, 8); - output.CopyFromAscii(value); + output.CopyFrom(pRawDate, _rawDate.Length); + } + } + else + { + if (_Date.Count == 1) + { + var value = _Date[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 31, 8); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Date) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 31, 8); + output.CopyFromAscii(value); + } + } } } } if (((_bits & 8L) != 0)) { - foreach(var value in _KeepAlive) + if (_KeepAlive.Count == 1) + { + var value = _KeepAlive[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 39, 14); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _KeepAlive) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 39, 14); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16L) != 0)) + { + if (_Pragma.Count == 1) + { + var value = _Pragma[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 53, 10); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Pragma) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 53, 10); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 32L) != 0)) + { + if (_Trailer.Count == 1) + { + var value = _Trailer[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 63, 11); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Trailer) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 63, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 64L) != 0)) + { + if (_rawTransferEncoding != null) { - if (value != null) + fixed (byte* pRawTransferEncoding = _rawTransferEncoding) { - output.CopyFrom(_headerBytes, 39, 14); - output.CopyFromAscii(value); + output.CopyFrom(pRawTransferEncoding, _rawTransferEncoding.Length); + } + } + else + { + if (_TransferEncoding.Count == 1) + { + var value = _TransferEncoding[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 74, 21); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _TransferEncoding) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 74, 21); + output.CopyFromAscii(value); + } + } } } } - if (((_bits & 16L) != 0)) + if (((_bits & 128L) != 0)) + { + if (_Upgrade.Count == 1) + { + var value = _Upgrade[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 95, 11); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Upgrade) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 95, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 256L) != 0)) + { + if (_Via.Count == 1) + { + var value = _Via[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 106, 7); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Via) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 106, 7); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 512L) != 0)) + { + if (_Warning.Count == 1) + { + var value = _Warning[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 113, 11); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Warning) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 113, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 1024L) != 0)) + { + if (_Allow.Count == 1) + { + var value = _Allow[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 124, 9); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Allow) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 124, 9); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 2048L) != 0)) { - foreach(var value in _Pragma) + if (_rawContentLength != null) { - if (value != null) + fixed (byte* pRawContentLength = _rawContentLength) { - output.CopyFrom(_headerBytes, 53, 10); - output.CopyFromAscii(value); + output.CopyFrom(pRawContentLength, _rawContentLength.Length); + } + } + else + { + if (_ContentLength.Count == 1) + { + var value = _ContentLength[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 133, 18); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentLength) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 133, 18); + output.CopyFromAscii(value); + } + } } } } - if (((_bits & 32L) != 0)) + if (((_bits & 4096L) != 0)) + { + if (_ContentType.Count == 1) + { + var value = _ContentType[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 151, 16); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentType) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 151, 16); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 8192L) != 0)) + { + if (_ContentEncoding.Count == 1) + { + var value = _ContentEncoding[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 167, 20); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentEncoding) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 167, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16384L) != 0)) + { + if (_ContentLanguage.Count == 1) + { + var value = _ContentLanguage[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 187, 20); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentLanguage) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 187, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 32768L) != 0)) + { + if (_ContentLocation.Count == 1) + { + var value = _ContentLocation[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 207, 20); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentLocation) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 207, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 65536L) != 0)) + { + if (_ContentMD5.Count == 1) + { + var value = _ContentMD5[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 227, 15); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentMD5) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 227, 15); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 131072L) != 0)) + { + if (_ContentRange.Count == 1) + { + var value = _ContentRange[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 242, 17); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ContentRange) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 242, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 262144L) != 0)) + { + if (_Expires.Count == 1) + { + var value = _Expires[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 259, 11); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Expires) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 259, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 524288L) != 0)) + { + if (_LastModified.Count == 1) + { + var value = _LastModified[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 270, 17); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _LastModified) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 270, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 1048576L) != 0)) + { + if (_AcceptRanges.Count == 1) + { + var value = _AcceptRanges[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 287, 17); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _AcceptRanges) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 287, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 2097152L) != 0)) + { + if (_Age.Count == 1) + { + var value = _Age[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 304, 7); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Age) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 304, 7); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 4194304L) != 0)) + { + if (_ETag.Count == 1) + { + var value = _ETag[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 311, 8); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ETag) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 311, 8); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 8388608L) != 0)) + { + if (_Location.Count == 1) + { + var value = _Location[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 319, 12); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Location) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 319, 12); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16777216L) != 0)) + { + if (_ProxyAutheticate.Count == 1) + { + var value = _ProxyAutheticate[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 331, 21); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _ProxyAutheticate) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 331, 21); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 33554432L) != 0)) + { + if (_RetryAfter.Count == 1) + { + var value = _RetryAfter[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 352, 15); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _RetryAfter) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 352, 15); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 67108864L) != 0)) { - foreach(var value in _Trailer) + if (_rawServer != null) { - if (value != null) + fixed (byte* pRawServer = _rawServer) { - output.CopyFrom(_headerBytes, 63, 11); - output.CopyFromAscii(value); + output.CopyFrom(pRawServer, _rawServer.Length); + } + } + else + { + if (_Server.Count == 1) + { + var value = _Server[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 367, 10); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Server) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 367, 10); + output.CopyFromAscii(value); + } + } } } } - if (((_bits & 64L) != 0)) + if (((_bits & 134217728L) != 0)) { - if (_rawTransferEncoding != null) + if (_SetCookie.Count == 1) + { + var value = _SetCookie[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 377, 14); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _SetCookie) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 377, 14); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 268435456L) != 0)) + { + if (_Vary.Count == 1) + { + var value = _Vary[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 391, 8); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Vary) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 391, 8); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 536870912L) != 0)) + { + if (_WWWAuthenticate.Count == 1) + { + var value = _WWWAuthenticate[0]; + if (value != null) + { + output.CopyFrom(pHeaderBytes + 399, 20); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _WWWAuthenticate) + { + if (value != null) + { + output.CopyFrom(pHeaderBytes + 399, 20); + output.CopyFromAscii(value); + } + } + } + } + + } + } +#else + + protected void CopyToFast(ref MemoryPoolIterator2 output) + { + + if (((_bits & 1L) != 0)) + { + if (_CacheControl.Count == 1) + { + var value = _CacheControl[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 0, 17); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _CacheControl) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 0, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 2L) != 0)) + { + if (_rawConnection != null) + { + output.CopyFrom(_rawConnection, 0, _rawConnection.Length); + } + else + { + if (_Connection.Count == 1) + { + var value = _Connection[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 17, 14); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Connection) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 17, 14); + output.CopyFromAscii(value); + } + } + } + } + } + + if (((_bits & 4L) != 0)) + { + if (_rawDate != null) + { + output.CopyFrom(_rawDate, 0, _rawDate.Length); + } + else + { + if (_Date.Count == 1) + { + var value = _Date[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 31, 8); + output.CopyFromAscii(value); + } + } + else { - output.CopyFrom(_rawTransferEncoding, 0, _rawTransferEncoding.Length); - } else - foreach(var value in _TransferEncoding) + foreach(var value in _Date) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 31, 8); + output.CopyFromAscii(value); + } + } + } + } + } + + if (((_bits & 8L) != 0)) + { + if (_KeepAlive.Count == 1) { + var value = _KeepAlive[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 39, 14); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _KeepAlive) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 39, 14); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16L) != 0)) + { + if (_Pragma.Count == 1) + { + var value = _Pragma[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 53, 10); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Pragma) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 53, 10); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 32L) != 0)) + { + if (_Trailer.Count == 1) + { + var value = _Trailer[0]; + if (value != null) + { + output.CopyFrom(_headerBytes, 63, 11); + output.CopyFromAscii(value); + } + } + else + { + foreach(var value in _Trailer) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 63, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 64L) != 0)) + { + if (_rawTransferEncoding != null) + { + output.CopyFrom(_rawTransferEncoding, 0, _rawTransferEncoding.Length); + } + else + { + if (_TransferEncoding.Count == 1) + { + var value = _TransferEncoding[0]; if (value != null) { output.CopyFrom(_headerBytes, 74, 21); output.CopyFromAscii(value); } } + else + { + foreach(var value in _TransferEncoding) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 74, 21); + output.CopyFromAscii(value); + } + } + } } - - if (((_bits & 128L) != 0)) - { - foreach(var value in _Upgrade) + } + + if (((_bits & 128L) != 0)) + { + if (_Upgrade.Count == 1) { + var value = _Upgrade[0]; if (value != null) { output.CopyFrom(_headerBytes, 95, 11); output.CopyFromAscii(value); } } - } - - if (((_bits & 256L) != 0)) - { - foreach(var value in _Via) + else + { + foreach(var value in _Upgrade) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 95, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 256L) != 0)) + { + if (_Via.Count == 1) { + var value = _Via[0]; if (value != null) { output.CopyFrom(_headerBytes, 106, 7); output.CopyFromAscii(value); } } - } - - if (((_bits & 512L) != 0)) - { - foreach(var value in _Warning) + else + { + foreach(var value in _Via) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 106, 7); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 512L) != 0)) + { + if (_Warning.Count == 1) { + var value = _Warning[0]; if (value != null) { output.CopyFrom(_headerBytes, 113, 11); output.CopyFromAscii(value); } } - } - - if (((_bits & 1024L) != 0)) - { - foreach(var value in _Allow) + else + { + foreach(var value in _Warning) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 113, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 1024L) != 0)) + { + if (_Allow.Count == 1) { + var value = _Allow[0]; if (value != null) { output.CopyFrom(_headerBytes, 124, 9); output.CopyFromAscii(value); } } - } - - if (((_bits & 2048L) != 0)) - { - if (_rawContentLength != null) + else { - output.CopyFrom(_rawContentLength, 0, _rawContentLength.Length); - } else - foreach(var value in _ContentLength) + foreach(var value in _Allow) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 124, 9); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 2048L) != 0)) + { + if (_rawContentLength != null) + { + output.CopyFrom(_rawContentLength, 0, _rawContentLength.Length); + } + else + { + if (_ContentLength.Count == 1) { + var value = _ContentLength[0]; if (value != null) { output.CopyFrom(_headerBytes, 133, 18); output.CopyFromAscii(value); } } + else + { + foreach(var value in _ContentLength) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 133, 18); + output.CopyFromAscii(value); + } + } + } } - - if (((_bits & 4096L) != 0)) - { - foreach(var value in _ContentType) + } + + if (((_bits & 4096L) != 0)) + { + if (_ContentType.Count == 1) { + var value = _ContentType[0]; if (value != null) { output.CopyFrom(_headerBytes, 151, 16); output.CopyFromAscii(value); } } - } - - if (((_bits & 8192L) != 0)) - { - foreach(var value in _ContentEncoding) + else + { + foreach(var value in _ContentType) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 151, 16); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 8192L) != 0)) + { + if (_ContentEncoding.Count == 1) { + var value = _ContentEncoding[0]; if (value != null) { output.CopyFrom(_headerBytes, 167, 20); output.CopyFromAscii(value); } } - } - - if (((_bits & 16384L) != 0)) - { - foreach(var value in _ContentLanguage) + else + { + foreach(var value in _ContentEncoding) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 167, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16384L) != 0)) + { + if (_ContentLanguage.Count == 1) { + var value = _ContentLanguage[0]; if (value != null) { output.CopyFrom(_headerBytes, 187, 20); output.CopyFromAscii(value); } } - } - - if (((_bits & 32768L) != 0)) - { - foreach(var value in _ContentLocation) + else + { + foreach(var value in _ContentLanguage) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 187, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 32768L) != 0)) + { + if (_ContentLocation.Count == 1) { + var value = _ContentLocation[0]; if (value != null) { output.CopyFrom(_headerBytes, 207, 20); output.CopyFromAscii(value); } } - } - - if (((_bits & 65536L) != 0)) - { - foreach(var value in _ContentMD5) + else + { + foreach(var value in _ContentLocation) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 207, 20); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 65536L) != 0)) + { + if (_ContentMD5.Count == 1) { + var value = _ContentMD5[0]; if (value != null) { output.CopyFrom(_headerBytes, 227, 15); output.CopyFromAscii(value); } } - } - - if (((_bits & 131072L) != 0)) - { - foreach(var value in _ContentRange) + else + { + foreach(var value in _ContentMD5) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 227, 15); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 131072L) != 0)) + { + if (_ContentRange.Count == 1) { + var value = _ContentRange[0]; if (value != null) { output.CopyFrom(_headerBytes, 242, 17); output.CopyFromAscii(value); } } - } - - if (((_bits & 262144L) != 0)) - { - foreach(var value in _Expires) + else + { + foreach(var value in _ContentRange) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 242, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 262144L) != 0)) + { + if (_Expires.Count == 1) { + var value = _Expires[0]; if (value != null) { output.CopyFrom(_headerBytes, 259, 11); output.CopyFromAscii(value); } } - } - - if (((_bits & 524288L) != 0)) - { - foreach(var value in _LastModified) + else + { + foreach(var value in _Expires) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 259, 11); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 524288L) != 0)) + { + if (_LastModified.Count == 1) { + var value = _LastModified[0]; if (value != null) { output.CopyFrom(_headerBytes, 270, 17); output.CopyFromAscii(value); } } - } - - if (((_bits & 1048576L) != 0)) - { - foreach(var value in _AcceptRanges) + else + { + foreach(var value in _LastModified) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 270, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 1048576L) != 0)) + { + if (_AcceptRanges.Count == 1) { + var value = _AcceptRanges[0]; if (value != null) { output.CopyFrom(_headerBytes, 287, 17); output.CopyFromAscii(value); } } - } - - if (((_bits & 2097152L) != 0)) - { - foreach(var value in _Age) + else + { + foreach(var value in _AcceptRanges) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 287, 17); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 2097152L) != 0)) + { + if (_Age.Count == 1) { + var value = _Age[0]; if (value != null) { output.CopyFrom(_headerBytes, 304, 7); output.CopyFromAscii(value); } } - } - - if (((_bits & 4194304L) != 0)) - { - foreach(var value in _ETag) + else + { + foreach(var value in _Age) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 304, 7); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 4194304L) != 0)) + { + if (_ETag.Count == 1) { + var value = _ETag[0]; if (value != null) { output.CopyFrom(_headerBytes, 311, 8); output.CopyFromAscii(value); } } - } - - if (((_bits & 8388608L) != 0)) - { - foreach(var value in _Location) + else + { + foreach(var value in _ETag) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 311, 8); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 8388608L) != 0)) + { + if (_Location.Count == 1) { + var value = _Location[0]; if (value != null) { output.CopyFrom(_headerBytes, 319, 12); output.CopyFromAscii(value); } } - } - - if (((_bits & 16777216L) != 0)) - { - foreach(var value in _ProxyAutheticate) + else + { + foreach(var value in _Location) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 319, 12); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 16777216L) != 0)) + { + if (_ProxyAutheticate.Count == 1) { + var value = _ProxyAutheticate[0]; if (value != null) { output.CopyFrom(_headerBytes, 331, 21); output.CopyFromAscii(value); } } - } - - if (((_bits & 33554432L) != 0)) - { - foreach(var value in _RetryAfter) + else + { + foreach(var value in _ProxyAutheticate) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 331, 21); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 33554432L) != 0)) + { + if (_RetryAfter.Count == 1) { + var value = _RetryAfter[0]; if (value != null) { output.CopyFrom(_headerBytes, 352, 15); output.CopyFromAscii(value); } } - } - - if (((_bits & 67108864L) != 0)) - { - if (_rawServer != null) + else { - output.CopyFrom(_rawServer, 0, _rawServer.Length); - } else - foreach(var value in _Server) + foreach(var value in _RetryAfter) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 352, 15); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 67108864L) != 0)) + { + if (_rawServer != null) + { + output.CopyFrom(_rawServer, 0, _rawServer.Length); + } + else + { + if (_Server.Count == 1) { + var value = _Server[0]; if (value != null) { output.CopyFrom(_headerBytes, 367, 10); output.CopyFromAscii(value); } } + else + { + foreach(var value in _Server) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 367, 10); + output.CopyFromAscii(value); + } + } + } } - - if (((_bits & 134217728L) != 0)) - { - foreach(var value in _SetCookie) + } + + if (((_bits & 134217728L) != 0)) + { + if (_SetCookie.Count == 1) { + var value = _SetCookie[0]; if (value != null) { output.CopyFrom(_headerBytes, 377, 14); output.CopyFromAscii(value); } } - } - - if (((_bits & 268435456L) != 0)) - { - foreach(var value in _Vary) + else + { + foreach(var value in _SetCookie) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 377, 14); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 268435456L) != 0)) + { + if (_Vary.Count == 1) { + var value = _Vary[0]; if (value != null) { output.CopyFrom(_headerBytes, 391, 8); output.CopyFromAscii(value); } } - } - - if (((_bits & 536870912L) != 0)) - { - foreach(var value in _WWWAuthenticate) + else + { + foreach(var value in _Vary) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 391, 8); + output.CopyFromAscii(value); + } + } + } + } + + if (((_bits & 536870912L) != 0)) + { + if (_WWWAuthenticate.Count == 1) { + var value = _WWWAuthenticate[0]; if (value != null) { output.CopyFrom(_headerBytes, 399, 20); output.CopyFromAscii(value); } } - } - + else + { + foreach(var value in _WWWAuthenticate) + { + if (value != null) + { + output.CopyFrom(_headerBytes, 399, 20); + output.CopyFromAscii(value); + } + } + } + } + } +#endif public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) { fixed(byte* ptr = keyBytes) { var pUB = ptr + keyOffset; var pUL = (ulong*)pUB; var pUI = (uint*)pUB; var pUS = (ushort*)pUB; diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseHeaders.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseHeaders.cs index a5a42e6a9..a6a16d7f9 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseHeaders.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseHeaders.cs @@ -10,15 +10,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http { public partial class FrameResponseHeaders : FrameHeaders { - private static byte[] _CrLf = new[] { (byte)'\r', (byte)'\n' }; - private static byte[] _colonSpace = new[] { (byte)':', (byte)' ' }; - - public bool HasConnection => HeaderConnection.Count != 0; - - public bool HasTransferEncoding => HeaderTransferEncoding.Count != 0; - - public bool HasContentLength => HeaderContentLength.Count != 0; - + private static byte[] _CrLfColonSpace = new[] { (byte)'\r', (byte)'\n', (byte)':', (byte)' ' }; public Enumerator GetEnumerator() { @@ -30,24 +22,71 @@ protected override IEnumerator> GetEnumerator return GetEnumerator(); } - public void CopyTo(ref MemoryPoolIterator2 output) + public unsafe void CopyTo(ref MemoryPoolIterator2 output) { CopyToFast(ref output); - if (MaybeUnknown != null) + if (MaybeUnknown != null && MaybeUnknown.Count > 0) { +#if DOTNET5_4 || DNXCORE50 + fixed (byte* pCrLfColonSpace = _CrLfColonSpace) + { + foreach (var kv in MaybeUnknown) + { + if (kv.Value.Count == 1) + { + var value = kv.Value[0]; + if (value != null) + { + output.CopyFrom(pCrLfColonSpace, 2); + output.CopyFromAscii(kv.Key); + output.CopyFrom(pCrLfColonSpace + 2, 2); + output.CopyFromAscii(value); + } + } + else + { + foreach (var value in kv.Value) + { + if (value != null) + { + output.CopyFrom(pCrLfColonSpace, 2); + output.CopyFromAscii(kv.Key); + output.CopyFrom(pCrLfColonSpace + 2, 2); + output.CopyFromAscii(value); + } + } + } + } + } +#else foreach (var kv in MaybeUnknown) { - foreach (var value in kv.Value) + if (kv.Value.Count == 1) { + var value = kv.Value[0]; if (value != null) { - output.CopyFrom(_CrLf, 0, 2); + output.CopyFrom(_CrLfColonSpace, 0, 2); output.CopyFromAscii(kv.Key); - output.CopyFrom(_colonSpace, 0, 2); + output.CopyFrom(_CrLfColonSpace, 2, 2); output.CopyFromAscii(value); } } + else + { + foreach (var value in kv.Value) + { + if (value != null) + { + output.CopyFrom(_CrLfColonSpace, 0, 2); + output.CopyFromAscii(kv.Key); + output.CopyFrom(_CrLfColonSpace, 2, 2); + output.CopyFromAscii(value); + } + } + } } +#endif } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/ISocketOutput.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/ISocketOutput.cs index 597326ca8..f0a12c192 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/ISocketOutput.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/ISocketOutput.cs @@ -18,7 +18,7 @@ public interface ISocketOutput /// /// Returns an iterator pointing to the tail of the response buffer. Response data can be appended - /// manually or by using . + /// manually or by using . /// Be careful to ensure all appended blocks are backed by a . /// MemoryPoolIterator2 ProducingStart(); diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs index d3c344cce..89ba5f592 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs @@ -22,7 +22,7 @@ abstract public class ListenerPrimary : Listener // this message is passed to write2 because it must be non-zero-length, // but it has no other functional significance - private readonly ArraySegment> _dummyMessage = new ArraySegment>(new[] { new ArraySegment(new byte[] { 1, 2, 3, 4 }) }); + private readonly ArraySegment _dummyMessage = new ArraySegment(new byte[] { 1, 2, 3, 4 }); protected ListenerPrimary(ServiceContext serviceContext) : base(serviceContext) { @@ -86,7 +86,7 @@ protected override void DispatchConnection(UvStreamHandle socket) else { var dispatchPipe = _dispatchPipes[index]; - var write = new UvWriteReq(Log); + var write = new UvWrite2Req(Log); write.Init(Thread.Loop); write.Write2( dispatchPipe, diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/MessageBody.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/MessageBody.cs index 8edd424a1..2057ca7d7 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/MessageBody.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/MessageBody.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNet.Server.Kestrel.Http @@ -38,62 +39,67 @@ protected MessageBody(FrameContext context) return result; } - public async Task Consume(CancellationToken cancellationToken = default(CancellationToken)) + public Task Consume(CancellationToken cancellationToken = default(CancellationToken)) { - Task result; - var send100checked = false; - do + var result = ReadAsyncImplementation(default(ArraySegment), cancellationToken); + if (!result.IsCompleted) { - result = ReadAsyncImplementation(default(ArraySegment), cancellationToken); - if (!result.IsCompleted) - { - if (!send100checked) - { - if (Interlocked.Exchange(ref _send100Continue, 0) == 1) - { - _context.FrameControl.ProduceContinue(); - } - send100checked = true; - } - } - else if (result.GetAwaiter().GetResult() == 0) - { - // Completed Task, end of stream - return; - } - else + if (Interlocked.Exchange(ref _send100Continue, 0) == 1) { - // Completed Task, get next Task rather than await - continue; + _context.FrameControl.ProduceContinue(); } - } while (await result != 0); + + return ConsumeAwaited(result, cancellationToken); + } + else if (result.GetAwaiter().GetResult() == 0) + { + // Completed Task, end of stream + return TaskUtilities.CompletedTask; + } + else + { + // Completed Task, but non-zero get next Task and await + return ConsumeAwaited(ReadAsyncImplementation(default(ArraySegment), cancellationToken), cancellationToken); + } + } + + private async Task ConsumeAwaited(Task currentTask, CancellationToken cancellationToken) + { + var count = await currentTask; + + if (count == 0) return; + + while (await ReadAsyncImplementation(default(ArraySegment), cancellationToken) != 0) + { + // Consume until complete + } } public abstract Task ReadAsyncImplementation(ArraySegment buffer, CancellationToken cancellationToken); public static MessageBody For( string httpVersion, - IDictionary headers, + FrameRequestHeaders headers, FrameContext context) { // see also http://tools.ietf.org/html/rfc2616#section-4.4 var keepAlive = httpVersion != "HTTP/1.0"; - string connection; - if (TryGet(headers, "Connection", out connection)) + var connection = headers.HeaderConnection.ToString(); + if (connection.Length > 0) { keepAlive = connection.Equals("keep-alive", StringComparison.OrdinalIgnoreCase); } - string transferEncoding; - if (TryGet(headers, "Transfer-Encoding", out transferEncoding)) + var transferEncoding = headers.HeaderTransferEncoding.ToString(); + if (transferEncoding.Length > 0) { return new ForChunkedEncoding(keepAlive, context); } - string contentLength; - if (TryGet(headers, "Content-Length", out contentLength)) + var contentLength = headers.HeaderContentLength.ToString(); + if (contentLength.Length > 0) { return new ForContentLength(keepAlive, int.Parse(contentLength), context); } @@ -106,30 +112,6 @@ public static MessageBody For( return new ForRemainingData(context); } - public static bool TryGet(IDictionary headers, string name, out string value) - { - StringValues values; - if (!headers.TryGetValue(name, out values) || values.Count == 0) - { - value = null; - return false; - } - var count = values.Count; - if (count == 0) - { - value = null; - return false; - } - if (count == 1) - { - value = values[0]; - return true; - } - value = string.Join(",", values.ToArray()); - return true; - } - - class ForRemainingData : MessageBody { public ForRemainingData(FrameContext context) @@ -156,17 +138,37 @@ public ForContentLength(bool keepAlive, int contentLength, FrameContext context) _inputLength = _contentLength; } - public override async Task ReadAsyncImplementation(ArraySegment buffer, CancellationToken cancellationToken) + public override Task ReadAsyncImplementation(ArraySegment buffer, CancellationToken cancellationToken) { var input = _context.SocketInput; var limit = buffer.Array == null ? _inputLength : Math.Min(buffer.Count, _inputLength); if (limit == 0) { - return 0; + return TaskUtilities.ZeroTask; } - var actual = await _context.SocketInput.ReadAsync(buffer.Array, buffer.Offset, limit); + var task = _context.SocketInput.ReadAsync(buffer.Array, buffer.Offset, limit); + + if (task.IsCompleted) + { + var actual = task.GetAwaiter().GetResult(); + if (actual == 0) + { + throw new InvalidDataException("Unexpected end of request content"); + } + _inputLength -= actual; + return task; + } + else + { + return ReadAsyncImplementationAwaited(task); + } + } + + private async Task ReadAsyncImplementationAwaited(Task currentTask) + { + var actual = await currentTask; _inputLength -= actual; if (actual == 0) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInput.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInput.cs index 5a7a1715d..b3a2466fa 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInput.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInput.cs @@ -5,7 +5,6 @@ using System.IO; using System.Runtime.CompilerServices; using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNet.Server.Kestrel.Infrastructure; namespace Microsoft.AspNet.Server.Kestrel.Http @@ -25,7 +24,6 @@ public class SocketInput : ICriticalNotifyCompletion private MemoryPoolBlock2 _head; private MemoryPoolBlock2 _tail; private MemoryPoolBlock2 _pinned; - private readonly object _sync = new Object(); public SocketInput(MemoryPool2 memory, IThreadPool threadPool) { @@ -34,8 +32,6 @@ public SocketInput(MemoryPool2 memory, IThreadPool threadPool) _awaitableState = _awaitableIsNotCompleted; } - public ArraySegment Buffer { get; set; } - public bool RemoteIntakeFin { get; set; } public bool IsCompleted @@ -46,86 +42,100 @@ public bool IsCompleted } } - public void Skip(int count) + public MemoryPoolBlock2 IncomingRawStart() { - Buffer = new ArraySegment(Buffer.Array, Buffer.Offset + count, Buffer.Count - count); - } + const int minimumSize = 2048; - public ArraySegment Take(int count) - { - var taken = new ArraySegment(Buffer.Array, Buffer.Offset, count); - Skip(count); - return taken; + if (_tail != null && minimumSize <= _tail.BlockEndOffset - _tail.End) + { + _pinned = _tail; + } + else + { + _pinned = _memory.Lease(); + } + + return _pinned; } - public IncomingBuffer IncomingStart(int minimumSize) + public void IncomingData(byte[] buffer, int offset, int count) { - lock (_sync) + if (count > 0) { - if (_tail != null && minimumSize <= _tail.Data.Offset + _tail.Data.Count - _tail.End) + if (_tail == null) { - _pinned = _tail; - var data = new ArraySegment(_pinned.Data.Array, _pinned.End, _pinned.Data.Offset + _pinned.Data.Count - _pinned.End); - var dataPtr = _pinned.Pin() + _pinned.End; - return new IncomingBuffer - { - Data = data, - DataPtr = dataPtr, - }; + _tail = _memory.Lease(); } - } - _pinned = _memory.Lease(minimumSize); - return new IncomingBuffer + var iterator = new MemoryPoolIterator2(_tail, _tail.End); + iterator.CopyFrom(buffer, offset, count); + + if (_head == null) + { + _head = _tail; + } + + _tail = iterator.Block; + } + else { - Data = _pinned.Data, - DataPtr = _pinned.Pin() + _pinned.End - }; + RemoteIntakeFin = true; + } + + TriggerAwaiters(); } public void IncomingComplete(int count, Exception error) { - Action awaitableState; - - lock (_sync) + // Unpin may called without an earlier Pin + if (_pinned != null) { - // Unpin may called without an earlier Pin - if (_pinned != null) + + _pinned.End += count; + + if (_head == null) { - _pinned.Unpin(); - - _pinned.End += count; - if (_head == null) - { - _head = _tail = _pinned; - } - else if (_tail == _pinned) - { - // NO-OP: this was a read into unoccupied tail-space - } - else - { - _tail.Next = _pinned; - _tail = _pinned; - } + _head = _tail = _pinned; } - _pinned = null; - - if (count == 0) + else if (_tail == _pinned) { - RemoteIntakeFin = true; + // NO-OP: this was a read into unoccupied tail-space } - if (error != null) + else { - _awaitableError = error; + _tail.Next = _pinned; + _tail = _pinned; } - awaitableState = Interlocked.Exchange( - ref _awaitableState, - _awaitableIsCompleted); + _pinned = null; + } - _manualResetEvent.Set(); + if (count == 0) + { + RemoteIntakeFin = true; } + if (error != null) + { + _awaitableError = error; + } + + TriggerAwaiters(); + } + + public void AbortAwaiting() + { + _awaitableError = new ObjectDisposedException(nameof(SocketInput), "The request was aborted"); + + TriggerAwaiters(); + } + + private void TriggerAwaiters() + { + var awaitableState = Interlocked.Exchange( + ref _awaitableState, + _awaitableIsCompleted); + + _manualResetEvent.Set(); if (awaitableState != _awaitableIsCompleted && awaitableState != _awaitableIsNotCompleted) @@ -136,10 +146,7 @@ public void IncomingComplete(int count, Exception error) public MemoryPoolIterator2 ConsumingStart() { - lock (_sync) - { - return new MemoryPoolIterator2(_head); - } + return new MemoryPoolIterator2(_head); } public void ConsumingComplete( @@ -148,50 +155,31 @@ public void ConsumingComplete( { MemoryPoolBlock2 returnStart = null; MemoryPoolBlock2 returnEnd = null; - lock (_sync) + if (!consumed.IsDefault) { - if (!consumed.IsDefault) - { - returnStart = _head; - returnEnd = consumed.Block; - _head = consumed.Block; - _head.Start = consumed.Index; - } - if (!examined.IsDefault && - examined.IsEnd && - RemoteIntakeFin == false && - _awaitableError == null) - { - _manualResetEvent.Reset(); + returnStart = _head; + returnEnd = consumed.Block; + _head = consumed.Block; + _head.Start = consumed.Index; + } + if (!examined.IsDefault && + examined.IsEnd && + RemoteIntakeFin == false && + _awaitableError == null) + { + _manualResetEvent.Reset(); - var awaitableState = Interlocked.CompareExchange( - ref _awaitableState, - _awaitableIsNotCompleted, - _awaitableIsCompleted); - } + var awaitableState = Interlocked.CompareExchange( + ref _awaitableState, + _awaitableIsNotCompleted, + _awaitableIsCompleted); } + while (returnStart != returnEnd) { var returnBlock = returnStart; returnStart = returnStart.Next; - returnBlock.Pool?.Return(returnBlock); - } - } - - public void AbortAwaiting() - { - _awaitableError = new ObjectDisposedException(nameof(SocketInput), "The request was aborted"); - - var awaitableState = Interlocked.Exchange( - ref _awaitableState, - _awaitableIsCompleted); - - _manualResetEvent.Set(); - - if (awaitableState != _awaitableIsCompleted && - awaitableState != _awaitableIsNotCompleted) - { - _threadPool.Run(awaitableState); + returnBlock.Pool.Return(returnBlock); } } @@ -247,11 +235,5 @@ public void GetResult() throw new IOException(error.Message, error); } } - - public struct IncomingBuffer - { - public ArraySegment Data; - public IntPtr DataPtr; - } } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInputExtensions.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInputExtensions.cs index c36d88155..351bd864c 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInputExtensions.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketInputExtensions.cs @@ -1,14 +1,36 @@ // 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. -using System; using System.Threading.Tasks; +using Microsoft.AspNet.Server.Kestrel.Infrastructure; namespace Microsoft.AspNet.Server.Kestrel.Http { public static class SocketInputExtensions { - public static async Task ReadAsync(this SocketInput input, byte[] buffer, int offset, int count) + public static Task ReadAsync(this SocketInput input, byte[] buffer, int offset, int count) + { + while (input.IsCompleted) + { + var begin = input.ConsumingStart(); + int actual; + var end = begin.CopyTo(buffer, offset, count, out actual); + input.ConsumingComplete(end, end); + + if (actual != 0) + { + return Task.FromResult(actual); + } + if (input.RemoteIntakeFin) + { + return TaskUtilities.ZeroTask; + } + } + + return input.ReadAsyncAwaited(buffer, offset, count); + } + + private static async Task ReadAsyncAwaited(this SocketInput input, byte[] buffer, int offset, int count) { while (true) { diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketOutput.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketOutput.cs index 9a0f9f8a1..b24def75f 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/SocketOutput.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/SocketOutput.cs @@ -16,7 +16,7 @@ public class SocketOutput : ISocketOutput { public const int MaxPooledWriteReqs = 1024; - private const int _maxPendingWrites = 3; + //private const int _maxPendingWrites = 3; private const int _maxBytesPreCompleted = 65536; private const int _initialTaskQueues = 64; private const int _maxPooledWriteContexts = 32; @@ -32,19 +32,16 @@ public class SocketOutput : ISocketOutput // This locks all access to _tail, _isProducing and _returnFromOnProducingComplete. // _head does not require a lock, since it is only used in the ctor and uv thread. - private readonly object _returnLock = new object(); + //private readonly object _returnLock = new object(); private MemoryPoolBlock2 _head; private MemoryPoolBlock2 _tail; private MemoryPoolIterator2 _lastStart; - // This locks access to to all of the below fields - private readonly object _contextLock = new object(); - // The number of write operations that have been scheduled so far // but have not completed. - private int _writesPending = 0; + //private int _writesPending = 0; private int _numBytesPreCompleted = 0; private Exception _lastWriteError; private WriteContext _nextWriteContext; @@ -53,6 +50,11 @@ public class SocketOutput : ISocketOutput private readonly Queue _writeContextPool; private readonly Queue _writeReqPool; + private int _writePending = 0; + + private readonly object _contextLock = new object(); + private readonly object _taskQueueLock = new object(); + public SocketOutput( KestrelThread thread, UvStreamHandle socket, @@ -78,16 +80,25 @@ public SocketOutput( _tail = _head; } - public Task WriteAsync( + int number = 0; + + public unsafe Task WriteAsync( ArraySegment buffer, - bool immediate = true, + bool immediate, bool socketShutdownSend = false, bool socketDisconnect = false) { if (buffer.Count > 0) { var tail = ProducingStart(); - tail.CopyFrom(buffer); +#if DOTNET5_4 || DNXCORE50 + fixed (byte* pBuffer = buffer.Array) + { + tail.CopyFrom(pBuffer + buffer.Offset, buffer.Count); + } +#else + tail.CopyFrom(buffer.Array, buffer.Offset, buffer.Count); +#endif // We do our own accounting below ProducingCompleteNoPreComplete(tail); } @@ -95,55 +106,67 @@ public Task WriteAsync( var scheduleWrite = false; - lock (_contextLock) + var nextWriteContext = Interlocked.Exchange(ref _nextWriteContext, null); + + if (nextWriteContext == null) { - if (_nextWriteContext == null) + lock (_contextLock) { if (_writeContextPool.Count > 0) { - _nextWriteContext = _writeContextPool.Dequeue(); + nextWriteContext = _writeContextPool.Dequeue(); } else { - _nextWriteContext = new WriteContext(this); + nextWriteContext = new WriteContext(this); } } + } - if (socketShutdownSend) - { - _nextWriteContext.SocketShutdownSend = true; - } - if (socketDisconnect) - { - _nextWriteContext.SocketDisconnect = true; - } + if (socketShutdownSend) + { + nextWriteContext.SocketShutdownSend = true; + } + if (socketDisconnect) + { + nextWriteContext.SocketDisconnect = true; + } - if (!immediate) - { - // immediate==false calls always return complete tasks, because there is guaranteed - // to be a subsequent immediate==true call which will go down one of the previous code-paths - _numBytesPreCompleted += buffer.Count; - } - else if (_lastWriteError == null && - _tasksPending.Count == 0 && - _numBytesPreCompleted + buffer.Count <= _maxBytesPreCompleted) - { - // Complete the write task immediately if all previous write tasks have been completed, - // the buffers haven't grown too large, and the last write to the socket succeeded. - _numBytesPreCompleted += buffer.Count; - } - else + Interlocked.Exchange(ref _nextWriteContext, nextWriteContext); + + if (!immediate) + { + // immediate==false calls always return complete tasks, because there is guaranteed + // to be a subsequent immediate==true call which will go down one of the previous code-paths + Interlocked.Add(ref _numBytesPreCompleted, buffer.Count); + } + else if (_lastWriteError == null && + _tasksPending.Count == 0 && + _numBytesPreCompleted + buffer.Count <= _maxBytesPreCompleted) + { + // Complete the write task immediately if all previous write tasks have been completed, + // the buffers haven't grown too large, and the last write to the socket succeeded. + Interlocked.Add(ref _numBytesPreCompleted, buffer.Count); + } + else + { + // immediate write, which is not eligable for instant completion above + tcs = new TaskCompletionSource(buffer.Count); + lock (_taskQueueLock) { - // immediate write, which is not eligable for instant completion above - tcs = new TaskCompletionSource(buffer.Count); _tasksPending.Enqueue(tcs); } + } - if (_writesPending < _maxPendingWrites && immediate) - { - scheduleWrite = true; - _writesPending++; - } + number++; + if (number > 11) + { + number = 0; + scheduleWrite = true; + } + else if (immediate) + { + scheduleWrite = true; } if (scheduleWrite) @@ -176,19 +199,15 @@ public void End(ProduceEndType endType) public MemoryPoolIterator2 ProducingStart() { - lock (_returnLock) - { - Debug.Assert(_lastStart.IsDefault); - if (_tail == null) - { - throw new IOException("The socket has been closed."); - } + if (_tail == null) + { + throw new IOException("The socket has been closed."); + } - _lastStart = new MemoryPoolIterator2(_tail, _tail.End); + _lastStart = new MemoryPoolIterator2(_tail, _tail.End); - return _lastStart; - } + return _lastStart; } public void ProducingComplete(MemoryPoolIterator2 end) @@ -198,37 +217,31 @@ public void ProducingComplete(MemoryPoolIterator2 end) int bytesProduced, buffersIncluded; BytesBetween(_lastStart, end, out bytesProduced, out buffersIncluded); - lock (_contextLock) - { - _numBytesPreCompleted += bytesProduced; - } - ProducingCompleteNoPreComplete(end); + + Interlocked.Add(ref _numBytesPreCompleted, bytesProduced); } private void ProducingCompleteNoPreComplete(MemoryPoolIterator2 end) { MemoryPoolBlock2 blockToReturn = null; - lock (_returnLock) - { - Debug.Assert(!_lastStart.IsDefault); - // If the socket has been closed, return the produced blocks - // instead of advancing the now non-existent tail. - if (_tail != null) - { - _tail = end.Block; - _tail.End = end.Index; - } - else - { - blockToReturn = _lastStart.Block; - } - - _lastStart = default(MemoryPoolIterator2); + // If the socket has been closed, return the produced blocks + // instead of advancing the now non-existent tail. + if (_tail != null) + { + _tail = end.Block; + _tail.End = end.Index; + } + else + { + blockToReturn = _lastStart.Block; } + _lastStart = default(MemoryPoolIterator2); + + if (blockToReturn != null) { ThreadPool.QueueUserWorkItem(_returnBlocks, blockToReturn); @@ -242,32 +255,27 @@ private static void ReturnBlocks(MemoryPoolBlock2 block) var returningBlock = block; block = returningBlock.Next; - returningBlock.Pool?.Return(returningBlock); + returningBlock.Pool.Return(returningBlock); } } private void ScheduleWrite() { - _thread.Post(_this => _this.WriteAllPending(), this); + if (Interlocked.CompareExchange(ref _writePending, 1, 0) == 0) + { + _thread.Post(_this => _this.WriteAllPending(), this); + } } // This is called on the libuv event loop private void WriteAllPending() { - WriteContext writingContext; + Volatile.Write(ref _writePending, 0); + var writingContext = Interlocked.Exchange(ref _nextWriteContext, null); - lock (_contextLock) + if (writingContext == null) { - if (_nextWriteContext != null) - { - writingContext = _nextWriteContext; - _nextWriteContext = null; - } - else - { - _writesPending--; - return; - } + return; } try @@ -276,13 +284,6 @@ private void WriteAllPending() } catch { - lock (_contextLock) - { - // Lock instead of using Interlocked.Decrement so _writesSending - // doesn't change in the middle of executing other synchronized code. - _writesPending--; - } - throw; } } @@ -304,37 +305,34 @@ private void OnWriteCompleted(WriteContext writeContext) } bool scheduleWrite = false; + PoolWriteContext(writeContext); - lock (_contextLock) + if (_nextWriteContext != null) { - PoolWriteContext(writeContext); - if (_nextWriteContext != null) - { - scheduleWrite = true; - } - else - { - _writesPending--; - } + scheduleWrite = true; + } - // _numBytesPreCompleted can temporarily go negative in the event there are - // completed writes that we haven't triggered callbacks for yet. - _numBytesPreCompleted -= bytesWritten; + // _numBytesPreCompleted can temporarily go negative in the event there are + // completed writes that we haven't triggered callbacks for yet. - // bytesLeftToBuffer can be greater than _maxBytesPreCompleted - // This allows large writes to complete once they've actually finished. - var bytesLeftToBuffer = _maxBytesPreCompleted - _numBytesPreCompleted; - while (_tasksPending.Count > 0 && - (int)(_tasksPending.Peek().Task.AsyncState) <= bytesLeftToBuffer) + // bytesLeftToBuffer can be greater than _maxBytesPreCompleted + // This allows large writes to complete once they've actually finished. + var bytesLeftToBuffer = _maxBytesPreCompleted - Interlocked.Add(ref _numBytesPreCompleted, -bytesWritten); + while (_tasksPending.Count > 0 && + (int)(_tasksPending.Peek().Task.AsyncState) <= bytesLeftToBuffer) + { + TaskCompletionSource tcs; + lock (_taskQueueLock) { - var tcs = _tasksPending.Dequeue(); - var bytesToWrite = (int)tcs.Task.AsyncState; + tcs = _tasksPending.Dequeue(); + } + var bytesToWrite = (int)tcs.Task.AsyncState; - _numBytesPreCompleted += bytesToWrite; - bytesLeftToBuffer -= bytesToWrite; + Interlocked.Add(ref _numBytesPreCompleted, bytesToWrite); - _tasksCompleted.Enqueue(tcs); - } + bytesLeftToBuffer -= bytesToWrite; + + _tasksCompleted.Enqueue(tcs); } while (_tasksCompleted.Count > 0) @@ -352,7 +350,7 @@ private void OnWriteCompleted(WriteContext writeContext) _log.ConnectionWriteCallback(_connectionId, status); - if (scheduleWrite) + if (scheduleWrite || _nextWriteContext != null) { ScheduleWrite(); } @@ -363,35 +361,34 @@ private void OnWriteCompleted(WriteContext writeContext) // This is called on the libuv event loop private void ReturnAllBlocks() { - lock (_returnLock) + var block = _head; + while (block != _tail) { - var block = _head; - while (block != _tail) - { - var returnBlock = block; - block = block.Next; - - returnBlock.Pool?.Return(returnBlock); - } + var returnBlock = block; + block = block.Next; - // Only return the _tail if we aren't between ProducingStart/Complete calls - if (_lastStart.IsDefault) - { - _tail.Pool?.Return(_tail); - } + returnBlock.Pool.Return(returnBlock); + } - _head = null; - _tail = null; + // Only return the _tail if we aren't between ProducingStart/Complete calls + if (_lastStart.IsDefault) + { + _tail.Pool.Return(_tail); } + + _head = null; + _tail = null; } private void PoolWriteContext(WriteContext writeContext) { - // called inside _contextLock if (_writeContextPool.Count < _maxPooledWriteContexts) { - writeContext.Reset(); - _writeContextPool.Enqueue(writeContext); + lock (_contextLock) + { + writeContext.Reset(); + _writeContextPool.Enqueue(writeContext); + } } } @@ -423,7 +420,7 @@ private static void BytesBetween(MemoryPoolIterator2 start, MemoryPoolIterator2 return; } - bytes = start.Block.Data.Offset + start.Block.Data.Count - start.Index; + bytes = start.Block.BlockEndOffset - start.Index; buffers = 1; for (var block = start.Block.Next; block != end.Block; block = block.Next) @@ -567,14 +564,12 @@ private void ScheduleReturnFullyWrittenBlocks() var end = _lockedEnd.Block; if (block == end) { - end.Unpin(); return; } while (block.Next != end) { block = block.Next; - block.Unpin(); } block.Next = null; @@ -588,13 +583,13 @@ private static void ReturnWrittenBlocks(MemoryPoolBlock2 block) var returnBlock = block; block = block.Next; - returnBlock.Unpin(); - returnBlock.Pool?.Return(returnBlock); + returnBlock.Pool.Return(returnBlock); } } private void LockWrite() { + var head = Self._head; var tail = Self._tail; diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelThread.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelThread.cs index de603b445..4056ed39f 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelThread.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/KestrelThread.cs @@ -10,6 +10,8 @@ using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.AspNet.Server.Kestrel.Networking; using Microsoft.Extensions.Logging; +using System.Collections.Concurrent; +using Microsoft.AspNet.Server.Kestrel.Http; namespace Microsoft.AspNet.Server.Kestrel { @@ -18,30 +20,30 @@ namespace Microsoft.AspNet.Server.Kestrel /// public class KestrelThread { - // maximum times the work queues swapped and are processed in a single pass - // as completing a task may immediately have write data to put on the network - // otherwise it needs to wait till the next pass of the libuv loop - private const int _maxLoops = 8; - private static Action _threadCallbackAdapter = (callback, state) => ((Action)callback).Invoke((KestrelThread)state); + private static Action _socketCallbackAdapter = (callback, state) => ((Action)callback).Invoke((SocketOutput)state); + private static Action _tcsCallbackAdapter = (callback, state) => ((Action>)callback).Invoke((TaskCompletionSource)state); + private static Action _listenerPrimaryCallbackAdapter = (callback, state) => ((Action)callback).Invoke((ListenerPrimary)state); + private static Action _listenerSecondaryCallbackAdapter = (callback, state) => ((Action)callback).Invoke((ListenerSecondary)state); + private KestrelEngine _engine; private readonly IApplicationLifetime _appLifetime; private Thread _thread; private UvLoopHandle _loop; private UvAsyncHandle _post; - private Queue _workAdding = new Queue(1024); - private Queue _workRunning = new Queue(1024); - private Queue _closeHandleAdding = new Queue(256); - private Queue _closeHandleRunning = new Queue(256); - private object _workSync = new Object(); + private ConcurrentQueue _workQueue = new ConcurrentQueue(); + private ConcurrentQueue _closeHandleQueue = new ConcurrentQueue(); private bool _stopImmediate = false; private bool _initCompleted = false; private ExceptionDispatchInfo _closeError; private IKestrelTrace _log; private IThreadPool _threadPool; + private volatile bool _loopIdle; + public KestrelThread(KestrelEngine engine) { + _loopIdle = true; _engine = engine; _appLifetime = engine.AppLifetime; _log = engine.Log; @@ -137,45 +139,51 @@ private void OnStopImmediate() private void Post(Action callback) { - lock (_workSync) - { - _workAdding.Enqueue(new Work { CallbackAdapter = _threadCallbackAdapter, Callback = callback, State = this }); - } - _post.Send(); + _workQueue.Enqueue(new Work { CallbackAdapter = _threadCallbackAdapter, Callback = callback, State = this }); + WakeUpLoop(); + } + + public void Post(Action callback, SocketOutput state) + { + _workQueue.Enqueue(new Work { CallbackAdapter = _socketCallbackAdapter, Callback = callback, State = state }); + WakeUpLoop(); } - public void Post(Action callback, T state) + public void Post(Action> callback, TaskCompletionSource state) { - lock (_workSync) + _workQueue.Enqueue(new Work { CallbackAdapter = _tcsCallbackAdapter, Callback = callback, State = state }); + WakeUpLoop(); + } + + public Task PostAsync(Action callback, ListenerPrimary state) + { + var tcs = new TaskCompletionSource(); + _workQueue.Enqueue(new Work { - _workAdding.Enqueue(new Work - { - CallbackAdapter = (callback2, state2) => ((Action)callback2).Invoke((T)state2), - Callback = callback, - State = state - }); - } - _post.Send(); + CallbackAdapter = _listenerPrimaryCallbackAdapter, + Callback = callback, + State = state, + Completion = tcs + }); + WakeUpLoop(); + return tcs.Task; } - public Task PostAsync(Action callback, T state) + public Task PostAsync(Action callback, ListenerSecondary state) { var tcs = new TaskCompletionSource(); - lock (_workSync) + _workQueue.Enqueue(new Work { - _workAdding.Enqueue(new Work - { - CallbackAdapter = (state1, state2) => ((Action)state1).Invoke((T)state2), - Callback = callback, - State = state, - Completion = tcs - }); - } - _post.Send(); + CallbackAdapter = _listenerSecondaryCallbackAdapter, + Callback = callback, + State = state, + Completion = tcs + }); + WakeUpLoop(); return tcs.Task; } - public void Send(Action callback, T state) + public void Send(Action callback, ListenerSecondary state) { if (_loop.ThreadId == Thread.CurrentThread.ManagedThreadId) { @@ -189,11 +197,17 @@ public void Send(Action callback, T state) private void PostCloseHandle(Action callback, IntPtr handle) { - lock (_workSync) + _closeHandleQueue.Enqueue(new CloseHandle { Callback = callback, Handle = handle }); + WakeUpLoop(); + } + + private void WakeUpLoop() + { + if (_loopIdle) { - _closeHandleAdding.Enqueue(new CloseHandle { Callback = callback, Handle = handle }); + _loopIdle = false; + _post.Send(); } - _post.Send(); } private void ThreadStart(object parameter) @@ -254,31 +268,19 @@ private void ThreadStart(object parameter) private void OnPost() { - var loopsRemaining = _maxLoops; - bool wasWork; do { - wasWork = DoPostWork(); - wasWork = DoPostCloseHandle() || wasWork; - loopsRemaining--; - } while (wasWork && loopsRemaining > 0); + DoPostWork(); + DoPostCloseHandle(); + _loopIdle = _workQueue.IsEmpty && _closeHandleQueue.IsEmpty; + } while (!_loopIdle); } - private bool DoPostWork() + private void DoPostWork() { - Queue queue; - lock (_workSync) - { - queue = _workAdding; - _workAdding = _workRunning; - _workRunning = queue; - } - - bool wasWork = queue.Count > 0; - - while (queue.Count != 0) + Work work; + while (_workQueue.TryDequeue(out work)) { - var work = queue.Dequeue(); try { work.CallbackAdapter(work.Callback, work.State); @@ -301,23 +303,12 @@ private bool DoPostWork() } } - return wasWork; } - private bool DoPostCloseHandle() + private void DoPostCloseHandle() { - Queue queue; - lock (_workSync) + CloseHandle closeHandle; + while (_closeHandleQueue.TryDequeue(out closeHandle)) { - queue = _closeHandleAdding; - _closeHandleAdding = _closeHandleRunning; - _closeHandleRunning = queue; - } - - bool wasWork = queue.Count > 0; - - while (queue.Count != 0) - { - var closeHandle = queue.Dequeue(); try { closeHandle.Callback(closeHandle.Handle); @@ -328,8 +319,6 @@ private bool DoPostCloseHandle() throw; } } - - return wasWork; } private struct Work diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPool2.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPool2.cs index 5c9ce81f6..27758978d 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPool2.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPool2.cs @@ -65,21 +65,8 @@ public class MemoryPool2 : IDisposable /// The block returned must be at least this size. It may be larger than this minimum size, and if so, /// the caller may write to the block's entire size rather than being limited to the minumumSize requested. /// The block that is reserved for the called. It must be passed to Return when it is no longer being used. - public MemoryPoolBlock2 Lease(int minimumSize = MaxPooledBlockLength) + public MemoryPoolBlock2 Lease() { - if (minimumSize > _blockLength) - { - // The requested minimumSize is actually larger then the usable memory of a single block. - // Because this is the degenerate case, a one-time-use byte[] array and tracking object are allocated. - // When this block tracking object is returned it is not added to the pool - instead it will be - // allowed to be garbage collected normally. - return MemoryPoolBlock2.Create( - new ArraySegment(new byte[minimumSize]), - dataPtr: IntPtr.Zero, - pool: null, - slab: null); - } - MemoryPoolBlock2 block; if (_blocks.TryDequeue(out block)) { diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolBlock2.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolBlock2.cs index 26156c6cc..80074ef5b 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolBlock2.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolBlock2.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics; -using System.Runtime.InteropServices; using System.Text; namespace Microsoft.AspNet.Server.Kestrel.Infrastructure @@ -11,19 +9,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure /// public class MemoryPoolBlock2 { - /// - /// If this block represents a one-time-use memory object, this GCHandle will hold that memory object at a fixed address - /// so it can be used in native operations. - /// - private GCHandle _pinHandle; - - /// - /// Native address of the first byte of this block's Data memory. It is null for one-time-use memory, or copied from - /// the Slab's ArrayPtr for a slab-block segment. The byte it points to corresponds to Data.Array[0], and in practice you will always - /// use the _dataArrayPtr + Start or _dataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes. - /// - private IntPtr _dataArrayPtr; - /// /// The array segment describing the range of memory this block is tracking. The caller which has leased this block may only read and /// modify the memory in this range. @@ -47,6 +32,22 @@ protected MemoryPoolBlock2() /// public MemoryPoolSlab2 Slab { get; private set; } + /// + /// /// Native address of the first byte of this block's Data memory. It is null for one-time-use memory, or copied from + /// the Slab's ArrayPtr for a slab-block segment. The byte it points to corresponds to Data.Array[0], and in practice you will always + /// use the _dataArrayPtr + Start or _dataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes. + /// + /// Called to ensure that a block is pinned, and return the pointer to the native address + /// of the first byte of this block's Data memory. Arriving data is read into Pin() + End. + /// Outgoing data is read from Pin() + Start. + /// + /// + public IntPtr Pin { get; private set; } + + public unsafe byte* Pointer { get; private set; } + + public int BlockEndOffset { get; private set; } + /// /// Convenience accessor /// @@ -74,63 +75,7 @@ protected MemoryPoolBlock2() /// public MemoryPoolBlock2 Next { get; set; } - ~MemoryPoolBlock2() - { - Debug.Assert(!_pinHandle.IsAllocated, "Ad-hoc memory block wasn't unpinned"); - // Debug.Assert(Slab == null || !Slab.IsActive, "Block being garbage collected instead of returned to pool"); - - if (_pinHandle.IsAllocated) - { - // if this is a one-time-use block, ensure that the GCHandle does not leak - _pinHandle.Free(); - } - - if (Slab != null && Slab.IsActive) - { - Pool.Return(new MemoryPoolBlock2 - { - _dataArrayPtr = _dataArrayPtr, - Data = Data, - Pool = Pool, - Slab = Slab, - }); - } - } - - /// - /// Called to ensure that a block is pinned, and return the pointer to the native address - /// of the first byte of this block's Data memory. Arriving data is read into Pin() + End. - /// Outgoing data is read from Pin() + Start. - /// - /// - public IntPtr Pin() - { - Debug.Assert(!_pinHandle.IsAllocated); - - if (_dataArrayPtr != IntPtr.Zero) - { - // this is a slab managed block - use the native address of the slab which is always locked - return _dataArrayPtr; - } - else - { - // this is one-time-use memory - lock the managed memory until Unpin is called - _pinHandle = GCHandle.Alloc(Data.Array, GCHandleType.Pinned); - return _pinHandle.AddrOfPinnedObject(); - } - } - - public void Unpin() - { - if (_dataArrayPtr == IntPtr.Zero) - { - // this is one-time-use memory - unlock the managed memory - Debug.Assert(_pinHandle.IsAllocated); - _pinHandle.Free(); - } - } - - public static MemoryPoolBlock2 Create( + public unsafe static MemoryPoolBlock2 Create( ArraySegment data, IntPtr dataPtr, MemoryPool2 pool, @@ -139,11 +84,13 @@ public static MemoryPoolBlock2 Create( return new MemoryPoolBlock2 { Data = data, - _dataArrayPtr = dataPtr, + Pin = dataPtr, Pool = pool, Slab = slab, Start = data.Offset, End = data.Offset, + Pointer = (byte*)(dataPtr.ToPointer()), + BlockEndOffset = data.Offset + data.Count }; } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.Generated.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.Generated.cs new file mode 100644 index 000000000..06aa0f16d --- /dev/null +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.Generated.cs @@ -0,0 +1,316 @@ + +using System; + +namespace Microsoft.AspNet.Server.Kestrel.Infrastructure +{ + public partial struct MemoryPoolIterator2 + { + private const byte _colon = 58; + private const int _headerAcce = 1701012321; + private const int _headerAllo = 1869376609; + private const int _headerAuth = 1752462689; + private const int _headerCach = 1751343459; + private const int _headerConn = 1852731235; + private const int _headerCont = 1953394531; + private const int _headerCook = 1802465123; + private const int _headerDate = 1702125924; + private const int _headerExpe = 1701869669; + private const int _headerExpi = 1768978533; + private const int _headerFrom = 1836020326; + private const int _headerHost = 1953722216; + private const int _headerIf_M = 1831691881; + private const int _headerIf_N = 1848469097; + private const int _headerIf_R = 1915577961; + private const int _headerIf_U = 1965909609; + private const int _headerKeep = 1885693291; + private const int _headerLast = 1953718636; + private const int _headerMax_ = 762863981; + private const int _headerPrag = 1734439536; + private const int _headerProx = 2020569712; + private const int _headerRang = 1735287154; + private const int _headerRefe = 1701209458; + private const int _headerTrai = 1767993972; + private const int _headerTran = 1851880052; + private const int _headerUpgr = 1919381621; + private const int _headerUser = 1919251317; + private const int _headerWarn = 1852989815; + + + public unsafe bool SeekCommonHeader() + { + if (BitConverter.IsLittleEndian != true) + { + return false; + } + + if (IsDefault) + { + return false; + } + + var block = _block; + var index = _index; + var following = block.End - index; + + if (following < 4) + { + return false; + } + + var currentPointer = block.Pointer + index; + var fourLowerChars = *(int*)(currentPointer) | 0x20202020; + + switch (fourLowerChars) + { + case _headerHost: + if (following >= 4 && *(currentPointer + 4) == _colon) // Host + { + _index = index + 4; + return true; + } + return false; + case _headerFrom: + if (following >= 4 && *(currentPointer + 4) == _colon) // From + { + _index = index + 4; + return true; + } + return false; + case _headerDate: + if (following >= 4 && *(currentPointer + 4) == _colon) // Date + { + _index = index + 4; + return true; + } + return false; + case _headerRang: + if (following >= 5 && *(currentPointer + 5) == _colon) // Range + { + _index = index + 5; + return true; + } + return false; + case _headerAllo: + if (following >= 5 && *(currentPointer + 5) == _colon) // Allow + { + _index = index + 5; + return true; + } + return false; + case _headerPrag: + if (following >= 6 && *(currentPointer + 6) == _colon) // Pragma + { + _index = index + 6; + return true; + } + return false; + case _headerExpe: + if (following >= 6 && *(currentPointer + 6) == _colon) // Expect + { + _index = index + 6; + return true; + } + return false; + case _headerCook: + if (following >= 6 && *(currentPointer + 6) == _colon) // Cookie + { + _index = index + 6; + return true; + } + return false; + case _headerAcce: + if (following >= 6 && *(currentPointer + 6) == _colon) // Accept + { + _index = index + 6; + return true; + } + + if (following >= 14 && *(currentPointer + 14) == _colon) // Accept-Charset + { + _index = index + 14; + return true; + } + + if (following >= 15 && *(currentPointer + 15) == _colon) // Accept-Language, Accept-Encoding + { + _index = index + 15; + return true; + } + return false; + case _headerWarn: + if (following >= 7 && *(currentPointer + 7) == _colon) // Warning + { + _index = index + 7; + return true; + } + return false; + case _headerUpgr: + if (following >= 7 && *(currentPointer + 7) == _colon) // Upgrade + { + _index = index + 7; + return true; + } + return false; + case _headerTrai: + if (following >= 7 && *(currentPointer + 7) == _colon) // Trailer + { + _index = index + 7; + return true; + } + return false; + case _headerRefe: + if (following >= 7 && *(currentPointer + 7) == _colon) // Referer + { + _index = index + 7; + return true; + } + return false; + case _headerExpi: + if (following >= 7 && *(currentPointer + 7) == _colon) // Expires + { + _index = index + 7; + return true; + } + return false; + case _headerIf_R: + if (following >= 8 && *(currentPointer + 8) == _colon) // If-Range + { + _index = index + 8; + return true; + } + return false; + case _headerIf_M: + if (following >= 8 && *(currentPointer + 8) == _colon) // If-Match + { + _index = index + 8; + return true; + } + + if (following >= 17 && *(currentPointer + 17) == _colon) // If-Modified-Since + { + _index = index + 17; + return true; + } + return false; + case _headerTran: + if (following >= 9 && *(currentPointer + 9) == _colon) // Translate + { + _index = index + 9; + return true; + } + + if (following >= 17 && *(currentPointer + 17) == _colon) // Transfer-Encoding + { + _index = index + 17; + return true; + } + return false; + case _headerUser: + if (following >= 10 && *(currentPointer + 10) == _colon) // User-Agent + { + _index = index + 10; + return true; + } + return false; + case _headerKeep: + if (following >= 10 && *(currentPointer + 10) == _colon) // Keep-Alive + { + _index = index + 10; + return true; + } + return false; + case _headerConn: + if (following >= 10 && *(currentPointer + 10) == _colon) // Connection + { + _index = index + 10; + return true; + } + return false; + case _headerCont: + if (following >= 11 && *(currentPointer + 11) == _colon) // Content-MD5 + { + _index = index + 11; + return true; + } + + if (following >= 12 && *(currentPointer + 12) == _colon) // Content-Type + { + _index = index + 12; + return true; + } + + if (following >= 13 && *(currentPointer + 13) == _colon) // Content-Range + { + _index = index + 13; + return true; + } + + if (following >= 14 && *(currentPointer + 14) == _colon) // Content-Length + { + _index = index + 14; + return true; + } + + if (following >= 16 && *(currentPointer + 16) == _colon) // Content-Location, Content-Language, Content-Encoding + { + _index = index + 16; + return true; + } + return false; + case _headerMax_: + if (following >= 12 && *(currentPointer + 12) == _colon) // Max-Forwards + { + _index = index + 12; + return true; + } + return false; + case _headerLast: + if (following >= 13 && *(currentPointer + 13) == _colon) // Last-Modified + { + _index = index + 13; + return true; + } + return false; + case _headerIf_N: + if (following >= 13 && *(currentPointer + 13) == _colon) // If-None-Match + { + _index = index + 13; + return true; + } + return false; + case _headerCach: + if (following >= 13 && *(currentPointer + 13) == _colon) // Cache-Control + { + _index = index + 13; + return true; + } + return false; + case _headerAuth: + if (following >= 13 && *(currentPointer + 13) == _colon) // Authorization + { + _index = index + 13; + return true; + } + return false; + case _headerProx: + if (following >= 19 && *(currentPointer + 19) == _colon) // Proxy-Authorization + { + _index = index + 19; + return true; + } + return false; + case _headerIf_U: + if (following >= 19 && *(currentPointer + 19) == _colon) // If-Unmodified-Since + { + _index = index + 19; + return true; + } + return false; + + default: + return false; + } + + } + } +} diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs index 08c4a75a3..60a0f512d 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs @@ -7,8 +7,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure { - public struct MemoryPoolIterator2 + public partial struct MemoryPoolIterator2 { + private readonly static int _vectorSpan = Vector.Count; + private MemoryPoolBlock2 _block; private int _index; @@ -59,26 +61,23 @@ public bool IsEnd public int Take() { - if (_block == null) + var block = _block; + if (block == null) { return -1; } - else if (_index < _block.End) + + var index = _index; + + if (index < block.End) { - return _block.Array[_index++]; + _index = index + 1; + return block.Array[index]; } - var block = _block; - var index = _index; - while (true) + do { - if (index < block.End) - { - _block = block; - _index = index + 1; - return block.Array[index]; - } - else if (block.Next == null) + if (block.Next == null) { return -1; } @@ -87,33 +86,34 @@ public int Take() block = block.Next; index = block.Start; } - } + + if (index < block.End) + { + _block = block; + _index = index + 1; + return block.Array[index]; + } + } while (true); } public int Peek() { - if (_block == null) + var block = _block; + if (block == null) { return -1; } - else if (_index < _block.End) - { - return _block.Array[_index]; - } - else if (_block.Next == null) + + var index = _index; + + if (index < block.End) { - return -1; + return block.Array[index]; } - var block = _block.Next; - var index = block.Start; - while (true) + do { - if (index < block.End) - { - return block.Array[index]; - } - else if (block.Next == null) + if (block.Next == null) { return -1; } @@ -122,113 +122,127 @@ public int Peek() block = block.Next; index = block.Start; } - } + + if (index < block.End) + { + return block.Array[index]; + } + } while (true); } public unsafe long PeekLong() { + var block = _block; if (_block == null) { return -1; } - else if (_block.End - _index >= sizeof(long)) + + var index = _index; + + if (block.End - index >= sizeof(long)) { - fixed (byte* ptr = _block.Array) - { - return *(long*)(ptr + _index); - } + return *(long*)(block.Pointer + index); } - else if (_block.Next == null) + + var next = block.Next; + if (next == null) { return -1; } else { - var blockBytes = _block.End - _index; + var blockBytes = block.End - index; var nextBytes = sizeof(long) - blockBytes; - if (_block.Next.End - _block.Next.Start < nextBytes) + if (next.End - next.Start < nextBytes) { return -1; } - long blockLong; - fixed (byte* ptr = _block.Array) - { - blockLong = *(long*)(ptr + _block.End - sizeof(long)); - } + var blockLong = *(long*)(block.Pointer + block.End - sizeof(long)); - long nextLong; - fixed (byte* ptr = _block.Next.Array) - { - nextLong = *(long*)(ptr + _block.Next.Start); - } + var nextLong = *(long*)(next.Pointer + next.Start); return (blockLong >> (sizeof(long) - blockBytes) * 8) | (nextLong << (sizeof(long) - nextBytes) * 8); } } - public int Seek(Vector byte0Vector) + public unsafe int Seek(ref Vector byte0Vector) { if (IsDefault) { return -1; } + var following = _block.End - _index; var block = _block; var index = _index; - var array = block.Array; + byte[] array; + var byte0 = byte0Vector[0]; + while (true) { - while (block.End == index) + while (following == 0) { - if (block.Next == null) + var newBlock = block.Next; + if (newBlock == null) { _block = block; _index = index; return -1; } - block = block.Next; - index = block.Start; - array = block.Array; + index = newBlock.Start; + following = newBlock.End - index; + block = newBlock; } - while (block.End != index) + array = block.Array; + while (following > 0) { - var following = block.End - index; - if (following >= Vector.Count) +#if !DEBUG // Need unit tests to test Vector path + // Check will be Jitted away https://github.com/dotnet/coreclr/issues/1079 + if (Vector.IsHardwareAccelerated) { - var data = new Vector(array, index); - var byte0Equals = Vector.Equals(data, byte0Vector); - - if (byte0Equals.Equals(Vector.Zero)) +#endif + if (following >= _vectorSpan) { - index += Vector.Count; - continue; - } + var byte0Equals = Vector.Equals(new Vector(array, index), byte0Vector); - _block = block; - _index = index + FindFirstEqualByte(byte0Equals); - return byte0Vector[0]; - } - - var byte0 = byte0Vector[0]; + if (byte0Equals.Equals(Vector.Zero)) + { + following -= _vectorSpan; + index += _vectorSpan; + continue; + } - while (following > 0) + _block = block; + _index = index + FindFirstEqualByte(ref byte0Equals); + return byte0; + } +#if !DEBUG // Need unit tests to test Vector path + } +#endif + var pCurrent = block.Pointer + index; + var pEnd = pCurrent + following; + do { - if (block.Array[index] == byte0) + if (*pCurrent == byte0) { _block = block; _index = index; return byte0; } - following--; + pCurrent++; index++; - } + } while (pCurrent < pEnd); + + following = 0; + break; } } } - public int Seek(Vector byte0Vector, Vector byte1Vector) + public unsafe int Seek(ref Vector byte0Vector, ref Vector byte1Vector) { if (IsDefault) { @@ -237,206 +251,236 @@ public int Seek(Vector byte0Vector, Vector byte1Vector) var block = _block; var index = _index; - var array = block.Array; + var following = block.End - index; + byte[] array; + int byte0Index = int.MaxValue; + int byte1Index = int.MaxValue; + var byte0 = byte0Vector[0]; + var byte1 = byte1Vector[0]; + while (true) { - while (block.End == index) + while (following == 0) { - if (block.Next == null) + var newBlock = block.Next; + if (newBlock == null) { _block = block; _index = index; return -1; } - block = block.Next; - index = block.Start; - array = block.Array; + index = newBlock.Start; + following = newBlock.End - index; + block = newBlock; } - while (block.End != index) + array = block.Array; + while (following > 0) { - var following = block.End - index; - if (following >= Vector.Count) - { - var data = new Vector(array, index); - var byte0Equals = Vector.Equals(data, byte0Vector); - var byte1Equals = Vector.Equals(data, byte1Vector); - int byte0Index = int.MaxValue; - int byte1Index = int.MaxValue; - if (!byte0Equals.Equals(Vector.Zero)) - { - byte0Index = FindFirstEqualByte(byte0Equals); - } - if (!byte1Equals.Equals(Vector.Zero)) - { - byte1Index = FindFirstEqualByte(byte1Equals); - } - - if (byte0Index == int.MaxValue && byte1Index == int.MaxValue) +#if !DEBUG // Need unit tests to test Vector path + // Check will be Jitted away https://github.com/dotnet/coreclr/issues/1079 + if (Vector.IsHardwareAccelerated) + { +#endif + if (following >= _vectorSpan) { - index += Vector.Count; - continue; - } + var data = new Vector(array, index); + var byte0Equals = Vector.Equals(data, byte0Vector); + var byte1Equals = Vector.Equals(data, byte1Vector); - _block = block; + if (!byte0Equals.Equals(Vector.Zero)) + { + byte0Index = FindFirstEqualByte(ref byte0Equals); + } + if (!byte1Equals.Equals(Vector.Zero)) + { + byte1Index = FindFirstEqualByte(ref byte1Equals); + } - if (byte0Index < byte1Index) - { - _index = index + byte0Index; - return byte0Vector[0]; - } + if (byte0Index == int.MaxValue && byte1Index == int.MaxValue) + { + following -= _vectorSpan; + index += _vectorSpan; + continue; + } - _index = index + byte1Index; - return byte1Vector[0]; - } + _block = block; - byte byte0 = byte0Vector[0]; - byte byte1 = byte1Vector[0]; + if (byte0Index < byte1Index) + { + _index = index + byte0Index; + return byte0; + } - while (following > 0) + _index = index + byte1Index; + return byte1; + } +#if !DEBUG // Need unit tests to test Vector path + } +#endif + var pCurrent = block.Pointer + index; + var pEnd = pCurrent + following; + do { - var byteIndex = block.Array[index]; - if (byteIndex == byte0) + if (*pCurrent == byte0) { _block = block; _index = index; return byte0; } - else if (byteIndex == byte1) + if (*pCurrent == byte1) { _block = block; _index = index; return byte1; } - following--; + pCurrent++; index++; - } + } while (pCurrent != pEnd); + + following = 0; + break; } } } - public int Seek(Vector byte0Vector, Vector byte1Vector, Vector byte2Vector) + public unsafe int Seek(ref Vector byte0Vector, ref Vector byte1Vector, ref Vector byte2Vector) { if (IsDefault) { return -1; } + var following = _block.End - _index; var block = _block; var index = _index; - var array = block.Array; + byte[] array; + int byte0Index = int.MaxValue; + int byte1Index = int.MaxValue; + int byte2Index = int.MaxValue; + var byte0 = byte0Vector[0]; + var byte1 = byte1Vector[0]; + var byte2 = byte2Vector[0]; + while (true) { - while (block.End == index) + while (following == 0) { - if (block.Next == null) + var newBlock = block.Next; + if (newBlock == null) { _block = block; _index = index; return -1; } - block = block.Next; - index = block.Start; - array = block.Array; + index = newBlock.Start; + following = newBlock.End - index; + block = newBlock; } - while (block.End != index) + array = block.Array; + while (following > 0) { - var following = block.End - index; - if (following >= Vector.Count) +#if !DEBUG // Need unit tests to test Vector path + // Check will be Jitted away https://github.com/dotnet/coreclr/issues/1079 + if (Vector.IsHardwareAccelerated) { - var data = new Vector(array, index); - var byte0Equals = Vector.Equals(data, byte0Vector); - var byte1Equals = Vector.Equals(data, byte1Vector); - var byte2Equals = Vector.Equals(data, byte2Vector); - int byte0Index = int.MaxValue; - int byte1Index = int.MaxValue; - int byte2Index = int.MaxValue; - - if (!byte0Equals.Equals(Vector.Zero)) - { - byte0Index = FindFirstEqualByte(byte0Equals); - } - if (!byte1Equals.Equals(Vector.Zero)) - { - byte1Index = FindFirstEqualByte(byte1Equals); - } - if (!byte2Equals.Equals(Vector.Zero)) +#endif + if (following >= _vectorSpan) { - byte2Index = FindFirstEqualByte(byte2Equals); - } - - if (byte0Index == int.MaxValue && byte1Index == int.MaxValue && byte2Index == int.MaxValue) - { - index += Vector.Count; - continue; - } + var data = new Vector(array, index); + var byte0Equals = Vector.Equals(data, byte0Vector); + var byte1Equals = Vector.Equals(data, byte1Vector); + var byte2Equals = Vector.Equals(data, byte2Vector); - int toReturn, toMove; - if (byte0Index < byte1Index) - { - if (byte0Index < byte2Index) + if (!byte0Equals.Equals(Vector.Zero)) { - toReturn = byte0Vector[0]; - toMove = byte0Index; + byte0Index = FindFirstEqualByte(ref byte0Equals); } - else + if (!byte1Equals.Equals(Vector.Zero)) { - toReturn = byte2Vector[0]; - toMove = byte2Index; + byte1Index = FindFirstEqualByte(ref byte1Equals); } - } - else - { - if (byte1Index < byte2Index) + if (!byte2Equals.Equals(Vector.Zero)) { - toReturn = byte1Vector[0]; - toMove = byte1Index; + byte2Index = FindFirstEqualByte(ref byte2Equals); } - else + + if (byte0Index == int.MaxValue && byte1Index == int.MaxValue && byte2Index == int.MaxValue) { - toReturn = byte2Vector[0]; - toMove = byte2Index; + following -= _vectorSpan; + index += _vectorSpan; + continue; } - } - _block = block; - _index = index + toMove; - return toReturn; - } + _block = block; - var byte0 = byte0Vector[0]; - var byte1 = byte1Vector[0]; - var byte2 = byte2Vector[0]; + int toReturn, toMove; + if (byte0Index < byte1Index) + { + if (byte0Index < byte2Index) + { + toReturn = byte0; + toMove = byte0Index; + } + else + { + toReturn = byte2; + toMove = byte2Index; + } + } + else + { + if (byte1Index < byte2Index) + { + toReturn = byte1; + toMove = byte1Index; + } + else + { + toReturn = byte2; + toMove = byte2Index; + } + } - while (following > 0) + _index = index + toMove; + return toReturn; + } +#if !DEBUG // Need unit tests to test Vector path + } +#endif + var pCurrent = block.Pointer + index; + var pEnd = pCurrent + following; + do { - var byteIndex = block.Array[index]; - if (byteIndex == byte0) + if (*pCurrent == byte0) { _block = block; _index = index; return byte0; } - else if (byteIndex == byte1) + if (*pCurrent == byte1) { _block = block; _index = index; return byte1; } - else if (byteIndex == byte2) + if (*pCurrent == byte2) { _block = block; _index = index; return byte2; } - following--; + pCurrent++; index++; - } + } while (pCurrent != pEnd); + + following = 0; + break; } } } - private static int FindFirstEqualByte(Vector byteEquals) + private static int FindFirstEqualByte(ref Vector byteEquals) { // Quasi-tree search var vector64 = Vector.AsVectorInt64(byteEquals); @@ -451,15 +495,14 @@ private static int FindFirstEqualByte(Vector byteEquals) if (vector32[shift] != 0) { if (byteEquals[offset] != 0) return offset; - if (byteEquals[++offset] != 0) return offset; - if (byteEquals[++offset] != 0) return offset; - return ++offset; - } - offset += 4; - if (byteEquals[offset] != 0) return offset; - if (byteEquals[++offset] != 0) return offset; - if (byteEquals[++offset] != 0) return offset; - return ++offset; + if (byteEquals[offset + 1] != 0) return offset + 1; + if (byteEquals[offset + 2] != 0) return offset + 2; + return offset + 3; + } + if (byteEquals[offset + 4] != 0) return offset + 4; + if (byteEquals[offset + 5] != 0) return offset + 5; + if (byteEquals[offset + 6] != 0) return offset + 6; + return offset + 7; } throw new InvalidOperationException(); } @@ -514,26 +557,29 @@ public int GetLength(MemoryPoolIterator2 end) var block = _block; var index = _index; var length = 0; - while (true) + checked { - if (block == end._block) - { - return length + end._index - index; - } - else if (block.Next == null) - { - throw new InvalidOperationException("end did not follow iterator"); - } - else + while (true) { - length += block.End - index; - block = block.Next; - index = block.Start; + if (block == end._block) + { + return length + end._index - index; + } + else if (block.Next == null) + { + throw new InvalidOperationException("end did not follow iterator"); + } + else + { + length += block.End - index; + block = block.Next; + index = block.Start; + } } } } - public MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int actual) + public unsafe MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int actual) { if (IsDefault) { @@ -552,7 +598,14 @@ public MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int a actual = count; if (array != null) { +#if DOTNET5_4 || DNXCORE50 + fixed (byte* pDst = array) + { + Buffer.MemoryCopy(block.Pointer + index, pDst + offset, remaining, remaining); + } +#else Buffer.BlockCopy(block.Array, index, array, offset, remaining); +#endif } return new MemoryPoolIterator2(block, index + remaining); } @@ -561,7 +614,14 @@ public MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int a actual = count - remaining + following; if (array != null) { +#if DOTNET5_4 || DNXCORE50 + fixed (byte* pDst = array) + { + Buffer.MemoryCopy(block.Pointer + index, pDst + offset, following, following); + } +#else Buffer.BlockCopy(block.Array, index, array, offset, following); +#endif } return new MemoryPoolIterator2(block, index + following); } @@ -569,7 +629,14 @@ public MemoryPoolIterator2 CopyTo(byte[] array, int offset, int count, out int a { if (array != null) { +#if DOTNET5_4 || DNXCORE50 + fixed (byte* pDst = array) + { + Buffer.MemoryCopy(block.Pointer + index, pDst + offset, following, following); + } +#else Buffer.BlockCopy(block.Array, index, array, offset, following); +#endif } offset += following; remaining -= following; @@ -584,118 +651,270 @@ public void CopyFrom(byte[] data) CopyFrom(data, 0, data.Length); } - public void CopyFrom(ArraySegment buffer) +#if DOTNET5_4 || DNXCORE50 + public unsafe void CopyFrom(byte* data, int count) { - CopyFrom(buffer.Array, buffer.Offset, buffer.Count); + var block = _block; + var blockIndex = _index; + var blockRemaining = block.BlockEndOffset - blockIndex; + + if (blockRemaining >= count) + { + _index = blockIndex + count; + + Buffer.MemoryCopy(data, block.Pointer + blockIndex, count, count); + + block.End = _index; + return; + } + + do + { + if (blockRemaining == 0) + { + var nextBlock = block.Pool.Lease(); + blockIndex = nextBlock.Data.Offset; + blockRemaining = nextBlock.Data.Count; + block.Next = nextBlock; + block = nextBlock; + } + + if (count > blockRemaining) + { + count -= blockRemaining; + + Buffer.MemoryCopy(data, block.Pointer + blockIndex, blockRemaining, blockRemaining); + + data += blockRemaining; + block.End = blockIndex + blockRemaining; + blockRemaining = 0; + continue; + } + else + { + _index = blockIndex + count; + + Buffer.MemoryCopy(data, block.Pointer + blockIndex, count, count); + + block.End = _index; + _block = block; + return; + } + } while (true); } - public void CopyFrom(byte[] data, int offset, int count) + public unsafe void CopyFrom(byte[] data, int offset, int count) { - Debug.Assert(_block != null); - Debug.Assert(_block.Pool != null); - Debug.Assert(_block.Next == null); - Debug.Assert(_block.End == _index); + var block = _block; + var blockIndex = _index; + var blockRemaining = block.BlockEndOffset - blockIndex; + + fixed (byte* pSrc = data) + { + if (blockRemaining >= count) + { + _index = blockIndex + count; + + Buffer.MemoryCopy(pSrc + offset, block.Pointer + blockIndex, count, count); + + block.End = _index; + return; + } - var pool = _block.Pool; + do + { + if (blockRemaining == 0) + { + var nextBlock = block.Pool.Lease(); + blockIndex = nextBlock.Data.Offset; + blockRemaining = nextBlock.Data.Count; + block.Next = nextBlock; + block = nextBlock; + } + + if (count > blockRemaining) + { + count -= blockRemaining; + + Buffer.MemoryCopy(pSrc + offset, block.Pointer + blockIndex, blockRemaining, blockRemaining); + + offset += blockRemaining; + block.End = blockIndex + blockRemaining; + blockRemaining = 0; + continue; + } + else + { + _index = blockIndex + count; + + Buffer.MemoryCopy(pSrc + offset, block.Pointer + blockIndex, count, count); + + block.End = _index; + _block = block; + return; + } + } while (true); + } + } +#else + public unsafe void CopyFrom(byte[] data, int offset, int count) + { var block = _block; var blockIndex = _index; + var blockRemaining = block.BlockEndOffset - blockIndex; - var bufferIndex = offset; - var remaining = count; - var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex; + if (blockRemaining >= count) + { + _index = blockIndex + count; + + Buffer.BlockCopy(data, offset, block.Array, blockIndex, count); + + block.End = _index; + return; + } - while (remaining > 0) + do { - if (bytesLeftInBlock == 0) + if (blockRemaining == 0) { - var nextBlock = pool.Lease(); - block.End = blockIndex; + var nextBlock = block.Pool.Lease(); + blockIndex = nextBlock.Data.Offset; + blockRemaining = nextBlock.Data.Count; block.Next = nextBlock; block = nextBlock; - - blockIndex = block.Data.Offset; - bytesLeftInBlock = block.Data.Count; } - var bytesToCopy = remaining < bytesLeftInBlock ? remaining : bytesLeftInBlock; + if (count > blockRemaining) + { + count -= blockRemaining; - Buffer.BlockCopy(data, bufferIndex, block.Array, blockIndex, bytesToCopy); + Buffer.BlockCopy(data, offset, block.Array, blockIndex, blockRemaining); - blockIndex += bytesToCopy; - bufferIndex += bytesToCopy; - remaining -= bytesToCopy; - bytesLeftInBlock -= bytesToCopy; - } + block.End = blockIndex + blockRemaining; + offset += blockRemaining; + blockRemaining = 0; + continue; + } + else + { + _index = blockIndex + count; - block.End = blockIndex; - _block = block; - _index = blockIndex; + Buffer.BlockCopy(data, offset, block.Array, blockIndex, count); + + block.End = _index; + _block = block; + return; + } + } while (true); } +#endif public unsafe void CopyFromAscii(string data) { - Debug.Assert(_block != null); - Debug.Assert(_block.Pool != null); - Debug.Assert(_block.Next == null); - Debug.Assert(_block.End == _index); - - var pool = _block.Pool; var block = _block; var blockIndex = _index; - var length = data.Length; + var count = data.Length; - var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex; - var bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3; + var blockRemaining = block.BlockEndOffset - blockIndex; fixed (char* pData = data) { - var input = pData; - var inputEnd = pData + length; - var inputEndMinusSpan = inputEnd - 3; + if (blockRemaining >= count) + { + _index = blockIndex + count; + + CopyFromAscii(pData, block.Pointer + blockIndex, count); - while (input < inputEnd) + block.End = _index; + return; + } + + var input = pData; + do { - if (bytesLeftInBlock == 0) + if (blockRemaining == 0) { - var nextBlock = pool.Lease(); - block.End = blockIndex; + var nextBlock = block.Pool.Lease(); + blockIndex = nextBlock.Data.Offset; + blockRemaining = nextBlock.Data.Count; block.Next = nextBlock; block = nextBlock; - - blockIndex = block.Data.Offset; - bytesLeftInBlock = block.Data.Count; - bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3; } - fixed (byte* pOutput = block.Data.Array) + if (count > blockRemaining) { - var output = pOutput + block.End; + count -= blockRemaining; - var copied = 0; - for (; input < inputEndMinusSpan && copied < bytesLeftInBlockMinusSpan; copied += 4) - { - *(output) = (byte)*(input); - *(output + 1) = (byte)*(input + 1); - *(output + 2) = (byte)*(input + 2); - *(output + 3) = (byte)*(input + 3); - output += 4; - input += 4; - } - for (; input < inputEnd && copied < bytesLeftInBlock; copied++) - { - *(output++) = (byte)*(input++); - } + CopyFromAscii(input, block.Pointer + blockIndex, blockRemaining); - blockIndex += copied; - bytesLeftInBlockMinusSpan -= copied; - bytesLeftInBlock -= copied; + block.End = blockIndex + blockRemaining; + input += blockRemaining; + blockRemaining = 0; + continue; } - } + else + { + _index = blockIndex + count; + + CopyFromAscii(input, block.Pointer + blockIndex, count); + + block.End = _index; + _block = block; + return; + } + } while (true); } + } - block.End = blockIndex; - _block = block; - _index = blockIndex; + private unsafe static void CopyFromAscii(char* input, byte* output, int count) + { + var i = 0; + + while (i + 11 < count) + { + i += 12; + *(output) = (byte)*(input); + *(output + 1) = (byte)*(input + 1); + *(output + 2) = (byte)*(input + 2); + *(output + 3) = (byte)*(input + 3); + *(output + 4) = (byte)*(input + 4); + *(output + 5) = (byte)*(input + 5); + *(output + 6) = (byte)*(input + 6); + *(output + 7) = (byte)*(input + 7); + *(output + 8) = (byte)*(input + 8); + *(output + 9) = (byte)*(input + 9); + *(output + 10) = (byte)*(input + 10); + *(output + 11) = (byte)*(input + 11); + output += 12; + input += 12; + } + if (i + 6 < count) + { + i += 6; + *(output) = (byte)*(input); + *(output + 1) = (byte)*(input + 1); + *(output + 2) = (byte)*(input + 2); + *(output + 3) = (byte)*(input + 3); + *(output + 4) = (byte)*(input + 4); + *(output + 5) = (byte)*(input + 5); + output += 6; + input += 6; + } + if (i + 3 < count) + { + i += 4; + *(output) = (byte)*(input); + *(output + 1) = (byte)*(input + 1); + *(output + 2) = (byte)*(input + 2); + *(output + 3) = (byte)*(input + 3); + output += 4; + input += 4; + } + while (i < count) + { + i++; + *(output++) = (byte)*(input++); + } } } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2Extensions.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2Extensions.cs index c9a23db15..748672a20 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2Extensions.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2Extensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Diagnostics; using System.Text; @@ -9,8 +10,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure { public static class MemoryPoolIterator2Extensions { - private const int _maxStackAllocBytes = 16384; - private static Encoding _utf8 = Encoding.UTF8; public const string HttpConnectMethod = "CONNECT"; @@ -69,103 +68,106 @@ private unsafe static long GetAsciiStringAsLong(string str) return *(long*)ptr; } } - - private static unsafe string GetAsciiStringStack(byte[] input, int inputOffset, int length) + + public unsafe static string GetAsciiString(this MemoryPoolIterator2 start, MemoryPoolIterator2 end) { - // avoid declaring other local vars, or doing work with stackalloc - // to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279 - char* output = stackalloc char[length]; - - return GetAsciiStringImplementation(output, input, inputOffset, length); - } - - private static unsafe string GetAsciiStringImplementation(char* output, byte[] input, int inputOffset, int length) - { - for (var i = 0; i < length; i++) + if (start.IsDefault || end.IsDefault) { - output[i] = (char)input[inputOffset + i]; + return null; } - return new string(output, 0, length); - } - - private static unsafe string GetAsciiStringStack(MemoryPoolBlock2 start, MemoryPoolIterator2 end, int inputOffset, int length) - { - // avoid declaring other local vars, or doing work with stackalloc - // to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279 - char* output = stackalloc char[length]; - - return GetAsciiStringImplementation(output, start, end, inputOffset, length); - } - - private unsafe static string GetAsciiStringHeap(MemoryPoolBlock2 start, MemoryPoolIterator2 end, int inputOffset, int length) - { - var buffer = new char[length]; + var length = start.GetLength(end); - fixed (char* output = buffer) + if (length == 0) { - return GetAsciiStringImplementation(output, start, end, inputOffset, length); + return null; } - } - private static unsafe string GetAsciiStringImplementation(char* output, MemoryPoolBlock2 start, MemoryPoolIterator2 end, int inputOffset, int length) - { - var outputOffset = 0; - var block = start; - var remaining = length; + // Bytes out of the range of ascii are treated as "opaque data" + // and kept in string as a char value that casts to same input byte value + // https://tools.ietf.org/html/rfc7230#section-3.2.4 - var endBlock = end.Block; - var endIndex = end.Index; + var inputOffset = start.Index; + var block = start.Block; - while (true) + var asciiString = new string('\0', length); + + fixed (char* outputStart = asciiString) { - int following = (block != endBlock ? block.End : endIndex) - inputOffset; + var output = outputStart; + var remaining = length; + + var endBlock = end.Block; + var endIndex = end.Index; - if (following > 0) + while (true) { - var input = block.Array; - for (var i = 0; i < following; i++) + int following = (block != endBlock ? block.End : endIndex) - inputOffset; + + if (following > 0) { - output[i + outputOffset] = (char)input[i + inputOffset]; + var input = block.Pointer + inputOffset; + var i = 0; + while (i + 11 < following) + { + i += 12; + *(output) = (char)*(input); + *(output + 1) = (char)*(input + 1); + *(output + 2) = (char)*(input + 2); + *(output + 3) = (char)*(input + 3); + *(output + 4) = (char)*(input + 4); + *(output + 5) = (char)*(input + 5); + *(output + 6) = (char)*(input + 6); + *(output + 7) = (char)*(input + 7); + *(output + 8) = (char)*(input + 8); + *(output + 9) = (char)*(input + 9); + *(output + 10) = (char)*(input + 10); + *(output + 11) = (char)*(input + 11); + output += 12; + input += 12; + } + if (i + 6 < following) + { + i += 6; + *(output) = (char)*(input); + *(output + 1) = (char)*(input + 1); + *(output + 2) = (char)*(input + 2); + *(output + 3) = (char)*(input + 3); + *(output + 4) = (char)*(input + 4); + *(output + 5) = (char)*(input + 5); + output += 6; + input += 6; + } + if (i + 3 < following) + { + i += 4; + *(output) = (char)*(input); + *(output + 1) = (char)*(input + 1); + *(output + 2) = (char)*(input + 2); + *(output + 3) = (char)*(input + 3); + output += 4; + input += 4; + } + while (i < following) + { + i++; + *(output++) = (char)*(input++); + } + + remaining -= following; } - remaining -= following; - outputOffset += following; - } + if (remaining == 0) + { + break; + } - if (remaining == 0) - { - return new string(output, 0, length); + block = block.Next; + inputOffset = block.Start; } - - block = block.Next; - inputOffset = block.Start; - } - } - - public static string GetAsciiString(this MemoryPoolIterator2 start, MemoryPoolIterator2 end) - { - if (start.IsDefault || end.IsDefault) - { - return default(string); - } - - var length = start.GetLength(end); - - // Bytes out of the range of ascii are treated as "opaque data" - // and kept in string as a char value that casts to same input byte value - // https://tools.ietf.org/html/rfc7230#section-3.2.4 - if (end.Block == start.Block) - { - return GetAsciiStringStack(start.Block.Array, start.Index, length); - } - - if (length > _maxStackAllocBytes) - { - return GetAsciiStringHeap(start.Block, end, start.Index, length); } - return GetAsciiStringStack(start.Block, end, start.Index, length); + return asciiString; } public static string GetUtf8String(this MemoryPoolIterator2 start, MemoryPoolIterator2 end) @@ -246,8 +248,9 @@ public static string GetUtf8String(this MemoryPoolIterator2 start, MemoryPoolIte } } - public static ArraySegment GetArraySegment(this MemoryPoolIterator2 start, MemoryPoolIterator2 end) + public static ArraySegment GetArraySegment(this MemoryPoolIterator2 start, MemoryPoolIterator2 end, out byte[] rentedBuffer) { + rentedBuffer = null; if (start.IsDefault || end.IsDefault) { return default(ArraySegment); @@ -258,9 +261,9 @@ public static ArraySegment GetArraySegment(this MemoryPoolIterator2 start, } var length = start.GetLength(end); - var array = new byte[length]; - start.CopyTo(array, 0, length, out length); - return new ArraySegment(array, 0, length); + rentedBuffer = ArrayPool.Shared.Rent(length); + start.CopyTo(rentedBuffer, 0, length, out length); + return new ArraySegment(rentedBuffer, 0, length); } /// diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/TaskUtilities.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/TaskUtilities.cs index e67ded5ac..6a56e7507 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/TaskUtilities.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/TaskUtilities.cs @@ -12,5 +12,6 @@ public static class TaskUtilities #else public static Task CompletedTask = Task.FromResult(null); #endif + public static Task ZeroTask = Task.FromResult(0); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq.cs b/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq.cs index 21a1aaf77..1a43b22f7 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Logging; @@ -20,9 +19,11 @@ public class UvWriteReq : UvRequest private Action _callback; private object _state; - private const int BUFFER_COUNT = 4; + private const int BUFFER_COUNT = 32; - private List _pins = new List(BUFFER_COUNT + 1); + private GCHandle _pinUvWriteReq; + private GCHandle _pinBufferArray; + private bool _bufferArrayIsPinned; public UvWriteReq(IKestrelTrace logger) : base(logger) { @@ -50,27 +51,27 @@ public unsafe void Write( try { // add GCHandle to keeps this SafeHandle alive while request processing - _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); + _pinUvWriteReq = GCHandle.Alloc(this, GCHandleType.Normal); var pBuffers = (Libuv.uv_buf_t*)_bufs; if (nBuffers > BUFFER_COUNT) { // create and pin buffer array when it's larger than the pre-allocated one var bufArray = new Libuv.uv_buf_t[nBuffers]; - var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); - _pins.Add(gcHandle); - pBuffers = (Libuv.uv_buf_t*)gcHandle.AddrOfPinnedObject(); + _pinBufferArray = GCHandle.Alloc(bufArray, GCHandleType.Pinned); + _bufferArrayIsPinned = true; + pBuffers = (Libuv.uv_buf_t*)_pinBufferArray.AddrOfPinnedObject(); } var block = start.Block; for (var index = 0; index < nBuffers; index++) { var blockStart = block == start.Block ? start.Index : block.Data.Offset; - var blockEnd = block == end.Block ? end.Index : block.Data.Offset + block.Data.Count; + var blockEnd = block == end.Block ? end.Index : block.BlockEndOffset; // create and pin each segment being written pBuffers[index] = Libuv.buf_init( - block.Pin() + blockStart, + block.Pin + blockStart, blockEnd - blockStart); block = block.Next; @@ -89,7 +90,6 @@ public unsafe void Write( var block = start.Block; for (var index = 0; index < nBuffers; index++) { - block.Unpin(); block = block.Next; } @@ -97,61 +97,14 @@ public unsafe void Write( } } - public unsafe void Write2( - UvStreamHandle handle, - ArraySegment> bufs, - UvStreamHandle sendHandle, - Action callback, - object state) - { - try - { - // add GCHandle to keeps this SafeHandle alive while request processing - _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); - - var pBuffers = (Libuv.uv_buf_t*)_bufs; - var nBuffers = bufs.Count; - if (nBuffers > BUFFER_COUNT) - { - // create and pin buffer array when it's larger than the pre-allocated one - var bufArray = new Libuv.uv_buf_t[nBuffers]; - var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); - _pins.Add(gcHandle); - pBuffers = (Libuv.uv_buf_t*)gcHandle.AddrOfPinnedObject(); - } - - for (var index = 0; index < nBuffers; index++) - { - // create and pin each segment being written - var buf = bufs.Array[bufs.Offset + index]; - - var gcHandle = GCHandle.Alloc(buf.Array, GCHandleType.Pinned); - _pins.Add(gcHandle); - pBuffers[index] = Libuv.buf_init( - gcHandle.AddrOfPinnedObject() + buf.Offset, - buf.Count); - } - - _callback = callback; - _state = state; - _uv.write2(this, handle, pBuffers, nBuffers, sendHandle, _uv_write_cb); - } - catch - { - _callback = null; - _state = null; - Unpin(this); - throw; - } - } - private static void Unpin(UvWriteReq req) { - foreach (var pin in req._pins) + req._pinUvWriteReq.Free(); + if (req._bufferArrayIsPinned) { - pin.Free(); + req._pinBufferArray.Free(); + req._bufferArrayIsPinned = false; } - req._pins.Clear(); } private static void UvWriteCb(IntPtr ptr, int status) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq2.cs b/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq2.cs new file mode 100644 index 000000000..a7cb8b7c9 --- /dev/null +++ b/src/Microsoft.AspNet.Server.Kestrel/Networking/UvWriteReq2.cs @@ -0,0 +1,114 @@ +// 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. + +using System; +using System.Runtime.InteropServices; +using Microsoft.AspNet.Server.Kestrel.Infrastructure; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNet.Server.Kestrel.Networking +{ + /// + /// Summary description for UvWriteRequest2 + /// + public class UvWrite2Req : UvRequest + { + private readonly static Libuv.uv_write_cb _uv_write2_cb = (IntPtr ptr, int status) => UvWrite2Cb(ptr, status); + + private IntPtr _bufs; + + private Action _callback; + private object _state; + private const int BUFFER_COUNT = 1; + + private GCHandle _pinUvWrite2Req; + private GCHandle _pinBuffer; + private bool _bufferIsPinned; + + public UvWrite2Req(IKestrelTrace logger) : base(logger) + { + } + + public void Init(UvLoopHandle loop) + { + var requestSize = loop.Libuv.req_size(Libuv.RequestType.WRITE); + var bufferSize = Marshal.SizeOf() * BUFFER_COUNT; + CreateMemory( + loop.Libuv, + loop.ThreadId, + requestSize + bufferSize); + _bufs = handle + requestSize; + } + + public unsafe void Write2( + UvStreamHandle handle, + ArraySegment buf, + UvStreamHandle sendHandle, + Action callback, + object state) + { + try + { + // add GCHandle to keeps this SafeHandle alive while request processing + _pinUvWrite2Req = GCHandle.Alloc(this, GCHandleType.Normal); + + var pBuffers = (Libuv.uv_buf_t*)_bufs; + _pinBuffer = GCHandle.Alloc(buf.Array, GCHandleType.Pinned); + _bufferIsPinned = true; + + pBuffers[0] = Libuv.buf_init( + _pinBuffer.AddrOfPinnedObject() + buf.Offset, + buf.Count); + + _callback = callback; + _state = state; + _uv.write2(this, handle, pBuffers, BUFFER_COUNT, sendHandle, _uv_write2_cb); + } + catch + { + _callback = null; + _state = null; + Unpin(this); + throw; + } + } + + private static void Unpin(UvWrite2Req req) + { + req._pinUvWrite2Req.Free(); + if (req._bufferIsPinned) + { + req._pinBuffer.Free(); + req._bufferIsPinned = false; + } + } + + private static void UvWrite2Cb(IntPtr ptr, int status) + { + var req = FromIntPtr(ptr); + Unpin(req); + + var callback = req._callback; + req._callback = null; + + var state = req._state; + req._state = null; + + Exception error = null; + if (status < 0) + { + req.Libuv.Check(status, out error); + } + + try + { + callback(req, status, error, state); + } + catch (Exception ex) + { + req._log.LogError("UvWriteCb", ex); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.Kestrel/project.json b/src/Microsoft.AspNet.Server.Kestrel/project.json index c95d40a6d..74aafd8e1 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/project.json +++ b/src/Microsoft.AspNet.Server.Kestrel/project.json @@ -20,7 +20,8 @@ "Microsoft.AspNet.Internal.libuv-Windows": { "version": "1.0.0-*", "type": "build" - } + }, + "System.Buffers": "4.0.0-*" }, "frameworks": { "dnx451": { }, @@ -73,7 +74,7 @@ "scripts": { "prepare": [ "dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode", - "dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs Http/Frame.Generated.cs" + "dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs Http/Frame.Generated.cs Infrastructure/MemoryPoolIterator2.Generated.cs" ], "postrestore": [ "dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.LibuvCopier", diff --git a/test/Microsoft.AspNet.Server.KestrelTests/AsciiDecoder.cs b/test/Microsoft.AspNet.Server.KestrelTests/AsciiDecoder.cs index 26c034d2d..972b040df 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/AsciiDecoder.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/AsciiDecoder.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Xunit; @@ -13,24 +14,32 @@ public class AsciiDecoderTests [Fact] private void FullByteRangeSupported() { - var byteRange = Enumerable.Range(0, 255).Select(x => (byte)x).ToArray(); + var byteRange = Enumerable.Range(0, 256).Select(x => (byte)x).ToArray(); - var mem = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - mem.End = byteRange.Length; + var handle = GCHandle.Alloc(byteRange, GCHandleType.Pinned); + try + { + var mem = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + mem.End = byteRange.Length; - var begin = mem.GetIterator(); - var end = GetIterator(begin, byteRange.Length); + var begin = mem.GetIterator(); + var end = GetIterator(begin, byteRange.Length); - var s = begin.GetAsciiString(end); + var s = begin.GetAsciiString(end); - Assert.Equal(s.Length, byteRange.Length); + Assert.Equal(s.Length, byteRange.Length); - for (var i = 0; i < byteRange.Length; i++) - { - var sb = (byte)s[i]; - var b = byteRange[i]; + for (var i = 0; i < byteRange.Length; i++) + { + var sb = (byte)s[i]; + var b = byteRange[i]; - Assert.Equal(sb, b); + Assert.Equal(sb, b); + } + } + finally + { + handle.Free(); } } @@ -38,67 +47,82 @@ private void FullByteRangeSupported() private void MultiBlockProducesCorrectResults() { var byteRange = Enumerable.Range(0, 512 + 64).Select(x => (byte)x).ToArray(); - var expectedByteRange = byteRange - .Concat(byteRange) - .Concat(byteRange) - .Concat(byteRange) - .ToArray(); - - var mem0 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - var mem1 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - var mem2 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - var mem3 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - mem0.End = byteRange.Length; - mem1.End = byteRange.Length; - mem2.End = byteRange.Length; - mem3.End = byteRange.Length; - - mem0.Next = mem1; - mem1.Next = mem2; - mem2.Next = mem3; - - var begin = mem0.GetIterator(); - var end = GetIterator(begin, expectedByteRange.Length); - - var s = begin.GetAsciiString(end); - - Assert.Equal(s.Length, expectedByteRange.Length); - - for (var i = 0; i < expectedByteRange.Length; i++) + var handle = GCHandle.Alloc(byteRange, GCHandleType.Pinned); + try { - var sb = (byte)s[i]; - var b = expectedByteRange[i]; - - Assert.Equal(sb, b); + var expectedByteRange = byteRange + .Concat(byteRange) + .Concat(byteRange) + .Concat(byteRange) + .ToArray(); + + var mem0 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + var mem1 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + var mem2 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + var mem3 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + mem0.End = byteRange.Length; + mem1.End = byteRange.Length; + mem2.End = byteRange.Length; + mem3.End = byteRange.Length; + + mem0.Next = mem1; + mem1.Next = mem2; + mem2.Next = mem3; + + var begin = mem0.GetIterator(); + var end = GetIterator(begin, expectedByteRange.Length); + + var s = begin.GetAsciiString(end); + + Assert.Equal(s.Length, expectedByteRange.Length); + + for (var i = 0; i < expectedByteRange.Length; i++) + { + var sb = (byte)s[i]; + var b = expectedByteRange[i]; + + Assert.Equal(sb, b); + } + } + finally + { + handle.Free(); } } [Fact] - private void HeapAllocationProducesCorrectResults() + private void LargeAllocationProducesCorrectResults() { var byteRange = Enumerable.Range(0, 16384 + 64).Select(x => (byte)x).ToArray(); - var expectedByteRange = byteRange.Concat(byteRange).ToArray(); + var handle = GCHandle.Alloc(byteRange, GCHandleType.Pinned); + try { + var expectedByteRange = byteRange.Concat(byteRange).ToArray(); - var mem0 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - var mem1 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), IntPtr.Zero, null, null); - mem0.End = byteRange.Length; - mem1.End = byteRange.Length; + var mem0 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + var mem1 = MemoryPoolBlock2.Create(new ArraySegment(byteRange), handle.AddrOfPinnedObject(), null, null); + mem0.End = byteRange.Length; + mem1.End = byteRange.Length; - mem0.Next = mem1; + mem0.Next = mem1; - var begin = mem0.GetIterator(); - var end = GetIterator(begin, expectedByteRange.Length); + var begin = mem0.GetIterator(); + var end = GetIterator(begin, expectedByteRange.Length); - var s = begin.GetAsciiString(end); + var s = begin.GetAsciiString(end); - Assert.Equal(s.Length, expectedByteRange.Length); + Assert.Equal(s.Length, expectedByteRange.Length); - for (var i = 0; i < expectedByteRange.Length; i++) - { - var sb = (byte)s[i]; - var b = expectedByteRange[i]; + for (var i = 0; i < expectedByteRange.Length; i++) + { + var sb = (byte)s[i]; + var b = expectedByteRange[i]; - Assert.Equal(sb, b); + Assert.Equal(sb, b); + } + } + finally + { + handle.Free(); } } diff --git a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs index 0bfa31b43..12250b161 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs @@ -931,6 +931,137 @@ await connection.ReceiveEnd( } } + [ConditionalTheory] + [MemberData(nameof(ConnectionFilterData))] + [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")] + public async Task RequestsPipelined(ServiceContext testContext) + { + using (var server = new TestServer(async httpContext => + { + var response = httpContext.Response; + var request = httpContext.Request; + + Assert.Equal("POST", request.Method); + + response.Headers.Clear(); + response.Headers["Content-Length"] = new[] { "11" }; + + await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11); + }, testContext)) + { + using (var connection = new TestConnection()) + { + await connection.SendPipelined( + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Hello", + "POST / HTTP/1.1", + "Content-Length: 5", + "", + "HelloPOST / HTTP/1.1", + "Transfer-Encoding: chunked", + "", + "C", "HelloChunked", "0", + "POST / HTTP/1.1", + "Content-Length: 7", + "", + "Goodbye"); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello WorldHTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello World"); + } + } + } + [ConditionalTheory] [MemberData(nameof(ConnectionFilterData))] [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")] diff --git a/test/Microsoft.AspNet.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/FrameTests.cs index cc9bc2661..2c7c028b0 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/FrameTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Linq; using System.Text; using Microsoft.AspNet.Server.Kestrel; @@ -33,9 +34,11 @@ public class FrameTests [InlineData(0x7fffffffL, "7fffffff\r\n")] public void ChunkedPrefixMustBeHexCrLfWithoutLeadingZeros(int dataCount, string expected) { - var beginChunkBytes = Frame.BeginChunkBytes(dataCount); + var tenByteBuffer = ArrayPool.Shared.Rent(10); + var beginChunkBytes = Frame.BeginChunkBytes(dataCount, tenByteBuffer); Assert.Equal(Encoding.ASCII.GetBytes(expected), beginChunkBytes.ToArray()); + ArrayPool.Shared.Return(tenByteBuffer); } [Theory] @@ -55,9 +58,7 @@ public void EmptyHeaderValuesCanBeParsed(string rawHeaders, int numHeaders) var headerCollection = new FrameRequestHeaders(); var headerArray = Encoding.ASCII.GetBytes(rawHeaders); - var inputBuffer = socketInput.IncomingStart(headerArray.Length); - Buffer.BlockCopy(headerArray, 0, inputBuffer.Data.Array, inputBuffer.Data.Offset, headerArray.Length); - socketInput.IncomingComplete(headerArray.Length, null); + socketInput.IncomingData(headerArray, 0, headerArray.Length); var success = Frame.TakeMessageHeaders(socketInput, headerCollection); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs index c56f5311d..201c34968 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs @@ -13,7 +13,7 @@ public void SeekWorks() { using (var pool = new MemoryPool2()) { - var block = pool.Lease(256); + var block = pool.Lease(); foreach (var ch in Enumerable.Range(0, 256).Select(x => (byte)x)) { block.Array[block.End++] = ch; @@ -27,27 +27,27 @@ public void SeekWorks() var vectorCh = new Vector(ch); var hit = iterator; - hit.Seek(vectorCh); + hit.Seek(ref vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorCh, vectorMaxValues); + hit.Seek(ref vectorCh, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorMaxValues, vectorCh); + hit.Seek(ref vectorMaxValues, ref vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); + hit.Seek(ref vectorCh, ref vectorMaxValues, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorMaxValues, vectorCh, vectorMaxValues); + hit.Seek(ref vectorMaxValues, ref vectorCh, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); + hit.Seek(ref vectorCh, ref vectorMaxValues, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); } } @@ -56,11 +56,14 @@ public void SeekWorks() [Fact] public void SeekWorksAcrossBlocks() { + Console.WriteLine($"Vector.IsHardwareAccelerated == {Vector.IsHardwareAccelerated}"); + Console.WriteLine($"Vector.Count == {Vector.Count}"); + using (var pool = new MemoryPool2()) { - var block1 = pool.Lease(256); - var block2 = block1.Next = pool.Lease(256); - var block3 = block2.Next = pool.Lease(256); + var block1 = pool.Lease(); + var block2 = block1.Next = pool.Lease(); + var block3 = block2.Next = pool.Lease(); foreach (var ch in Enumerable.Range(0, 34).Select(x => (byte)x)) { @@ -83,27 +86,27 @@ public void SeekWorksAcrossBlocks() var vectorCh = new Vector(ch); var hit = iterator; - hit.Seek(vectorCh); + hit.Seek(ref vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorCh, vectorMaxValues); + hit.Seek(ref vectorCh, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorMaxValues, vectorCh); + hit.Seek(ref vectorMaxValues, ref vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); + hit.Seek(ref vectorCh, ref vectorMaxValues, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorMaxValues, vectorCh, vectorMaxValues); + hit.Seek(ref vectorMaxValues, ref vectorCh, ref vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(vectorMaxValues, vectorMaxValues, vectorCh); + hit.Seek(ref vectorMaxValues, ref vectorMaxValues, ref vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); } } @@ -114,7 +117,7 @@ public void GetLengthBetweenIteratorsWorks() { using (var pool = new MemoryPool2()) { - var block = pool.Lease(256); + var block = pool.Lease(); block.End += 256; TestAllLengths(block, 256); pool.Return(block); @@ -123,7 +126,7 @@ public void GetLengthBetweenIteratorsWorks() for (var fragment = 0; fragment < 256; fragment += 4) { var next = block; - block = pool.Lease(4); + block = pool.Lease(); block.Next = next; block.End += 4; } @@ -159,8 +162,8 @@ public void AddDoesNotAdvanceAtEndOfCurrentBlock() { using (var pool = new MemoryPool2()) { - var block1 = pool.Lease(256); - var block2 = block1.Next = pool.Lease(256); + var block1 = pool.Lease(); + var block2 = block1.Next = pool.Lease(); block1.End += 100; block2.End += 200; @@ -197,8 +200,8 @@ public void CopyToCorrectlyTraversesBlocks() { using (var pool = new MemoryPool2()) { - var block1 = pool.Lease(128); - var block2 = block1.Next = pool.Lease(128); + var block1 = pool.Lease(); + var block2 = block1.Next = pool.Lease(); for (int i = 0; i < 128; i++) { @@ -232,7 +235,7 @@ public void CopyFromCorrectlyTraversesBlocks() { using (var pool = new MemoryPool2()) { - var block1 = pool.Lease(128); + var block1 = pool.Lease(); var start = block1.GetIterator(); var end = start; var bufferSize = block1.Data.Count * 3; @@ -245,7 +248,7 @@ public void CopyFromCorrectlyTraversesBlocks() Assert.Null(block1.Next); - end.CopyFrom(new ArraySegment(buffer)); + end.CopyFrom(buffer); Assert.NotNull(block1.Next); @@ -265,10 +268,10 @@ public void IsEndCorrectlyTraversesBlocks() { using (var pool = new MemoryPool2()) { - var block1 = pool.Lease(128); - var block2 = block1.Next = pool.Lease(128); - var block3 = block2.Next = pool.Lease(128); - var block4 = block3.Next = pool.Lease(128); + var block1 = pool.Lease(); + var block2 = block1.Next = pool.Lease(); + var block3 = block2.Next = pool.Lease(); + var block4 = block3.Next = pool.Lease(); // There is no data in block2 or block4, so IsEnd should be true after 256 bytes are read. block1.End += 128; diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs index 67c4a7e6a..26b9e04a2 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs @@ -42,7 +42,7 @@ public void Dispose() [InlineData("/localhost:5000/PATH/PATH2/ HTTP/1.1", " %?", ' ', 27)] public void MemorySeek(string raw, string search, char expectResult, int expectIndex) { - var block = _pool.Lease(256); + var block = _pool.Lease(); var chars = raw.ToCharArray().Select(c => (byte)c).ToArray(); Buffer.BlockCopy(chars, 0, block.Array, block.Start, chars.Length); block.End += chars.Length; @@ -50,18 +50,25 @@ public void MemorySeek(string raw, string search, char expectResult, int expectI var begin = block.GetIterator(); var searchFor = search.ToCharArray(); + int found = -1; if (searchFor.Length == 1) { - found = begin.Seek(new Vector((byte)searchFor[0])); + var search0 = new Vector((byte)searchFor[0]); + found = begin.Seek(ref search0); } else if (searchFor.Length == 2) { - found = begin.Seek(new Vector((byte)searchFor[0]), new Vector((byte)searchFor[1])); + var search0 = new Vector((byte)searchFor[0]); + var search1 = new Vector((byte)searchFor[1]); + found = begin.Seek(ref search0, ref search1); } else if (searchFor.Length == 3) { - found = begin.Seek(new Vector((byte)searchFor[0]), new Vector((byte)searchFor[1]), new Vector((byte)searchFor[2])); + var search0 = new Vector((byte)searchFor[0]); + var search1 = new Vector((byte)searchFor[1]); + var search2 = new Vector((byte)searchFor[2]); + found = begin.Seek(ref search0, ref search1, ref search2); } else { @@ -78,7 +85,7 @@ public void Put() var blocks = new MemoryPoolBlock2[4]; for (var i = 0; i < 4; ++i) { - blocks[i] = _pool.Lease(16); + blocks[i] = _pool.Lease(); blocks[i].End += 16; for (var j = 0; j < blocks.Length; ++j) @@ -218,7 +225,8 @@ public void GetsKnownString(string input, char endChar, bool expectedResult, str block.End += chars.Length; var begin = block.GetIterator(); var end = begin; - end.Seek(new Vector((byte)endChar)); + var endVector = new Vector((byte)endChar); + end.Seek(ref endVector); string knownString; // Act diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MessageBodyTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MessageBodyTests.cs index 19e7d2e9b..f93c144c8 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MessageBodyTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MessageBodyTests.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Server.Kestrel.Http; -using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNet.Server.KestrelTests @@ -20,7 +18,7 @@ public class MessageBodyTests public void Http10ConnectionClose() { var input = new TestInput(); - var body = MessageBody.For("HTTP/1.0", new Dictionary(), input.FrameContext); + var body = MessageBody.For("HTTP/1.0", new FrameRequestHeaders(), input.FrameContext); var stream = new FrameRequestStream().StartAcceptingReads(body); input.Add("Hello", true); @@ -38,7 +36,7 @@ public void Http10ConnectionClose() public async Task Http10ConnectionCloseAsync() { var input = new TestInput(); - var body = MessageBody.For("HTTP/1.0", new Dictionary(), input.FrameContext); + var body = MessageBody.For("HTTP/1.0", new FrameRequestHeaders(), input.FrameContext); var stream = new FrameRequestStream().StartAcceptingReads(body); input.Add("Hello", true); @@ -56,7 +54,7 @@ public async Task Http10ConnectionCloseAsync() public async Task CanHandleLargeBlocks() { var input = new TestInput(); - var body = MessageBody.For("HTTP/1.0", new Dictionary(), input.FrameContext); + var body = MessageBody.For("HTTP/1.0", new FrameRequestHeaders(), input.FrameContext); var stream = new FrameRequestStream().StartAcceptingReads(body); // Input needs to be greater than 4032 bytes to allocate a block not backed by a slab. diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MultipleLoopTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MultipleLoopTests.cs index 44a5757f8..17e2495b6 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MultipleLoopTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MultipleLoopTests.cs @@ -62,9 +62,12 @@ public void ServerPipeListenForConnections() var writeRequest = new UvWriteReq(new KestrelTrace(new TestKestrelTrace())); writeRequest.Init(loop); + var data = new byte[] { 1, 2, 3, 4 }; + var pin = GCHandle.Alloc(data, GCHandleType.Pinned); + var block = MemoryPoolBlock2.Create( - new ArraySegment(new byte[] { 1, 2, 3, 4 }), - dataPtr: IntPtr.Zero, + new ArraySegment(data), + dataPtr: pin.AddrOfPinnedObject(), pool: null, slab: null); var start = new MemoryPoolIterator2(block, 0); @@ -79,7 +82,7 @@ public void ServerPipeListenForConnections() writeRequest.Dispose(); serverConnectionPipe.Dispose(); serverListenPipe.Dispose(); - block.Unpin(); + pin.Free(); }, null); @@ -163,11 +166,11 @@ public void ServerPipeDispatchConnections() serverConnectionPipeAcceptedEvent.WaitOne(); - var writeRequest = new UvWriteReq(new KestrelTrace(new TestKestrelTrace())); + var writeRequest = new UvWrite2Req(new KestrelTrace(new TestKestrelTrace())); writeRequest.Init(loop); writeRequest.Write2( serverConnectionPipe, - new ArraySegment>(new ArraySegment[] { new ArraySegment(new byte[] { 1, 2, 3, 4 }) }), + new ArraySegment(new byte[] { 1, 2, 3, 4 }), serverConnectionTcp, (_3, status2, error2, _4) => { diff --git a/test/Microsoft.AspNet.Server.KestrelTests/NetworkingTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/NetworkingTests.cs index edaa50870..84741387f 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/NetworkingTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/NetworkingTests.cs @@ -201,9 +201,11 @@ public async Task SocketCanReadAndWrite() { var req = new UvWriteReq(new KestrelTrace(new TestKestrelTrace())); req.Init(loop); + var blockData = new byte[] { 65, 66, 67, 68, 69 }; + var pin = GCHandle.Alloc(blockData, GCHandleType.Pinned); var block = MemoryPoolBlock2.Create( - new ArraySegment(new byte[] { 65, 66, 67, 68, 69 }), - dataPtr: IntPtr.Zero, + new ArraySegment(blockData), + dataPtr: pin.AddrOfPinnedObject(), pool: null, slab: null); var start = new MemoryPoolIterator2(block, 0); @@ -215,7 +217,7 @@ public async Task SocketCanReadAndWrite() 1, (_1, _2, _3, _4) => { - block.Unpin(); + pin.Free(); }, null); } diff --git a/test/Microsoft.AspNet.Server.KestrelTests/SocketOutputTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/SocketOutputTests.cs index bda6bfb65..cd30626c6 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/SocketOutputTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/SocketOutputTests.cs @@ -50,7 +50,7 @@ public void CanWrite1MB() var completedWh = new ManualResetEventSlim(); // Act - socketOutput.WriteAsync(buffer).ContinueWith( + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith( (t) => { Assert.Null(t.Exception); @@ -101,14 +101,14 @@ public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted( }; // Act - socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith(onCompleted); // Assert // The first write should pre-complete since it is <= _maxBytesPreCompleted. Assert.True(completedWh.Wait(1000)); // Arrange completedWh.Reset(); // Act - socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith(onCompleted); // Assert // Too many bytes are already pre-completed for the second write to pre-complete. Assert.False(completedWh.Wait(1000)); @@ -162,28 +162,28 @@ public void WritesDontCompleteImmediatelyWhenTooManyBytesIncludingNonImmediateAr }; // Act - socketOutput.WriteAsync(halfBuffer, false).ContinueWith(onCompleted); + socketOutput.WriteAsync(halfBuffer, immediate: false).ContinueWith(onCompleted); // Assert // The first write should pre-complete since it is not immediate. Assert.True(completedWh.Wait(1000)); // Arrange completedWh.Reset(); // Act - socketOutput.WriteAsync(halfBuffer).ContinueWith(onCompleted); + socketOutput.WriteAsync(halfBuffer, immediate: true).ContinueWith(onCompleted); // Assert // The second write should pre-complete since it is <= _maxBytesPreCompleted. Assert.True(completedWh.Wait(1000)); // Arrange completedWh.Reset(); // Act - socketOutput.WriteAsync(halfBuffer, false).ContinueWith(onCompleted); + socketOutput.WriteAsync(halfBuffer, immediate: false).ContinueWith(onCompleted); // Assert // The third write should pre-complete since it is not immediate, even though too many. Assert.True(completedWh.Wait(1000)); // Arrange completedWh.Reset(); // Act - socketOutput.WriteAsync(halfBuffer).ContinueWith(onCompleted); + socketOutput.WriteAsync(halfBuffer, immediate: true).ContinueWith(onCompleted); // Assert // Too many bytes are already pre-completed for the fourth write to pre-complete. Assert.False(completedWh.Wait(1000)); @@ -247,7 +247,7 @@ public void WritesDontGetCompletedTooQuickly() }; // Act (Pre-complete the maximum number of bytes in preparation for the rest of the test) - socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith(onCompleted); // Assert // The first write should pre-complete since it is <= _maxBytesPreCompleted. Assert.True(completedWh.Wait(1000)); @@ -257,8 +257,8 @@ public void WritesDontGetCompletedTooQuickly() onWriteWh.Reset(); // Act - socketOutput.WriteAsync(buffer).ContinueWith(onCompleted); - socketOutput.WriteAsync(buffer).ContinueWith(onCompleted2); + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith(onCompleted); + socketOutput.WriteAsync(buffer, immediate: true).ContinueWith(onCompleted2); Assert.True(onWriteWh.Wait(1000)); completeQueue.Dequeue()(0); @@ -308,11 +308,11 @@ public void ProducingStartAndProducingCompleteCanBeUsedDirectly() // block 1 var start = socketOutput.ProducingStart(); - start.Block.End = start.Block.Data.Offset + start.Block.Data.Count; + start.Block.End = start.Block.BlockEndOffset; // block 2 var block2 = memory.Lease(); - block2.End = block2.Data.Offset + block2.Data.Count; + block2.End = block2.BlockEndOffset; start.Block.Next = block2; var end = new MemoryPoolIterator2(block2, block2.End); @@ -320,7 +320,7 @@ public void ProducingStartAndProducingCompleteCanBeUsedDirectly() socketOutput.ProducingComplete(end); // A call to Write is required to ensure a write is scheduled - socketOutput.WriteAsync(default(ArraySegment)); + socketOutput.WriteAsync(default(ArraySegment), immediate: true); Assert.True(nBufferWh.Wait(1000)); Assert.Equal(2, nBuffers); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/TestConnection.cs b/test/Microsoft.AspNet.Server.KestrelTests/TestConnection.cs index e47c2fc31..474a355ce 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/TestConnection.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/TestConnection.cs @@ -55,6 +55,16 @@ public async Task Send(params string[] lines) _stream.Flush(); } + public async Task SendPipelined(params string[] lines) + { + var text = String.Join("\r\n", lines); + var writer = new StreamWriter(_stream, Encoding.ASCII); + await writer.WriteAsync(text); + writer.Flush(); + _stream.Flush(); + _socket.Shutdown(SocketShutdown.Send); + } + public async Task SendEnd(params string[] lines) { await Send(lines); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/TestInput.cs b/test/Microsoft.AspNet.Server.KestrelTests/TestInput.cs index 827d47ba8..36a3f7f8f 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/TestInput.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/TestInput.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Server.Kestrel; @@ -29,11 +30,9 @@ public TestInput() public void Add(string text, bool fin = false) { - var encoding = System.Text.Encoding.ASCII; - var count = encoding.GetByteCount(text); - var buffer = FrameContext.SocketInput.IncomingStart(text.Length); - count = encoding.GetBytes(text, 0, text.Length, buffer.Data.Array, buffer.Data.Offset); - FrameContext.SocketInput.IncomingComplete(count, null); + var data = Encoding.ASCII.GetBytes(text); + FrameContext.SocketInput.IncomingData(data, 0, data.Length); + if (fin) { FrameContext.SocketInput.RemoteIntakeFin = true; diff --git a/test/Microsoft.AspNet.Server.KestrelTests/UrlPathDecoder.cs b/test/Microsoft.AspNet.Server.KestrelTests/UrlPathDecoder.cs index 02769fd01..9f13f48cd 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/UrlPathDecoder.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/UrlPathDecoder.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Xunit; @@ -111,20 +112,28 @@ public void InvalidUTF8(string raw, string expect) [InlineData("%C2%B5%40%C3%9F%C3%B6%C3%A4%C3%BC%C3%A0%C3%A1", 44, "µ@ßöäüà%C3%A", 12)] public void DecodeWithBoundary(string raw, int rawLength, string expect, int expectLength) { - var begin = BuildSample(raw); - var end = GetIterator(begin, rawLength); + var store = raw.Select(c => (byte)c).ToArray(); + var handle = GCHandle.Alloc(store, GCHandleType.Pinned); + try + { + var begin = BuildSample(store, handle.AddrOfPinnedObject()); + var end = GetIterator(begin, rawLength); - var end2 = UrlPathDecoder.Unescape(begin, end); - var result = begin.GetUtf8String(end2); + var end2 = UrlPathDecoder.Unescape(begin, end); + var result = begin.GetUtf8String(end2); - Assert.Equal(expectLength, result.Length); - Assert.Equal(expect, result); + Assert.Equal(expectLength, result.Length); + Assert.Equal(expect, result); + } + finally + { + handle.Free(); + } } - private MemoryPoolIterator2 BuildSample(string data) + private MemoryPoolIterator2 BuildSample(byte[] store, IntPtr dataPtr) { - var store = data.Select(c => (byte)c).ToArray(); - var mem = MemoryPoolBlock2.Create(new ArraySegment(store), IntPtr.Zero, null, null); + var mem = MemoryPoolBlock2.Create(new ArraySegment(store), dataPtr, null, null); mem.End = store.Length; return mem.GetIterator(); @@ -143,30 +152,57 @@ private MemoryPoolIterator2 GetIterator(MemoryPoolIterator2 begin, int displacem private void PositiveAssert(string raw, string expect) { - var begin = BuildSample(raw); - var end = GetIterator(begin, raw.Length); + var store = raw.Select(c => (byte)c).ToArray(); + var handle = GCHandle.Alloc(store, GCHandleType.Pinned); + try + { + var begin = BuildSample(store, handle.AddrOfPinnedObject()); + var end = GetIterator(begin, raw.Length); - var result = UrlPathDecoder.Unescape(begin, end); - Assert.Equal(expect, begin.GetUtf8String(result)); + var result = UrlPathDecoder.Unescape(begin, end); + Assert.Equal(expect, begin.GetUtf8String(result)); + } + finally + { + handle.Free(); + } } private void PositiveAssert(string raw) { - var begin = BuildSample(raw); - var end = GetIterator(begin, raw.Length); + var store = raw.Select(c => (byte)c).ToArray(); + var handle = GCHandle.Alloc(store, GCHandleType.Pinned); + try + { + var begin = BuildSample(store, handle.AddrOfPinnedObject()); + var end = GetIterator(begin, raw.Length); - var result = UrlPathDecoder.Unescape(begin, end); - Assert.NotEqual(raw.Length, begin.GetUtf8String(result).Length); + var result = UrlPathDecoder.Unescape(begin, end); + Assert.NotEqual(raw.Length, begin.GetUtf8String(result).Length); + } + finally + { + handle.Free(); + } } private void NegativeAssert(string raw) { - var begin = BuildSample(raw); - var end = GetIterator(begin, raw.Length); + var store = raw.Select(c => (byte)c).ToArray(); + var handle = GCHandle.Alloc(store, GCHandleType.Pinned); + try + { + var begin = BuildSample(store, handle.AddrOfPinnedObject()); + var end = GetIterator(begin, raw.Length); - var resultEnd = UrlPathDecoder.Unescape(begin, end); - var result = begin.GetUtf8String(resultEnd); - Assert.Equal(raw, result); + var resultEnd = UrlPathDecoder.Unescape(begin, end); + var result = begin.GetUtf8String(resultEnd); + Assert.Equal(raw, result); + } + finally + { + handle.Free(); + } } } } diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/KnownHeaders.cs b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/KnownHeaders.cs index df3cef028..856a8b708 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/KnownHeaders.cs +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/KnownHeaders.cs @@ -15,73 +15,8 @@ static string Each(IEnumerable values, Func formatter) return values.Any() ? values.Select(formatter).Aggregate((a, b) => a + b) : ""; } - class KnownHeader + static string[] commonHeaders = new[] { - public string Name { get; set; } - public int Index { get; set; } - public string Identifier => Name.Replace("-", ""); - - public byte[] Bytes => Encoding.ASCII.GetBytes($"\r\n{Name}: "); - public int BytesOffset { get; set; } - public int BytesCount { get; set; } - public bool EnhancedSetter { get; set; } - public string TestBit() => $"((_bits & {1L << Index}L) != 0)"; - public string SetBit() => $"_bits |= {1L << Index}L"; - public string ClearBit() => $"_bits &= ~{1L << Index}L"; - public string EqualIgnoreCaseBytes() - { - var result = ""; - var delim = ""; - var index = 0; - while (index != Name.Length) - { - if (Name.Length - index >= 8) - { - result += delim + Term(Name, index, 8, "pUL", "uL"); - index += 8; - } - else if (Name.Length - index >= 4) - { - result += delim + Term(Name, index, 4, "pUI", "u"); - index += 4; - } - else if (Name.Length - index >= 2) - { - result += delim + Term(Name, index, 2, "pUS", "u"); - index += 2; - } - else - { - result += delim + Term(Name, index, 1, "pUB", "u"); - index += 1; - } - delim = " && "; - } - return $"({result})"; - } - protected string Term(string name, int offset, int count, string array, string suffix) - { - ulong mask = 0; - ulong comp = 0; - for (var scan = 0; scan < count; scan++) - { - var ch = (byte)name[offset + count - scan - 1]; - var isAlpha = (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); - comp = (comp << 8) + (ch & (isAlpha ? 0xdfu : 0xffu)); - mask = (mask << 8) + (isAlpha ? 0xdfu : 0xffu); - } - return $"(({array}[{offset / count}] & {mask}{suffix}) == {comp}{suffix})"; - } - } - public virtual void BeforeCompile(BeforeCompileContext context) - { - var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile()); - context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree); - } - public static string GeneratedFile() - { - var commonHeaders = new[] - { "Cache-Control", "Connection", "Date", @@ -103,8 +38,9 @@ public static string GeneratedFile() "Expires", "Last-Modified" }; - var requestHeaders = commonHeaders.Concat(new[] - { + + static KnownHeader[] requestHeaders = commonHeaders.Concat(new[] + { "Accept", "Accept-Charset", "Accept-Encoding", @@ -131,16 +67,25 @@ public static string GeneratedFile() Name = header, Index = index }).ToArray(); - var enhancedHeaders = new[] - { + + static string[] enhancedHeaders = new[] + { "Connection", "Server", "Date", "Transfer-Encoding", "Content-Length", }; - var responseHeaders = commonHeaders.Concat(new[] - { + + static string[] fastCheckHeaders = new[] + { + "Connection", + "Transfer-Encoding", + "Content-Length", + }; + + static KnownHeader[] responseHeaders = commonHeaders.Concat(new[] + { "Accept-Ranges", "Age", "ETag", @@ -155,14 +100,96 @@ public static string GeneratedFile() { Name = header, Index = index, - EnhancedSetter = enhancedHeaders.Contains(header) + EnhancedSetter = enhancedHeaders.Contains(header), + FastCheck = fastCheckHeaders.Contains(header) }).ToArray(); + + class KnownHeader + { + public string Name { get; set; } + public int Index { get; set; } + public string Identifier => Name.Replace("-", ""); + + public byte[] Bytes => Encoding.ASCII.GetBytes($"\r\n{Name}: "); + public int BytesOffset { get; set; } + public int BytesCount { get; set; } + public bool EnhancedSetter { get; set; } + public bool FastCheck { get; set; } + public string TestBit() => $"((_bits & {1L << Index}L) != 0)"; + public string SetBit() => $"_bits |= {1L << Index}L"; + public string ClearBit() => $"_bits &= ~{1L << Index}L"; + public string EqualIgnoreCaseBytes() + { + var result = ""; + var delim = ""; + var index = 0; + while (index != Name.Length) + { + if (Name.Length - index >= 8) + { + result += delim + Term(Name, index, 8, "pUL", "uL"); + index += 8; + } + else if (Name.Length - index >= 4) + { + result += delim + Term(Name, index, 4, "pUI", "u"); + index += 4; + } + else if (Name.Length - index >= 2) + { + result += delim + Term(Name, index, 2, "pUS", "u"); + index += 2; + } + else + { + result += delim + Term(Name, index, 1, "pUB", "u"); + index += 1; + } + delim = " && "; + } + return $"({result})"; + } + protected string Term(string name, int offset, int count, string array, string suffix) + { + ulong mask = 0; + ulong comp = 0; + for (var scan = 0; scan < count; scan++) + { + var ch = (byte)name[offset + count - scan - 1]; + var isAlpha = (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); + comp = (comp << 8) + (ch & (isAlpha ? 0xdfu : 0xffu)); + mask = (mask << 8) + (isAlpha ? 0xdfu : 0xffu); + } + return $"(({array}[{offset / count}] & {mask}{suffix}) == {comp}{suffix})"; + } + } + public virtual void BeforeCompile(BeforeCompileContext context) + { + var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile()); + context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree); + } + + public unsafe static int IntValue(string fourLowerChars) + { + var buffer = new byte[4]; + fixed (byte* ptr = buffer) + { + buffer[0] = (byte)fourLowerChars[0]; + buffer[1] = (byte)fourLowerChars[1]; + buffer[2] = (byte)fourLowerChars[2]; + buffer[3] = (byte)fourLowerChars[3]; + return *(int*)ptr; + } + } + + public static string GeneratedFile() + { var loops = new[] { new { Headers = requestHeaders, - HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length), + HeadersByLength = requestHeaders.OrderBy(x => x.Name.Length < 4 ? x.Name.Length + 19 : x.Name.Length).ThenByDescending(s => s.Name).GroupBy(x => x.Name.Length), ClassName = "FrameRequestHeaders", Bytes = default(byte[]) }, @@ -174,6 +201,7 @@ public static string GeneratedFile() Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray() } }; + foreach (var loop in loops.Where(l => l.Bytes != null)) { var offset = 0; @@ -187,7 +215,6 @@ public static string GeneratedFile() return $@" using System; using System.Collections.Generic; -using System.Text; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Primitives; @@ -208,6 +235,8 @@ public partial class {loop.ClassName} private StringValues _" + header.Identifier + ";")} {Each(loop.Headers.Where(header => header.EnhancedSetter), header => @" private byte[] _raw" + header.Identifier + ";")} + {Each(loop.Headers.Where(header => header.FastCheck), header => @" + public bool Has" + header.Identifier + $" => {header.TestBit()};")} {Each(loop.Headers, header => $@" public StringValues Header{header.Identifier} {{ @@ -379,27 +408,87 @@ protected override void CopyToFast(KeyValuePair[] array, i ")} ((ICollection>)MaybeUnknown)?.CopyTo(array, arrayIndex); }} +#if DOTNET5_4 || DNXCORE50 {(loop.ClassName == "FrameResponseHeaders" ? $@" - protected void CopyToFast(ref MemoryPoolIterator2 output) + protected unsafe void CopyToFast(ref MemoryPoolIterator2 output) {{ + fixed (byte* pHeaderBytes = _headerBytes) + {{ {Each(loop.Headers, header => $@" if ({header.TestBit()}) {{ {(header.EnhancedSetter == false ? "" : $@" if (_raw{header.Identifier} != null) {{ - output.CopyFrom(_raw{header.Identifier}, 0, _raw{header.Identifier}.Length); - }} else ")} - foreach(var value in _{header.Identifier}) + fixed (byte* pRaw{header.Identifier} = _raw{header.Identifier}) + {{ + output.CopyFrom(pRaw{header.Identifier}, _raw{header.Identifier}.Length); + }} + }} + else + {{")} + if (_{header.Identifier}.Count == 1) + {{ + var value = _{header.Identifier}[0]; + if (value != null) + {{ + output.CopyFrom(pHeaderBytes + {header.BytesOffset}, {header.BytesCount}); + output.CopyFromAscii(value); + }} + }} + else + {{ + foreach(var value in _{header.Identifier}) + {{ + if (value != null) + {{ + output.CopyFrom(pHeaderBytes + {header.BytesOffset}, {header.BytesCount}); + output.CopyFromAscii(value); + }} + }} + }}{(header.EnhancedSetter == false ? "" : @" + }")} + }} + ")} + }} + }}" : "")} +#else + {(loop.ClassName == "FrameResponseHeaders" ? $@" + protected void CopyToFast(ref MemoryPoolIterator2 output) + {{ + {Each(loop.Headers, header => $@" + if ({header.TestBit()}) + {{ {(header.EnhancedSetter == false ? "" : $@" + if (_raw{header.Identifier} != null) + {{ + output.CopyFrom(_raw{header.Identifier}, 0, _raw{header.Identifier}.Length); + }} + else + {{")} + if (_{header.Identifier}.Count == 1) {{ + var value = _{header.Identifier}[0]; if (value != null) {{ output.CopyFrom(_headerBytes, {header.BytesOffset}, {header.BytesCount}); output.CopyFromAscii(value); }} }} - }} - ")} + else + {{ + foreach(var value in _{header.Identifier}) + {{ + if (value != null) + {{ + output.CopyFrom(_headerBytes, {header.BytesOffset}, {header.BytesCount}); + output.CopyFromAscii(value); + }} + }} + }}{(header.EnhancedSetter == false ? "" : @" + }")} + }} + ")} }}" : "")} +#endif public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value) {{ fixed(byte* ptr = keyBytes) {{ var pUB = ptr + keyOffset; var pUL = (ulong*)pUB; var pUI = (uint*)pUB; var pUS = (ushort*)pUB; @@ -465,6 +554,66 @@ public bool MoveNext() ")}}} "; } + + public static string GeneratedMemoryPoolIterator2() + { + return $@" +using System; + +namespace Microsoft.AspNet.Server.Kestrel.Infrastructure +{{ + public partial struct MemoryPoolIterator2 + {{ + private const byte _colon = {(byte)':'}; +{Each(requestHeaders.Where(x => x.Name.Length >= 4).OrderBy(x => x.Name.Substring(0, 4)).ThenBy(x => x.Name.Length).GroupBy(x => x.Name.Substring(0, 4)), header => +$@" private const int _header{header.Key.Substring(0, 4).Replace('-', '_')} = {IntValue(header.Key.Substring(0, 4).ToLower())}; +")} + + public unsafe bool SeekCommonHeader() + {{ + if (BitConverter.IsLittleEndian != {BitConverter.IsLittleEndian.ToString().ToLower()}) + {{ + return false; + }} + + if (IsDefault) + {{ + return false; + }} + + var block = _block; + var index = _index; + var following = block.End - index; + + if (following < 4) + {{ + return false; + }} + + var currentPointer = block.Pointer + index; + var fourLowerChars = *(int*)(currentPointer) | 0x20202020; + + switch (fourLowerChars) + {{ +{Each(requestHeaders.Where(x => x.Name.Length >= 4).OrderBy(x => x.Name.Length).ThenByDescending(x => x.Name).GroupBy(x => x.Name.Substring(0, 4)), headers => +$@" case _header{headers.Key.Substring(0, 4).Replace('-', '_')}:{Each(headers.GroupBy(x => x.Name.Length), headersByLength => $@" + if (following >= {headersByLength.Key} && *(currentPointer + {headersByLength.Key}) == _colon) // {string.Join(", ", headersByLength.Select(header => header.Name))} + {{ + _index = index + {headersByLength.Key}; + return true; + }} +")} return false; +")} + default: + return false; + }} + + }} + }} +}} +"; + } + public virtual void AfterCompile(AfterCompileContext context) { } diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs index 3727772c0..6faa4a1a4 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs @@ -9,6 +9,7 @@ public int Main(string[] args) { var text0 = KnownHeaders.GeneratedFile(); var text1 = FrameFeatureCollection.GeneratedFile(); + var text2 = KnownHeaders.GeneratedMemoryPoolIterator2(); if (args.Length == 1) { @@ -32,6 +33,26 @@ public int Main(string[] args) File.WriteAllText(args[1], text1); } } + else if (args.Length == 3) + { + var existing0 = File.Exists(args[0]) ? File.ReadAllText(args[0]) : ""; + if (!string.Equals(text0, existing0)) + { + File.WriteAllText(args[0], text0); + } + + var existing1 = File.Exists(args[1]) ? File.ReadAllText(args[1]) : ""; + if (!string.Equals(text1, existing1)) + { + File.WriteAllText(args[1], text1); + } + + var existing2 = File.Exists(args[2]) ? File.ReadAllText(args[2]) : ""; + if (!string.Equals(text2, existing2)) + { + File.WriteAllText(args[2], text2); + } + } else { Console.WriteLine(text0); diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json index ede3a70f5..d4c900158 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json @@ -1,6 +1,8 @@ { "version": "1.0.0-*", + "compilationOptions": { "allowUnsafe": true }, + "dependencies": { "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*", "Microsoft.AspNet.Http.Features": "1.0.0-*",