Beispiel #1
0
        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();
            }
        }
Beispiel #2
0
            public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
            {
                if (httpContext == null)
                {
                    return(false);
                }

                return(GrpcProtocolHelpers.IsGrpcContentType(httpContext.Request.ContentType));
            }
Beispiel #3
0
        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));
        }
Beispiel #5
0
        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);
            }
        }
Beispiel #6
0
        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();
        }
Beispiel #8
0
        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);
            }
        }