From 799014cfe777885e323c9306b080c61043190b28 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Fri, 31 Jul 2020 03:59:38 +0430 Subject: [PATCH] Throw BadHttpRequestException in HttpSys (#24213) --- .../src/RequestProcessing/RequestContext.cs | 10 ++++- .../src/RequestProcessing/RequestStream.cs | 10 +++-- .../FunctionalTests/RequestBodyLimitTests.cs | 43 +++++++++++++------ .../test/FunctionalTests/ServerTests.cs | 26 ++++++++++- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs index de0cefb72d..997339ac14 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs @@ -289,7 +289,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys Response.Trailers.IsReadOnly = false; Response.Headers.Clear(); Response.Trailers.Clear(); - SetFatalResponse(500); + + if (ex is BadHttpRequestException badHttpRequestException) + { + SetFatalResponse(badHttpRequestException.StatusCode); + } + else + { + SetFatalResponse(StatusCodes.Status500InternalServerError); + } } } finally diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs index 758a060b94..c5e00a9239 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; @@ -432,8 +433,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys var contentLength = RequestContext.Request.ContentLength; if (contentLength.HasValue && _maxSize.HasValue && contentLength.Value > _maxSize.Value) { - throw new IOException( - $"The request's Content-Length {contentLength.Value} is larger than the request body size limit {_maxSize.Value}."); + throw new BadHttpRequestException( + $"The request's Content-Length {contentLength.Value} is larger than the request body size limit {_maxSize.Value}.", + StatusCodes.Status413PayloadTooLarge); } HasStarted = true; @@ -450,7 +452,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys _totalRead += bytesRead; if (_maxSize.HasValue && _totalRead > _maxSize.Value) { - exception = new IOException($"The total number of bytes read {_totalRead} has exceeded the request body size limit {_maxSize.Value}."); + exception = new BadHttpRequestException( + $"The total number of bytes read {_totalRead} has exceeded the request body size limit {_maxSize.Value}.", + StatusCodes.Status413PayloadTooLarge); return true; } exception = null; diff --git a/src/Servers/HttpSys/test/FunctionalTests/RequestBodyLimitTests.cs b/src/Servers/HttpSys/test/FunctionalTests/RequestBodyLimitTests.cs index fa4ae52632..4f825d8ae6 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/RequestBodyLimitTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/RequestBodyLimitTests.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing; using Xunit; @@ -159,10 +160,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(feature.IsReadOnly); Assert.Equal(11, httpContext.Request.ContentLength); byte[] input = new byte[100]; - var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); - ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -182,10 +185,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(feature.IsReadOnly); Assert.Equal(11, httpContext.Request.ContentLength); byte[] input = new byte[100]; - var ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); + var ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); - ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -205,10 +210,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(feature.IsReadOnly); Assert.Equal(11, httpContext.Request.ContentLength); byte[] input = new byte[100]; - var ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + var ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); - ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -229,10 +236,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(feature.IsReadOnly); Assert.Null(httpContext.Request.ContentLength); byte[] input = new byte[100]; - var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); - ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -252,9 +261,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(feature.IsReadOnly); Assert.Null(httpContext.Request.ContentLength); byte[] input = new byte[100]; - var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); - ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); }, options => options.MaxRequestBodySize = 10)) { @@ -275,10 +286,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Null(httpContext.Request.ContentLength); byte[] input = new byte[100]; var body = httpContext.Request.Body; - var ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); + var ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); - ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); + ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -303,8 +316,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys int read = httpContext.Request.Body.Read(input, 0, input.Length); Assert.Equal(10, read); content.Block.Release(); - var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); return Task.FromResult(0); }, options => options.MaxRequestBodySize = 10)) { @@ -328,8 +342,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(10, read); content.Block.Release(); - var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message); + Assert.Equal(StatusCodes.Status413PayloadTooLarge, ex.StatusCode); }, options => options.MaxRequestBodySize = 10)) { string response = await SendRequestAsync(address, content, chunked: true); diff --git a/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs index fbea889de4..5fc71a2047 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/ServerTests.cs @@ -204,11 +204,33 @@ namespace Microsoft.AspNetCore.Server.HttpSys })) { Task requestTask = SendRequestAsync(address); - await Assert.ThrowsAsync(async () => await requestTask); + var ex = await Assert.ThrowsAsync(async () => await requestTask); + Assert.Equal(StatusCodes.Status500InternalServerError, (int)ex.StatusCode); // Do it again to make sure the server didn't crash requestTask = SendRequestAsync(address); - await Assert.ThrowsAsync(async () => await requestTask); + ex = await Assert.ThrowsAsync(async () => await requestTask); + Assert.Equal(StatusCodes.Status500InternalServerError, (int)ex.StatusCode); + } + } + + [ConditionalFact] + public async Task Server_BadHttpRequestException_SetStatusCode() + { + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + throw new BadHttpRequestException("Something happened", StatusCodes.Status418ImATeapot); + })) + { + Task requestTask = SendRequestAsync(address); + var ex = await Assert.ThrowsAsync(async () => await requestTask); + Assert.Equal(StatusCodes.Status418ImATeapot, (int)ex.StatusCode); + + // Do it again to make sure the server didn't crash + requestTask = SendRequestAsync(address); + ex = await Assert.ThrowsAsync(async () => await requestTask); + Assert.Equal(StatusCodes.Status418ImATeapot, (int)ex.StatusCode); } }