diff --git a/aspnetcore/fundamentals/middleware/index.md b/aspnetcore/fundamentals/middleware/index.md index c857774abcdb..e9eac056cc53 100644 --- a/aspnetcore/fundamentals/middleware/index.md +++ b/aspnetcore/fundamentals/middleware/index.md @@ -260,6 +260,7 @@ ASP.NET Core ships with the following middleware components. The *Order* column | [HTTP Strict Transport Security (HSTS)](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) | Security enhancement middleware that adds a special response header. | Before responses are sent and after components that modify requests. Examples: Forwarded Headers, URL Rewriting. | | [MVC](xref:mvc/overview) | Processes requests with MVC/Razor Pages. | Terminal if a request matches a route. | | [OWIN](xref:fundamentals/owin) | Interop with OWIN-based apps, servers, and middleware. | Terminal if the OWIN Middleware fully processes the request. | +| [Request Decompression](xref:fundamentals/middleware/request-decompression) | Provides support for decompressing requests. | Before components that read the request body. | | [Response Caching](xref:performance/caching/middleware) | Provides support for caching responses. | Before components that require caching. `UseCORS` must come before `UseResponseCaching`.| | [Response Compression](xref:performance/response-compression) | Provides support for compressing responses. | Before components that require compression. | | [Request Localization](xref:fundamentals/localization) | Provides localization support. | Before localization sensitive components. Must appear after Routing Middleware when using . | diff --git a/aspnetcore/fundamentals/middleware/request-decompression.md b/aspnetcore/fundamentals/middleware/request-decompression.md new file mode 100644 index 000000000000..47e669f7efa8 --- /dev/null +++ b/aspnetcore/fundamentals/middleware/request-decompression.md @@ -0,0 +1,83 @@ +--- +title: Request Decompression in ASP.NET Core +author: david-acker +description: Learn how to use the request decompression middleware in ASP.NET Core +monikerRange: '>= aspnetcore-7.0' +ms.author: riande +ms.date: 8/17/2022 +uid: fundamentals/middleware/request-decompression +--- +# Request decompression in ASP.NET Core + +By [David Acker](https://github.com/david-acker) + +Request decompression middleware: + +* Enables API endpoints to accept requests with compressed content. +* Uses the [`Content-Encoding`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Encoding) HTTP header to automatically identify and decompress requests which contain compressed content. +* Eliminates the need to write code to handle compressed requests. + +When the `Content-Encoding` header value on a request matches one of the available decompression providers, the middleware: + +* Uses the matching provider to wrap the in an appropriate decompression stream. +* Removes the `Content-Encoding` header, indicating that the request body is no longer compressed. + +Requests that don't include a `Content-Encoding` header are ignored by the request decompression middleware. + +Decompression: + +* Occurs when the body of the request is being read. That is, decompression occurs at the endpoint on model binding. The request body is not decompressed eagerly. +* When attempting to read the decompressed request body, if the compressed data is invalid for the specified `Content-Encoding`, an exception is thrown. + +If the middleware encounters a request with compressed content but is unable to decompress it, the request is passed to the next delegate in the pipeline. For example, a request with an unsupported `Content-Encoding` header value or multiple `Content-Encoding` header values, is passed to the next delegate in the pipeline. For example, Brotli can throw `System.InvalidOperationException:` Decoder ran into invalid data, Deflate and GZip can throw `System.IO.InvalidDataException`: The archive entry was compressed using an unsupported compression method. + +## Configuration + +The following code shows how to enable request decompression for the [default](#default) `Content-Encoding` types: + +[!code-csharp[](samples/request-decompression/7.x/Program.cs?name=snippet_WithDefaultProviders&highlight=3,7)] + + + +## Default decompression providers + +The `Content-Encoding` header values that the request decompression middleware supports by default are listed in the following table: + +| [`Content-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) header values | Description | +| --------- | --------- | +| `br` | [Brotli compressed data format](https://tools.ietf.org/html/rfc7932) | +| `deflate` | [DEFLATE compressed data format](https://tools.ietf.org/html/rfc1951) | +| `gzip` | [Gzip file format](https://tools.ietf.org/html/rfc1952) | + +## Custom decompression providers + +Support for custom encodings can be added by creating custom decompression provider classes that implement : + +[!code-csharp[](samples/request-decompression/7.x/CustomDecompressionProvider.cs?name=snippet_CustomDecompressionProvider)] + +Custom decompression providers are registered with along with their corresponding `Content-Encoding` header values: + +[!code-csharp[](samples/request-decompression/7.x/Program.cs?name=snippet_WithCustomProvider&highlight=3-6,10)] + +## Request size limits + +In order to guard against [zip bombs or decompression bombs](https://en.wikipedia.org/wiki/Zip_bomb): + +* The maximum size of the decompressed request body is limited to the request body size limit enforced by the endpoint or server. +* If the number of bytes read from the decompressed request body stream exceeds the limit, an [InvalidOperationException](xref:System.InvalidOperationException) is thrown to prevent additional bytes from being read from the stream. + +The maximum request size for an endpoint is set by: + +* , such as or for MVC endpoints. +* The global server size limit . If not set, [`MaxRequestBodySize`](https://github.com/dotnet/aspnetcore/blob/197c1693d3c830af52b587e8d88891bc9689be44/src/Servers/Kestrel/Core/src/KestrelServerLimits.cs#L148-L157) uses the [default value](https://github.com/dotnet/aspnetcore/blob/197c1693d3c830af52b587e8d88891bc9689be44/src/Servers/Kestrel/Core/src/KestrelServerLimits.cs#L153). `MaxRequestBodySize` can be overridden per request with [`IHttpMaxRequestBodySizeFeature.MaxRequestBodySize`](xref:Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature.MaxRequestBodySize) + +> [!WARNING] +> Disabling the request body size limit poses a security risk in regards to uncontrolled resource consumption, particularly if the request body is being buffered. Ensure that safeguards are in place to mitigate the risk of [denial-of-service](https://www.cisa.gov/uscert/ncas/tips/ST04-015) (DoS) attacks. + +## Additional Resources + +* +* [Mozilla Developer Network: Content-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) +* [Brotli Compressed Data Format](https://www.rfc-editor.org/rfc/rfc7932) +* [DEFLATE Compressed Data Format Specification version 1.3](https://www.rfc-editor.org/rfc/rfc1951) +* [GZIP file format specification version 4.3](https://www.rfc-editor.org/rfc/rfc1952) diff --git a/aspnetcore/fundamentals/middleware/samples/readme.txt b/aspnetcore/fundamentals/middleware/samples/readme.txt deleted file mode 100644 index ee57ae4b26b5..000000000000 --- a/aspnetcore/fundamentals/middleware/samples/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Delete this file after writing sample for [#26541](https://github.com/dotnet/AspNetCore.Docs/issues/26541) diff --git a/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/CustomDecompressionProvider.cs b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/CustomDecompressionProvider.cs new file mode 100644 index 000000000000..58dedc929e12 --- /dev/null +++ b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/CustomDecompressionProvider.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.RequestDecompression; + +namespace RequestDecompressionSample; + +#region snippet_CustomDecompressionProvider +public class CustomDecompressionProvider : IDecompressionProvider +{ + public Stream GetDecompressionStream(Stream stream) + { + // Perform custom decompression logic here + return stream; + } +} +#endregion diff --git a/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/Program.cs b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/Program.cs new file mode 100644 index 000000000000..ee7775fe32a8 --- /dev/null +++ b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/Program.cs @@ -0,0 +1,37 @@ +#define WithDefaultProviders // WithDefaultProviders WithCustomProvider + +using Microsoft.AspNetCore.Http.HttpResults; +using RequestDecompressionSample; + +#if WithDefaultProviders +#region snippet_WithDefaultProviders +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddRequestDecompression(); + +var app = builder.Build(); + +app.UseRequestDecompression(); + +app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body)); + +app.Run(); +#endregion +#elif WithCustomProvider +#region snippet_WithCustomProvider +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddRequestDecompression(options => +{ + options.DecompressionProviders.Add("custom", new CustomDecompressionProvider()); +}); + +var app = builder.Build(); + +app.UseRequestDecompression(); + +app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body)); + +app.Run(); +#endregion +#endif diff --git a/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/RequestDecompressionSample.csproj b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/RequestDecompressionSample.csproj new file mode 100644 index 000000000000..f1fe53268f8d --- /dev/null +++ b/aspnetcore/fundamentals/middleware/samples/request-decompression/7.x/RequestDecompressionSample.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + \ No newline at end of file