aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Auth/AuthInterceptors.cs24
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj1
-rw-r--r--src/csharp/Grpc.Auth/GrpcCredentials.cs93
-rw-r--r--src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs (renamed from src/csharp/Grpc.Core.Tests/ClientBaseTest.cs)25
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs73
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/FakeCredentials.cs (renamed from src/csharp/Grpc.IntegrationTesting/proto/empty.proto)52
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj4
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs2
-rw-r--r--src/csharp/Grpc.Core/CallCredentials.cs142
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs16
-rw-r--r--src/csharp/Grpc.Core/Channel.cs4
-rw-r--r--src/csharp/Grpc.Core/ChannelCredentials.cs238
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs31
-rw-r--r--src/csharp/Grpc.Core/Credentials.cs138
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj4
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec2
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs6
-rw-r--r--src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs113
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs2
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj49
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/packages.config11
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj49
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/packages.config11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Empty.cs5
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs97
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs7
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs446
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs97
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Test.cs37
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs188
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/messages.proto132
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/test.proto71
-rw-r--r--src/csharp/build_packages.bat4
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c66
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh2
44 files changed, 1766 insertions, 526 deletions
diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs
index c8ab4d9af6..fa92566775 100644
--- a/src/csharp/Grpc.Auth/AuthInterceptors.cs
+++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs
@@ -41,8 +41,8 @@ using Grpc.Core.Utils;
namespace Grpc.Auth
{
/// <summary>
- /// Factory methods to create authorization interceptors. Interceptors created can be registered with gRPC client classes (autogenerated client stubs that
- /// inherit from <see cref="Grpc.Core.ClientBase"/>).
+ /// Factory methods to create authorization interceptors.
+ /// <seealso cref="GrpcCredentials"/>
/// </summary>
public static class AuthInterceptors
{
@@ -50,31 +50,29 @@ namespace Grpc.Auth
private const string Schema = "Bearer";
/// <summary>
- /// Creates interceptor that will obtain access token from any credential type that implements
+ /// Creates an <see cref="AsyncAuthInterceptor"/> that will obtain access token from any credential type that implements
/// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
- /// <returns>The header interceptor.</returns>
- public static HeaderInterceptor FromCredential(ITokenAccess credential)
+ /// <returns>The interceptor.</returns>
+ public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
{
- return new HeaderInterceptor((method, authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
- // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
- var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
- .ConfigureAwait(false).GetAwaiter().GetResult();
+ var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false);
metadata.Add(CreateBearerTokenHeader(accessToken));
});
}
/// <summary>
- /// Creates OAuth2 interceptor that will use given access token as authorization.
+ /// Creates an <see cref="AsyncAuthInterceptor"/> that will use given access token as authorization.
/// </summary>
/// <param name="accessToken">OAuth2 access token.</param>
- /// <returns>The header interceptor.</returns>
- public static HeaderInterceptor FromAccessToken(string accessToken)
+ /// <returns>The interceptor.</returns>
+ public static AsyncAuthInterceptor FromAccessToken(string accessToken)
{
Preconditions.CheckNotNull(accessToken);
- return new HeaderInterceptor((method, authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
metadata.Add(CreateBearerTokenHeader(accessToken));
});
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 4fb087d4a3..80ab07d2ae 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -78,6 +78,7 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
+ <Compile Include="GrpcCredentials.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AuthInterceptors.cs" />
</ItemGroup>
diff --git a/src/csharp/Grpc.Auth/GrpcCredentials.cs b/src/csharp/Grpc.Auth/GrpcCredentials.cs
new file mode 100644
index 0000000000..d8b10804c6
--- /dev/null
+++ b/src/csharp/Grpc.Auth/GrpcCredentials.cs
@@ -0,0 +1,93 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading;
+
+using Google.Apis.Auth.OAuth2;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+ /// <summary>
+ /// Factory methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes.
+ /// </summary>
+ public static class GrpcCredentials
+ {
+ /// <summary>
+ /// Creates a <see cref="MetadataCredentials"/> instance that will obtain access tokens
+ /// from any credential that implements <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
+ /// </summary>
+ /// <param name="credential">The credential to use to obtain access tokens.</param>
+ /// <returns>The <c>MetadataCredentials</c> instance.</returns>
+ public static MetadataCredentials Create(ITokenAccess credential)
+ {
+ return new MetadataCredentials(AuthInterceptors.FromCredential(credential));
+ }
+
+ /// <summary>
+ /// Convenience method to create a <see cref="ChannelCredentials"/> instance from
+ /// <c>ITokenAccess</c> credential and <c>SslCredentials</c> instance.
+ /// </summary>
+ /// <param name="credential">The credential to use to obtain access tokens.</param>
+ /// <param name="sslCredentials">The <c>SslCredentials</c> instance.</param>
+ /// <returns>The channel credentials for access token based auth over a secure channel.</returns>
+ public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials)
+ {
+ return ChannelCredentials.Create(sslCredentials, Create(credential));
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="MetadataCredentials"/> that will use given access token to authenticate
+ /// with a gRPC service.
+ /// </summary>
+ /// <param name="accessToken">OAuth2 access token.</param>
+ /// /// <returns>The <c>MetadataCredentials</c> instance.</returns>
+ public static MetadataCredentials FromAccessToken(string accessToken)
+ {
+ return new MetadataCredentials(AuthInterceptors.FromAccessToken(accessToken));
+ }
+
+ /// <summary>
+ /// Converts a <c>ITokenAccess</c> object into a <see cref="MetadataCredentials"/> object supported
+ /// by gRPC.
+ /// </summary>
+ /// <param name="credential"></param>
+ /// <returns></returns>
+ public static MetadataCredentials ToGrpcCredentials(this ITokenAccess credential)
+ {
+ return GrpcCredentials.Create(credential);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
index 2dc10ebe97..451963229a 100644
--- a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
@@ -32,6 +32,10 @@
#endregion
using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@@ -39,24 +43,23 @@ using NUnit.Framework;
namespace Grpc.Core.Tests
{
- public class ClientBaseTest
+ public class CallCredentialsTest
{
[Test]
- public void GetAuthUriBase_Valid()
+ public void CallCredentials_ComposeAtLeastTwo()
{
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/"));
+ Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials()));
}
[Test]
- public void GetAuthUriBase_Invalid()
+ public void CallCredentials_ToNativeCredentials()
{
- Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:"));
- Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/"));
- Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443")); // just two slashes
- Assert.IsNull(ClientBase.GetAuthUriBase(""));
+ var composite = CallCredentials.Compose(
+ new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }),
+ new MetadataCredentials(async (uri, m) => { await Task.Delay(2); }));
+ using (var nativeComposite = composite.ToNativeCredentials())
+ {
+ }
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
new file mode 100644
index 0000000000..489bf38575
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
@@ -0,0 +1,73 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class ChannelCredentialsTest
+ {
+ [Test]
+ public void InsecureCredentials_IsNonComposable()
+ {
+ Assert.IsFalse(ChannelCredentials.Insecure.IsComposable);
+ }
+
+ [Test]
+ public void ChannelCredentials_CreateComposite()
+ {
+ var composite = ChannelCredentials.Create(new FakeChannelCredentials(true), new FakeCallCredentials());
+ Assert.IsFalse(composite.IsComposable);
+
+ Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
+ Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
+
+ // forbid composing non-composable
+ Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
+ }
+
+ [Test]
+ public void ChannelCredentials_CreateWrapped()
+ {
+ ChannelCredentials.Create(new FakeCallCredentials());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index dfbd92879e..f4ae9abefd 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -44,13 +44,13 @@ namespace Grpc.Core.Tests
[Test]
public void Constructor_RejectsInvalidParams()
{
- Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
+ Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, ChannelCredentials.Insecure));
}
[Test]
public void State_IdleAfterCreation()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.AreEqual(ChannelState.Idle, channel.State);
channel.ShutdownAsync().Wait();
}
@@ -58,7 +58,7 @@ namespace Grpc.Core.Tests
[Test]
public void WaitForStateChangedAsync_InvalidArgument()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
channel.ShutdownAsync().Wait();
}
@@ -66,7 +66,7 @@ namespace Grpc.Core.Tests
[Test]
public void ResolvedTarget()
{
- var channel = new Channel("127.0.0.1", Credentials.Insecure);
+ var channel = new Channel("127.0.0.1", ChannelCredentials.Insecure);
Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1"));
channel.ShutdownAsync().Wait();
}
@@ -74,7 +74,7 @@ namespace Grpc.Core.Tests
[Test]
public void Shutdown_AllowedOnlyOnce()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
channel.ShutdownAsync().Wait();
Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult());
}
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
index 6d0eb937d6..87d55cd276 100644
--- a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -1,3 +1,4 @@
+#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
@@ -28,16 +29,45 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-syntax = "proto3";
+#endregion
-package grpc.testing;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
-// An empty message that you can re-use to avoid defining duplicated empty
-// messages in your project. A typical example is to use it as argument or the
-// return value of a service API. For instance:
-//
-// service Foo {
-// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
-// };
-//
-message Empty {}
+namespace Grpc.Core.Tests
+{
+ internal class FakeChannelCredentials : ChannelCredentials
+ {
+ readonly bool composable;
+
+ public FakeChannelCredentials(bool composable)
+ {
+ this.composable = composable;
+ }
+
+ internal override bool IsComposable
+ {
+ get { return composable; }
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
+
+ internal class FakeCallCredentials : CallCredentials
+ {
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index f730936062..91d072abab 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -63,8 +63,10 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
- <Compile Include="ClientBaseTest.cs" />
+ <Compile Include="CallCredentialsTest.cs" />
+ <Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
+ <Compile Include="ChannelCredentialsTest.cs" />
<Compile Include="ShutdownTest.cs" />
<Compile Include="Internal\AsyncCallTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 685c5f7d6c..246072bff1 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests
[SetUp]
public void Init()
{
- channel = new Channel("localhost", Credentials.Insecure);
+ channel = new Channel("localhost", ChannelCredentials.Insecure);
fakeCall = new FakeNativeCall();
diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
index 83707e0c6d..37fb36946a 100644
--- a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
@@ -119,7 +119,7 @@ namespace Grpc.Core.Tests
[Test]
public void RequestParsingError_UnaryRequest()
{
- helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
{
return Task.FromResult("RESPONSE");
});
@@ -161,7 +161,7 @@ namespace Grpc.Core.Tests
{
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
- CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync());
+ CollectionAssert.AreEqual(new[] { "A", "B" }, await requestStream.ToListAsync());
return "RESPONSE";
});
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 765732c768..567e04eddc 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -154,7 +154,7 @@ namespace Grpc.Core.Tests
{
if (channel == null)
{
- channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure);
}
return channel;
}
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
new file mode 100644
index 0000000000..809c9f412d
--- /dev/null
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -0,0 +1,142 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Client-side call credentials. Provide authorization with per-call granularity.
+ /// </summary>
+ public abstract class CallCredentials
+ {
+ /// <summary>
+ /// Composes multiple multiple <c>CallCredentials</c> objects into
+ /// a single <c>CallCredentials</c> object.
+ /// </summary>
+ /// <param name="credentials">credentials to compose</param>
+ /// <returns>The new <c>CompositeCallCredentials</c></returns>
+ public static CallCredentials Compose(params CallCredentials[] credentials)
+ {
+ return new CompositeCallCredentials(credentials);
+ }
+
+ /// <summary>
+ /// Creates native object for the credentials.
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal abstract CredentialsSafeHandle ToNativeCredentials();
+ }
+
+ /// <summary>
+ /// Asynchronous authentication interceptor for <see cref="MetadataCredentials"/>.
+ /// </summary>
+ /// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
+ /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
+ /// <returns></returns>
+ public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
+
+ /// <summary>
+ /// Client-side credentials that delegate metadata based auth to an interceptor.
+ /// The interceptor is automatically invoked for each remote call that uses <c>MetadataCredentials.</c>
+ /// </summary>
+ public class MetadataCredentials : CallCredentials
+ {
+ readonly AsyncAuthInterceptor interceptor;
+
+ /// <summary>
+ /// Initializes a new instance of <c>MetadataCredentials</c> class.
+ /// </summary>
+ /// <param name="interceptor">authentication interceptor</param>
+ public MetadataCredentials(AsyncAuthInterceptor interceptor)
+ {
+ this.interceptor = interceptor;
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
+ return plugin.Credentials;
+ }
+ }
+
+ /// <summary>
+ /// Credentials that allow composing multiple credentials objects into one <see cref="CallCredentials"/> object.
+ /// </summary>
+ internal sealed class CompositeCallCredentials : CallCredentials
+ {
+ readonly List<CallCredentials> credentials;
+
+ /// <summary>
+ /// Initializes a new instance of <c>CompositeCallCredentials</c> class.
+ /// The resulting credentials object will be composite of all the credentials specified as parameters.
+ /// </summary>
+ /// <param name="credentials">credentials to compose</param>
+ public CompositeCallCredentials(params CallCredentials[] credentials)
+ {
+ Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
+ this.credentials = new List<CallCredentials>(credentials);
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return ToNativeRecursive(0);
+ }
+
+ // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier.
+ // In practice, we won't usually see composites from more than two credentials anyway.
+ private CredentialsSafeHandle ToNativeRecursive(int startIndex)
+ {
+ if (startIndex == credentials.Count - 1)
+ {
+ return credentials[startIndex].ToNativeCredentials();
+ }
+
+ using (var cred1 = credentials[startIndex].ToNativeCredentials())
+ using (var cred2 = ToNativeRecursive(startIndex + 1))
+ {
+ var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+ if (nativeComposite.IsInvalid)
+ {
+ throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
+ }
+ return nativeComposite;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index c3bc9c3156..c0f94c63c2 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -49,6 +49,7 @@ namespace Grpc.Core
CancellationToken cancellationToken;
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
+ CallCredentials credentials;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@@ -58,14 +59,16 @@ namespace Grpc.Core
/// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
/// <param name="writeOptions">Write options that will be used for this call.</param>
/// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
+ /// <param name="credentials">Credentials to use for this call.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
- WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null)
+ WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null)
{
this.headers = headers;
this.deadline = deadline;
this.cancellationToken = cancellationToken;
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
+ this.credentials = credentials;
}
/// <summary>
@@ -115,6 +118,17 @@ namespace Grpc.Core
}
/// <summary>
+ /// Credentials to use for this call.
+ /// </summary>
+ public CallCredentials Credentials
+ {
+ get
+ {
+ return this.credentials;
+ }
+ }
+
+ /// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index f1942727cd..6b99055d4c 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -68,7 +68,7 @@ namespace Grpc.Core
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null)
+ public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
{
this.target = Preconditions.CheckNotNull(target, "target");
this.environment = GrpcEnvironment.AddRef();
@@ -96,7 +96,7 @@ namespace Grpc.Core
/// <param name="port">The port.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
+ public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
new file mode 100644
index 0000000000..599674e02b
--- /dev/null
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -0,0 +1,238 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Client-side channel credentials. Used for creation of a secure channel.
+ /// </summary>
+ public abstract class ChannelCredentials
+ {
+ static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
+
+ /// <summary>
+ /// Returns instance of credentials that provides no security and
+ /// will result in creating an unsecure channel with no encryption whatsoever.
+ /// </summary>
+ public static ChannelCredentials Insecure
+ {
+ get
+ {
+ return InsecureInstance;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new instance of <c>ChannelCredentials</c> class by composing
+ /// given channel credentials with call credentials.
+ /// </summary>
+ /// <param name="channelCredentials">Channel credentials.</param>
+ /// <param name="callCredentials">Call credentials.</param>
+ /// <returns>The new composite <c>ChannelCredentials</c></returns>
+ public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials)
+ {
+ return new CompositeChannelCredentials(channelCredentials, callCredentials);
+ }
+
+ /// <summary>
+ /// Creates a new instance of <c>ChannelCredentials</c> by wrapping
+ /// an instance of <c>CallCredentials</c>.
+ /// </summary>
+ /// <param name="callCredentials">Call credentials.</param>
+ /// <returns>The <c>ChannelCredentials</c> wrapping given call credentials.</returns>
+ public static ChannelCredentials Create(CallCredentials callCredentials)
+ {
+ return new WrappedCallCredentials(callCredentials);
+ }
+
+ /// <summary>
+ /// Creates native object for the credentials. May return null if insecure channel
+ /// should be created.
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal abstract CredentialsSafeHandle ToNativeCredentials();
+
+ /// <summary>
+ /// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
+ /// </summary>
+ internal virtual bool IsComposable
+ {
+ get { return false; }
+ }
+
+ private sealed class InsecureCredentialsImpl : ChannelCredentials
+ {
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Client-side SSL credentials.
+ /// </summary>
+ public sealed class SslCredentials : ChannelCredentials
+ {
+ readonly string rootCertificates;
+ readonly KeyCertificatePair keyCertificatePair;
+
+ /// <summary>
+ /// Creates client-side SSL credentials loaded from
+ /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
+ /// If that fails, gets the roots certificates from a well known place on disk.
+ /// </summary>
+ public SslCredentials() : this(null, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates client-side SSL credentials from
+ /// a string containing PEM encoded root certificates.
+ /// </summary>
+ public SslCredentials(string rootCertificates) : this(rootCertificates, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates client-side SSL credentials.
+ /// </summary>
+ /// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
+ /// <param name="keyCertificatePair">a key certificate pair.</param>
+ public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
+ {
+ this.rootCertificates = rootCertificates;
+ this.keyCertificatePair = keyCertificatePair;
+ }
+
+ /// <summary>
+ /// PEM encoding of the server root certificates.
+ /// </summary>
+ public string RootCertificates
+ {
+ get
+ {
+ return this.rootCertificates;
+ }
+ }
+
+ /// <summary>
+ /// Client side key and certificate pair.
+ /// If null, client will not use key and certificate pair.
+ /// </summary>
+ public KeyCertificatePair KeyCertificatePair
+ {
+ get
+ {
+ return this.keyCertificatePair;
+ }
+ }
+
+ // Composing composite makes no sense.
+ internal override bool IsComposable
+ {
+ get { return true; }
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
+ }
+ }
+
+ /// <summary>
+ /// Credentials that allow composing one <see cref="ChannelCredentials"/> object and
+ /// one or more <see cref="CallCredentials"/> objects into a single <see cref="ChannelCredentials"/>.
+ /// </summary>
+ internal sealed class CompositeChannelCredentials : ChannelCredentials
+ {
+ readonly ChannelCredentials channelCredentials;
+ readonly CallCredentials callCredentials;
+
+ /// <summary>
+ /// Initializes a new instance of <c>CompositeChannelCredentials</c> class.
+ /// The resulting credentials object will be composite of all the credentials specified as parameters.
+ /// </summary>
+ /// <param name="channelCredentials">channelCredentials to compose</param>
+ /// <param name="callCredentials">channelCredentials to compose</param>
+ public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials)
+ {
+ this.channelCredentials = Preconditions.CheckNotNull(channelCredentials);
+ this.callCredentials = Preconditions.CheckNotNull(callCredentials);
+ Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ using (var cred1 = channelCredentials.ToNativeCredentials())
+ using (var cred2 = callCredentials.ToNativeCredentials())
+ {
+ var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+ if (nativeComposite.IsInvalid)
+ {
+ throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
+ }
+ return nativeComposite;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Credentials wrapping <see cref="CallCredentials"/> as <see cref="ChannelCredentials"/>.
+ /// </summary>
+ internal sealed class WrappedCallCredentials : ChannelCredentials
+ {
+ readonly CallCredentials callCredentials;
+
+ /// <summary>
+ /// Wraps instance of <c>CallCredentials</c> as <c>ChannelCredentials</c>.
+ /// </summary>
+ /// <param name="callCredentials">credentials to wrap</param>
+ public WrappedCallCredentials(CallCredentials callCredentials)
+ {
+ this.callCredentials = Preconditions.CheckNotNull(callCredentials);
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return callCredentials.ToNativeCredentials();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f4533e735c..e5b398062b 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -40,18 +40,17 @@ namespace Grpc.Core
/// <summary>
/// Interceptor for call headers.
/// </summary>
- public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
+ /// <remarks>Header interceptor is no longer to recommented way to perform authentication.
+ /// For header (initial metadata) based auth such as OAuth2 or JWT access token, use <see cref="MetadataCredentials"/>.
+ /// </remarks>
+ public delegate void HeaderInterceptor(IMethod method, Metadata metadata);
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
- // Regex for removal of the optional DNS scheme, trailing port, and trailing backslash
- static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$");
-
readonly Channel channel;
- readonly string authUriBase;
/// <summary>
/// Initializes a new instance of <c>ClientBase</c> class.
@@ -60,13 +59,14 @@ namespace Grpc.Core
public ClientBase(Channel channel)
{
this.channel = channel;
- this.authUriBase = GetAuthUriBase(channel.Target);
}
/// <summary>
- /// Can be used to register a custom header (request metadata) interceptor.
+ /// Can be used to register a custom header interceptor.
/// The interceptor is invoked each time a new call on this client is started.
+ /// It is not recommented to use header interceptor to add auth headers to RPC calls.
/// </summary>
+ /// <seealso cref="HeaderInterceptor"/>
public HeaderInterceptor HeaderInterceptor
{
get;
@@ -115,24 +115,9 @@ namespace Grpc.Core
{
options = options.WithHeaders(new Metadata());
}
- var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
- interceptor(method, authUri, options.Headers);
+ interceptor(method, options.Headers);
}
return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
-
- /// <summary>
- /// Creates Auth URI base from channel's target (the one passed at channel creation).
- /// Fully-qualified service name is to be appended to this.
- /// </summary>
- internal static string GetAuthUriBase(string target)
- {
- var match = ChannelTargetPattern.Match(target);
- if (!match.Success)
- {
- return null;
- }
- return "https://" + match.Groups[2].Value + "/";
- }
}
}
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs
deleted file mode 100644
index 4fcac0c4c0..0000000000
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ /dev/null
@@ -1,138 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#endregion
-
-using System;
-using Grpc.Core.Internal;
-
-namespace Grpc.Core
-{
- /// <summary>
- /// Client-side credentials. Used for creation of a secure channel.
- /// </summary>
- public abstract class Credentials
- {
- static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
-
- /// <summary>
- /// Returns instance of credential that provides no security and
- /// will result in creating an unsecure channel with no encryption whatsoever.
- /// </summary>
- public static Credentials Insecure
- {
- get
- {
- return InsecureInstance;
- }
- }
-
- /// <summary>
- /// Creates native object for the credentials. May return null if insecure channel
- /// should be created.
- /// </summary>
- /// <returns>The native credentials.</returns>
- internal abstract CredentialsSafeHandle ToNativeCredentials();
-
- private sealed class InsecureCredentialsImpl : Credentials
- {
- internal override CredentialsSafeHandle ToNativeCredentials()
- {
- return null;
- }
- }
- }
-
- /// <summary>
- /// Client-side SSL credentials.
- /// </summary>
- public sealed class SslCredentials : Credentials
- {
- readonly string rootCertificates;
- readonly KeyCertificatePair keyCertificatePair;
-
- /// <summary>
- /// Creates client-side SSL credentials loaded from
- /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
- /// If that fails, gets the roots certificates from a well known place on disk.
- /// </summary>
- public SslCredentials() : this(null, null)
- {
- }
-
- /// <summary>
- /// Creates client-side SSL credentials from
- /// a string containing PEM encoded root certificates.
- /// </summary>
- public SslCredentials(string rootCertificates) : this(rootCertificates, null)
- {
- }
-
- /// <summary>
- /// Creates client-side SSL credentials.
- /// </summary>
- /// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
- /// <param name="keyCertificatePair">a key certificate pair.</param>
- public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
- {
- this.rootCertificates = rootCertificates;
- this.keyCertificatePair = keyCertificatePair;
- }
-
- /// <summary>
- /// PEM encoding of the server root certificates.
- /// </summary>
- public string RootCertificates
- {
- get
- {
- return this.rootCertificates;
- }
- }
-
- /// <summary>
- /// Client side key and certificate pair.
- /// If null, client will not use key and certificate pair.
- /// </summary>
- public KeyCertificatePair KeyCertificatePair
- {
- get
- {
- return this.keyCertificatePair;
- }
- }
-
- internal override CredentialsSafeHandle ToNativeCredentials()
- {
- return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
- }
- }
-}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index ad2af17bc7..92d4e19eac 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -48,7 +48,9 @@
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" />
+ <Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" />
+ <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
<Compile Include="Internal\INativeCall.cs" />
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
@@ -79,7 +81,7 @@
<Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" />
- <Compile Include="Credentials.cs" />
+ <Compile Include="ChannelCredentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
<Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 06de55c8c3..67a04afc22 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -16,7 +16,7 @@
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Ix-Async" version="1.2.3" />
- <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
+ <dependency id="grpc.native.csharp" version="$GrpcNativeCsharpVersion$" />
</dependencies>
</metadata>
<files>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index e3b00781c6..800462c854 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -344,9 +344,13 @@ namespace Grpc.Core.Internal
var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
- return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
- parentCall, ContextPropagationToken.DefaultMask, cq,
- details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value));
+ var credentials = details.Options.Credentials;
+ using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
+ {
+ return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
+ parentCall, ContextPropagationToken.DefaultMask, cq,
+ details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
+ }
}
// Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index c3611a7761..0be7a4dd3a 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -99,6 +99,9 @@ namespace Grpc.Core.Internal
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
[DllImport("grpc_csharp_ext.dll")]
@@ -113,6 +116,11 @@ namespace Grpc.Core.Internal
this.completionRegistry = completionRegistry;
}
+ public void SetCredentials(CredentialsSafeHandle credentials)
+ {
+ grpcsharp_call_set_credentials(this, credentials).CheckOk();
+ }
+
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
{
var ctx = BatchContextSafeHandle.Create();
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 7a1c6e3dac..d270d77526 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -82,9 +82,13 @@ namespace Grpc.Core.Internal
return grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
- public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+ public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials)
{
var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline);
+ if (credentials != null)
+ {
+ result.SetCredentials(credentials);
+ }
result.SetCompletionRegistry(registry);
return result;
}
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
index feed335362..bab45108e0 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
@@ -44,6 +44,9 @@ namespace Grpc.Core.Internal
static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_credentials_release(IntPtr credentials);
private CredentialsSafeHandle()
@@ -69,6 +72,11 @@ namespace Grpc.Core.Internal
}
}
+ public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2)
+ {
+ return grpcsharp_composite_credentials_create(creds1, creds2);
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_credentials_release(handle);
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
new file mode 100644
index 0000000000..f76492cba4
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
+
+ internal class NativeMetadataCredentialsPlugin
+ {
+ const string GetMetadataExceptionMsg = "Exception occured in metadata credentials plugin.";
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
+
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
+
+ AsyncAuthInterceptor interceptor;
+ GCHandle gcHandle;
+ NativeMetadataInterceptor nativeInterceptor;
+ CredentialsSafeHandle credentials;
+
+ public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
+ {
+ this.interceptor = Preconditions.CheckNotNull(interceptor, "interceptor");
+ this.nativeInterceptor = NativeMetadataInterceptorHandler;
+
+ // Make sure the callback doesn't get garbage collected until it is destroyed.
+ this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal);
+ this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
+ }
+
+ public CredentialsSafeHandle Credentials
+ {
+ get { return credentials; }
+ }
+
+ private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
+ {
+ if (isDestroy)
+ {
+ gcHandle.Free();
+ return;
+ }
+
+ try
+ {
+ string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr);
+ StartGetMetadata(serviceUrl, callbackPtr, userDataPtr);
+ }
+ catch (Exception e)
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
+ Logger.Error(e, GetMetadataExceptionMsg);
+ }
+ }
+
+ private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr)
+ {
+ try
+ {
+ var metadata = new Metadata();
+ await interceptor(serviceUrl, metadata);
+
+ using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null);
+ }
+ }
+ catch (Exception e)
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
+ Logger.Error(e, GetMetadataExceptionMsg);
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index 01e4a80bab..64e429ed5a 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,7 +39,7 @@ namespace Math
{
public static void Main(string[] args)
{
- var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure);
+ var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure);
Math.IMathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index e2975b5da9..290d42808e 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -61,7 +61,7 @@ namespace Math.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
- channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Math.NewClient(channel);
}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index 6c3a53bec0..d90f21c2e1 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -63,7 +63,7 @@ namespace Grpc.HealthCheck.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
- channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 2c38c9645c..8bc2082a1d 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>6d22e68f</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+ <None Include="packages.config" />
</ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/packages.config b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
new file mode 100644
index 0000000000..7a02c95db9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 949ad61375..1eadbeb920 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>d9ee8e52</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+ <None Include="packages.config" />
</ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/packages.config b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
new file mode 100644
index 0000000000..7a02c95db9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs
index 28c28c9afd..9bf2b8f7cf 100644
--- a/src/csharp/Grpc.IntegrationTesting/Empty.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: empty.proto
+// source: test/proto/empty.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -23,7 +23,8 @@ namespace Grpc.Testing {
static Empty() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM="));
+ "ChZ0ZXN0L3Byb3RvL2VtcHR5LnByb3RvEgxncnBjLnRlc3RpbmciBwoFRW1w",
+ "dHliBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index a0bcf431f7..2b75305731 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -96,6 +96,7 @@
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
<Compile Include="InteropClientServerTest.cs" />
+ <Compile Include="MetadataCredentialsTest.cs" />
<Compile Include="TestServiceImpl.cs" />
<Compile Include="InteropServer.cs" />
<Compile Include="InteropClient.cs" />
@@ -118,9 +119,6 @@
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
- <None Include="proto\test.proto" />
- <None Include="proto\empty.proto" />
- <None Include="proto\messages.proto" />
<None Include="data\README">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 504d798b89..cb50b44841 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -33,20 +33,21 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using CommandLine;
+using CommandLine.Text;
using Google.Apis.Auth.OAuth2;
using Google.Protobuf;
using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
+using Newtonsoft.Json.Linq;
using NUnit.Framework;
-using CommandLine.Text;
-using System.IO;
namespace Grpc.IntegrationTesting
{
@@ -66,11 +67,13 @@ namespace Grpc.IntegrationTesting
[Option("test_case", DefaultValue = "large_unary")]
public string TestCase { get; set; }
- [Option("use_tls")]
- public bool UseTls { get; set; }
+ // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
+ [Option("use_tls", DefaultValue = false)]
+ public bool? UseTls { get; set; }
- [Option("use_test_ca")]
- public bool UseTestCa { get; set; }
+ // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca)
+ [Option("use_test_ca", DefaultValue = false)]
+ public bool? UseTestCa { get; set; }
[Option("default_service_account", Required = false)]
public string DefaultServiceAccount { get; set; }
@@ -116,7 +119,7 @@ namespace Grpc.IntegrationTesting
private async Task Run()
{
- var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure;
+ var credentials = await CreateCredentialsAsync();
List<ChannelOption> channelOptions = null;
if (!string.IsNullOrEmpty(options.ServerHostOverride))
@@ -132,6 +135,26 @@ namespace Grpc.IntegrationTesting
await channel.ShutdownAsync();
}
+ private async Task<ChannelCredentials> CreateCredentialsAsync()
+ {
+ var credentials = options.UseTls.Value ? TestCredentials.CreateTestClientCredentials(options.UseTestCa.Value) : ChannelCredentials.Insecure;
+
+ if (options.TestCase == "jwt_token_creds")
+ {
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ Assert.IsTrue(googleCredential.IsCreateScopedRequired);
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
+ }
+
+ if (options.TestCase == "compute_engine_creds")
+ {
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ Assert.IsFalse(googleCredential.IsCreateScopedRequired);
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
+ }
+ return credentials;
+ }
+
private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options)
{
switch (options.TestCase)
@@ -155,16 +178,16 @@ namespace Grpc.IntegrationTesting
await RunEmptyStreamAsync(client);
break;
case "compute_engine_creds":
- await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "jwt_token_creds":
- await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount);
+ RunJwtTokenCreds(client);
break;
case "oauth2_auth_token":
- await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ await RunOAuth2AuthTokenAsync(client, options.OAuthScope);
break;
case "per_rpc_creds":
- await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ await RunPerRpcCredsAsync(client, options.OAuthScope);
break;
case "cancel_after_begin":
await RunCancelAfterBeginAsync(client);
@@ -318,13 +341,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running compute_engine_creds");
- var credential = await GoogleCredential.GetApplicationDefaultAsync();
- Assert.IsFalse(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
-
+
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@@ -334,6 +354,7 @@ namespace Grpc.IntegrationTesting
FillOauthScope = true
};
+ // not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
@@ -344,13 +365,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount)
+ public static void RunJwtTokenCreds(TestService.TestServiceClient client)
{
Console.WriteLine("running jwt_token_creds");
- var credential = await GoogleCredential.GetApplicationDefaultAsync();
- Assert.IsTrue(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
-
+
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@@ -359,53 +377,50 @@ namespace Grpc.IntegrationTesting
FillUsername = true,
};
+ // not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running oauth2_auth_token");
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
-
+ var credentials = GrpcCredentials.FromAccessToken(oauth2Token);
var request = new SimpleRequest
{
FillUsername = true,
FillOauthScope = true
};
- var response = client.UnaryCall(request);
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Assert.False(string.IsNullOrEmpty(response.OauthScope));
Assert.True(oauthScope.Contains(response.OauthScope));
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running per_rpc_creds");
- ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
- string accessToken = await credential.GetAccessTokenForRequestAsync();
- var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken);
+ ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ var credentials = GrpcCredentials.Create(googleCredential);
var request = new SimpleRequest
{
FillUsername = true,
};
- var headers = new Metadata();
- headerInterceptor(null, "", headers);
- var response = client.UnaryCall(request, headers: headers);
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
@@ -485,5 +500,17 @@ namespace Grpc.IntegrationTesting
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
+
+ // extracts the client_email field from service account file used for auth test cases
+ private static string GetEmailFromServiceAccountFile()
+ {
+ string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
+ Assert.IsNotNull(keyFile);
+
+ var jobject = JObject.Parse(File.ReadAllText(keyFile));
+ string email = jobject.GetValue("client_email").Value<string>();
+ Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
+ return email;
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 513f8722d6..29f842be2e 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -54,8 +54,9 @@ namespace Grpc.IntegrationTesting
[Option("port", DefaultValue = 8070)]
public int Port { get; set; }
- [Option("use_tls")]
- public bool UseTls { get; set; }
+ // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
+ [Option("use_tls", DefaultValue = false)]
+ public bool? UseTls { get; set; }
[HelpOption]
public string GetUsage()
@@ -99,7 +100,7 @@ namespace Grpc.IntegrationTesting
string host = "0.0.0.0";
int port = options.Port;
- if (options.UseTls)
+ if (options.UseTls.Value)
{
server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index a3cbb7d76e..51a56f067b 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: messages.proto
+// source: test/proto/messages.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -21,37 +21,48 @@ namespace Grpc.Testing {
static Messages() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE",
- "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5",
- "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB",
- "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6",
- "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
- "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl",
- "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
- "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
- "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
- "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
- "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
- "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
- "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
- "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
- "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
- "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
- "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0",
- "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
- "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V",
- "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM="));
+ "Chl0ZXN0L3Byb3RvL21lc3NhZ2VzLnByb3RvEgxncnBjLnRlc3RpbmciQAoH",
+ "UGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU",
+ "eXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIMCgRjb2RlGAEgASgF",
+ "Eg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVlc3QSMAoNcmVzcG9u",
+ "c2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIVCg1y",
+ "ZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyABKAsyFS5ncnBjLnRl",
+ "c3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQgASgIEhgKEGZpbGxf",
+ "b2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiAB",
+ "KA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNl",
+ "X3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIl8KDlNp",
+ "bXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
+ "UGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0aF9zY29wZRgDIAEo",
+ "CSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYKB3BheWxvYWQYASAB",
+ "KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJlYW1pbmdJbnB1dENh",
+ "bGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRfc2l6ZRgBIAEoBSI3",
+ "ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEoBRITCgtpbnRlcnZh",
+ "bF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QSMAoN",
+ "cmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlw",
+ "ZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAuZ3JwYy50ZXN0aW5n",
+ "LlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50",
+ "ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiABKA4y",
+ "HS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNlX3N0",
+ "YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIkUKG1N0cmVh",
+ "bWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3Jw",
+ "Yy50ZXN0aW5nLlBheWxvYWQiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQY",
+ "ASABKAgSEgoKYmFja29mZl9tcxgCIAMoBSo/CgtQYXlsb2FkVHlwZRIQCgxD",
+ "T01QUkVTU0FCTEUQABISCg5VTkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC",
+ "KjIKD0NvbXByZXNzaW9uVHlwZRIICgROT05FEAASCAoER1pJUBABEgsKB0RF",
+ "RkxBVEUQAmIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.EchoStatus), new[]{ "Code", "Message" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null)
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ReconnectInfo), new[]{ "Passed", "BackoffMs" }, null, null, null)
}));
}
#endregion
@@ -64,6 +75,12 @@ namespace Grpc.Testing {
RANDOM = 2,
}
+ public enum CompressionType {
+ NONE = 0,
+ GZIP = 1,
+ DEFLATE = 2,
+ }
+
#endregion
#region Messages
@@ -196,12 +213,140 @@ namespace Grpc.Testing {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class EchoStatus : pb::IMessage<EchoStatus> {
+ private static readonly pb::MessageParser<EchoStatus> _parser = new pb::MessageParser<EchoStatus>(() => new EchoStatus());
+ public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public EchoStatus() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public EchoStatus(EchoStatus other) : this() {
+ code_ = other.code_;
+ message_ = other.message_;
+ }
+
+ public EchoStatus Clone() {
+ return new EchoStatus(this);
+ }
+
+ public const int CodeFieldNumber = 1;
+ private int code_;
+ public int Code {
+ get { return code_; }
+ set {
+ code_ = value;
+ }
+ }
+
+ public const int MessageFieldNumber = 2;
+ private string message_ = "";
+ public string Message {
+ get { return message_; }
+ set {
+ message_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as EchoStatus);
+ }
+
+ public bool Equals(EchoStatus other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Code != other.Code) return false;
+ if (Message != other.Message) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Code != 0) hash ^= Code.GetHashCode();
+ if (Message.Length != 0) hash ^= Message.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Code != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(Code);
+ }
+ if (Message.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Message);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Code != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Code);
+ }
+ if (Message.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
+ }
+ return size;
+ }
+
+ public void MergeFrom(EchoStatus other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Code != 0) {
+ Code = other.Code;
+ }
+ if (other.Message.Length != 0) {
+ Message = other.Message;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Code = input.ReadInt32();
+ break;
+ }
+ case 18: {
+ Message = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class SimpleRequest : pb::IMessage<SimpleRequest> {
private static readonly pb::MessageParser<SimpleRequest> _parser = new pb::MessageParser<SimpleRequest>(() => new SimpleRequest());
public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -220,6 +365,8 @@ namespace Grpc.Testing {
Payload = other.payload_ != null ? other.Payload.Clone() : null;
fillUsername_ = other.fillUsername_;
fillOauthScope_ = other.fillOauthScope_;
+ responseCompression_ = other.responseCompression_;
+ ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public SimpleRequest Clone() {
@@ -271,6 +418,24 @@ namespace Grpc.Testing {
}
}
+ public const int ResponseCompressionFieldNumber = 6;
+ private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ public global::Grpc.Testing.CompressionType ResponseCompression {
+ get { return responseCompression_; }
+ set {
+ responseCompression_ = value;
+ }
+ }
+
+ public const int ResponseStatusFieldNumber = 7;
+ private global::Grpc.Testing.EchoStatus responseStatus_;
+ public global::Grpc.Testing.EchoStatus ResponseStatus {
+ get { return responseStatus_; }
+ set {
+ responseStatus_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as SimpleRequest);
}
@@ -287,6 +452,8 @@ namespace Grpc.Testing {
if (!object.Equals(Payload, other.Payload)) return false;
if (FillUsername != other.FillUsername) return false;
if (FillOauthScope != other.FillOauthScope) return false;
+ if (ResponseCompression != other.ResponseCompression) return false;
+ if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@@ -297,6 +464,8 @@ namespace Grpc.Testing {
if (payload_ != null) hash ^= Payload.GetHashCode();
if (FillUsername != false) hash ^= FillUsername.GetHashCode();
if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -325,6 +494,14 @@ namespace Grpc.Testing {
output.WriteRawTag(40);
output.WriteBool(FillOauthScope);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ output.WriteRawTag(48);
+ output.WriteEnum((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ output.WriteRawTag(58);
+ output.WriteMessage(ResponseStatus);
+ }
}
public int CalculateSize() {
@@ -344,6 +521,12 @@ namespace Grpc.Testing {
if (FillOauthScope != false) {
size += 1 + 1;
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
+ }
return size;
}
@@ -369,6 +552,15 @@ namespace Grpc.Testing {
if (other.FillOauthScope != false) {
FillOauthScope = other.FillOauthScope;
}
+ if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ ResponseCompression = other.ResponseCompression;
+ }
+ if (other.responseStatus_ != null) {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ ResponseStatus.MergeFrom(other.ResponseStatus);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -401,6 +593,17 @@ namespace Grpc.Testing {
FillOauthScope = input.ReadBool();
break;
}
+ case 48: {
+ responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+ break;
+ }
+ case 58: {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ input.ReadMessage(responseStatus_);
+ break;
+ }
}
}
}
@@ -413,7 +616,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -573,7 +776,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -681,7 +884,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -783,7 +986,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -911,7 +1114,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -928,6 +1131,8 @@ namespace Grpc.Testing {
responseType_ = other.responseType_;
responseParameters_ = other.responseParameters_.Clone();
Payload = other.payload_ != null ? other.Payload.Clone() : null;
+ responseCompression_ = other.responseCompression_;
+ ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public StreamingOutputCallRequest Clone() {
@@ -960,6 +1165,24 @@ namespace Grpc.Testing {
}
}
+ public const int ResponseCompressionFieldNumber = 6;
+ private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ public global::Grpc.Testing.CompressionType ResponseCompression {
+ get { return responseCompression_; }
+ set {
+ responseCompression_ = value;
+ }
+ }
+
+ public const int ResponseStatusFieldNumber = 7;
+ private global::Grpc.Testing.EchoStatus responseStatus_;
+ public global::Grpc.Testing.EchoStatus ResponseStatus {
+ get { return responseStatus_; }
+ set {
+ responseStatus_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as StreamingOutputCallRequest);
}
@@ -974,6 +1197,8 @@ namespace Grpc.Testing {
if (ResponseType != other.ResponseType) return false;
if(!responseParameters_.Equals(other.responseParameters_)) return false;
if (!object.Equals(Payload, other.Payload)) return false;
+ if (ResponseCompression != other.ResponseCompression) return false;
+ if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@@ -982,6 +1207,8 @@ namespace Grpc.Testing {
if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
hash ^= responseParameters_.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -999,6 +1226,14 @@ namespace Grpc.Testing {
output.WriteRawTag(26);
output.WriteMessage(Payload);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ output.WriteRawTag(48);
+ output.WriteEnum((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ output.WriteRawTag(58);
+ output.WriteMessage(ResponseStatus);
+ }
}
public int CalculateSize() {
@@ -1010,6 +1245,12 @@ namespace Grpc.Testing {
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
+ }
return size;
}
@@ -1027,6 +1268,15 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
+ if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ ResponseCompression = other.ResponseCompression;
+ }
+ if (other.responseStatus_ != null) {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ ResponseStatus.MergeFrom(other.ResponseStatus);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -1051,6 +1301,17 @@ namespace Grpc.Testing {
input.ReadMessage(payload_);
break;
}
+ case 48: {
+ responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+ break;
+ }
+ case 58: {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ input.ReadMessage(responseStatus_);
+ break;
+ }
}
}
}
@@ -1063,7 +1324,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[8]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1165,6 +1426,127 @@ namespace Grpc.Testing {
}
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ReconnectInfo : pb::IMessage<ReconnectInfo> {
+ private static readonly pb::MessageParser<ReconnectInfo> _parser = new pb::MessageParser<ReconnectInfo>(() => new ReconnectInfo());
+ public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[9]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ReconnectInfo() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ReconnectInfo(ReconnectInfo other) : this() {
+ passed_ = other.passed_;
+ backoffMs_ = other.backoffMs_.Clone();
+ }
+
+ public ReconnectInfo Clone() {
+ return new ReconnectInfo(this);
+ }
+
+ public const int PassedFieldNumber = 1;
+ private bool passed_;
+ public bool Passed {
+ get { return passed_; }
+ set {
+ passed_ = value;
+ }
+ }
+
+ public const int BackoffMsFieldNumber = 2;
+ private static readonly pb::FieldCodec<int> _repeated_backoffMs_codec
+ = pb::FieldCodec.ForInt32(18);
+ private readonly pbc::RepeatedField<int> backoffMs_ = new pbc::RepeatedField<int>();
+ public pbc::RepeatedField<int> BackoffMs {
+ get { return backoffMs_; }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ReconnectInfo);
+ }
+
+ public bool Equals(ReconnectInfo other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Passed != other.Passed) return false;
+ if(!backoffMs_.Equals(other.backoffMs_)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Passed != false) hash ^= Passed.GetHashCode();
+ hash ^= backoffMs_.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Passed != false) {
+ output.WriteRawTag(8);
+ output.WriteBool(Passed);
+ }
+ backoffMs_.WriteTo(output, _repeated_backoffMs_codec);
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Passed != false) {
+ size += 1 + 1;
+ }
+ size += backoffMs_.CalculateSize(_repeated_backoffMs_codec);
+ return size;
+ }
+
+ public void MergeFrom(ReconnectInfo other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Passed != false) {
+ Passed = other.Passed;
+ }
+ backoffMs_.Add(other.backoffMs_);
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Passed = input.ReadBool();
+ break;
+ }
+ case 18:
+ case 16: {
+ backoffMs_.AddEntriesFrom(input, _repeated_backoffMs_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
#endregion
}
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
new file mode 100644
index 0000000000..5325b2fa14
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class MetadataCredentialsTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ TestService.ITestServiceClient client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair(File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) });
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
+ };
+ server.Start();
+
+ var options = new List<ChannelOption>
+ {
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
+ };
+
+ var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) =>
+ {
+ await Task.Delay(100); // make sure the operation is asynchronous.
+ metadata.Add("authorization", "SECRET_TOKEN");
+ });
+
+ var clientCredentials = ChannelCredentials.Create(
+ new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)),
+ new MetadataCredentials(asyncAuthInterceptor));
+ channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
+ client = TestService.NewClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void MetadataCredentials()
+ {
+ var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
+ Assert.AreEqual(10, response.Payload.Body.Length);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs
index 466ec57d3d..cf47707058 100644
--- a/src/csharp/Grpc.IntegrationTesting/Test.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Test.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: test.proto
+// source: test/proto/test.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -21,21 +21,26 @@ namespace Grpc.Testing {
static Test() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz",
- "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw",
- "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5",
- "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0",
- "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n",
- "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj",
- "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry",
- "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0",
- "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs",
- "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T",
- "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl",
- "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs",
- "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku",
- "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi",
- "BnByb3RvMw=="));
+ "ChV0ZXN0L3Byb3RvL3Rlc3QucHJvdG8SDGdycGMudGVzdGluZxoWdGVzdC9w",
+ "cm90by9lbXB0eS5wcm90bxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bzK7",
+ "BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3JwYy50ZXN0aW5nLkVt",
+ "cHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5Q2FsbBIbLmdycGMu",
+ "dGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5nLlNpbXBsZVJl",
+ "c3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5ncnBjLnRlc3Rpbmcu",
+ "U3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBjLnRlc3RpbmcuU3Ry",
+ "ZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3RyZWFtaW5nSW5wdXRD",
+ "YWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0Q2FsbFJlcXVlc3Qa",
+ "KC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxsUmVzcG9uc2UoARJp",
+ "Cg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRw",
+ "dXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRwdXRD",
+ "YWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxsEiguZ3JwYy50ZXN0",
+ "aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0GikuZ3JwYy50ZXN0aW5n",
+ "LlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAEyVQoUVW5pbXBsZW1l",
+ "bnRlZFNlcnZpY2USPQoRVW5pbXBsZW1lbnRlZENhbGwSEy5ncnBjLnRlc3Rp",
+ "bmcuRW1wdHkaEy5ncnBjLnRlc3RpbmcuRW1wdHkyfwoQUmVjb25uZWN0U2Vy",
+ "dmljZRIxCgVTdGFydBITLmdycGMudGVzdGluZy5FbXB0eRoTLmdycGMudGVz",
+ "dGluZy5FbXB0eRI4CgRTdG9wEhMuZ3JwYy50ZXN0aW5nLkVtcHR5GhsuZ3Jw",
+ "Yy50ZXN0aW5nLlJlY29ubmVjdEluZm9iBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, },
new pbr::GeneratedCodeInfo(null, null));
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index f63e148475..8c884b7408 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: test.proto
+// source: test/proto/test.proto
#region Designer generated code
using System;
@@ -207,5 +207,191 @@ namespace Grpc.Testing {
}
}
+ public static class UnimplementedService
+ {
+ static readonly string __ServiceName = "grpc.testing.UnimplementedService";
+
+ static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+ MethodType.Unary,
+ __ServiceName,
+ "UnimplementedCall",
+ __Marshaller_Empty,
+ __Marshaller_Empty);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Test.Descriptor.Services[1]; }
+ }
+
+ // client interface
+ public interface IUnimplementedServiceClient
+ {
+ global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ }
+
+ // server-side interface
+ public interface IUnimplementedService
+ {
+ Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ }
+
+ // client stub
+ public class UnimplementedServiceClient : ClientBase, IUnimplementedServiceClient
+ {
+ public UnimplementedServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnimplementedCall, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnimplementedCall, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
+ }
+
+ // creates a new client
+ public static UnimplementedServiceClient NewClient(Channel channel)
+ {
+ return new UnimplementedServiceClient(channel);
+ }
+
+ }
+ public static class ReconnectService
+ {
+ static readonly string __ServiceName = "grpc.testing.ReconnectService";
+
+ static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_Start = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+ MethodType.Unary,
+ __ServiceName,
+ "Start",
+ __Marshaller_Empty,
+ __Marshaller_Empty);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
+ MethodType.Unary,
+ __ServiceName,
+ "Stop",
+ __Marshaller_Empty,
+ __Marshaller_ReconnectInfo);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Test.Descriptor.Services[2]; }
+ }
+
+ // client interface
+ public interface IReconnectServiceClient
+ {
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ }
+
+ // server-side interface
+ public interface IReconnectService
+ {
+ Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.Empty request, ServerCallContext context);
+ Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
+ }
+
+ // client stub
+ public class ReconnectServiceClient : ClientBase, IReconnectServiceClient
+ {
+ public ReconnectServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Start, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Start, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Stop, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Stop, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_Start, serviceImpl.Start)
+ .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
+ }
+
+ // creates a new client
+ public static ReconnectServiceClient NewClient(Channel channel)
+ {
+ return new ReconnectServiceClient(channel);
+ }
+
+ }
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
deleted file mode 100644
index 7df85e3c13..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
+++ /dev/null
@@ -1,132 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Message definitions to be used by integration test service definitions.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// The type of payload that should be returned.
-enum PayloadType {
- // Compressable text format.
- COMPRESSABLE = 0;
-
- // Uncompressable binary format.
- UNCOMPRESSABLE = 1;
-
- // Randomly chosen from all other formats defined in this enum.
- RANDOM = 2;
-}
-
-// A block of data, to simply increase gRPC message size.
-message Payload {
- // The type of data in body.
- PayloadType type = 1;
- // Primary contents of payload.
- bytes body = 2;
-}
-
-// Unary request.
-message SimpleRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, server randomly chooses one from other formats.
- PayloadType response_type = 1;
-
- // Desired payload size in the response from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 response_size = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-
- // Whether SimpleResponse should include username.
- bool fill_username = 4;
-
- // Whether SimpleResponse should include OAuth scope.
- bool fill_oauth_scope = 5;
-}
-
-// Unary response, as configured by the request.
-message SimpleResponse {
- // Payload to increase message size.
- Payload payload = 1;
- // The user the request came from, for verifying authentication was
- // successful when the client expected it.
- string username = 2;
- // OAuth scope.
- string oauth_scope = 3;
-}
-
-// Client-streaming request.
-message StreamingInputCallRequest {
- // Optional input payload sent along with the request.
- Payload payload = 1;
-
- // Not expecting any payload from the response.
-}
-
-// Client-streaming response.
-message StreamingInputCallResponse {
- // Aggregated size of payloads received from the client.
- int32 aggregated_payload_size = 1;
-}
-
-// Configuration for a particular response.
-message ResponseParameters {
- // Desired payload sizes in responses from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 size = 1;
-
- // Desired interval between consecutive responses in the response stream in
- // microseconds.
- int32 interval_us = 2;
-}
-
-// Server-streaming request.
-message StreamingOutputCallRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, the payload from each response in the stream
- // might be of different types. This is to simulate a mixed type of payload
- // stream.
- PayloadType response_type = 1;
-
- // Configuration for each expected response message.
- repeated ResponseParameters response_parameters = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-}
-
-// Server-streaming response, as configured by the request and parameters.
-message StreamingOutputCallResponse {
- // Payload to increase response size.
- Payload payload = 1;
-}
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/test.proto b/src/csharp/Grpc.IntegrationTesting/proto/test.proto
deleted file mode 100644
index 5496f72af0..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/proto/test.proto
+++ /dev/null
@@ -1,71 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// An integration test service that covers all the method signature permutations
-// of unary/streaming requests/responses.
-syntax = "proto3";
-
-import "empty.proto";
-import "messages.proto";
-
-package grpc.testing;
-
-// A simple service to test the various types of RPCs and experiment with
-// performance with various types of payload.
-service TestService {
- // One empty request followed by one empty response.
- rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
-
- // One request followed by one response.
- rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
-
- // One request followed by a sequence of responses (streamed download).
- // The server returns the payload with client desired type and sizes.
- rpc StreamingOutputCall(StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by one response (streamed upload).
- // The server returns the aggregated size of client payload as the result.
- rpc StreamingInputCall(stream StreamingInputCallRequest)
- returns (StreamingInputCallResponse);
-
- // A sequence of requests with each request served by the server immediately.
- // As one request could lead to multiple responses, this interface
- // demonstrates the idea of full duplexing.
- rpc FullDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by a sequence of responses.
- // The server buffers all the client requests and then serves them in order. A
- // stream of responses are returned to the client when the server starts with
- // first request.
- rpc HalfDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-}
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index a3505b1e01..b864a955a8 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -20,9 +20,9 @@ endlocal
@call ..\..\vsprojects\build_plugins.bat || goto :error
-%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
+%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
+%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpVersion=%CORE_VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 51e0728fb9..679ca43d74 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -68,7 +68,7 @@ grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
/*
* Helper to maintain lifetime of batch op inputs and store batch op outputs.
*/
-typedef struct gprcsharp_batch_context {
+typedef struct grpcsharp_batch_context {
grpc_metadata_array send_initial_metadata;
grpc_byte_buffer *send_message;
struct {
@@ -665,16 +665,16 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
- grpc_call *call, grpcsharp_batch_context *ctx) {
- /* TODO: don't use magic number */
- grpc_op ops[1];
- ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
- ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
- ops[0].flags = 0;
- ops[0].reserved = NULL;
+ grpc_call *call, grpcsharp_batch_context *ctx) {
+ /* TODO: don't use magic number */
+ grpc_op ops[1];
+ ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
+ ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
+ ops[0].flags = 0;
+ ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -785,6 +785,11 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
NULL);
}
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call,
+ grpc_credentials *creds) {
+ return grpc_call_set_credentials(call, creds);
+}
+
/* Server */
GPR_EXPORT grpc_server *GPR_CALLTYPE
@@ -892,6 +897,47 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
return grpc_server_add_secure_http2_port(server, addr, creds);
}
+GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create(
+ grpc_credentials *creds1,
+ grpc_credentials *creds2) {
+ return grpc_composite_credentials_create(creds1, creds2, NULL);
+}
+
+/* Metadata credentials plugin */
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data, grpc_metadata_array *metadata,
+ grpc_status_code status, const char *error_details) {
+ cb(user_data, metadata->metadata, metadata->count, status, error_details);
+}
+
+typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
+ void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
+ void *user_data, gpr_int32 is_destroy);
+
+static void grpcsharp_get_metadata_handler(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data) {
+ grpcsharp_metadata_interceptor_func interceptor =
+ (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
+ interceptor(state, service_url, cb, user_data, 0);
+}
+
+static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
+ grpcsharp_metadata_interceptor_func interceptor =
+ (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
+ interceptor(state, NULL, NULL, NULL, 1);
+}
+
+GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
+ grpcsharp_metadata_interceptor_func metadata_interceptor) {
+ grpc_metadata_credentials_plugin plugin;
+ plugin.get_metadata = grpcsharp_get_metadata_handler;
+ plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
+ plugin.state = (void*)(gpr_intptr)metadata_interceptor;
+ return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+}
+
/* Logging */
typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line,
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index a17f45b587..f879e074aa 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -42,7 +42,7 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
- -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto
+ -I ../.. ../../test/proto/*.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto