mirror of https://github.com/grpc/grpc.git
parent
9967e42a7f
commit
3ab3f5e586
3 changed files with 112 additions and 33 deletions
@ -0,0 +1,46 @@ |
||||
using System.Text; |
||||
using Grpc.Core.Internal; |
||||
using NUnit.Framework; |
||||
|
||||
namespace Grpc.Core.Tests.Internal |
||||
{ |
||||
public class WellKnownStringsTest |
||||
{ |
||||
[Test] |
||||
[TestCase("", true)] |
||||
[TestCase("u", false)] |
||||
[TestCase("us", false)] |
||||
[TestCase("use", false)] |
||||
[TestCase("user", false)] |
||||
[TestCase("user-", false)] |
||||
[TestCase("user-a", false)] |
||||
[TestCase("user-ag", false)] |
||||
[TestCase("user-age", false)] |
||||
[TestCase("user-agent", true)] |
||||
[TestCase("user-agent ", false)] |
||||
[TestCase("useragent ", false)] |
||||
[TestCase("User-Agent", false)] |
||||
[TestCase("sdlkfjlskjfdlkjs;lfdksflsdfkh skjdfh sdkfhskdhf skjfhk sdhjkjh", false)] |
||||
|
||||
// test for endianness snafus (reversed in segments) |
||||
[TestCase("ega-resutn", false)] |
||||
public unsafe void TestWellKnownStrings(string input, bool expected) |
||||
{ |
||||
// create a copy of the data; no cheating! |
||||
byte[] bytes = Encoding.ASCII.GetBytes(input); |
||||
fixed(byte* ptr = bytes) |
||||
{ |
||||
string result = WellKnownStrings.TryIdentify(ptr, bytes.Length); |
||||
if (expected) Assert.AreEqual(input, result); |
||||
else Assert.IsNull(result); |
||||
|
||||
if (expected) |
||||
{ |
||||
// try again, and check we get the same instance |
||||
string again = WellKnownStrings.TryIdentify(ptr, bytes.Length); |
||||
Assert.AreSame(result, again); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,66 @@ |
||||
using System; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Text; |
||||
|
||||
namespace Grpc.Core.Internal |
||||
{ |
||||
/// <summary> |
||||
/// Utility type for identifying "well-known" strings (i.e. headers/keys etc that |
||||
/// we expect to see frequently, and don't want to allocate lots of copies of) |
||||
/// </summary> |
||||
internal static class WellKnownStrings |
||||
{ |
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
private static unsafe ulong Coerce64(byte* value) |
||||
{ |
||||
return *(ulong*)value; |
||||
} |
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
private static unsafe uint Coerce32(byte* value) |
||||
{ |
||||
return *(uint*)value; |
||||
} |
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
private static unsafe ushort Coerce16(byte* value) |
||||
{ |
||||
return *(ushort*)value; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test whether the provided byte sequence is recognized as a well-known string; if |
||||
/// so, return a shared instance of that string; otherwise, return null |
||||
/// </summary> |
||||
public static unsafe string TryIdentify(byte* source, int length) |
||||
{ |
||||
// note: the logic here is hard-coded to constants for optimal processing; |
||||
// refer to an ASCII/hex converter (and remember to reverse **segments** for little-endian) |
||||
if (BitConverter.IsLittleEndian) // this is a JIT intrinsic; branch removal happens on modern runtimes |
||||
{ |
||||
switch (length) |
||||
{ |
||||
case 0: return ""; |
||||
case 10: |
||||
switch(Coerce64(source)) |
||||
{ |
||||
case 0x6567612d72657375: return Coerce16(source + 8) == 0x746e ? "user-agent" : null; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
switch (length) |
||||
{ |
||||
case 0: return ""; |
||||
case 10: |
||||
switch (Coerce64(source)) |
||||
{ |
||||
case 0x757365722d616765: return Coerce16(source + 8) == 0x6e74 ? "user-agent" : null; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue