MemoryPoolIterator byref structs
This commit is contained in:
parent
90c7be1fc0
commit
12e2f30577
|
|
@ -975,7 +975,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
|||
Log.IsEnabled(LogLevel.Information) ? start.GetAsciiStringEscaped(end, MaxInvalidRequestLineChars) : string.Empty);
|
||||
}
|
||||
|
||||
method = begin.GetAsciiString(scan);
|
||||
method = begin.GetAsciiString(ref scan);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
|
|
@ -1031,7 +1031,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
|||
RejectRequest(RequestRejectionReason.InvalidRequestLine,
|
||||
Log.IsEnabled(LogLevel.Information) ? start.GetAsciiStringEscaped(end, MaxInvalidRequestLineChars) : string.Empty);
|
||||
}
|
||||
queryString = begin.GetAsciiString(scan);
|
||||
queryString = begin.GetAsciiString(ref scan);
|
||||
}
|
||||
|
||||
var queryEnd = scan;
|
||||
|
|
@ -1081,16 +1081,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
|||
if (needDecode)
|
||||
{
|
||||
// Read raw target before mutating memory.
|
||||
rawTarget = pathBegin.GetAsciiString(queryEnd);
|
||||
rawTarget = pathBegin.GetAsciiString(ref queryEnd);
|
||||
|
||||
// URI was encoded, unescape and then parse as utf8
|
||||
pathEnd = UrlPathDecoder.Unescape(pathBegin, pathEnd);
|
||||
requestUrlPath = pathBegin.GetUtf8String(pathEnd);
|
||||
requestUrlPath = pathBegin.GetUtf8String(ref pathEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// URI wasn't encoded, parse as ASCII
|
||||
requestUrlPath = pathBegin.GetAsciiString(pathEnd);
|
||||
requestUrlPath = pathBegin.GetAsciiString(ref pathEnd);
|
||||
|
||||
if (queryString.Length == 0)
|
||||
{
|
||||
|
|
@ -1100,7 +1100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
|||
}
|
||||
else
|
||||
{
|
||||
rawTarget = pathBegin.GetAsciiString(queryEnd);
|
||||
rawTarget = pathBegin.GetAsciiString(ref queryEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1341,7 +1341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
|||
} while (ch != ByteCR);
|
||||
|
||||
var name = beginName.GetArraySegment(endName);
|
||||
var value = beginValue.GetAsciiString(endValue);
|
||||
var value = beginValue.GetAsciiString(ref endValue);
|
||||
|
||||
consumed = scan;
|
||||
requestHeaders.Append(name.Array, name.Offset, name.Count, value);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
||||
{
|
||||
|
|
@ -19,6 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
0x02ul << 40 |
|
||||
0x01ul << 48 ) + 1;
|
||||
|
||||
private static readonly Encoding _utf8 = Encoding.UTF8;
|
||||
private static readonly int _vectorSpan = Vector<byte>.Count;
|
||||
|
||||
private MemoryPoolBlock _block;
|
||||
|
|
@ -1026,6 +1029,164 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
_index = blockIndex;
|
||||
}
|
||||
|
||||
public unsafe string GetAsciiString(ref MemoryPoolIterator end)
|
||||
{
|
||||
if (IsDefault || end.IsDefault)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var length = GetLength(end);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var inputOffset = Index;
|
||||
var block = Block;
|
||||
|
||||
var asciiString = new string('\0', length);
|
||||
|
||||
fixed (char* outputStart = asciiString)
|
||||
{
|
||||
var output = outputStart;
|
||||
var remaining = length;
|
||||
|
||||
var endBlock = end.Block;
|
||||
var endIndex = end.Index;
|
||||
|
||||
var outputOffset = 0;
|
||||
while (true)
|
||||
{
|
||||
int following = (block != endBlock ? block.End : endIndex) - inputOffset;
|
||||
|
||||
if (following > 0)
|
||||
{
|
||||
if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following))
|
||||
{
|
||||
throw BadHttpRequestException.GetException(RequestRejectionReason.NonAsciiOrNullCharactersInInputString);
|
||||
}
|
||||
|
||||
outputOffset += following;
|
||||
remaining -= following;
|
||||
}
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
block = block.Next;
|
||||
inputOffset = block.Start;
|
||||
}
|
||||
}
|
||||
|
||||
return asciiString;
|
||||
}
|
||||
|
||||
public string GetUtf8String(ref MemoryPoolIterator end)
|
||||
{
|
||||
if (IsDefault || end.IsDefault)
|
||||
{
|
||||
return default(string);
|
||||
}
|
||||
if (end.Block == Block)
|
||||
{
|
||||
return _utf8.GetString(Block.Array, Index, end.Index - Index);
|
||||
}
|
||||
|
||||
var decoder = _utf8.GetDecoder();
|
||||
|
||||
var length = GetLength(end);
|
||||
var charLength = length;
|
||||
// Worse case is 1 byte = 1 char
|
||||
var chars = new char[charLength];
|
||||
var charIndex = 0;
|
||||
|
||||
var block = Block;
|
||||
var index = Index;
|
||||
var remaining = length;
|
||||
while (true)
|
||||
{
|
||||
int bytesUsed;
|
||||
int charsUsed;
|
||||
bool completed;
|
||||
var following = block.End - index;
|
||||
if (remaining <= following)
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
remaining,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
true,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
return new string(chars, 0, charIndex + charsUsed);
|
||||
}
|
||||
else if (block.Next == null)
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
following,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
true,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
return new string(chars, 0, charIndex + charsUsed);
|
||||
}
|
||||
else
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
following,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
false,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
charIndex += charsUsed;
|
||||
remaining -= following;
|
||||
block = block.Next;
|
||||
index = block.Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ArraySegment<byte> GetArraySegment(MemoryPoolIterator end)
|
||||
{
|
||||
if (IsDefault || end.IsDefault)
|
||||
{
|
||||
return default(ArraySegment<byte>);
|
||||
}
|
||||
if (end.Block == Block)
|
||||
{
|
||||
return new ArraySegment<byte>(Block.Array, Index, end.Index - Index);
|
||||
}
|
||||
|
||||
return GetArraySegmentMultiBlock(ref end);
|
||||
}
|
||||
|
||||
private ArraySegment<byte> GetArraySegmentMultiBlock(ref MemoryPoolIterator end)
|
||||
{
|
||||
var length = GetLength(end);
|
||||
var array = new byte[length];
|
||||
CopyTo(array, 0, length, out length);
|
||||
return new ArraySegment<byte>(array, 0, length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector<byte> GetVector(byte vectorByte)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||
|
|
@ -71,62 +72,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
}
|
||||
}
|
||||
|
||||
public unsafe static string GetAsciiString(this MemoryPoolIterator start, MemoryPoolIterator end)
|
||||
{
|
||||
if (start.IsDefault || end.IsDefault)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var length = start.GetLength(end);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var inputOffset = start.Index;
|
||||
var block = start.Block;
|
||||
|
||||
var asciiString = new string('\0', length);
|
||||
|
||||
fixed (char* outputStart = asciiString)
|
||||
{
|
||||
var output = outputStart;
|
||||
var remaining = length;
|
||||
|
||||
var endBlock = end.Block;
|
||||
var endIndex = end.Index;
|
||||
|
||||
var outputOffset = 0;
|
||||
while (true)
|
||||
{
|
||||
int following = (block != endBlock ? block.End : endIndex) - inputOffset;
|
||||
|
||||
if (following > 0)
|
||||
{
|
||||
if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following))
|
||||
{
|
||||
throw BadHttpRequestException.GetException(RequestRejectionReason.NonAsciiOrNullCharactersInInputString);
|
||||
}
|
||||
|
||||
outputOffset += following;
|
||||
remaining -= following;
|
||||
}
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
block = block.Next;
|
||||
inputOffset = block.Start;
|
||||
}
|
||||
}
|
||||
|
||||
return asciiString;
|
||||
}
|
||||
|
||||
public static string GetAsciiStringEscaped(this MemoryPoolIterator start, MemoryPoolIterator end, int maxChars)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
|
@ -147,102 +92,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetUtf8String(this MemoryPoolIterator start, MemoryPoolIterator end)
|
||||
{
|
||||
if (start.IsDefault || end.IsDefault)
|
||||
{
|
||||
return default(string);
|
||||
}
|
||||
if (end.Block == start.Block)
|
||||
{
|
||||
return _utf8.GetString(start.Block.Array, start.Index, end.Index - start.Index);
|
||||
}
|
||||
|
||||
var decoder = _utf8.GetDecoder();
|
||||
|
||||
var length = start.GetLength(end);
|
||||
var charLength = length;
|
||||
// Worse case is 1 byte = 1 char
|
||||
var chars = new char[charLength];
|
||||
var charIndex = 0;
|
||||
|
||||
var block = start.Block;
|
||||
var index = start.Index;
|
||||
var remaining = length;
|
||||
while (true)
|
||||
{
|
||||
int bytesUsed;
|
||||
int charsUsed;
|
||||
bool completed;
|
||||
var following = block.End - index;
|
||||
if (remaining <= following)
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
remaining,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
true,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
return new string(chars, 0, charIndex + charsUsed);
|
||||
}
|
||||
else if (block.Next == null)
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
following,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
true,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
return new string(chars, 0, charIndex + charsUsed);
|
||||
}
|
||||
else
|
||||
{
|
||||
decoder.Convert(
|
||||
block.Array,
|
||||
index,
|
||||
following,
|
||||
chars,
|
||||
charIndex,
|
||||
charLength - charIndex,
|
||||
false,
|
||||
out bytesUsed,
|
||||
out charsUsed,
|
||||
out completed);
|
||||
charIndex += charsUsed;
|
||||
remaining -= following;
|
||||
block = block.Next;
|
||||
index = block.Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ArraySegment<byte> GetArraySegment(this MemoryPoolIterator start, MemoryPoolIterator end)
|
||||
{
|
||||
if (start.IsDefault || end.IsDefault)
|
||||
{
|
||||
return default(ArraySegment<byte>);
|
||||
}
|
||||
if (end.Block == start.Block)
|
||||
{
|
||||
return new ArraySegment<byte>(start.Block.Array, start.Index, end.Index - start.Index);
|
||||
}
|
||||
|
||||
var length = start.GetLength(end);
|
||||
var array = new byte[length];
|
||||
start.CopyTo(array, 0, length, out length);
|
||||
return new ArraySegment<byte>(array, 0, length);
|
||||
}
|
||||
|
||||
public static ArraySegment<byte> PeekArraySegment(this MemoryPoolIterator iter)
|
||||
{
|
||||
if (iter.IsDefault || iter.IsEnd)
|
||||
|
|
@ -283,6 +132,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
/// <param name="begin">The iterator from which to start the known string lookup.</param>
|
||||
/// <param name="knownMethod">A reference to a pre-allocated known string, if the input matches any.</param>
|
||||
/// <returns><c>true</c> if the input matches a known string, <c>false</c> otherwise.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetKnownMethod(this MemoryPoolIterator begin, out string knownMethod)
|
||||
{
|
||||
knownMethod = null;
|
||||
|
|
@ -323,6 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
/// <param name="begin">The iterator from which to start the known string lookup.</param>
|
||||
/// <param name="knownVersion">A reference to a pre-allocated known string, if the input matches any.</param>
|
||||
/// <returns><c>true</c> if the input matches a known string, <c>false</c> otherwise.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetKnownVersion(this MemoryPoolIterator begin, out string knownVersion)
|
||||
{
|
||||
knownVersion = null;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var begin = mem.GetIterator();
|
||||
var end = GetIterator(begin, byteRange.Length);
|
||||
|
||||
var s = begin.GetAsciiString(end);
|
||||
var s = begin.GetAsciiString(ref end);
|
||||
|
||||
Assert.Equal(s.Length, byteRange.Length);
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var begin = mem.GetIterator();
|
||||
var end = GetIterator(begin, byteRange.Length);
|
||||
|
||||
Assert.Throws<BadHttpRequestException>(() => begin.GetAsciiString(end));
|
||||
Assert.Throws<BadHttpRequestException>(() => begin.GetAsciiString(ref end));
|
||||
|
||||
pool.Return(mem);
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var begin = mem0.GetIterator();
|
||||
var end = GetIterator(begin, expectedByteRange.Length);
|
||||
|
||||
var s = begin.GetAsciiString(end);
|
||||
var s = begin.GetAsciiString(ref end);
|
||||
|
||||
Assert.Equal(s.Length, expectedByteRange.Length);
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var begin = mem0.GetIterator();
|
||||
var end = GetIterator(begin, expectedByteRange.Length);
|
||||
|
||||
var s = begin.GetAsciiString(end);
|
||||
var s = begin.GetAsciiString(ref end);
|
||||
|
||||
Assert.Equal(expectedByteRange.Length, s.Length);
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var end = GetIterator(begin, rawLength);
|
||||
|
||||
var end2 = UrlPathDecoder.Unescape(begin, end);
|
||||
var result = begin.GetUtf8String(end2);
|
||||
var result = begin.GetUtf8String(ref end2);
|
||||
|
||||
Assert.Equal(expectLength, result.Length);
|
||||
Assert.Equal(expect, result);
|
||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var end = GetIterator(begin, raw.Length);
|
||||
|
||||
var result = UrlPathDecoder.Unescape(begin, end);
|
||||
Assert.Equal(expect, begin.GetUtf8String(result));
|
||||
Assert.Equal(expect, begin.GetUtf8String(ref result));
|
||||
}
|
||||
|
||||
private void PositiveAssert(MemoryPoolBlock mem, string raw)
|
||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var end = GetIterator(begin, raw.Length);
|
||||
|
||||
var result = UrlPathDecoder.Unescape(begin, end);
|
||||
Assert.NotEqual(raw.Length, begin.GetUtf8String(result).Length);
|
||||
Assert.NotEqual(raw.Length, begin.GetUtf8String(ref result).Length);
|
||||
}
|
||||
|
||||
private void NegativeAssert(MemoryPoolBlock mem, string raw)
|
||||
|
|
@ -219,7 +219,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
|||
var end = GetIterator(begin, raw.Length);
|
||||
|
||||
var resultEnd = UrlPathDecoder.Unescape(begin, end);
|
||||
var result = begin.GetUtf8String(resultEnd);
|
||||
var result = begin.GetUtf8String(ref resultEnd);
|
||||
Assert.Equal(raw, result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue