protected override async Task HandleCallAsyncCore(HttpContext httpContext) { var serverCallContext = CreateServerCallContext(httpContext); GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response); try { serverCallContext.Initialize(); var requestPayload = await httpContext.Request.BodyReader.ReadSingleMessageAsync(serverCallContext); var request = Method.RequestMarshaller.Deserializer(requestPayload); TResponse?response = null; if (_pipelineInvoker == null) { var activator = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >(); TService?service = null; try { service = activator.Create(); response = await _invoker(service, request, serverCallContext); } finally { if (service != null) { activator.Release(service); } } } else { response = await _pipelineInvoker(request, serverCallContext); } if (response == null) { // This is consistent with Grpc.Core when a null value is returned throw new RpcException(new Status(StatusCode.Cancelled, "No message returned from method.")); } var responseBodyWriter = httpContext.Response.BodyWriter; await responseBodyWriter.WriteMessageAsync(response, serverCallContext, Method.ResponseMarshaller.Serializer); await serverCallContext.EndCallAsync(); } catch (Exception ex) { serverCallContext.ProcessHandlerError(ex, Method.Name); } finally { serverCallContext.Dispose(); } }
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) { return(false); } return(GrpcProtocolHelpers.IsGrpcContentType(httpContext.Request.ContentType)); }
public Task HandleCallAsync(HttpContext httpContext) { if (GrpcProtocolHelpers.IsInvalidContentType(httpContext, out var error)) { // This might be a CORS preflight request and CORS middleware hasn't been configured if (HttpMethods.IsOptions(httpContext.Request.Method)) { GrpcServerLog.UnhandledCorsPreflightRequest(Logger); GrpcProtocolHelpers.BuildHttpErrorResponse(httpContext.Response, StatusCodes.Status405MethodNotAllowed, StatusCode.Internal, "Unhandled CORS preflight request received. CORS may not be configured correctly in the application."); httpContext.Response.Headers[HeaderNames.Allow] = HttpMethods.Post; return(Task.CompletedTask); } else { GrpcServerLog.UnsupportedRequestContentType(Logger, httpContext.Request.ContentType); GrpcProtocolHelpers.BuildHttpErrorResponse(httpContext.Response, StatusCodes.Status415UnsupportedMediaType, StatusCode.Internal, error); return(Task.CompletedTask); } } if (httpContext.Request.Protocol != GrpcProtocolConstants.Http2Protocol && httpContext.Request.Protocol != GrpcProtocolConstants.Http20Protocol) { GrpcServerLog.UnsupportedRequestProtocol(Logger, httpContext.Request.Protocol); var protocolError = $"Request protocol '{httpContext.Request.Protocol}' is not supported."; GrpcProtocolHelpers.BuildHttpErrorResponse(httpContext.Response, StatusCodes.Status426UpgradeRequired, StatusCode.Internal, protocolError); httpContext.Response.Headers[HeaderNames.Upgrade] = GrpcProtocolConstants.Http2Protocol; return(Task.CompletedTask); } var serverCallContext = new HttpContextServerCallContext(httpContext, MethodInvoker.Options, typeof(TRequest), typeof(TResponse), Logger); httpContext.Features.Set <IServerCallContextFeature>(serverCallContext); GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response); try { serverCallContext.Initialize(); var handleCallTask = HandleCallAsyncCore(httpContext, serverCallContext); if (handleCallTask.IsCompletedSuccessfully) { return(serverCallContext.EndCallAsync()); } else { return(AwaitHandleCall(serverCallContext, MethodInvoker.Method, handleCallTask)); } } catch (Exception ex) { return(serverCallContext.ProcessHandlerErrorAsync(ex, MethodInvoker.Method.Name)); }
public Task HandleCallAsync(HttpContext httpContext) { if (!GrpcProtocolHelpers.IsValidContentType(httpContext, out var error)) { GrpcProtocolHelpers.SendHttpError(httpContext.Response, StatusCodes.Status415UnsupportedMediaType, StatusCode.Internal, error); return(Task.CompletedTask); } return(HandleCallAsyncCore(httpContext)); }
internal GrpcChannel(Uri address, GrpcChannelOptions channelOptions) : base(address.Authority) { _lock = new object(); _methodInfoCache = new ConcurrentDictionary <IMethod, GrpcMethodInfo>(); // Dispose the HTTP client/handler if... // 1. No client/handler was specified and so the channel created the client itself // 2. User has specified a client/handler and set DisposeHttpClient to true _shouldDisposeHttpClient = (channelOptions.HttpClient == null && channelOptions.HttpHandler == null) || channelOptions.DisposeHttpClient; Address = address; HttpInvoker = channelOptions.HttpClient ?? CreateInternalHttpInvoker(channelOptions.HttpHandler); IsWinHttp = channelOptions.HttpHandler != null?HttpHandlerFactory.HasHttpHandlerType(channelOptions.HttpHandler, "System.Net.Http.WinHttpHandler") : false; SendMaxMessageSize = channelOptions.MaxSendMessageSize; ReceiveMaxMessageSize = channelOptions.MaxReceiveMessageSize; MaxRetryAttempts = channelOptions.MaxRetryAttempts; MaxRetryBufferSize = channelOptions.MaxRetryBufferSize; MaxRetryBufferPerCallSize = channelOptions.MaxRetryBufferPerCallSize; CompressionProviders = ResolveCompressionProviders(channelOptions.CompressionProviders); MessageAcceptEncoding = GrpcProtocolHelpers.GetMessageAcceptEncoding(CompressionProviders); LoggerFactory = channelOptions.LoggerFactory ?? NullLoggerFactory.Instance; Logger = LoggerFactory.CreateLogger <GrpcChannel>(); ThrowOperationCanceledOnCancellation = channelOptions.ThrowOperationCanceledOnCancellation; _createMethodInfoFunc = CreateMethodInfo; ActiveCalls = new HashSet <IDisposable>(); if (channelOptions.ServiceConfig is { } serviceConfig) { RetryThrottling = serviceConfig.RetryThrottling != null?CreateChannelRetryThrottling(serviceConfig.RetryThrottling) : null; _serviceConfigMethods = CreateServiceConfigMethods(serviceConfig); _random = new Random(); } if (channelOptions.Credentials != null) { var configurator = new DefaultChannelCredentialsConfigurator(); channelOptions.Credentials.InternalPopulateConfiguration(configurator, null); IsSecure = configurator.IsSecure; CallCredentials = configurator.CallCredentials; ValidateChannelCredentials(); } if (!string.IsNullOrEmpty(Address.PathAndQuery) && Address.PathAndQuery != "/") { Log.AddressPathUnused(Logger, Address.OriginalString); } }
protected override async Task ResolveAsync(CancellationToken cancellationToken) { try { var elapsedTimeSinceLastRefresh = SystemClock.UtcNow - _lastResolveStart; if (elapsedTimeSinceLastRefresh < MinimumDnsResolutionRate) { var delay = MinimumDnsResolutionRate - elapsedTimeSinceLastRefresh; DnsResolverLog.StartingRateLimitDelay(_logger, delay, MinimumDnsResolutionRate); await Task.Delay(delay, cancellationToken).ConfigureAwait(false); } var lastResolveStart = SystemClock.UtcNow; if (string.IsNullOrEmpty(_dnsAddress)) { throw new InvalidOperationException($"Resolver address '{_originalAddress}' is not valid. Please use dns:/// for DNS provider."); } DnsResolverLog.StartingDnsQuery(_logger, _dnsAddress); var addresses = #if NET6_0_OR_GREATER await Dns.GetHostAddressesAsync(_dnsAddress, cancellationToken).ConfigureAwait(false); #else await Dns.GetHostAddressesAsync(_dnsAddress).ConfigureAwait(false); #endif DnsResolverLog.ReceivedDnsResults(_logger, addresses.Length, _dnsAddress, addresses); var endpoints = addresses.Select(a => new BalancerAddress(a.ToString(), _port)).ToArray(); var resolverResult = ResolverResult.ForResult(endpoints); Listener(resolverResult); // Only update last resolve start if successful. Backoff will handle limiting resolves on failure. _lastResolveStart = lastResolveStart; } catch (Exception ex) { var message = $"Error getting DNS hosts for address '{_dnsAddress}'."; DnsResolverLog.ErrorQueryingDns(_logger, _dnsAddress, ex); Listener(ResolverResult.ForFailure(GrpcProtocolHelpers.CreateStatusFromException(message, ex, StatusCode.Unavailable))); } }
protected override async Task HandleCallAsyncCore(HttpContext httpContext) { GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response); var serverCallContext = new HttpContextServerCallContext(httpContext, ServiceOptions, Logger); var activator = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >(); TService service = null; try { serverCallContext.Initialize(); // Decode request var requestPayload = await httpContext.Request.BodyPipe.ReadSingleMessageAsync(serverCallContext); var request = Method.RequestMarshaller.Deserializer(requestPayload); service = activator.Create(); await _invoker( service, request, new HttpContextStreamWriter <TResponse>(serverCallContext, Method.ResponseMarshaller.Serializer), serverCallContext); } catch (Exception ex) { serverCallContext.ProcessHandlerError(ex, Method.Name); } finally { serverCallContext.Dispose(); if (service != null) { activator.Release(service); } } httpContext.Response.ConsolidateTrailers(serverCallContext); // Flush any buffered content await httpContext.Response.BodyPipe.FlushAsync(); }
public void IsGrpcContentType(string contentType, bool valid) { var v = MediaTypeHeaderValue.Parse(contentType); Assert.AreEqual(valid, GrpcProtocolHelpers.IsGrpcContentType(v)); }
private async Task ResolveNowAsync(CancellationToken cancellationToken) { // Reset resolve success to false. Will be set to true when an OK result is sent to listener. _resolveSuccessful = false; try { var backoffPolicy = _backoffPolicyFactory?.Create(); for (var attempt = 0; ; attempt++) { try { await ResolveAsync(cancellationToken).ConfigureAwait(false); // ResolveAsync may report a failure but not throw. Check to see whether an OK result // has been reported. If not then start retry loop. if (_resolveSuccessful) { return; } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // Ignore cancellation. break; } catch (Exception ex) { Log.ResolveError(_logger, GetType(), ex); var status = GrpcProtocolHelpers.CreateStatusFromException("Error refreshing resolver.", ex); Listener(ResolverResult.ForFailure(status)); } // No backoff policy specified. Exit immediately. if (backoffPolicy == null) { break; } var backoffTicks = backoffPolicy.NextBackoff().Ticks; // Task.Delay supports up to Int32.MaxValue milliseconds. // Note that even if the maximum backoff is configured to this maximum, the jitter could push it over the limit. // Force an upper bound here to ensure an unsupported backoff is never used. backoffTicks = Math.Min(backoffTicks, TimeSpan.TicksPerMillisecond * int.MaxValue); var backkoff = TimeSpan.FromTicks(backoffTicks); Log.StartingResolveBackoff(_logger, GetType(), backkoff); await Task.Delay(backkoff, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // Ignore cancellation. } catch (Exception ex) { Log.ErrorRetryingResolve(_logger, GetType(), ex); } }