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); } }
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(); }
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(); }
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(); }
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(); }
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); }
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); }
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); }
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)); }
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)); }
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; } }
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; } }
public HttpContextStreamReader(HttpContextServerCallContext serverCallContext, Func <DeserializationContext, TRequest> deserializer) { _serverCallContext = serverCallContext; _deserializer = deserializer; }
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; } }
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; } }
public HttpContextStreamWriter(HttpContextServerCallContext context, GrpcServiceOptions serviceOptions, Func <TResponse, byte[]> serializer) { _context = context; _serviceOptions = serviceOptions; _serializer = serializer; }
public HttpContextStreamWriter(HttpContextServerCallContext context, Func <TResponse, byte[]> serializer) { _context = context; _serializer = serializer; }
private static async Task WriteMessageCoreAsyncAwaited(this PipeWriter pipeWriter, byte[] messageData, HttpContextServerCallContext serverCallContext, bool flush, Task startAsyncTask) { await startAsyncTask; await pipeWriter.WriteMessageCoreAsync(messageData, serverCallContext, flush); }
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); }
public HttpContextStreamReader(HttpContext context, HttpContextServerCallContext serverCallContext, Func <byte[], TRequest> deserializer) { _httpContext = context; _serverCallContext = serverCallContext; _deserializer = deserializer; }
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); }
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(); }
public HttpContextSerializationContext(HttpContextServerCallContext serverCallContext) { _serverCallContext = serverCallContext; }
internal long MaxTimerDueTime = uint.MaxValue - 1; // Max System.Threading.Timer due time public LongTimeoutServerCallDeadlineManager(HttpContextServerCallContext serverCallContext) : base(serverCallContext) { }
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) { }