private async Task ReadCredentials(HttpRequestMessage request) { // In C-Core the call credential auth metadata is only applied if the channel is secure // The equivalent in grpc-dotnet is only applying metadata if HttpClient is using TLS // HttpClient scheme will be HTTP if it is using H2C (HTTP2 without TLS) if (Channel.Address.Scheme == Uri.UriSchemeHttps) { var configurator = new DefaultCallCredentialsConfigurator(); if (Options.Credentials != null) { await GrpcProtocolHelpers.ReadCredentialMetadata(configurator, Channel, request, Method, Options.Credentials).ConfigureAwait(false); } if (Channel.CallCredentials?.Count > 0) { foreach (var credentials in Channel.CallCredentials) { await GrpcProtocolHelpers.ReadCredentialMetadata(configurator, Channel, request, Method, credentials).ConfigureAwait(false); } } } else { GrpcCallLog.CallCredentialsNotUsed(Logger); } }
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; } }
private void ValidateHeaders() { Log.ResponseHeadersReceived(Logger); Debug.Assert(HttpResponse != null); if (HttpResponse.StatusCode != HttpStatusCode.OK) { _headerValidationError = "Bad gRPC response. Expected HTTP status code 200. Got status code: " + (int)HttpResponse.StatusCode; } else if (HttpResponse.Content?.Headers.ContentType == null) { _headerValidationError = "Bad gRPC response. Response did not have a content-type header."; } else { var grpcEncoding = HttpResponse.Content.Headers.ContentType.ToString(); if (!GrpcProtocolHelpers.IsGrpcContentType(grpcEncoding)) { _headerValidationError = "Bad gRPC response. Invalid content-type value: " + grpcEncoding; } } if (_headerValidationError != null) { // Response is not valid gRPC // Clean up/cancel any pending operations DisposeCore(); throw new InvalidOperationException(_headerValidationError); } // Success! }
private HttpRequestMessage CreateHttpRequestMessage() { var message = new HttpRequestMessage(HttpMethod.Post, _uri); message.Version = new Version(2, 0); // User agent is optional but recommended message.Headers.UserAgent.Add(GrpcProtocolConstants.UserAgentHeader); // TE is required by some servers, e.g. C Core // A missing TE header results in servers aborting the gRPC call message.Headers.TE.Add(GrpcProtocolConstants.TEHeader); if (Options.Headers != null && Options.Headers.Count > 0) { foreach (var entry in Options.Headers) { // Deadline is set via CallOptions.Deadline if (entry.Key == GrpcProtocolConstants.TimeoutHeader) { continue; } var value = entry.IsBinary ? Convert.ToBase64String(entry.ValueBytes) : entry.Value; message.Headers.Add(entry.Key, value); } } if (_timeout != null) { message.Headers.Add(GrpcProtocolConstants.TimeoutHeader, GrpcProtocolHelpers.EncodeTimeout(Convert.ToInt64(_timeout.Value.TotalMilliseconds))); } return(message); }
public static Metadata BuildMetadata(HttpResponseHeaders responseHeaders) { var headers = new Metadata(); foreach (var header in responseHeaders) { // ASP.NET Core includes pseudo headers in the set of request headers // whereas, they are not in gRPC implementations. We will filter them // out when we construct the list of headers on the context. if (header.Key.StartsWith(':')) { continue; } // Exclude grpc related headers if (header.Key.StartsWith("grpc-", StringComparison.OrdinalIgnoreCase)) { continue; } else if (header.Key.EndsWith(Metadata.BinaryHeaderSuffix, StringComparison.OrdinalIgnoreCase)) { headers.Add(header.Key, GrpcProtocolHelpers.ParseBinaryHeader(string.Join(",", header.Value))); } else { headers.Add(header.Key, string.Join(",", header.Value)); } } return(headers); }
private void CreateWriter(HttpRequestMessage message) { RequestGrpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers); ClientStreamWriter = new HttpContentClientStreamWriter <TRequest, TResponse>(this); message.Content = new PushStreamContent <TRequest, TResponse>(ClientStreamWriter, GrpcProtocolConstants.GrpcContentTypeHeaderValue); }
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); }
private Status?ValidateHeaders(HttpResponseMessage httpResponse) { Log.ResponseHeadersReceived(Logger); if (httpResponse.StatusCode != HttpStatusCode.OK) { return(new Status(StatusCode.Cancelled, "Bad gRPC response. Expected HTTP status code 200. Got 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)); } else { // gRPC status can be returned in the header when there is no message (e.g. unimplemented status) if (GrpcProtocolHelpers.TryGetStatusCore(httpResponse.Headers, out var status)) { return(status); } } // Call is still in progress return(null); }
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; } }
private async Task <bool> MoveNextCore(CancellationToken cancellationToken) { CancellationTokenSource?cts = null; try { // Linking tokens is expensive. Only create a linked token if the token passed in requires it if (cancellationToken.CanBeCanceled) { cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _call.CancellationToken); cancellationToken = cts.Token; } else { cancellationToken = _call.CancellationToken; } cancellationToken.ThrowIfCancellationRequested(); if (_httpResponse == null) { Debug.Assert(_call.SendTask != null); await _call.SendTask.ConfigureAwait(false); Debug.Assert(_call.HttpResponse != null); _httpResponse = _call.HttpResponse; } if (_responseStream == null) { _responseStream = await _httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); } Current = await _responseStream.ReadStreamedMessageAsync( _call.Logger, _call.Method.ResponseMarshaller.ContextualDeserializer, GrpcProtocolHelpers.GetGrpcEncoding(_httpResponse), _call.Channel.ReceiveMaxMessageSize, _call.Channel.CompressionProviders, cancellationToken).ConfigureAwait(false); if (Current == null) { // No more content in response so mark as finished _call.FinishResponse(); return(false); } GrpcEventSource.Log.MessageReceived(); return(true); } catch (OperationCanceledException) { throw _call.CreateCanceledStatusException(); } finally { cts?.Dispose(); } }
private void SetMessageContent(TRequest request, HttpRequestMessage message) { message.Content = new PushUnaryContent <TRequest, TResponse>( request, this, GrpcProtocolHelpers.GetRequestEncoding(message.Headers), GrpcProtocolConstants.GrpcContentTypeHeaderValue); }
private HttpRequestMessage CreateHttpRequestMessage(TimeSpan?timeout) { var message = new HttpRequestMessage(HttpMethod.Post, _grpcMethodInfo.CallUri); message.Version = GrpcProtocolConstants.Http2Version; #if NET5_0 message.VersionPolicy = HttpVersionPolicy.RequestVersionOrHigher; #endif // Set raw headers on request using name/values. Typed headers allocate additional objects. var headers = message.Headers; // User agent is optional but recommended. headers.TryAddWithoutValidation(GrpcProtocolConstants.UserAgentHeader, GrpcProtocolConstants.UserAgentHeaderValue); // TE is required by some servers, e.g. C Core. // A missing TE header results in servers aborting the gRPC call. headers.TryAddWithoutValidation(GrpcProtocolConstants.TEHeader, GrpcProtocolConstants.TEHeaderValue); headers.TryAddWithoutValidation(GrpcProtocolConstants.MessageAcceptEncodingHeader, Channel.MessageAcceptEncoding); // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#exposed-retry-metadata if (_attemptCount > 1) { headers.TryAddWithoutValidation(GrpcProtocolConstants.RetryPreviousAttemptsHeader, (_attemptCount - 1).ToString(CultureInfo.InvariantCulture)); } if (Options.Headers != null && Options.Headers.Count > 0) { foreach (var entry in Options.Headers) { if (entry.Key == GrpcProtocolConstants.TimeoutHeader) { // grpc-timeout is set via CallOptions.Deadline continue; } else if (entry.Key == GrpcProtocolConstants.CompressionRequestAlgorithmHeader) { // grpc-internal-encoding-request is used in the client to set message compression. // 'grpc-encoding' is sent even if WriteOptions.Flags = NoCompress. In that situation // individual messages will not be written with compression. headers.TryAddWithoutValidation(GrpcProtocolConstants.MessageEncodingHeader, entry.Value); } else { GrpcProtocolHelpers.AddHeader(headers, entry); } } } if (timeout != null) { headers.TryAddWithoutValidation(GrpcProtocolConstants.TimeoutHeader, GrpcProtocolHelpers.EncodeTimeout(timeout.Value.Ticks / TimeSpan.TicksPerMillisecond)); } return(message); }
private void BuildMetadata(HttpResponseMessage httpResponse) { try { _metadataTcs.TrySetResult(GrpcProtocolHelpers.BuildMetadata(httpResponse.Headers)); } catch (Exception ex) { _metadataTcs.TrySetException(ex); } }
public HttpContentClientStreamWriter( GrpcCall <TRequest, TResponse> call, HttpRequestMessage message) { _call = call; WriteStreamTcs = new TaskCompletionSource <Stream>(TaskCreationOptions.RunContinuationsAsynchronously); CompleteTcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); _writeLock = new object(); WriteOptions = _call.Options.WriteOptions; _grpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers); }
/// <summary> /// Resolve the specified exception to an end-user exception that will be thrown from the client. /// The resolved exception is normally a RpcException. Returns true when the resolved exception is changed. /// </summary> internal bool ResolveException(string summary, Exception ex, [NotNull] out Status?status, out Exception resolvedException) { if (ex is OperationCanceledException) { status = (CallTask.IsCompletedSuccessfully()) ? CallTask.Result : new Status(StatusCode.Cancelled, string.Empty); if (!Channel.ThrowOperationCanceledOnCancellation) { resolvedException = CreateRpcException(status.Value); return(true); } } else if (ex is RpcException rpcException) { status = rpcException.Status; // If trailers have been set, and the RpcException isn't using them, then // create new RpcException with trailers. Want to try and avoid this as // the exact stack location will be lost. // // Trailers could be set in another thread so copy to local variable. var trailers = Trailers; if (trailers != null && rpcException.Trailers != trailers) { resolvedException = CreateRpcException(status.Value); return(true); } } else { var s = GrpcProtocolHelpers.CreateStatusFromException(summary, ex); // The server could exceed the deadline and return a CANCELLED status before the // client's deadline timer is triggered. When CANCELLED is received check the // deadline against the clock and change status to DEADLINE_EXCEEDED if required. if (s.StatusCode == StatusCode.Cancelled) { lock (this) { if (IsDeadlineExceededUnsynchronized()) { s = new Status(StatusCode.DeadlineExceeded, s.Detail, s.DebugException); } } } status = s; resolvedException = CreateRpcException(s); return(true); } resolvedException = ex; return(false); }
public HttpContentClientStreamWriter( GrpcCall <TRequest, TResponse> call, HttpRequestMessage message, Task <Stream> writeStreamTask, TaskCompletionSource <bool> completeTcs) { _call = call; _writeStreamTask = writeStreamTask; _completeTcs = completeTcs; _writeLock = new object(); WriteOptions = _call.Options.WriteOptions; _grpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers); }
public Metadata GetTrailers() { using (StartScope()) { if (_trailers == null) { ValidateTrailersAvailable(); Debug.Assert(HttpResponse != null); _trailers = GrpcProtocolHelpers.BuildMetadata(HttpResponse.TrailingHeaders); } return(_trailers); } }
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; } }
private void SetMessageContent(TRequest request, HttpRequestMessage message) { message.Content = new PushStreamContent( (stream) => { var grpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers); return(stream.WriteMessage <TRequest>( Logger, request, Method.RequestMarshaller.Serializer, grpcEncoding, Options.CancellationToken)); }, GrpcProtocolConstants.GrpcContentTypeHeaderValue); }
private HttpRequestMessage CreateHttpRequestMessage(TimeSpan?timeout) { var message = new HttpRequestMessage(HttpMethod.Post, _grpcMethodInfo.CallUri); message.Version = HttpVersion.Version20; // Set raw headers on request using name/values. Typed headers allocate additional objects. var headers = message.Headers; // User agent is optional but recommended. headers.Add(GrpcProtocolConstants.UserAgentHeader, GrpcProtocolConstants.UserAgentHeaderValue); // TE is required by some servers, e.g. C Core. // A missing TE header results in servers aborting the gRPC call. headers.Add(GrpcProtocolConstants.TEHeader, GrpcProtocolConstants.TEHeaderValue); headers.Add(GrpcProtocolConstants.MessageAcceptEncodingHeader, Channel.MessageAcceptEncoding); if (Options.Headers != null && Options.Headers.Count > 0) { foreach (var entry in Options.Headers) { if (entry.Key == GrpcProtocolConstants.TimeoutHeader) { // grpc-timeout is set via CallOptions.Deadline continue; } else if (entry.Key == GrpcProtocolConstants.CompressionRequestAlgorithmHeader) { // grpc-internal-encoding-request is used in the client to set message compression. // 'grpc-encoding' is sent even if WriteOptions.Flags = NoCompress. In that situation // individual messages will not be written with compression. headers.Add(GrpcProtocolConstants.MessageEncodingHeader, entry.Value); } else { GrpcProtocolHelpers.AddHeader(headers, entry); } } } if (timeout != null) { headers.Add(GrpcProtocolConstants.TimeoutHeader, GrpcProtocolHelpers.EncodeTimeout(timeout.Value.Ticks / TimeSpan.TicksPerMillisecond)); } return(message); }
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); }
public async Task <TResponse> GetResponseAsync() { Debug.Assert(SendTask != null); try { using (StartScope()) { await SendTask.ConfigureAwait(false); Debug.Assert(HttpResponse != null); // Trailers are only available once the response body had been read var responseStream = await HttpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); var message = await responseStream.ReadSingleMessageAsync( Logger, Method.ResponseMarshaller.ContextualDeserializer, GrpcProtocolHelpers.GetGrpcEncoding(HttpResponse), Channel.ReceiveMaxMessageSize, Channel.CompressionProviders, _callCts.Token).ConfigureAwait(false); FinishResponse(); if (message == null) { Log.MessageNotReturned(Logger); throw new InvalidOperationException("Call did not return a response message"); } GrpcEventSource.Log.MessageReceived(); // The task of this method is cached so there is no need to cache the message here return(message); } } catch (OperationCanceledException) { EnsureNotDisposed(); throw CreateCanceledStatusException(); } }
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); }
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); }
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); }
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; } } }
private void SetMessageContent(TRequest request, HttpRequestMessage message) { RequestGrpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers); if (!Channel.IsWinHttp) { message.Content = new PushUnaryContent <TRequest, TResponse>( request, this, GrpcProtocolConstants.GrpcContentTypeHeaderValue); } else { // WinHttp doesn't support streaming request data so a length needs to be specified. message.Content = new LengthUnaryContent <TRequest, TResponse>( request, this, GrpcProtocolConstants.GrpcContentTypeHeaderValue); } }
private bool IsCancellationOrDeadlineException(Exception ex) { // Don't log OperationCanceledException if deadline has exceeded // or the call has been canceled. if (ex is OperationCanceledException && _callTcs.Task.IsCompletedSuccessfully() && (_callTcs.Task.Result.StatusCode == StatusCode.DeadlineExceeded || _callTcs.Task.Result.StatusCode == StatusCode.Cancelled)) { return(true); } // Exception may specify RST_STREAM or abort code that resolves to cancellation. // If protocol error is cancellation and deadline has been exceeded then that // means the server canceled and the local deadline timer hasn't triggered. if (GrpcProtocolHelpers.ResolveRpcExceptionStatusCode(ex) == StatusCode.Cancelled) { return(true); } return(false); }
internal void ResolveException(string summary, Exception ex, [NotNull] out Status?status, out Exception resolvedException) { if (ex is OperationCanceledException) { status = (CallTask.IsCompletedSuccessfully) ? CallTask.Result : new Status(StatusCode.Cancelled, string.Empty); resolvedException = Channel.ThrowOperationCanceledOnCancellation ? ex : CreateRpcException(status.Value); } else if (ex is RpcException rpcException) { status = rpcException.Status; resolvedException = CreateRpcException(status.Value); } else { var exceptionMessage = CommonGrpcProtocolHelpers.ConvertToRpcExceptionMessage(ex); var statusCode = GrpcProtocolHelpers.ResolveRpcExceptionStatusCode(ex); status = new Status(statusCode, summary + " " + exceptionMessage, ex); resolvedException = CreateRpcException(status.Value); } }
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(); } }