@ -15,8 +15,7 @@
# endregion
using System ;
using System.Runtime.InteropServices ;
using System.Threading.Tasks ;
using Grpc.Core.Profiling ;
using System.Text ;
namespace Grpc.Core.Internal
{
@ -51,7 +50,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Reads metadata from pointer to grpc_metadata_array
/// </summary>
public static Metadata ReadMetadataFromPtrUnsafe ( IntPtr metadataArray )
public static unsafe Metadata ReadMetadataFromPtrUnsafe ( IntPtr metadataArray )
{
if ( metadataArray = = IntPtr . Zero )
{
@ -66,16 +65,50 @@ namespace Grpc.Core.Internal
var index = new UIntPtr ( i ) ;
UIntPtr keyLen ;
IntPtr keyPtr = Native . grpcsharp_metadata_array_get_key ( metadataArray , index , out keyLen ) ;
string key = Marshal . PtrToStringAnsi ( keyPtr , ( int ) keyLen . ToUInt32 ( ) ) ;
int keyLen32 = checked ( ( int ) keyLen . ToUInt32 ( ) ) ;
string key = WellKnownStrings . TryIdentify ( ( byte * ) keyPtr . ToPointer ( ) , keyLen32 )
? ? Marshal . PtrToStringAnsi ( keyPtr , keyLen32 ) ;
UIntPtr valueLen ;
IntPtr valuePtr = Native . grpcsharp_metadata_array_get_value ( metadataArray , index , out valueLen ) ;
var bytes = new byte [ valueLen . ToUInt64 ( ) ] ;
Marshal . Copy ( valuePtr , bytes , 0 , bytes . Length ) ;
metadata . Add ( Metadata . Entry . CreateUnsafe ( key , bytes ) ) ;
int len32 = checked ( ( int ) valueLen . ToUInt64 ( ) ) ;
metadata . Add ( Metadata . Entry . CreateUnsafe ( key , ( byte * ) valuePtr . ToPointer ( ) , len32 ) ) ;
}
return metadata ;
}
private static class WellKnownStrings
{
// turn a string of ASCII-length 8 into a ulong using the CPUs current
// endianness; this allows us to do the same thing in TryIdentify,
// testing string prefixes (of length >= 8) in a single load/compare
private static unsafe ulong Thunk8 ( string value )
{
int byteCount = Encoding . ASCII . GetByteCount ( value ) ;
if ( byteCount ! = 8 ) throw new ArgumentException ( nameof ( value ) ) ;
ulong result = 0 ;
fixed ( char * cPtr = value )
{
Encoding . ASCII . GetBytes ( cPtr , value . Length , ( byte * ) & result , byteCount ) ;
}
return result ;
}
private static readonly ulong UserAgent = Thunk8 ( "user-age" ) ;
public static unsafe string TryIdentify ( byte * source , int length )
{
switch ( length )
{
case 1 0 :
// test the first 8 bytes via evilness
ulong first8 = * ( ulong * ) source ;
if ( first8 = = UserAgent & source [ 8 ] = = ( byte ) 'n' & source [ 9 ] = = ( byte ) 't' )
return "user-agent" ;
break ;
}
return null ;
}
}
internal IntPtr Handle
{
get