Skip to content

Commit 799014c

Browse files
authored
Throw BadHttpRequestException in HttpSys (#24213)
1 parent d0cca51 commit 799014c

File tree

4 files changed

+69
-20
lines changed

4 files changed

+69
-20
lines changed

src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,15 @@ public async void Execute()
289289
Response.Trailers.IsReadOnly = false;
290290
Response.Headers.Clear();
291291
Response.Trailers.Clear();
292-
SetFatalResponse(500);
292+
293+
if (ex is BadHttpRequestException badHttpRequestException)
294+
{
295+
SetFatalResponse(badHttpRequestException.StatusCode);
296+
}
297+
else
298+
{
299+
SetFatalResponse(StatusCodes.Status500InternalServerError);
300+
}
293301
}
294302
}
295303
finally

src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Runtime.InteropServices;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Http;
1011
using Microsoft.AspNetCore.HttpSys.Internal;
1112
using Microsoft.Extensions.Logging;
1213

@@ -432,8 +433,9 @@ private void CheckSizeLimit()
432433
var contentLength = RequestContext.Request.ContentLength;
433434
if (contentLength.HasValue && _maxSize.HasValue && contentLength.Value > _maxSize.Value)
434435
{
435-
throw new IOException(
436-
$"The request's Content-Length {contentLength.Value} is larger than the request body size limit {_maxSize.Value}.");
436+
throw new BadHttpRequestException(
437+
$"The request's Content-Length {contentLength.Value} is larger than the request body size limit {_maxSize.Value}.",
438+
StatusCodes.Status413PayloadTooLarge);
437439
}
438440

439441
HasStarted = true;
@@ -450,7 +452,9 @@ internal bool TryCheckSizeLimit(int bytesRead, out Exception exception)
450452
_totalRead += bytesRead;
451453
if (_maxSize.HasValue && _totalRead > _maxSize.Value)
452454
{
453-
exception = new IOException($"The total number of bytes read {_totalRead} has exceeded the request body size limit {_maxSize.Value}.");
455+
exception = new BadHttpRequestException(
456+
$"The total number of bytes read {_totalRead} has exceeded the request body size limit {_maxSize.Value}.",
457+
StatusCodes.Status413PayloadTooLarge);
454458
return true;
455459
}
456460
exception = null;

src/Servers/HttpSys/test/FunctionalTests/RequestBodyLimitTests.cs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Net.Http;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Http;
1011
using Microsoft.AspNetCore.Http.Features;
1112
using Microsoft.AspNetCore.Testing;
1213
using Xunit;
@@ -159,10 +160,12 @@ public async Task ContentLengthExceedsLimit_ReadSync_ThrowsImmediately()
159160
Assert.False(feature.IsReadOnly);
160161
Assert.Equal(11, httpContext.Request.ContentLength);
161162
byte[] input = new byte[100];
162-
var ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
163+
var ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
163164
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
164-
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
165+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
166+
ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
165167
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
168+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
166169
return Task.FromResult(0);
167170
}, options => options.MaxRequestBodySize = 10))
168171
{
@@ -182,10 +185,12 @@ public async Task ContentLengthExceedsLimit_ReadAsync_ThrowsImmediately()
182185
Assert.False(feature.IsReadOnly);
183186
Assert.Equal(11, httpContext.Request.ContentLength);
184187
byte[] input = new byte[100];
185-
var ex = Assert.Throws<IOException>(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); });
188+
var ex = Assert.Throws<BadHttpRequestException>(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); });
186189
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
187-
ex = Assert.Throws<IOException>(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); });
190+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
191+
ex = Assert.Throws<BadHttpRequestException>(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); });
188192
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
193+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
189194
return Task.FromResult(0);
190195
}, options => options.MaxRequestBodySize = 10))
191196
{
@@ -205,10 +210,12 @@ public async Task ContentLengthExceedsLimit_ReadBeginEnd_ThrowsImmediately()
205210
Assert.False(feature.IsReadOnly);
206211
Assert.Equal(11, httpContext.Request.ContentLength);
207212
byte[] input = new byte[100];
208-
var ex = Assert.Throws<IOException>(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null));
213+
var ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null));
209214
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
210-
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null));
215+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
216+
ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null));
211217
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
218+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
212219
return Task.FromResult(0);
213220
}, options => options.MaxRequestBodySize = 10))
214221
{
@@ -229,10 +236,12 @@ public async Task ChunkedExceedsLimit_ReadSync_ThrowsAtLimit()
229236
Assert.False(feature.IsReadOnly);
230237
Assert.Null(httpContext.Request.ContentLength);
231238
byte[] input = new byte[100];
232-
var ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
239+
var ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
233240
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
234-
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
241+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
242+
ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
235243
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
244+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
236245
return Task.FromResult(0);
237246
}, options => options.MaxRequestBodySize = 10))
238247
{
@@ -252,9 +261,11 @@ public async Task ChunkedExceedsLimit_ReadAsync_ThrowsAtLimit()
252261
Assert.False(feature.IsReadOnly);
253262
Assert.Null(httpContext.Request.ContentLength);
254263
byte[] input = new byte[100];
255-
var ex = await Assert.ThrowsAsync<IOException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
264+
var ex = await Assert.ThrowsAsync<BadHttpRequestException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
256265
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
257-
ex = await Assert.ThrowsAsync<IOException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
266+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
267+
ex = await Assert.ThrowsAsync<BadHttpRequestException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
268+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
258269
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
259270
}, options => options.MaxRequestBodySize = 10))
260271
{
@@ -275,10 +286,12 @@ public async Task ChunkedExceedsLimit_ReadBeginEnd_ThrowsAtLimit()
275286
Assert.Null(httpContext.Request.ContentLength);
276287
byte[] input = new byte[100];
277288
var body = httpContext.Request.Body;
278-
var ex = Assert.Throws<IOException>(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null)));
289+
var ex = Assert.Throws<BadHttpRequestException>(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null)));
279290
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
280-
ex = Assert.Throws<IOException>(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null)));
291+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
292+
ex = Assert.Throws<BadHttpRequestException>(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null)));
281293
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
294+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
282295
return Task.FromResult(0);
283296
}, options => options.MaxRequestBodySize = 10))
284297
{
@@ -303,8 +316,9 @@ public async Task Chunked_ReadSyncPartialBodyUnderLimit_ThrowsAfterLimit()
303316
int read = httpContext.Request.Body.Read(input, 0, input.Length);
304317
Assert.Equal(10, read);
305318
content.Block.Release();
306-
var ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
319+
var ex = Assert.Throws<BadHttpRequestException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
307320
Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message);
321+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
308322
return Task.FromResult(0);
309323
}, options => options.MaxRequestBodySize = 10))
310324
{
@@ -328,8 +342,9 @@ public async Task Chunked_ReadAsyncPartialBodyUnderLimit_ThrowsAfterLimit()
328342
int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length);
329343
Assert.Equal(10, read);
330344
content.Block.Release();
331-
var ex = await Assert.ThrowsAsync<IOException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
345+
var ex = await Assert.ThrowsAsync<BadHttpRequestException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
332346
Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message);
347+
Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode);
333348
}, options => options.MaxRequestBodySize = 10))
334349
{
335350
string response = await SendRequestAsync(address, content, chunked: true);

src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,33 @@ public async Task Server_AppException_ClientReset()
204204
}))
205205
{
206206
Task<string> requestTask = SendRequestAsync(address);
207-
await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
207+
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
208+
Assert.Equal(StatusCodes.Status500InternalServerError, (int)ex.StatusCode);
208209

209210
// Do it again to make sure the server didn't crash
210211
requestTask = SendRequestAsync(address);
211-
await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
212+
ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
213+
Assert.Equal(StatusCodes.Status500InternalServerError, (int)ex.StatusCode);
214+
}
215+
}
216+
217+
[ConditionalFact]
218+
public async Task Server_BadHttpRequestException_SetStatusCode()
219+
{
220+
string address;
221+
using (Utilities.CreateHttpServer(out address, httpContext =>
222+
{
223+
throw new BadHttpRequestException("Something happened", StatusCodes.Status418ImATeapot);
224+
}))
225+
{
226+
Task<string> requestTask = SendRequestAsync(address);
227+
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
228+
Assert.Equal(StatusCodes.Status418ImATeapot, (int)ex.StatusCode);
229+
230+
// Do it again to make sure the server didn't crash
231+
requestTask = SendRequestAsync(address);
232+
ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await requestTask);
233+
Assert.Equal(StatusCodes.Status418ImATeapot, (int)ex.StatusCode);
212234
}
213235
}
214236

0 commit comments

Comments
 (0)