< Summary

Information
Class: IceRpc.Compressor.CompressorMiddleware
Assembly: IceRpc.Compressor
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorMiddleware.cs
Tag: 2300_35243572715
Line coverage
95%
Covered lines: 40
Uncovered lines: 2
Coverable lines: 42
Total lines: 89
Line coverage: 95.2%
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%
DispatchAsync()94.44%1818100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Compressor/CompressorMiddleware.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 a middleware that decompresses the payloads of incoming requests and compresses the payloads of
 13/// outgoing responses.</summary>
 14/// <remarks>This middleware decompresses the payload of an incoming request when the request carries a
 15/// <see cref="RequestFieldKey.CompressionFormat" /> field with a supported compression format (currently
 16/// <see cref="CompressionFormat.Brotli" /> or <see cref="CompressionFormat.Deflate" />).<br/>
 17/// This middleware compresses the payload of a response and sets the <see cref="ResponseFieldKey.CompressionFormat" />
 18/// field when the request has the <see cref="ICompressFeature" /> feature set and the response's CompressionFormat
 19/// field is unset.</remarks>
 20/// <seealso cref="CompressorRouterExtensions"/>
 21/// <seealso cref="CompressorDispatcherBuilderExtensions"/>
 22public class CompressorMiddleware : IDispatcher
 23{
 24    private readonly CompressionFormat _compressionFormat;
 25    private readonly CompressionLevel _compressionLevel;
 26    private readonly ReadOnlySequence<byte> _encodedCompressionFormatValue;
 27    private readonly IDispatcher _next;
 28
 29    /// <summary>Constructs a Compressor middleware.</summary>
 30    /// <param name="next">The next dispatcher in the dispatch pipeline.</param>
 31    /// <param name="compressionFormat">The compression format for the compress operation.</param>
 32    /// <param name="compressionLevel">The compression level for the compress operation.</param>
 933    public CompressorMiddleware(
 934        IDispatcher next,
 935        CompressionFormat compressionFormat,
 936        CompressionLevel compressionLevel = CompressionLevel.Fastest)
 937    {
 938        _next = next;
 939        if (compressionFormat != CompressionFormat.Brotli && compressionFormat != CompressionFormat.Deflate)
 040        {
 041            throw new NotSupportedException($"The compression format '{compressionFormat}' is not supported.");
 42        }
 943        _compressionFormat = compressionFormat;
 944        _compressionLevel = compressionLevel;
 945        _encodedCompressionFormatValue = new(new byte[] { (byte)compressionFormat });
 946    }
 47
 48    /// <inheritdoc/>
 49    public async ValueTask<OutgoingResponse> DispatchAsync(
 50        IncomingRequest request,
 51        CancellationToken cancellationToken = default)
 952    {
 953        if (request.Protocol.HasFields && request.Fields.ContainsKey(RequestFieldKey.CompressionFormat))
 554        {
 555            CompressionFormat compressionFormat = request.Fields.DecodeValue(
 556                RequestFieldKey.CompressionFormat,
 1057                (ref SliceDecoder decoder) => decoder.DecodeCompressionFormat());
 58
 559            if (compressionFormat == CompressionFormat.Brotli)
 260            {
 261                request.Payload = PipeReader.Create(
 262                    new BrotliStream(request.Payload.AsStream(), CompressionMode.Decompress));
 263            }
 364            else if (compressionFormat == CompressionFormat.Deflate)
 265            {
 266                request.Payload = PipeReader.Create(
 267                    new DeflateStream(request.Payload.AsStream(), CompressionMode.Decompress));
 268            }
 69            // else nothing to do
 570        }
 71
 972        OutgoingResponse response = await _next.DispatchAsync(request, cancellationToken).ConfigureAwait(false);
 73
 74        // The ICompressFeature is typically set through the Slice compress attribute.
 75
 976        if (request.Protocol.HasFields &&
 977            response.StatusCode == StatusCode.Ok &&
 978            request.Features.Get<ICompressFeature>() is ICompressFeature compress &&
 979            compress.Value &&
 980            !response.Fields.ContainsKey(ResponseFieldKey.CompressionFormat))
 481        {
 882            response.Use(next => new CompressorPipeWriter(next, _compressionFormat, _compressionLevel));
 83
 484            response.Fields = response.Fields.With(ResponseFieldKey.CompressionFormat, _encodedCompressionFormatValue);
 485        }
 86
 987        return response;
 988    }
 89}