1 #region Copyright notice and license 2 // Copyright 2019 The gRPC Authors 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 #endregion 16 17 using System; 18 using System.Runtime.CompilerServices; 19 20 namespace Grpc.Core.Internal 21 { 22 /// <summary> 23 /// Utility type for identifying "well-known" strings (i.e. headers/keys etc that 24 /// we expect to see frequently, and don't want to allocate lots of copies of) 25 /// </summary> 26 internal static class WellKnownStrings 27 { 28 [MethodImpl(MethodImplOptions.AggressiveInlining)] Coerce64(byte* value)29 private static unsafe ulong Coerce64(byte* value) 30 { 31 return *(ulong*)value; 32 } 33 [MethodImpl(MethodImplOptions.AggressiveInlining)] Coerce32(byte* value)34 private static unsafe uint Coerce32(byte* value) 35 { 36 return *(uint*)value; 37 } 38 [MethodImpl(MethodImplOptions.AggressiveInlining)] Coerce16(byte* value)39 private static unsafe ushort Coerce16(byte* value) 40 { 41 return *(ushort*)value; 42 } 43 44 45 /// <summary> 46 /// Test whether the provided byte sequence is recognized as a well-known string; if 47 /// so, return a shared instance of that string; otherwise, return null 48 /// </summary> 49 [MethodImpl(MethodImplOptions.AggressiveInlining)] TryIdentify(IntPtr source, int length)50 public static unsafe string TryIdentify(IntPtr source, int length) 51 { 52 return TryIdentify((byte*)source.ToPointer(), length); 53 } 54 55 /// <summary> 56 /// Test whether the provided byte sequence is recognized as a well-known string; if 57 /// so, return a shared instance of that string; otherwise, return null 58 /// </summary> TryIdentify(byte* source, int length)59 public static unsafe string TryIdentify(byte* source, int length) 60 { 61 // note: the logic here is hard-coded to constants for optimal processing; 62 // refer to an ASCII/hex converter (and remember to reverse **segments** for little-endian) 63 if (BitConverter.IsLittleEndian) // this is a JIT intrinsic; branch removal happens on modern runtimes 64 { 65 switch (length) 66 { 67 case 0: return ""; 68 case 10: 69 switch(Coerce64(source)) 70 { 71 case 0x6567612d72657375: return Coerce16(source + 8) == 0x746e ? "user-agent" : null; 72 } 73 break; 74 } 75 } 76 else 77 { 78 switch (length) 79 { 80 case 0: return ""; 81 case 10: 82 switch (Coerce64(source)) 83 { 84 case 0x757365722d616765: return Coerce16(source + 8) == 0x6e74 ? "user-agent" : null; 85 } 86 break; 87 } 88 } 89 return null; 90 } 91 } 92 } 93