[API Proposal] Expose ZstandardDecompressionOptions
api-ready-for-reviewapi-proposal
## Background and Motivation
The ASP.NET Core request decompression middleware (`Microsoft.AspNetCore.RequestDecompression`) supports the Zstandard (`zstd`) content encoding. Today its zstd provider constructs the decoder with default settings and offers no way to configure decompression behavior.
[dotnet/runtime #129768](https://github.com/dotnet/runtime/pull/129768) adds a new `System.IO.Compression.ZstandardDecompressionOptions` type that lets callers configure the Zstandard decoder, most notably:
- `MaxWindowLog` — caps the maximum decompression window size (as a base‑2 logarithm). Limiting this helps mitigate decompression‑bomb denial‑of‑service attacks where a small payload declares a very large window and forces the server to allocate a large amount of memory.
- `Dictionary` — enables dictionary‑based decompression.
The response compression middleware already exposes a symmetric `ZstandardCompressionProviderOptions`. This proposal adds the decompression counterpart so servers can configure the zstd decoder used when decompressing request bodies, following the same `IOptions<>`/DI pattern.
## Proposed API
```diff
namespace Microsoft.AspNetCore.RequestDecompression;
+ /// <summary>
+ /// Options for the Zstandard (zstd) request decompression provider.
+ /// </summary>
+ public class ZstandardDecompressionProviderOptions : IOptions<ZstandardDecompressionProviderOptions>
+ {
+ public ZstandardDecompressionProviderOptions();
+
+ /// <summary>
+ /// The decompression options to use for the stream.
+ /// </summary>
+ public System.IO.Compression.ZstandardDecompressionOptions DecompressionOptions { get; set; }
+ }
```
This depends on the new `System.IO.Compression.ZstandardDecompressionOptions` runtime type from [dotnet/runtime #129768](https://github.com/dotnet/runtime/pull/129768).
We'll make `DecompressionOptions` default to `MaxWindowLog = 23` (8 MB) per RFC see below.
## Usage Examples
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRequestDecompression();
// Raise the maximum Zstandard window size accepted from clients to 2^24 bytes (16 MB). Requests whose zstd
// frame declares a larger window are rejected with an InvalidDataException.
builder.Services.Configure<ZstandardDecompressionProviderOptions>(options =>
{
options.DecompressionOptions.MaxWindowLog = 24;
});
var app = builder.Build();
app.UseRequestDecompression();
app.Run();
```
## Alternative Designs
- **Expose the raw `ZstandardDecompressionOptions` directly on `RequestDecompressionOptions`** (e.g., a `ZstandardOptions` property configured inside `AddRequestDecompression(options => ...)`). This is simpler but inconsistent with the existing `Microsoft.AspNetCore.ResponseCompression.ZstandardCompressionProviderOptions`, which is a dedicated provider-options type resolved from DI via `IOptions<>`. The proposed shape mirrors the response side so request and response zstd configuration look and behave the same, and so the default providers (and their options) can be resolved from DI through the provider factory.
- **Analogous APIs:** This is the direct decompression analogue of the, shipping in 11.0, `ZstandardCompressionProviderOptions` (response compression), which wraps `ZstandardCompressionOptions` in the same way.
## Risks
- **No breaking change.** Zstandard request decompression is new in 11.0 and has not shipped, so introducing these options and defaulting `MaxWindowLog` to `23` (an 8 MB window) does not change any previously shipped behavior.
- **MaxWindowLog limits the advertised window, not the decompressed size.** The window size is a property of how a payload was compressed and is recorded in the zstd frame header; it is independent of how large the data actually decompresses to. As a consequence, a request body that decompresses to well under the default request body size limit (30 MB) but was produced by an encoder that advertised a large window (for example 128 MB, i.e. window log 27) will be rejected with an InvalidDataException if the configured MaxWindowLog is lower. Picking a default therefore trades DoS protection against rejecting otherwise-small payloads from clients that use large windows - it is deliberately not derived from the request body size limit.
- **The default aligns with the HTTP standard and with browsers.** [RFC 9659](https://www.rfc-editor.org/rfc/rfc9659.html#section-3) ("Window Sizing for Zstandard Content Encoding", which updates RFC 8878) makes an 8 MB window a requirement for the zstd HTTP content coding: decoders MUST support windows up to 8 MB and encoders MUST NOT generate frames requiring more. Browsers enforce exactly this - for example, Chromium sets `ZSTD_d_windowLogMax = 23` in [net/filter/zstd_source_stream.cc](https://source.chromium.org/chromium/chromium/src/+/main:net/filter/zstd_source_stream.cc). Defaulting to 23 puts the middleware on the same contract: it accepts every standards-compliant client — and any encoder at default settings, which advertise windows of 2 MB or less - and rejects only deliberately oversized windows (such as `zstd --long`, which defaults to a 128 MB / window-log-27 window).
1 条评论