Exemplo n.º 1
0
        private async Task <Metadata> GetResponseHeadersCoreAsync()
        {
            Debug.Assert(_httpResponseTask != null);

            try
            {
                var httpResponse = await _httpResponseTask.ConfigureAwait(false);

                // Check if the headers have a status. If they do then wait for the overall call task
                // to complete before returning headers. This means that if the call failed with a
                // a status then it is possible to await response headers and then call GetStatus().
                var grpcStatus = GrpcProtocolHelpers.GetHeaderValue(httpResponse.Headers, GrpcProtocolConstants.StatusTrailer);
                if (grpcStatus != null)
                {
                    await CallTask.ConfigureAwait(false);
                }

                return(GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers));
            }
            catch (Exception ex)
            {
                ResolveException(ex, out _, out var resolvedException);
                throw resolvedException;
            }
        }
Exemplo n.º 2
0
        private Status?ValidateHeaders(HttpResponseMessage httpResponse)
        {
            GrpcCallLog.ResponseHeadersReceived(Logger);

            // gRPC status can be returned in the header when there is no message (e.g. unimplemented status)
            // An explicitly specified status header has priority over other failing statuses
            if (GrpcProtocolHelpers.TryGetStatusCore(httpResponse.Headers, out var status))
            {
                // Trailers are in the header because there is no message.
                // Note that some default headers will end up in the trailers (e.g. Date, Server).
                _trailers = GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers);
                return(status);
            }

            if (httpResponse.StatusCode != HttpStatusCode.OK)
            {
                var statusCode = MapHttpStatusToGrpcCode(httpResponse.StatusCode);
                return(new Status(statusCode, "Bad gRPC response. HTTP status code: " + (int)httpResponse.StatusCode));
            }

            if (httpResponse.Content?.Headers.ContentType == null)
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Response did not have a content-type header."));
            }

            var grpcEncoding = httpResponse.Content.Headers.ContentType;

            if (!GrpcProtocolHelpers.IsGrpcContentType(grpcEncoding))
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Invalid content-type value: " + grpcEncoding));
            }

            // Call is still in progress
            return(null);
        }
Exemplo n.º 3
0
        private async Task <Metadata> GetResponseHeadersCoreAsync()
        {
            CompatibilityExtensions.Assert(_httpResponseTask != null);

            try
            {
                var httpResponse = await _httpResponseTask.ConfigureAwait(false);

                // Check if the headers have a status. If they do then wait for the overall call task
                // to complete before returning headers. This means that if the call failed with a
                // a status then it is possible to await response headers and then call GetStatus().
                var grpcStatus = GrpcProtocolHelpers.GetHeaderValue(httpResponse.Headers, GrpcProtocolConstants.StatusTrailer);
                if (grpcStatus != null)
                {
                    await CallTask.ConfigureAwait(false);
                }

                var metadata = GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers);

                // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#exposed-retry-metadata
                if (_attemptCount > 1)
                {
                    metadata.Add(GrpcProtocolConstants.RetryPreviousAttemptsHeader, (_attemptCount - 1).ToString(CultureInfo.InvariantCulture));
                }

                return(metadata);
            }
            catch (Exception ex) when(ResolveException(ErrorStartingCallMessage, ex, out _, out var resolvedException))
            {
                throw resolvedException;
            }
        }
Exemplo n.º 4
0
 private void BuildMetadata(HttpResponseMessage httpResponse)
 {
     try
     {
         _metadataTcs.TrySetResult(GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers));
     }
     catch (Exception ex)
     {
         _metadataTcs.TrySetException(ex);
     }
 }
Exemplo n.º 5
0
        public Metadata GetTrailers()
        {
            using (StartScope())
            {
                if (_trailers == null)
                {
                    ValidateTrailersAvailable();

                    Debug.Assert(HttpResponse != null);
                    _trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.TrailingHeaders);
                }

                return(_trailers);
            }
        }
Exemplo n.º 6
0
        private async Task <Metadata> GetResponseHeadersCoreAsync()
        {
            Debug.Assert(_httpResponseTask != null);

            try
            {
                var httpResponse = await _httpResponseTask.ConfigureAwait(false);

                return(GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers));
            }
            catch (Exception ex)
            {
                ResolveException(ex, out _, out var resolvedException);
                throw resolvedException;
            }
        }
Exemplo n.º 7
0
        private bool TryGetTrailers([NotNullWhen(true)] out Metadata?trailers)
        {
            if (_trailers == null)
            {
                // Trailers are read from the end of the request.
                // If the request isn't finished then we can't get the trailers.
                if (!ResponseFinished)
                {
                    trailers = null;
                    return(false);
                }

                Debug.Assert(HttpResponse != null);
                _trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.TrailingHeaders);
            }

            trailers = _trailers;
            return(true);
        }
Exemplo n.º 8
0
        internal static Status?ValidateHeaders(HttpResponseMessage httpResponse, out Metadata?trailers)
        {
            // gRPC status can be returned in the header when there is no message (e.g. unimplemented status)
            // An explicitly specified status header has priority over other failing statuses
            if (GrpcProtocolHelpers.TryGetStatusCore(httpResponse.Headers, out var status))
            {
                // Trailers are in the header because there is no message.
                // Note that some default headers will end up in the trailers (e.g. Date, Server).
                trailers = GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers);
                return(status);
            }

            trailers = null;

            // ALPN negotiation is sending HTTP/1.1 and HTTP/2.
            // Check that the response wasn't downgraded to HTTP/1.1.
            if (httpResponse.Version < GrpcProtocolConstants.Http2Version)
            {
                return(new Status(StatusCode.Internal, $"Bad gRPC response. Response protocol downgraded to HTTP/{httpResponse.Version.ToString(2)}."));
            }

            if (httpResponse.StatusCode != HttpStatusCode.OK)
            {
                var statusCode = MapHttpStatusToGrpcCode(httpResponse.StatusCode);
                return(new Status(statusCode, "Bad gRPC response. HTTP status code: " + (int)httpResponse.StatusCode));
            }

            // Don't access Headers.ContentType property because it is not threadsafe.
            var contentType = GrpcProtocolHelpers.GetHeaderValue(httpResponse.Content?.Headers, "Content-Type");

            if (contentType == null)
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Response did not have a content-type header."));
            }

            if (!CommonGrpcProtocolHelpers.IsContentType(GrpcProtocolConstants.GrpcContentType, contentType))
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Invalid content-type value: " + contentType));
            }

            // Call is still in progress
            return(null);
        }
Exemplo n.º 9
0
        protected bool TryGetTrailers([NotNullWhen(true)] out Metadata?trailers)
        {
            if (Trailers == null)
            {
                // Trailers are read from the end of the request.
                // If the request isn't finished then we can't get the trailers.
                if (!ResponseFinished)
                {
                    trailers = null;
                    return(false);
                }

                CompatibilityExtensions.Assert(HttpResponse != null);
                Trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.TrailingHeaders());
            }

            trailers = Trailers;
            return(true);
        }
Exemplo n.º 10
0
        private Status?ValidateHeaders(HttpResponseMessage httpResponse)
        {
            GrpcCallLog.ResponseHeadersReceived(Logger);

            // gRPC status can be returned in the header when there is no message (e.g. unimplemented status)
            // An explicitly specified status header has priority over other failing statuses
            if (GrpcProtocolHelpers.TryGetStatusCore(httpResponse.Headers, out var status))
            {
                // Trailers are in the header because there is no message.
                // Note that some default headers will end up in the trailers (e.g. Date, Server).
                _trailers = GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers);
                return(status);
            }

            // ALPN negotiation is sending HTTP/1.1 and HTTP/2.
            // Check that the response wasn't downgraded to HTTP/1.1.
            if (httpResponse.Version < HttpVersion.Version20)
            {
                return(new Status(StatusCode.Internal, $"Bad gRPC response. Response protocol downgraded to HTTP/{httpResponse.Version.ToString(2)}."));
            }

            if (httpResponse.StatusCode != HttpStatusCode.OK)
            {
                var statusCode = MapHttpStatusToGrpcCode(httpResponse.StatusCode);
                return(new Status(statusCode, "Bad gRPC response. HTTP status code: " + (int)httpResponse.StatusCode));
            }

            if (httpResponse.Content?.Headers.ContentType == null)
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Response did not have a content-type header."));
            }

            var grpcEncoding = httpResponse.Content.Headers.ContentType;

            if (!CommonGrpcProtocolHelpers.IsContentType(GrpcProtocolConstants.GrpcContentType, grpcEncoding?.MediaType))
            {
                return(new Status(StatusCode.Cancelled, "Bad gRPC response. Invalid content-type value: " + grpcEncoding));
            }

            // Call is still in progress
            return(null);
        }
Exemplo n.º 11
0
        private async Task <Metadata> GetResponseHeadersCoreAsync()
        {
            try
            {
                var httpResponse = await HttpResponseTask.ConfigureAwait(false);

                // Check if the headers have a status. If they do then wait for the overall call task
                // to complete before returning headers. This means that if the call failed with a
                // a status then it is possible to await response headers and then call GetStatus().
                var grpcStatus = GrpcProtocolHelpers.GetHeaderValue(httpResponse.Headers, GrpcProtocolConstants.StatusTrailer);
                if (grpcStatus != null)
                {
                    await CallTask.ConfigureAwait(false);
                }

                var metadata = GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers);

                // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#exposed-retry-metadata
                if (_attemptCount > 1)
                {
                    metadata.Add(GrpcProtocolConstants.RetryPreviousAttemptsHeader, (_attemptCount - 1).ToString(CultureInfo.InvariantCulture));
                }

                return(metadata);
            }
            catch (Exception ex)
            {
                // If there was an error fetching response headers then it's likely the same error is reported
                // by response TCS. The user is unlikely to observe both errors.
                // Observe the task's exception to prevent TaskScheduler.UnobservedTaskException from firing.
                _responseTcs?.Task.ObserveException();

                if (ResolveException(ErrorStartingCallMessage, ex, out _, out var resolvedException))
                {
                    throw resolvedException;
                }
                else
                {
                    throw;
                }
            }
        }
Exemplo n.º 12
0
        public async Task <Metadata> GetResponseHeadersAsync()
        {
            Debug.Assert(SendTask != null);

            try
            {
                using (StartScope())
                {
                    await SendTask.ConfigureAwait(false);

                    Debug.Assert(HttpResponse != null);

                    // The task of this method is cached so there is no need to cache the headers here
                    return(GrpcProtocolHelpers.BuildMetadata(HttpResponse.Headers));
                }
            }
            catch (OperationCanceledException) when(!Channel.ThrowOperationCanceledOnCancellation)
            {
                throw CreateCanceledStatusException();
            }
        }