< Summary

Information
Class: IceRpc.Deadline.DeadlineMiddleware
Assembly: IceRpc.Deadline
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Deadline/DeadlineMiddleware.cs
Tag: 275_13775359185
Line coverage
82%
Covered lines: 24
Uncovered lines: 5
Coverable lines: 29
Total lines: 67
Line coverage: 82.7%
Branch coverage
62%
Covered branches: 5
Total branches: 8
Branch coverage: 62.5%
Method coverage
100%
Covered methods: 3
Total methods: 3
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
DispatchAsync(...)62.5%9.37872.22%
PerformDispatchAsync()100%11100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Deadline/DeadlineMiddleware.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Extensions.DependencyInjection;
 4using IceRpc.Features;
 5using ZeroC.Slice;
 6
 7namespace IceRpc.Deadline;
 8
 9/// <summary>Represents a middleware that decodes deadline fields into deadline features. When the decoded deadline
 10/// expires, this middleware cancels the dispatch and returns an <see cref="OutgoingResponse" /> with status code
 11/// <see cref="StatusCode.DeadlineExceeded" />.</summary>
 12/// <seealso cref="DeadlineRouterExtensions"/>
 13/// <seealso cref="DeadlineDispatcherBuilderExtensions"/>
 14public class DeadlineMiddleware : IDispatcher
 15{
 16    private readonly IDispatcher _next;
 17
 18    /// <summary>Constructs a deadline middleware.</summary>
 19    /// <param name="next">The next dispatcher in the dispatch pipeline.</param>
 420    public DeadlineMiddleware(IDispatcher next) => _next = next;
 21
 22    /// <inheritdoc/>
 23    public ValueTask<OutgoingResponse> DispatchAsync(
 24        IncomingRequest request,
 25        CancellationToken cancellationToken = default)
 226    {
 227        TimeSpan? timeout = null;
 28
 29        // not found returns default == DateTime.MinValue.
 230        DateTime deadline = request.Fields.DecodeValue(
 231            RequestFieldKey.Deadline,
 432            (ref SliceDecoder decoder) => decoder.DecodeTimeStamp());
 33
 234        if (deadline != DateTime.MinValue)
 235        {
 236            timeout = deadline - DateTime.UtcNow;
 37
 238            if (timeout <= TimeSpan.Zero)
 039            {
 040                return new(new OutgoingResponse(
 041                    request,
 042                    StatusCode.DeadlineExceeded,
 043                    "The request deadline has expired."));
 44            }
 45
 246            request.Features = request.Features.With<IDeadlineFeature>(new DeadlineFeature(deadline));
 247        }
 48
 249        return timeout is null ? _next.DispatchAsync(request, cancellationToken) : PerformDispatchAsync(timeout.Value);
 50
 51        async ValueTask<OutgoingResponse> PerformDispatchAsync(TimeSpan timeout)
 252        {
 253            using var timeoutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 254            timeoutTokenSource.CancelAfter(timeout);
 55
 56            try
 257            {
 258                return await _next.DispatchAsync(request, timeoutTokenSource.Token).ConfigureAwait(false);
 59            }
 160            catch (OperationCanceledException exception) when (exception.CancellationToken == timeoutTokenSource.Token)
 161            {
 162                cancellationToken.ThrowIfCancellationRequested();
 163                return new OutgoingResponse(request, StatusCode.DeadlineExceeded, "The request deadline has expired.");
 64            }
 265        }
 266    }
 67}