diff options
Diffstat (limited to 'src/csharp')
-rw-r--r-- | src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs | 9 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs | 59 | ||||
-rw-r--r-- | src/csharp/ext/grpc_csharp_ext.c | 8 |
3 files changed, 68 insertions, 8 deletions
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs index b56bdbb23f..a8cb357181 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -61,12 +61,9 @@ namespace Grpc.Core.Internal try { - var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr), - Marshal.PtrToStringAnsi(methodNamePtr)); - // Don't await, we are in a native callback and need to return. - #pragma warning disable 4014 - GetMetadataAsync(context, callbackPtr, userDataPtr); - #pragma warning restore 4014 + var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr), Marshal.PtrToStringAnsi(methodNamePtr)); + // Make a guarantee that credentials_notify_from_plugin is invoked async to be compliant with c-core API. + ThreadPool.QueueUserWorkItem(async (stateInfo) => await GetMetadataAsync(context, callbackPtr, userDataPtr)); } catch (Exception e) { diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index e81157cf97..eba6276a1f 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -90,6 +90,54 @@ namespace Grpc.IntegrationTesting } [Test] + public async Task MetadataCredentials_Composed() + { + var first = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + // Attempt to exercise the case where async callback is inlineable/synchronously-runnable. + metadata.Add("first_authorization", "FIRST_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var second = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + metadata.Add("second_authorization", "SECOND_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var third = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + metadata.Add("third_authorization", "THIRD_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(), + CallCredentials.Compose(first, second, third)); + channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options); + var client = new TestService.TestServiceClient(channel); + var call = client.StreamingOutputCall(new StreamingOutputCallRequest { }); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.IsFalse(await call.ResponseStream.MoveNext()); + } + + [Test] + public async Task MetadataCredentials_ComposedPerCall() + { + channel = new Channel(Host, server.Ports.Single().BoundPort, TestCredentials.CreateSslCredentials(), options); + var client = new TestService.TestServiceClient(channel); + var first = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + metadata.Add("first_authorization", "FIRST_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var second = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + metadata.Add("second_authorization", "SECOND_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var third = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { + metadata.Add("third_authorization", "THIRD_SECRET_TOKEN"); + return TaskUtils.CompletedTask; + })); + var call = client.StreamingOutputCall(new StreamingOutputCallRequest{ }, + new CallOptions(credentials: CallCredentials.Compose(first, second, third))); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.IsFalse(await call.ResponseStream.MoveNext()); + } + + [Test] public void MetadataCredentials_InterceptorLeavesMetadataEmpty() { var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(), @@ -125,6 +173,17 @@ namespace Grpc.IntegrationTesting Assert.AreEqual("SECRET_TOKEN", authToken); return Task.FromResult(new SimpleResponse()); } + + public override async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context) + { + var first = context.RequestHeaders.First((entry) => entry.Key == "first_authorization").Value; + Assert.AreEqual("FIRST_SECRET_TOKEN", first); + var second = context.RequestHeaders.First((entry) => entry.Key == "second_authorization").Value; + Assert.AreEqual("SECOND_SECRET_TOKEN", second); + var third = context.RequestHeaders.First((entry) => entry.Key == "third_authorization").Value; + Assert.AreEqual("THIRD_SECRET_TOKEN", third); + await responseStream.WriteAsync(new StreamingOutputCallResponse()); + } } } } diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index aebce364c5..92291f9011 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -1023,13 +1023,17 @@ typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)( grpc_credentials_plugin_metadata_cb cb, void *user_data, int32_t is_destroy); -static void grpcsharp_get_metadata_handler( +static int grpcsharp_get_metadata_handler( void *state, grpc_auth_metadata_context context, - grpc_credentials_plugin_metadata_cb cb, void *user_data) { + grpc_credentials_plugin_metadata_cb cb, void *user_data, + grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], + size_t *num_creds_md, grpc_status_code *status, + const char **error_details) { grpcsharp_metadata_interceptor_func interceptor = (grpcsharp_metadata_interceptor_func)(intptr_t)state; interceptor(state, context.service_url, context.method_name, cb, user_data, 0); + return 0; /* Asynchronous return. */ } static void grpcsharp_metadata_credentials_destroy_handler(void *state) { |