< Summary

Information
Class: IceRpc.Compressor.CompressorInterceptor
Assembly: IceRpc.Compressor
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorInterceptor.cs
Tag: 2300_35243572715
Line coverage
95%
Covered lines: 39
Uncovered lines: 2
Coverable lines: 41
Total lines: 87
Line coverage: 95.1%
Branch coverage
90%
Covered branches: 18
Total branches: 20
Branch coverage: 90%
Method coverage
100%
Covered methods: 2
Fully covered methods: 1
Total methods: 2
Method coverage: 100%
Full method coverage: 50%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)75%4484.61%
InvokeAsync()93.75%1616100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorInterceptor.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Extensions.DependencyInjection;
 4using IceRpc.Features;
 5using System.Buffers;
 6using System.IO.Compression;
 7using System.IO.Pipelines;
 8using ZeroC.Slice.Codec;
 9
 10namespace IceRpc.Compressor;
 11
 12/// <summary>Represents an interceptor that compresses the payloads of outgoing requests and decompresses the payloads
 13/// of incoming responses.</summary>
 14/// <remarks>This interceptor compresses the payload of a request and sets the
 15/// <see cref="RequestFieldKey.CompressionFormat" /> field when this request has the <see cref="ICompressFeature" />
 16/// feature set and the CompressionFormat field is unset.<br/>
 17/// This interceptor decompresses the payload of a response when this response's status code is
 18/// <see cref="StatusCode.Ok" /> and the response carries a <see cref="ResponseFieldKey.CompressionFormat" /> field
 19/// with a supported compression format (currently <see cref="CompressionFormat.Brotli" /> or
 20/// <see cref="CompressionFormat.Deflate" />).</remarks>
 21/// <seealso cref="CompressorPipelineExtensions"/>
 22/// <seealso cref="CompressorDispatcherBuilderExtensions"/>
 23public class CompressorInterceptor : IInvoker
 24{
 25    private readonly CompressionFormat _compressionFormat;
 26    private readonly CompressionLevel _compressionLevel;
 27    private readonly ReadOnlySequence<byte> _encodedCompressionFormatValue;
 28    private readonly IInvoker _next;
 29
 30    /// <summary>Constructs a Compressor interceptor.</summary>
 31    /// <param name="next">The next invoker in the invocation pipeline.</param>
 32    /// <param name="compressionFormat">The compression format for the compress operation.</param>
 33    /// <param name="compressionLevel">The compression level for the compress operation.</param>
 1334    public CompressorInterceptor(
 1335        IInvoker next,
 1336        CompressionFormat compressionFormat,
 1337        CompressionLevel compressionLevel = CompressionLevel.Fastest)
 1338    {
 1339        _next = next;
 1340        if (compressionFormat != CompressionFormat.Brotli && compressionFormat != CompressionFormat.Deflate)
 041        {
 042            throw new NotSupportedException($"The compression format '{compressionFormat}' is not supported.");
 43        }
 1344        _compressionFormat = compressionFormat;
 1345        _compressionLevel = compressionLevel;
 1346        _encodedCompressionFormatValue = new(new byte[] { (byte)compressionFormat });
 1347    }
 48
 49    /// <inheritdoc/>
 50    public async Task<IncomingResponse> InvokeAsync(OutgoingRequest request, CancellationToken cancellationToken)
 1351    {
 52        // The ICompressFeature is typically set through the Slice compress attribute.
 53
 1354        if (request.Protocol.HasFields &&
 1355            request.Features.Get<ICompressFeature>() is ICompressFeature compress &&
 1356            compress.Value &&
 1357            !request.Fields.ContainsKey(RequestFieldKey.CompressionFormat))
 858        {
 1659            request.Use(next => new CompressorPipeWriter(next, _compressionFormat, _compressionLevel));
 60
 861            request.Fields = request.Fields.With(RequestFieldKey.CompressionFormat, _encodedCompressionFormatValue);
 862        }
 63
 1364        IncomingResponse response = await _next.InvokeAsync(request, cancellationToken).ConfigureAwait(false);
 65
 1366        if (request.Protocol.HasFields && response.StatusCode == StatusCode.Ok)
 1367        {
 1368            CompressionFormat compressionFormat = response.Fields.DecodeValue(
 1369               ResponseFieldKey.CompressionFormat,
 1870               (ref SliceDecoder decoder) => decoder.DecodeCompressionFormat());
 71
 1372            if (compressionFormat == CompressionFormat.Brotli)
 273            {
 274                response.Payload = PipeReader.Create(
 275                    new BrotliStream(response.Payload.AsStream(), CompressionMode.Decompress));
 276            }
 1177            else if (compressionFormat == CompressionFormat.Deflate)
 278            {
 279                response.Payload = PipeReader.Create(
 280                    new DeflateStream(response.Payload.AsStream(), CompressionMode.Decompress));
 281            }
 82            // else nothing to do
 1383        }
 84
 1385        return response;
 1386    }
 87}