Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
When using the request decompression middleware and the compressed body is below the request body size limit, but the decompressed body exceeds it, the request fails with an InvalidOperationException
and returns HTTP Status 500 instead of 413 (Content Too Large).
Without compression or if the compressed body already exceeds the limit, this internally causes a BadHttpRequestException
with StatusCode 413 which can properly be handled in a middleware. I would expect the same behaviour here instead of an InvalidOperationException
which cannot be handled properly.
The SizeLimitedStream
that throws the exception was introduced as part of #40279 .
Expected Behavior
Same behaviour as without compression, meaning a BadHttpRequestException
with StatusCode 413.
Steps To Reproduce
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRequestDecompression();
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.Limits.MaxRequestBodySize = 30;
});
var app = builder.Build();
app.UseRequestDecompression();
app.MapPost("/", ([FromBody]string foo) => foo);
app.Run();
Then run:
echo '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' | gzip | curl -v -i --data-binary @- -H "Content-Encoding: gzip" -H "Content-Type: application/json" http://localhost:5146/
which results in:
* Host localhost:5146 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:5146...
* Connected to localhost (::1) port 5146
* using HTTP/1.x
> POST / HTTP/1.1
> Host: localhost:5146
> User-Agent: curl/8.11.0
> Accept: */*
> Content-Encoding: gzip
> Content-Type: application/json
> Content-Length: 26
>
* upload completely sent off: 26 bytes
< HTTP/1.1 500 Internal Server Error
HTTP/1.1 500 Internal Server Error
< Content-Type: text/plain; charset=utf-8
Content-Type: text/plain; charset=utf-8
< Date: Mon, 28 Apr 2025 13:16:25 GMT
Date: Mon, 28 Apr 2025 13:16:25 GMT
< Server: Kestrel
Server: Kestrel
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
<
System.InvalidOperationException: The maximum number of bytes have been read.
at SizeLimitedStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at System.Text.Json.Serialization.ReadBufferState.ReadFromStreamAsync(Stream utf8Json, CancellationToken cancellationToken, Boolean fillBuffer)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass102_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.RequestDecompression.RequestDecompressionMiddleware.InvokeCore(HttpContext context, Stream decompressionStream)
at Microsoft.AspNetCore.RequestDecompression.RequestDecompressionMiddleware.InvokeCore(HttpContext context, Stream decompressionStream)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: localhost:5146
User-Agent: curl/8.11.0
Content-Type: application/json
Content-Length: 26
* Connection #0 to host localhost left intact
Exceptions (if any)
System.InvalidOperationException: The maximum number of bytes have been read.
at SizeLimitedStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at System.Text.Json.Serialization.ReadBufferState.ReadFromStreamAsync(Stream utf8Json, CancellationToken cancellationToken, Boolean fillBuffer)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass102_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.RequestDecompression.RequestDecompressionMiddleware.InvokeCore(HttpContext context, Stream decompressionStream)
at Microsoft.AspNetCore.RequestDecompression.RequestDecompressionMiddleware.InvokeCore(HttpContext context, Stream decompressionStream)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
.NET Version
10.0.100-preview.3.25201.16
Anything else?
Reproducible with .NET 9.0.4 and .NET 10 Preview 3 .