コード例 #1
0
        public ServerCallDeadlineManager(HttpContextServerCallContext serverCallContext, ISystemClock clock, TimeSpan timeout, long maxTimerDueTime = DefaultMaxTimerDueTime)
        {
            // Set fields that need to exist before setting up deadline CTS
            // Ensures callback can run successfully before CTS timer starts
            _serverCallContext = serverCallContext;

            Deadline = clock.UtcNow.Add(timeout);

            _systemClock = clock;

            var timerMilliseconds = CommonGrpcProtocolHelpers.GetTimerDueTime(timeout, maxTimerDueTime);

            if (timerMilliseconds == maxTimerDueTime)
            {
                // Create timer and set to field before setting time.
                // Ensures there is no weird situation where the timer triggers
                // before the field is set. Shouldn't happen because only long deadlines
                // will take this path but better to be safe than sorry.
                _longDeadlineTimer = new Timer(DeadlineExceededLongDelegate, (this, maxTimerDueTime), Timeout.Infinite, Timeout.Infinite);
                _longDeadlineTimer.Change(timerMilliseconds, Timeout.Infinite);
            }
            else
            {
                _longDeadlineTimer = new Timer(DeadlineExceededDelegate, this, timerMilliseconds, Timeout.Infinite);
            }
        }
コード例 #2
0
        public override async Task HandleCallAsync(HttpContext httpContext)
        {
            httpContext.Response.ContentType = "application/grpc";
            httpContext.Response.Headers.Append("grpc-encoding", "identity");

            var requestPayload = await httpContext.Request.BodyPipe.ReadSingleMessageAsync();

            var request = Method.RequestMarshaller.Deserializer(requestPayload);

            // Activate the implementation type via DI.
            var activator         = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >();
            var service           = activator.Create();
            var serverCallContext = new HttpContextServerCallContext(httpContext);
            var streamWriter      = new HttpContextStreamWriter <TResponse>(serverCallContext, Method.ResponseMarshaller.Serializer);

            await _invoker(
                service,
                request,
                streamWriter,
                serverCallContext);

            httpContext.Response.ConsolidateTrailers(serverCallContext);

            // Flush any buffered content
            await httpContext.Response.BodyPipe.FlushAsync();
        }
コード例 #3
0
        public override async Task HandleCallAsync(HttpContext httpContext)
        {
            httpContext.Response.ContentType = "application/grpc";
            httpContext.Response.Headers.Append("grpc-encoding", "identity");

            // Setup ServerCallContext
            var serverCallContext = new HttpContextServerCallContext(httpContext, Logger);

            serverCallContext.Initialize();

            // Activate the implementation type via DI.
            var activator = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >();
            var service   = activator.Create();

            try
            {
                using (serverCallContext)
                {
                    await _invoker(
                        service,
                        new HttpContextStreamReader <TRequest>(httpContext, ServiceOptions, Method.RequestMarshaller.Deserializer),
                        new HttpContextStreamWriter <TResponse>(serverCallContext, ServiceOptions, Method.ResponseMarshaller.Serializer),
                        serverCallContext);
                }
            }
            finally
            {
                activator.Release(service);
            }

            httpContext.Response.ConsolidateTrailers(serverCallContext);

            // Flush any buffered content
            await httpContext.Response.BodyPipe.FlushAsync();
        }
コード例 #4
0
        public override async Task HandleCallAsync(HttpContext httpContext)
        {
            httpContext.Response.ContentType = "application/grpc";
            httpContext.Response.Headers.Append("grpc-encoding", "identity");

            var requestPayload = await httpContext.Request.BodyPipe.ReadSingleMessageAsync();

            var request = Method.RequestMarshaller.Deserializer(requestPayload);

            // Activate the implementation type via DI.
            var activator         = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >();
            var service           = activator.Create();
            var serverCallContext = new HttpContextServerCallContext(httpContext);

            serverCallContext.Initialize();

            TResponse response;

            using (serverCallContext)
            {
                response = await _invoker(
                    service,
                    request,
                    serverCallContext);
            }

            // TODO(JunTaoLuo, JamesNK): make sure the response is not null
            var responseBodyPipe = httpContext.Response.BodyPipe;
            await responseBodyPipe.WriteMessageAsync(response, Method.ResponseMarshaller.Serializer, serverCallContext.WriteOptions);

            httpContext.Response.ConsolidateTrailers(serverCallContext);

            // Flush any buffered content
            await httpContext.Response.BodyPipe.FlushAsync();
        }
コード例 #5
0
        public override async Task HandleCallAsync(HttpContext httpContext)
        {
            httpContext.Response.ContentType = "application/grpc";
            httpContext.Response.Headers.Append("grpc-encoding", "identity");

            var serverCallContext = new HttpContextServerCallContext(httpContext, ServiceOptions, Logger);

            var      activator = httpContext.RequestServices.GetRequiredService <IGrpcServiceActivator <TService> >();
            TService service   = null;

            TResponse response = null;

            try
            {
                serverCallContext.Initialize();

                var requestPayload = await httpContext.Request.BodyPipe.ReadSingleMessageAsync(serverCallContext);

                var request = Method.RequestMarshaller.Deserializer(requestPayload);

                service = activator.Create();

                response = await _invoker(
                    service,
                    request,
                    serverCallContext);

                if (response == null)
                {
                    // This is consistent with Grpc.Core when a null value is returned
                    throw new RpcException(new Status(StatusCode.Cancelled, "Cancelled"));
                }

                var responseBodyPipe = httpContext.Response.BodyPipe;
                await responseBodyPipe.WriteMessageAsync(response, serverCallContext, Method.ResponseMarshaller.Serializer);
            }
            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();
        }
コード例 #6
0
        public static void ConsolidateTrailers(this HttpResponse httpResponse, HttpContextServerCallContext context)
        {
            var trailersDestination = GrpcProtocolHelpers.GetTrailersDestination(httpResponse);

            if (context.HasResponseTrailers)
            {
                foreach (var trailer in context.ResponseTrailers)
                {
                    var value = (trailer.IsBinary) ? Convert.ToBase64String(trailer.ValueBytes) : trailer.Value;
                    trailersDestination.Append(trailer.Key, value);
                }
            }

            // Append status trailers, these overwrite any existing status trailers set via ServerCallContext.ResponseTrailers
            GrpcProtocolHelpers.SetStatus(trailersDestination, context.Status);
        }
コード例 #7
0
        public static void ConsolidateTrailers(this HttpResponse httpResponse, HttpContextServerCallContext context)
        {
            if (context.HasResponseTrailers)
            {
                foreach (var trailer in context.ResponseTrailers)
                {
                    // TODO(juntaoluo): What about binary trailers
                    if (!trailer.IsBinary)
                    {
                        httpResponse.AppendTrailer(trailer.Key, trailer.Value);
                    }
                }
            }

            // Append status trailers, these overwrite any existing status trailers set via ServerCallContext.ResponseTrailers
            httpResponse.AppendTrailer(GrpcProtocolConstants.StatusTrailer, context.Status.StatusCode.ToTrailerString());
            httpResponse.AppendTrailer(GrpcProtocolConstants.MessageTrailer, context.Status.Detail);
        }
コード例 #8
0
        public static void ConsolidateTrailers(this HttpResponse httpResponse, HttpContextServerCallContext context)
        {
            if (context.HasResponseTrailers)
            {
                foreach (var trailer in context.ResponseTrailers)
                {
                    if (trailer.IsBinary)
                    {
                        httpResponse.AppendTrailer(trailer.Key, Convert.ToBase64String(trailer.ValueBytes));
                    }
                    else
                    {
                        httpResponse.AppendTrailer(trailer.Key, trailer.Value);
                    }
                }
            }

            // Append status trailers, these overwrite any existing status trailers set via ServerCallContext.ResponseTrailers
            GrpcProtocolHelpers.AppendStatusTrailers(httpResponse, context.Status);
        }
コード例 #9
0
        public static Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Func <TResponse, byte[]> serializer, bool canFlush)
        {
            var responsePayload = serializer(response);

            // Flush messages unless WriteOptions.Flags has BufferHint set
            var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint;

            return(pipeWriter.WriteMessageAsync(responsePayload, serverCallContext, flush));
        }
コード例 #10
0
        public static Task WriteMessageAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush = false)
        {
            if (messageData.Length > serverCallContext.ServiceOptions.SendMaxMessageSize)
            {
                return(Task.FromException(new RpcException(SendingMessageExceedsLimitStatus)));
            }

            // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader
            var response = serverCallContext.HttpContext.Response;

            if (!response.HasStarted)
            {
                var startAsyncTask = response.StartAsync();
                if (!startAsyncTask.IsCompletedSuccessfully)
                {
                    return(pipeWriter.WriteMessageCoreAsyncAwaited(messageData, serverCallContext, flush, startAsyncTask));
                }
            }

            return(pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush));
        }
コード例 #11
0
        public static async Task WriteSingleMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer)
            where TResponse : class
        {
            var logger = serverCallContext.Logger;

            try
            {
                // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader
                var httpResponse = serverCallContext.HttpContext.Response;
                if (!httpResponse.HasStarted)
                {
                    await httpResponse.StartAsync();
                }

                GrpcServerLog.SendingMessage(logger);

                var serializationContext = serverCallContext.SerializationContext;
                serializationContext.Reset();
                serializationContext.ResponseBufferWriter = pipeWriter;
                serializer(response, serializationContext);

                GrpcServerLog.MessageSent(serverCallContext.Logger);
                GrpcEventSource.Log.MessageSent();
            }
            catch (Exception ex)
            {
                GrpcServerLog.ErrorSendingMessage(logger, ex);
                throw;
            }
        }
コード例 #12
0
        public static async Task WriteStreamedMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, CancellationToken cancellationToken = default)
            where TResponse : class
        {
            var logger = serverCallContext.Logger;

            try
            {
                // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader
                var httpResponse = serverCallContext.HttpContext.Response;
                if (!httpResponse.HasStarted)
                {
                    await httpResponse.StartAsync();
                }

                GrpcServerLog.SendingMessage(logger);

                var serializationContext = serverCallContext.SerializationContext;
                serializationContext.Reset();
                serializationContext.ResponseBufferWriter = pipeWriter;
                serializer(response, serializationContext);

                // Flush messages unless WriteOptions.Flags has BufferHint set
                var flush = ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint;

                if (flush)
                {
                    var flushResult = await pipeWriter.FlushAsync();

                    // Workaround bug where FlushAsync doesn't return IsCanceled = true on request abort.
                    // https://github.com/dotnet/aspnetcore/issues/40788
                    // Also, sometimes the request CT isn't triggered. Also check CT passed into method.
                    if (!flushResult.IsCompleted &&
                        (serverCallContext.CancellationToken.IsCancellationRequested || cancellationToken.IsCancellationRequested))
                    {
                        throw new OperationCanceledException("Request aborted while sending the message.");
                    }
                }

                GrpcServerLog.MessageSent(serverCallContext.Logger);
                GrpcEventSource.Log.MessageSent();
            }
            catch (Exception ex)
            {
                GrpcServerLog.ErrorSendingMessage(logger, ex);
                throw;
            }
        }
コード例 #13
0
 public HttpContextStreamReader(HttpContextServerCallContext serverCallContext, Func <DeserializationContext, TRequest> deserializer)
 {
     _serverCallContext = serverCallContext;
     _deserializer      = deserializer;
 }
コード例 #14
0
ファイル: PipeExtensions.cs プロジェクト: aTiKhan/grpc-dotnet
        public static async Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush)
            where TResponse : class
        {
            var logger = serverCallContext.Logger;

            try
            {
                // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader
                var httpResponse = serverCallContext.HttpContext.Response;
                if (!httpResponse.HasStarted)
                {
                    await httpResponse.StartAsync();
                }

                GrpcServerLog.SendingMessage(logger);

                var serializationContext = serverCallContext.SerializationContext;
                serializationContext.Reset();
                serializationContext.ResponseBufferWriter = pipeWriter;
                serializer(response, serializationContext);

                // Flush messages unless WriteOptions.Flags has BufferHint set
                var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint;

                if (flush)
                {
                    await pipeWriter.FlushAsync();
                }

                GrpcServerLog.MessageSent(serverCallContext.Logger);
                GrpcEventSource.Log.MessageSent();
            }
            catch (Exception ex)
            {
                GrpcServerLog.ErrorSendingMessage(logger, ex);
                throw;
            }
        }
コード例 #15
0
        public static async Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush)
        {
            var logger = serverCallContext.Logger;

            try
            {
                Log.SendingMessage(logger);

                var serializationContext = serverCallContext.SerializationContext;
                serializer(response, serializationContext);
                var responsePayload = serializationContext.Payload;
                serializationContext.Payload = null;

                if (responsePayload == null)
                {
                    throw new InvalidOperationException("Serialization did not return a payload.");
                }

                Log.SerializedMessage(serverCallContext.Logger, typeof(TResponse), responsePayload.Length);

                // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader
                var httpResponse = serverCallContext.HttpContext.Response;
                if (!httpResponse.HasStarted)
                {
                    await httpResponse.StartAsync();
                }

                var isCompressed =
                    serverCallContext.CanWriteCompressed() &&
                    !string.Equals(serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);

                if (isCompressed)
                {
                    responsePayload = CompressMessage(
                        serverCallContext.Logger,
                        serverCallContext.ResponseGrpcEncoding !,
                        serverCallContext.ServiceOptions.ResponseCompressionLevel,
                        serverCallContext.ServiceOptions.CompressionProviders,
                        responsePayload);
                }

                if (responsePayload.Length > serverCallContext.ServiceOptions.SendMaxMessageSize)
                {
                    throw new RpcException(SendingMessageExceedsLimitStatus);
                }

                WriteHeader(pipeWriter, responsePayload.Length, isCompressed);
                pipeWriter.Write(responsePayload);

                // Flush messages unless WriteOptions.Flags has BufferHint set
                var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint;

                if (flush)
                {
                    serverCallContext.HasBufferedMessage = false;
                    await pipeWriter.FlushAsync();
                }
                else
                {
                    // Set flag so buffered message will be written at the end
                    serverCallContext.HasBufferedMessage = true;
                }

                Log.MessageSent(serverCallContext.Logger);
                GrpcEventSource.Log.MessageSent();
            }
            catch (Exception ex)
            {
                Log.ErrorSendingMessage(logger, ex);
                throw;
            }
        }
コード例 #16
0
 public HttpContextStreamWriter(HttpContextServerCallContext context, GrpcServiceOptions serviceOptions, Func <TResponse, byte[]> serializer)
 {
     _context        = context;
     _serviceOptions = serviceOptions;
     _serializer     = serializer;
 }
コード例 #17
0
 public HttpContextStreamWriter(HttpContextServerCallContext context, Func <TResponse, byte[]> serializer)
 {
     _context    = context;
     _serializer = serializer;
 }
コード例 #18
0
 private static async Task WriteMessageCoreAsyncAwaited(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush, Task startAsyncTask)
 {
     await startAsyncTask;
     await pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush);
 }
コード例 #19
0
        private static Task WriteMessageCoreAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush)
        {
            WriteHeader(pipeWriter, messageData.Length);
            pipeWriter.Write(messageData);

            if (flush)
            {
                var valueTask = pipeWriter.FlushAsync();

                if (valueTask.IsCompletedSuccessfully)
                {
                    // We do this to reset the underlying value task (which happens in GetResult())
                    valueTask.GetAwaiter().GetResult();
                    return(Task.CompletedTask);
                }

                return(valueTask.AsTask());
            }

            return(Task.CompletedTask);
        }
コード例 #20
0
 public HttpContextStreamReader(HttpContext context, HttpContextServerCallContext serverCallContext, Func <byte[], TRequest> deserializer)
 {
     _httpContext       = context;
     _serverCallContext = serverCallContext;
     _deserializer      = deserializer;
 }
コード例 #21
0
        private static Task WriteMessageCoreAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush)
        {
            Debug.Assert(serverCallContext.ResponseGrpcEncoding != null);

            var isCompressed =
                serverCallContext.CanWriteCompressed() &&
                !string.Equals(serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);

            if (isCompressed)
            {
                messageData = GrpcProtocolHelpers.CompressMessage(
                    serverCallContext.ResponseGrpcEncoding,
                    serverCallContext.ServiceOptions.ResponseCompressionLevel,
                    serverCallContext.ServiceOptions.CompressionProviders,
                    messageData);
            }

            WriteHeader(pipeWriter, messageData.Length, isCompressed);
            pipeWriter.Write(messageData);

            if (flush)
            {
                var valueTask = pipeWriter.FlushAsync();

                if (valueTask.IsCompletedSuccessfully)
                {
                    // We do this to reset the underlying value task (which happens in GetResult())
                    valueTask.GetAwaiter().GetResult();
                    return(Task.CompletedTask);
                }

                return(valueTask.AsTask());
            }

            return(Task.CompletedTask);
        }
コード例 #22
0
        private static Task WriteMessageCoreAsync(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush)
        {
            Debug.Assert(serverCallContext.ResponseGrpcEncoding != null);

            var isCompressed =
                serverCallContext.CanWriteCompressed() &&
                !string.Equals(serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);

            if (isCompressed)
            {
                messageData = GrpcProtocolHelpers.CompressMessage(
                    serverCallContext.ResponseGrpcEncoding,
                    serverCallContext.ServiceOptions.ResponseCompressionLevel,
                    serverCallContext.ServiceOptions.CompressionProviders,
                    messageData);
            }

            WriteHeader(pipeWriter, messageData.Length, isCompressed);
            pipeWriter.Write(messageData);

            if (flush)
            {
                serverCallContext.HasBufferedMessage = false;
                return(pipeWriter.FlushAsync().GetAsTask());
            }
            else
            {
                // Set flag so buffered message will be written at the end
                serverCallContext.HasBufferedMessage = true;
            }

            return(Task.CompletedTask);
        }
 public HttpContextStreamWriter(HttpContextServerCallContext context, Action <TResponse, SerializationContext> serializer)
 {
     _context    = context;
     _serializer = serializer;
     _writeLock  = new object();
 }
コード例 #24
0
 public HttpContextSerializationContext(HttpContextServerCallContext serverCallContext)
 {
     _serverCallContext = serverCallContext;
 }
        internal long MaxTimerDueTime = uint.MaxValue - 1; // Max System.Threading.Timer due time

        public LongTimeoutServerCallDeadlineManager(HttpContextServerCallContext serverCallContext) : base(serverCallContext)
        {
        }
コード例 #26
0
        public static Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush)
        {
            var serializationContext = serverCallContext.SerializationContext;

            serializer(response, serializationContext);
            var responsePayload = serializationContext.Payload;

            serializationContext.Payload = null;

            if (responsePayload == null)
            {
                return(Task.FromException(new InvalidOperationException("Serialization did not return a payload.")));
            }

            // Flush messages unless WriteOptions.Flags has BufferHint set
            var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint;

            return(pipeWriter.WriteMessageAsync(responsePayload, serverCallContext, flush));
        }
 public DefaultServerCallDeadlineManager(HttpContextServerCallContext serverCallContext) : base(serverCallContext)
 {
 }