Skip to content

Commit 7e446c6

Browse files
authored
Throw BadHttpRequestException when decompressed data exceeds request body size limit (#61812)
1 parent c5625e5 commit 7e446c6

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

src/Middleware/RequestDecompression/src/RequestDecompressionMiddleware.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ private async Task InvokeCore(HttpContext context, Stream decompressionStream)
6262
context.GetEndpoint()?.Metadata?.GetMetadata<IRequestSizeLimitMetadata>()?.MaxRequestBodySize
6363
?? context.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize;
6464

65-
context.Request.Body = new SizeLimitedStream(decompressionStream, sizeLimit);
65+
context.Request.Body = new SizeLimitedStream(decompressionStream, sizeLimit, static (long sizeLimit) => throw new BadHttpRequestException(
66+
$"The decompressed request body is larger than the request body size limit {sizeLimit}.",
67+
StatusCodes.Status413PayloadTooLarge));
6668
await _next(context);
6769
}
6870
finally

src/Middleware/RequestDecompression/test/RequestDecompressionMiddlewareTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,8 +499,8 @@ public async Task Endpoint_HasRequestSizeLimit_UsedForRequest(bool exceedsLimit)
499499
if (exceedsLimit)
500500
{
501501
Assert.NotNull(exception);
502-
Assert.IsAssignableFrom<InvalidOperationException>(exception);
503-
Assert.Equal("The maximum number of bytes have been read.", exception.Message);
502+
Assert.IsAssignableFrom<BadHttpRequestException>(exception);
503+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ((BadHttpRequestException)exception).StatusCode);
504504
}
505505
else
506506
{
@@ -583,8 +583,8 @@ public async Task Feature_HasRequestSizeLimit_UsedForRequest(bool exceedsLimit)
583583
if (exceedsLimit)
584584
{
585585
Assert.NotNull(exception);
586-
Assert.IsAssignableFrom<InvalidOperationException>(exception);
587-
Assert.Equal("The maximum number of bytes have been read.", exception.Message);
586+
Assert.IsAssignableFrom<BadHttpRequestException>(exception);
587+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ((BadHttpRequestException)exception).StatusCode);
588588
}
589589
else
590590
{

src/Shared/SizeLimitedStream.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
#nullable enable
5+
46
internal sealed class SizeLimitedStream : Stream
57
{
68
private readonly Stream _innerStream;
79
private readonly long? _sizeLimit;
8-
10+
private readonly Action<long>? _handleSizeLimit;
911
private long _totalBytesRead;
1012

11-
public SizeLimitedStream(Stream innerStream, long? sizeLimit)
13+
public SizeLimitedStream(Stream innerStream, long? sizeLimit, Action<long>? handleSizeLimit = null)
1214
{
1315
ArgumentNullException.ThrowIfNull(innerStream);
1416

1517
_innerStream = innerStream;
1618
_sizeLimit = sizeLimit;
19+
_handleSizeLimit = handleSizeLimit;
1720
}
1821

1922
public override bool CanRead => _innerStream.CanRead;
@@ -48,7 +51,14 @@ public override int Read(byte[] buffer, int offset, int count)
4851
_totalBytesRead += bytesRead;
4952
if (_totalBytesRead > _sizeLimit)
5053
{
51-
throw new InvalidOperationException("The maximum number of bytes have been read.");
54+
if (_handleSizeLimit != null)
55+
{
56+
_handleSizeLimit(_sizeLimit.Value);
57+
}
58+
else
59+
{
60+
throw new InvalidOperationException("The maximum number of bytes have been read.");
61+
}
5262
}
5363

5464
return bytesRead;
@@ -81,7 +91,14 @@ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, Cancellation
8191
_totalBytesRead += bytesRead;
8292
if (_totalBytesRead > _sizeLimit)
8393
{
84-
throw new InvalidOperationException("The maximum number of bytes have been read.");
94+
if (_handleSizeLimit != null)
95+
{
96+
_handleSizeLimit(_sizeLimit.Value);
97+
}
98+
else
99+
{
100+
throw new InvalidOperationException("The maximum number of bytes have been read.");
101+
}
85102
}
86103

87104
return bytesRead;

0 commit comments

Comments
 (0)