< Summary

Information
Class: IceRpc.Compressor.CompressorInterceptor
Assembly: IceRpc.Compressor
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorInterceptor.cs
Tag: 1321_24790053727
Line coverage
95%
Covered lines: 46
Uncovered lines: 2
Coverable lines: 48
Total lines: 96
Line coverage: 95.8%
Branch coverage
90%
Covered branches: 20
Total branches: 22
Branch coverage: 90.9%
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()94.44%1818100%

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.Diagnostics;
 7using System.IO.Compression;
 8using System.IO.Pipelines;
 9using ZeroC.Slice.Codec;
 10
 11namespace IceRpc.Compressor;
 12
 13/// <summary>Represents an interceptor that compresses the payloads of outgoing requests and decompresses the payloads
 14/// of incoming responses.</summary>
 15/// <remarks>This interceptor compresses the payload of a request and sets the
 16/// <see cref="RequestFieldKey.CompressionFormat" /> field when this request has the <see cref="ICompressFeature" />
 17/// feature set and the CompressionFormat field is unset.<br/>
 18/// This interceptor decompresses the payload of a response when this response's status code is
 19/// <see cref="StatusCode.Ok" /> and the response carries a <see cref="ResponseFieldKey.CompressionFormat" /> field
 20/// with a supported compression format (currently <see cref="CompressionFormat.Brotli" /> or
 21/// <see cref="CompressionFormat.Deflate" />).</remarks>
 22/// <seealso cref="CompressorPipelineExtensions"/>
 23/// <seealso cref="CompressorDispatcherBuilderExtensions"/>
 24public class CompressorInterceptor : IInvoker
 25{
 26    private readonly CompressionFormat _compressionFormat;
 27    private readonly CompressionLevel _compressionLevel;
 28    private readonly ReadOnlySequence<byte> _encodedCompressionFormatValue;
 29    private readonly IInvoker _next;
 30
 31    /// <summary>Constructs a Compressor interceptor.</summary>
 32    /// <param name="next">The next invoker in the invocation pipeline.</param>
 33    /// <param name="compressionFormat">The compression format for the compress operation.</param>
 34    /// <param name="compressionLevel">The compression level for the compress operation.</param>
 935    public CompressorInterceptor(
 936        IInvoker next,
 937        CompressionFormat compressionFormat,
 938        CompressionLevel compressionLevel = CompressionLevel.Fastest)
 939    {
 940        _next = next;
 941        if (compressionFormat != CompressionFormat.Brotli && compressionFormat != CompressionFormat.Deflate)
 042        {
 043            throw new NotSupportedException($"The compression format '{compressionFormat}' is not supported.");
 44        }
 945        _compressionFormat = compressionFormat;
 946        _compressionLevel = compressionLevel;
 947        _encodedCompressionFormatValue = new(new byte[] { (byte)compressionFormat });
 948    }
 49
 50    /// <inheritdoc/>
 51    public async Task<IncomingResponse> InvokeAsync(OutgoingRequest request, CancellationToken cancellationToken)
 952    {
 53        // The ICompressFeature is typically set through the Slice compress attribute.
 54
 955        if (request.Protocol.HasFields &&
 956            request.Features.Get<ICompressFeature>() is ICompressFeature compress &&
 957            compress.Value &&
 958            !request.Fields.ContainsKey(RequestFieldKey.CompressionFormat))
 459        {
 460            if (_compressionFormat == CompressionFormat.Brotli)
 261            {
 462                request.Use(next => PipeWriter.Create(new BrotliStream(next.AsStream(), _compressionLevel)));
 263            }
 64            else
 265            {
 266                Debug.Assert(_compressionFormat == CompressionFormat.Deflate);
 467                request.Use(next => PipeWriter.Create(new DeflateStream(next.AsStream(), _compressionLevel)));
 268            }
 69
 470            request.Fields = request.Fields.With(RequestFieldKey.CompressionFormat, _encodedCompressionFormatValue);
 471        }
 72
 973        IncomingResponse response = await _next.InvokeAsync(request, cancellationToken).ConfigureAwait(false);
 74
 975        if (request.Protocol.HasFields && response.StatusCode == StatusCode.Ok)
 976        {
 977            CompressionFormat compressionFormat = response.Fields.DecodeValue(
 978               ResponseFieldKey.CompressionFormat,
 1479               (ref SliceDecoder decoder) => decoder.DecodeCompressionFormat());
 80
 981            if (compressionFormat == CompressionFormat.Brotli)
 282            {
 283                response.Payload = PipeReader.Create(
 284                    new BrotliStream(response.Payload.AsStream(), CompressionMode.Decompress));
 285            }
 786            else if (compressionFormat == CompressionFormat.Deflate)
 287            {
 288                response.Payload = PipeReader.Create(
 289                    new DeflateStream(response.Payload.AsStream(), CompressionMode.Decompress));
 290            }
 91            // else nothing to do
 992        }
 93
 994        return response;
 995    }
 96}