aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs9
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs59
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c8
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) {