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

                return(GrpcProtocolHelpers.IsGrpcContentType(httpContext.Request.ContentType));
            }
示例#3
0
        private ICompressionProvider?ResolveCompressionProvider()
        {
            if (_serverCallContext.ResponseGrpcEncoding != null &&
                GrpcProtocolHelpers.CanWriteCompressed(_serverCallContext.WriteOptions) &&
                _serverCallContext.Options.CompressionProviders.TryGetValue(_serverCallContext.ResponseGrpcEncoding, out var compressionProvider))
            {
                return(compressionProvider);
            }

            return(null);
        }
        public RequestDelegate CreateUnimplementedMethod()
        {
            var logger = _loggerFactory.CreateLogger <ServerCallHandlerFactory <TService> >();

            return(httpContext =>
            {
                GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response);

                var unimplementedMethod = httpContext.Request.RouteValues["unimplementedMethod"]?.ToString();
                Log.MethodUnimplemented(logger, unimplementedMethod);

                GrpcProtocolHelpers.SetStatusTrailers(httpContext.Response, new Status(StatusCode.Unimplemented, "Method is unimplemented."));
                return Task.CompletedTask;
            });
        }
        public RequestDelegate CreateUnimplementedService()
        {
            var logger = _loggerFactory.CreateLogger <ServerCallHandlerFactory <TService> >();

            return(httpContext =>
            {
                GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response);

                var unimplementedService = httpContext.Request.RouteValues["unimplementedService"]?.ToString() ?? "<unknown>";
                Log.ServiceUnimplemented(logger, unimplementedService);

                GrpcProtocolHelpers.SetStatus(GrpcProtocolHelpers.GetTrailersDestination(httpContext.Response), new Status(StatusCode.Unimplemented, "Service is unimplemented."));
                return Task.CompletedTask;
            });
        }
        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);
        }
        private TimeSpan GetTimeout()
        {
            if (HttpContext.Request.Headers.TryGetValue(GrpcProtocolConstants.TimeoutHeader, out var values))
            {
                // CancellationTokenSource does not support greater than int.MaxValue milliseconds
                if (GrpcProtocolHelpers.TryDecodeTimeout(values, out var timeout) &&
                    timeout > TimeSpan.Zero &&
                    timeout.TotalMilliseconds <= int.MaxValue)
                {
                    return(timeout);
                }

                InvalidTimeoutIgnored(_logger, values);
            }

            return(TimeSpan.Zero);
        }
示例#8
0
        private ICompressionProvider?ResolveCompressionProvider()
        {
            Debug.Assert(
                _serverCallContext.ResponseGrpcEncoding != null,
                "Response encoding should have been calculated at this point.");

            var canCompress =
                GrpcProtocolHelpers.CanWriteCompressed(_serverCallContext.WriteOptions) &&
                !string.Equals(_serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);

            if (canCompress)
            {
                if (_serverCallContext.Options.CompressionProviders.TryGetValue(_serverCallContext.ResponseGrpcEncoding, out var compressionProvider))
                {
                    return(compressionProvider);
                }
            }

            return(null);
        }
        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 void Initialize()
        {
            var timeout = GrpcProtocolHelpers.GetTimeout(HttpContext);

            if (timeout != TimeSpan.MaxValue)
            {
                // CancellationTokenSource does not support greater than int.MaxValue milliseconds
                if (timeout.TotalMilliseconds > int.MaxValue)
                {
                    throw new InvalidOperationException("A timeout greater than 2147483647 milliseconds is not supported.");
                }

                _deadline = Clock.UtcNow.Add(timeout);
                _cts      = new CancellationTokenSource(timeout);
            }
            else
            {
                _deadline = DateTime.MaxValue;
                _cts      = new CancellationTokenSource();
            }
        }
        public RequestDelegate CreateUnimplementedMethod()
        {
            var logger = _loggerFactory.CreateLogger <ServerCallHandlerFactory <TService> >();

            return(httpContext =>
            {
                // CORS preflight request should be handled by CORS middleware.
                // If it isn't then return 404 from endpoint request delegate.
                if (GrpcProtocolHelpers.IsCorsPreflightRequest(httpContext))
                {
                    httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
                    return Task.CompletedTask;
                }

                GrpcProtocolHelpers.AddProtocolHeaders(httpContext.Response);

                var unimplementedMethod = httpContext.Request.RouteValues["unimplementedMethod"]?.ToString() ?? "<unknown>";
                Log.MethodUnimplemented(logger, unimplementedMethod);
                GrpcEventSource.Log.CallUnimplemented(httpContext.Request.Path.Value);

                GrpcProtocolHelpers.SetStatus(GrpcProtocolHelpers.GetTrailersDestination(httpContext.Response), new Status(StatusCode.Unimplemented, "Method is unimplemented."));
                return Task.CompletedTask;
            });
        }
示例#12
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);
        }
示例#13
0
        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
            {
                GrpcServerLog.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.");
                }

                GrpcServerLog.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 canCompress =
                    GrpcProtocolHelpers.CanWriteCompressed(serverCallContext.WriteOptions) &&
                    !string.Equals(serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);

                var isCompressed = false;
                if (canCompress)
                {
                    Debug.Assert(
                        serverCallContext.ServiceOptions.ResolvedCompressionProviders != null,
                        "Compression providers should have been resolved for service.");

                    if (TryCompressMessage(
                            serverCallContext.Logger,
                            serverCallContext.ResponseGrpcEncoding !,
                            serverCallContext.ServiceOptions.ResponseCompressionLevel,
                            serverCallContext.ServiceOptions.ResolvedCompressionProviders,
                            responsePayload,
                            out var result))
                    {
                        responsePayload = result;
                        isCompressed    = true;
                    }
                }

                if (responsePayload.Length > serverCallContext.ServiceOptions.MaxSendMessageSize)
                {
                    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;
                }

                GrpcServerLog.MessageSent(serverCallContext.Logger);
                GrpcEventSource.Log.MessageSent();
            }
            catch (Exception ex)
            {
                GrpcServerLog.ErrorSendingMessage(logger, ex);
                throw;
            }
        }