Skip to content

[API Proposal]: ZstandardDecompressionOptions #128456

Description

@rzikm

Background and motivation

The new Zstandard APIs provide a way to configure the ZstandardEncoder with ZstandardCompressionOptions, but there is no symmetric options for ZstandardDecoder. This is problematic in case user wants to configure maxWindowLog on a decompressing ZstandardStream. Currently, it is possible by passing ZstandardStream a pre-configured ZstandardDecoder:

var decoder = new ZstandardDecoder(dictionary, maxWindowLog);
var stream = new ZstandardStream(decoder);

However, in this case, ZstandardStream does not own the ZstandardDecoder instance, and caller is responsible for disposing it (or reusing it in the future). But this may be difficult for some scenarios, consider e.g. ASP.NET Core decompression middleware:

 internal sealed class ZstandardDecompressionProvider : IDecompressionProvider
{
    /// <inheritdoc />
    public Stream GetDecompressionStream(Stream stream)
    {
        var decoder = new ZstandardDecoder(dictionary, maxWindowLog);
        return new ZstandardStream(stream, decoder, leaveOpen: true);
    }
}

There is no good way to tie the decoder's lifetime to the stream, except creating another wrapper stream, or leaving it to be GC'd.

API Proposal

namespace System.IO.Compression;

public class ZstandardDecompressionOptions
{
    public ZstandardDictionary? Dictionary { get; set; }

    // The maximum allowed window size when decompressing payloads, expressed as base 2 logarithm.
    // Value 0 indicates the implementation-defined default window size.
    // range from ZstandardCompressionOptions.MinWindowLog - MaxWindowLog
    public int MaxWindowLog { get; set; } 
}

public partial class ZstandardDecoder
{
    // not strictly necessary, other ctors can be used, but will complete the API symmetry with encoder options
    public ZstandardDecoder(ZstandardDecompressionOptions decompressionOptions);
}

public partial class ZstandardStream
{
    // symmetric to ZstandardStream(Stream! stream, ZstandardCompressionOptions! compressionOptions, bool leaveOpen = false);
    public ZstandardStream(Stream stream, ZstandardDecompressionOptions decompressionOptions, bool leaveOpen = false);
}

API Usage

ASP.NET Core can benefit from this and allow configuring maxWindowLog in incoming request decompression:

internal sealed class ZstandardDecompressionProvider : IDecompressionProvider
{
    // configured by the app code
    public ZstandardDecompressionOptions Options { get; set; }

    /// <inheritdoc />
    public Stream GetDecompressionStream(Stream stream)
    {
        // the stream now owns the lifetime of the internally created ZstandardDecoder.
        return new ZstandardStream(stream, Options, leaveOpen: true);
    }
}

Alternative Designs

Allow specifying whether ZstandardStream takes over the ownership of passed in ZstandardEncoder/Decoder:

public partial class ZstandardStream
{
    public ZstandardStream(Stream stream, ZstandardEncoder encoder, bool leaveOpen = false, bool shouldDisposeEncoder = false);
    public ZstandardStream(Stream stream, ZstandardDecoder decoder, bool leaveOpen = false, bool shouldDisposeDecoder = false);
}

Risks

None.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions