Skip to content

InvalidOperationException when decompressed data exceeds request body size limit #61723

Open
@mus65

Description

@mus65

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 .

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions