Merge branch 'benaadams/exceptions' into dev
This commit is contained in:
commit
2244f190e1
|
|
@ -2,15 +2,106 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel
|
namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
{
|
{
|
||||||
public sealed class BadHttpRequestException : IOException
|
public sealed class BadHttpRequestException : IOException
|
||||||
{
|
{
|
||||||
internal BadHttpRequestException(string message)
|
private BadHttpRequestException(string message)
|
||||||
: base(message)
|
: base(message)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static BadHttpRequestException GetException(RequestRejectionReason reason)
|
||||||
|
{
|
||||||
|
BadHttpRequestException ex;
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case RequestRejectionReason.MissingMethod:
|
||||||
|
ex = new BadHttpRequestException("Missing method.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.InvalidMethod:
|
||||||
|
ex = new BadHttpRequestException("Invalid method.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.MissingRequestTarget:
|
||||||
|
ex = new BadHttpRequestException("Missing request target.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.MissingHTTPVersion:
|
||||||
|
ex = new BadHttpRequestException("Missing HTTP version.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.UnrecognizedHTTPVersion:
|
||||||
|
ex = new BadHttpRequestException("Unrecognized HTTP version.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.MissingLFInRequestLine:
|
||||||
|
ex = new BadHttpRequestException("Missing LF in request line.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence:
|
||||||
|
ex = new BadHttpRequestException("Headers corrupted, invalid header sequence.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.HeaderLineMustNotStartWithWhitespace:
|
||||||
|
ex = new BadHttpRequestException("Header line must not start with whitespace.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.NoColonCharacterFoundInHeaderLine:
|
||||||
|
ex = new BadHttpRequestException("No ':' character found in header line.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName:
|
||||||
|
ex = new BadHttpRequestException("Whitespace is not allowed in header name.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.HeaderLineMustEndInCRLFOnlyCRFound:
|
||||||
|
ex = new BadHttpRequestException("Header line must end in CRLF; only CR found.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.HeaderValueLineFoldingNotSupported:
|
||||||
|
ex = new BadHttpRequestException("Header value line folding not supported.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.MalformedRequestInvalidHeaders:
|
||||||
|
ex = new BadHttpRequestException("Malformed request: invalid headers.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.UnexpectedEndOfRequestContent:
|
||||||
|
ex = new BadHttpRequestException("Unexpected end of request content.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.BadChunkSuffix:
|
||||||
|
ex = new BadHttpRequestException("Bad chunk suffix.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.BadChunkSizeData:
|
||||||
|
ex = new BadHttpRequestException("Bad chunk size data.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.ChunkedRequestIncomplete:
|
||||||
|
ex = new BadHttpRequestException("Chunked request incomplete.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.PathContainsNullCharacters:
|
||||||
|
ex = new BadHttpRequestException("The path contains null characters.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.InvalidCharactersInHeaderName:
|
||||||
|
ex = new BadHttpRequestException("Invalid characters in header name.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.NonAsciiOrNullCharactersInInputString:
|
||||||
|
ex = new BadHttpRequestException("The input string contains non-ASCII or null characters.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ex = new BadHttpRequestException("Bad request.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static BadHttpRequestException GetException(RequestRejectionReason reason, string value)
|
||||||
|
{
|
||||||
|
BadHttpRequestException ex;
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case RequestRejectionReason.MalformedRequestLineStatus:
|
||||||
|
ex = new BadHttpRequestException($"Malformed request: {value}");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.InvalidContentLength:
|
||||||
|
ex = new BadHttpRequestException($"Invalid content length: {value}");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ex = new BadHttpRequestException("Bad request.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (HasResponseStarted)
|
if (HasResponseStarted)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Status code cannot be set, response has already started.");
|
ThrowResponseAlreadyStartedException(nameof(StatusCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
_statusCode = value;
|
_statusCode = value;
|
||||||
|
|
@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (HasResponseStarted)
|
if (HasResponseStarted)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Reason phrase cannot be set, response had already started.");
|
ThrowResponseAlreadyStartedException(nameof(ReasonPhrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
_reasonPhrase = value;
|
_reasonPhrase = value;
|
||||||
|
|
@ -569,13 +569,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (_applicationException != null)
|
if (_applicationException != null)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(
|
ThrowResponseAbortedException();
|
||||||
"The response has been aborted due to an unhandled application exception.",
|
|
||||||
_applicationException);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProduceStart(appCompleted: false);
|
ProduceStart(appCompleted: false);
|
||||||
|
|
||||||
return TaskUtilities.CompletedTask;
|
return TaskUtilities.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -585,9 +582,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (_applicationException != null)
|
if (_applicationException != null)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(
|
ThrowResponseAbortedException();
|
||||||
"The response has been aborted due to an unhandled application exception.",
|
|
||||||
_applicationException);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProduceStart(appCompleted: false);
|
ProduceStart(appCompleted: false);
|
||||||
|
|
@ -819,7 +814,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (method == null)
|
if (method == null)
|
||||||
{
|
{
|
||||||
RejectRequest("Missing method.");
|
RejectRequest(RequestRejectionReason.MissingMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: We're not in the fast path any more (GetKnownMethod should have handled any HTTP Method we're aware of)
|
// Note: We're not in the fast path any more (GetKnownMethod should have handled any HTTP Method we're aware of)
|
||||||
|
|
@ -828,7 +823,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (!IsValidTokenChar(method[i]))
|
if (!IsValidTokenChar(method[i]))
|
||||||
{
|
{
|
||||||
RejectRequest("Invalid method.");
|
RejectRequest(RequestRejectionReason.InvalidMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -873,7 +868,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (pathBegin.Peek() == ' ')
|
if (pathBegin.Peek() == ' ')
|
||||||
{
|
{
|
||||||
RejectRequest("Missing request target.");
|
RejectRequest(RequestRejectionReason.MissingRequestTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
scan.Take();
|
scan.Take();
|
||||||
|
|
@ -895,11 +890,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (httpVersion == null)
|
if (httpVersion == null)
|
||||||
{
|
{
|
||||||
RejectRequest("Missing HTTP version.");
|
RejectRequest(RequestRejectionReason.MissingHTTPVersion);
|
||||||
}
|
}
|
||||||
else if (httpVersion != "HTTP/1.0" && httpVersion != "HTTP/1.1")
|
else if (httpVersion != "HTTP/1.0" && httpVersion != "HTTP/1.1")
|
||||||
{
|
{
|
||||||
RejectRequest("Unrecognized HTTP version.");
|
RejectRequest(RequestRejectionReason.UnrecognizedHTTPVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -911,7 +906,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (next != '\n')
|
else if (next != '\n')
|
||||||
{
|
{
|
||||||
RejectRequest("Missing LF in request line.");
|
RejectRequest(RequestRejectionReason.MissingLFInRequestLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11
|
// URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11
|
||||||
|
|
@ -1065,11 +1060,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers don't end in CRLF line.
|
// Headers don't end in CRLF line.
|
||||||
RejectRequest("Headers corrupted, invalid header sequence.");
|
RejectRequest(RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence);
|
||||||
}
|
}
|
||||||
else if (ch == ' ' || ch == '\t')
|
else if (ch == ' ' || ch == '\t')
|
||||||
{
|
{
|
||||||
RejectRequest("Header line must not start with whitespace.");
|
RejectRequest(RequestRejectionReason.HeaderLineMustNotStartWithWhitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
var beginName = scan;
|
var beginName = scan;
|
||||||
|
|
@ -1082,13 +1077,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
ch = scan.Take();
|
ch = scan.Take();
|
||||||
if (ch != ':')
|
if (ch != ':')
|
||||||
{
|
{
|
||||||
RejectRequest("No ':' character found in header line.");
|
RejectRequest(RequestRejectionReason.NoColonCharacterFoundInHeaderLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
var validateName = beginName;
|
var validateName = beginName;
|
||||||
if (validateName.Seek(ref _vectorSpaces, ref _vectorTabs, ref _vectorColons) != ':')
|
if (validateName.Seek(ref _vectorSpaces, ref _vectorTabs, ref _vectorColons) != ':')
|
||||||
{
|
{
|
||||||
RejectRequest("Whitespace is not allowed in header name.");
|
RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var beginValue = scan;
|
var beginValue = scan;
|
||||||
|
|
@ -1128,7 +1123,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (ch != '\n')
|
else if (ch != '\n')
|
||||||
{
|
{
|
||||||
RejectRequest("Header line must end in CRLF; only CR found.");
|
RejectRequest(RequestRejectionReason.HeaderLineMustEndInCRLFOnlyCRFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
var next = scan.Peek();
|
var next = scan.Peek();
|
||||||
|
|
@ -1155,7 +1150,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
// explaining that obsolete line folding is unacceptable, or replace
|
// explaining that obsolete line folding is unacceptable, or replace
|
||||||
// each received obs-fold with one or more SP octets prior to
|
// each received obs-fold with one or more SP octets prior to
|
||||||
// interpreting the field value or forwarding the message downstream.
|
// interpreting the field value or forwarding the message downstream.
|
||||||
RejectRequest("Header value line folding not supported.");
|
RejectRequest(RequestRejectionReason.HeaderValueLineFoldingNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim trailing whitespace from header value by repeatedly advancing to next
|
// Trim trailing whitespace from header value by repeatedly advancing to next
|
||||||
|
|
@ -1203,9 +1198,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
statusCode != 304;
|
statusCode != 304;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RejectRequest(string message)
|
private void ThrowResponseAlreadyStartedException(string value)
|
||||||
{
|
{
|
||||||
var ex = new BadHttpRequestException(message);
|
throw new InvalidOperationException(value + " cannot be set, response had already started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThrowResponseAbortedException()
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(
|
||||||
|
"The response has been aborted due to an unhandled application exception.",
|
||||||
|
_applicationException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RejectRequest(RequestRejectionReason reason)
|
||||||
|
{
|
||||||
|
var ex = BadHttpRequestException.GetException(reason);
|
||||||
|
SetBadRequestState(ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RejectRequest(RequestRejectionReason reason, string value)
|
||||||
|
{
|
||||||
|
var ex = BadHttpRequestException.GetException(reason, value);
|
||||||
SetBadRequestState(ex);
|
SetBadRequestState(ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4904,7 +4904,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (!AsciiUtilities.TryGetAsciiString(ptr, keyBuffer, keyLength))
|
if (!AsciiUtilities.TryGetAsciiString(ptr, keyBuffer, keyLength))
|
||||||
{
|
{
|
||||||
throw new BadHttpRequestException("Invalid characters in header name");
|
throw BadHttpRequestException.GetException(RequestRejectionReason.InvalidCharactersInHeaderName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (_isReadOnly)
|
if (_isReadOnly)
|
||||||
{
|
{
|
||||||
ThrowReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
SetValueFast(key, value);
|
SetValueFast(key, value);
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ThrowReadOnlyException()
|
protected void ThrowHeadersReadOnlyException()
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Headers are read-only, response has already started.");
|
throw new InvalidOperationException("Headers are read-only, response has already started.");
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (_isReadOnly)
|
if (_isReadOnly)
|
||||||
{
|
{
|
||||||
ThrowReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
AddValueFast(key, value);
|
AddValueFast(key, value);
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (_isReadOnly)
|
if (_isReadOnly)
|
||||||
{
|
{
|
||||||
ThrowReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
ClearFast();
|
ClearFast();
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (_isReadOnly)
|
if (_isReadOnly)
|
||||||
{
|
{
|
||||||
ThrowReadOnlyException();
|
ThrowHeadersReadOnlyException();
|
||||||
}
|
}
|
||||||
return RemoveFast(key);
|
return RemoveFast(key);
|
||||||
}
|
}
|
||||||
|
|
@ -226,10 +226,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (ch < 0x20 || ch > 0x7E)
|
if (ch < 0x20 || ch > 0x7E)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(string.Format("Invalid non-ASCII or control character in header: 0x{0:X4}", (ushort)ch));
|
ThrowInvalidHeaderCharacter(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ThrowInvalidHeaderCharacter(char ch)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(string.Format("Invalid non-ASCII or control character in header: 0x{0:X4}", (ushort)ch));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (requestLineStatus != RequestLineStatus.Done)
|
if (requestLineStatus != RequestLineStatus.Done)
|
||||||
{
|
{
|
||||||
RejectRequest($"Malformed request: {requestLineStatus}");
|
RejectRequest(RequestRejectionReason.MalformedRequestLineStatus, requestLineStatus.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
// sent immediately before the a FIN from the client.
|
// sent immediately before the a FIN from the client.
|
||||||
if (!TakeMessageHeaders(SocketInput, FrameRequestHeaders))
|
if (!TakeMessageHeaders(SocketInput, FrameRequestHeaders))
|
||||||
{
|
{
|
||||||
RejectRequest($"Malformed request: invalid headers.");
|
RejectRequest(RequestRejectionReason.MalformedRequestInvalidHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
long contentLength;
|
long contentLength;
|
||||||
if (!long.TryParse(unparsedContentLength, out contentLength) || contentLength < 0)
|
if (!long.TryParse(unparsedContentLength, out contentLength) || contentLength < 0)
|
||||||
{
|
{
|
||||||
context.RejectRequest($"Invalid content length: {unparsedContentLength}");
|
context.RejectRequest(RequestRejectionReason.InvalidContentLength, unparsedContentLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -184,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
_inputLength -= actual;
|
_inputLength -= actual;
|
||||||
if (actual == 0)
|
if (actual == 0)
|
||||||
{
|
{
|
||||||
_context.RejectRequest("Unexpected end of request content");
|
_context.RejectRequest(RequestRejectionReason.UnexpectedEndOfRequestContent);
|
||||||
}
|
}
|
||||||
return new ValueTask<int>(actual);
|
return new ValueTask<int>(actual);
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
_inputLength -= actual;
|
_inputLength -= actual;
|
||||||
if (actual == 0)
|
if (actual == 0)
|
||||||
{
|
{
|
||||||
_context.RejectRequest("Unexpected end of request content");
|
_context.RejectRequest(RequestRejectionReason.UnexpectedEndOfRequestContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actual;
|
return actual;
|
||||||
|
|
@ -248,7 +248,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (fin)
|
else if (fin)
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
await input;
|
await input;
|
||||||
|
|
@ -266,7 +266,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (fin)
|
else if (fin)
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
await input;
|
await input;
|
||||||
|
|
@ -288,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (fin)
|
else if (fin)
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
await input;
|
await input;
|
||||||
|
|
@ -306,7 +306,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (fin)
|
else if (fin)
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
await input;
|
await input;
|
||||||
|
|
@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (fin)
|
else if (fin)
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
await input;
|
await input;
|
||||||
|
|
@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThrowChunkedRequestIncomplete();
|
_context.RejectRequest(RequestRejectionReason.ChunkedRequestIncomplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,7 +503,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.RejectRequest("Bad chunk suffix");
|
_context.RejectRequest(RequestRejectionReason.BadChunkSuffix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -559,15 +559,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.RejectRequest("Bad chunk size data");
|
_context.RejectRequest(RequestRejectionReason.BadChunkSizeData);
|
||||||
return -1; // can't happen, but compiler complains
|
return -1; // can't happen, but compiler complains
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThrowChunkedRequestIncomplete()
|
|
||||||
{
|
|
||||||
_context.RejectRequest("Chunked request incomplete");
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Mode
|
private enum Mode
|
||||||
{
|
{
|
||||||
Prefix,
|
Prefix,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
{
|
||||||
|
public enum RequestRejectionReason
|
||||||
|
{
|
||||||
|
MissingMethod,
|
||||||
|
InvalidMethod,
|
||||||
|
MissingRequestTarget,
|
||||||
|
MissingHTTPVersion,
|
||||||
|
UnrecognizedHTTPVersion,
|
||||||
|
MissingLFInRequestLine,
|
||||||
|
HeadersCorruptedInvalidHeaderSequence,
|
||||||
|
HeaderLineMustNotStartWithWhitespace,
|
||||||
|
NoColonCharacterFoundInHeaderLine,
|
||||||
|
WhitespaceIsNotAllowedInHeaderName,
|
||||||
|
HeaderLineMustEndInCRLFOnlyCRFound,
|
||||||
|
HeaderValueLineFoldingNotSupported,
|
||||||
|
MalformedRequestLineStatus,
|
||||||
|
MalformedRequestInvalidHeaders,
|
||||||
|
InvalidContentLength,
|
||||||
|
UnexpectedEndOfRequestContent,
|
||||||
|
BadChunkSuffix,
|
||||||
|
BadChunkSizeData,
|
||||||
|
ChunkedRequestIncomplete,
|
||||||
|
PathContainsNullCharacters,
|
||||||
|
InvalidCharactersInHeaderName,
|
||||||
|
NonAsciiOrNullCharactersInInputString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (byte1 == 0)
|
if (byte1 == 0)
|
||||||
{
|
{
|
||||||
throw new BadHttpRequestException("The path contains null characters.");
|
throw BadHttpRequestException.GetException(RequestRejectionReason.PathContainsNullCharacters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (byte1 == -1)
|
if (byte1 == -1)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -115,7 +116,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following))
|
if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following))
|
||||||
{
|
{
|
||||||
throw new BadHttpRequestException("The input string contains non-ASCII or null characters.");
|
throw BadHttpRequestException.GetException(RequestRejectionReason.NonAsciiOrNullCharactersInInputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputOffset += following;
|
outputOffset += following;
|
||||||
|
|
|
||||||
|
|
@ -451,7 +451,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{{
|
{{
|
||||||
if (!AsciiUtilities.TryGetAsciiString(ptr, keyBuffer, keyLength))
|
if (!AsciiUtilities.TryGetAsciiString(ptr, keyBuffer, keyLength))
|
||||||
{{
|
{{
|
||||||
throw new BadHttpRequestException(""Invalid characters in header name"");
|
throw BadHttpRequestException.GetException(RequestRejectionReason.InvalidCharactersInHeaderName);
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue