Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"The response ended prematurely" when connecting to insecure gRPC channel

I'm trying to establish a connection to an insecure gRPC server. I'm using gRPC for communication between two processes inside of a Docker container, that's why I don't need any encryption or strong authentication.

The server behaves as expected and I can do calls using grpcurl like that:

grpcurl -plaintext localhost:42652 SomeService.DoSomething

Now I'm trying to call the same RPC method from a .Net Core application:

// Registration of the DI service
services.AddGrpcClient<DaemonService.DaemonServiceClient>(options => {
    // Enable support for unencrypted HTTP2
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    options.Address = new Uri("http://localhost:42652");

    // Just a test, doesn't change anything.
    options.ChannelOptionsActions.Add(channelOptions => channelOptions.Credentials = ChannelCredentials.Insecure);
});

// Call
var reply = _someServiceClient.DoSomething(new Request());

But the call in the last line results in an exception:

fail: Grpc.Net.Client.Internal.GrpcCall[6]
      Error starting gRPC call.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.SendAsync(HttpRequestMessage request)
fail: Grpc.Net.Client.Internal.GrpcCall[3]
      Call failed with gRPC error status. Status code: 'Cancelled', Message: 'Error starting gRPC call.'.
fail: SomeNamespace.Session.Program[0]
      An error occured.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.SendAsync(HttpRequestMessage request)
   at Grpc.Net.Client.Internal.GrpcCall`2.GetResponseAsync()
   at Grpc.Net.Client.Internal.HttpClientCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)
   at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[TRequest,TResponse](TRequest req, ClientInterceptorContext`2 ctx)
   at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[TRequest,TResponse](TRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation)
   at Grpc.Core.Interceptors.InterceptingCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)
   at SomeNamespace.RpcServices.DaemonService.DaemonServiceClient.GetVncContainerEnvironment(EmptyRequest request, CallOptions options) in /src/SomeNamespace.RpcServices/obj/Release/netcoreapp3.0/Vnc-container-daemonGrpc.cs:line 98
   at SomeNamespace.RpcServices.DaemonService.DaemonServiceClient.GetVncContainerEnvironment(EmptyRequest request, Metadata headers, Nullable`1 deadline, CancellationToken cancellationToken) in /src/SomeNamespace.RpcServices/obj/Release/netcoreapp3.0/Vnc-container-daemonGrpc.cs:line 94
   at SomeNamespace.Rpc.RpcEventListener.StartListening() in /src/SomeNamespace/Rpc/RpcEventListener.cs:line 32

Do you have an idea what I've to do different? I cannot find much documentation about establishing insecure connections like that.

like image 523
Marcus Wichelmann Avatar asked Sep 22 '19 19:09

Marcus Wichelmann


1 Answers

I found the fix on my own:

It works when I move the AppContext.SetSwitch above the AddGrpcClient.

// Enable support for unencrypted HTTP2  
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

// Registration of the DI service
services.AddGrpcClient<DaemonService.DaemonServiceClient>(options => {
    options.Address = new Uri("http://localhost:42652");
    options.ChannelOptionsActions.Add(channelOptions => channelOptions.Credentials = ChannelCredentials.Insecure);
});
like image 143
Marcus Wichelmann Avatar answered Oct 15 '22 13:10

Marcus Wichelmann