Skip to content

Commit 47f5ebe

Browse files
committed
WIP
1 parent 33a98af commit 47f5ebe

File tree

7 files changed

+129
-45
lines changed

7 files changed

+129
-45
lines changed

src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,14 @@ protected override void ApplicationAbort()
134134
/// </summary>
135135
public void StopProcessingNextRequest(ConnectionEndReason reason)
136136
{
137-
KestrelMetrics.AddConnectionEndReason(MetricsContext, reason);
137+
DisableKeepAlive(reason);
138+
Input.CancelPendingRead();
139+
}
138140

141+
internal override void DisableKeepAlive(ConnectionEndReason reason)
142+
{
143+
KestrelMetrics.AddConnectionEndReason(MetricsContext, reason);
139144
_keepAlive = false;
140-
Input.CancelPendingRead();
141145
}
142146

143147
public void SendTimeoutResponse()
@@ -225,6 +229,7 @@ bool TrimAndTakeStartLine(ref SequenceReader<byte> reader)
225229
if (!_parser.ParseRequestLine(new Http1ParsingHandler(this), ref trimmedReader))
226230
{
227231
// We read the maximum allowed but didn't complete the start line.
232+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestLine);
228233
KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
229234
}
230235

@@ -268,6 +273,7 @@ bool TrimAndTakeMessageHeaders(ref SequenceReader<byte> reader, bool trailers)
268273
if (!_parser.ParseHeaders(new Http1ParsingHandler(this, trailers), ref trimmedReader))
269274
{
270275
// We read the maximum allowed but didn't complete the headers.
276+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
271277
KestrelBadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize);
272278
}
273279

@@ -602,10 +608,12 @@ internal void EnsureHostHeaderExists()
602608
return;
603609
}
604610

611+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
605612
KestrelBadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader);
606613
}
607614
else if (hostCount > 1)
608615
{
616+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
609617
KestrelBadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
610618
}
611619
else if (_requestTargetForm != HttpRequestTarget.OriginForm)
@@ -615,6 +623,7 @@ internal void EnsureHostHeaderExists()
615623
}
616624
else if (!HttpUtilities.IsHostHeaderValid(hostText))
617625
{
626+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
618627
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
619628
}
620629
}
@@ -625,6 +634,7 @@ private void ValidateNonOriginHostHeader(string hostText)
625634
{
626635
if (hostText != RawTarget)
627636
{
637+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
628638
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
629639
}
630640
}
@@ -649,6 +659,7 @@ private void ValidateNonOriginHostHeader(string hostText)
649659
}
650660
else
651661
{
662+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
652663
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
653664
}
654665
}
@@ -657,6 +668,7 @@ private void ValidateNonOriginHostHeader(string hostText)
657668

658669
if (!HttpUtilities.IsHostHeaderValid(hostText))
659670
{
671+
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
660672
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
661673
}
662674
}
@@ -792,6 +804,7 @@ private void OnBadRequest(ReadOnlySequence<byte> requestData, BadHttpRequestExce
792804
break;
793805
case RequestRejectionReason.InvalidRequestLine:
794806
case RequestRejectionReason.RequestLineTooLong:
807+
case RequestRejectionReason.InvalidRequestTarget:
795808
KestrelMetrics.AddConnectionEndReason(MetricsContext, ConnectionEndReason.InvalidRequestLine);
796809
break;
797810
case RequestRejectionReason.InvalidRequestHeadersNoCRLF:
@@ -801,7 +814,6 @@ private void OnBadRequest(ReadOnlySequence<byte> requestData, BadHttpRequestExce
801814
case RequestRejectionReason.TooManyHeaders:
802815
case RequestRejectionReason.MultipleContentLengths:
803816
case RequestRejectionReason.MalformedRequestInvalidHeaders:
804-
case RequestRejectionReason.InvalidRequestTarget:
805817
case RequestRejectionReason.InvalidCharactersInHeaderName:
806818
case RequestRejectionReason.LengthRequiredHttp10:
807819
case RequestRejectionReason.OptionsMethodRequired:

src/Servers/Kestrel/Core/src/Internal/Http/Http1ContentLengthMessageBody.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,7 @@ protected override void OnReadStarting()
247247
var maxRequestBodySize = _context.MaxRequestBodySize;
248248
if (_contentLength > maxRequestBodySize)
249249
{
250-
_context.DisableHttp1KeepAlive();
251-
KestrelMetrics.AddConnectionEndReason(_context.MetricsContext, ConnectionEndReason.MaxRequestBodySizeExceeded);
250+
_context.DisableKeepAlive(ConnectionEndReason.MaxRequestBodySizeExceeded);
252251
KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge, maxRequestBodySize.GetValueOrDefault().ToString(CultureInfo.InvariantCulture));
253252
}
254253
}

src/Servers/Kestrel/Core/src/Internal/Http/Http1MessageBody.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ protected async Task OnConsumeAsyncAwaited()
117117

118118
protected override void OnOnbservedBytesExceedMaxRequestBodySize(long? maxRequestBodySize)
119119
{
120-
_context.DisableHttp1KeepAlive();
121-
KestrelMetrics.AddConnectionEndReason(_context.MetricsContext, ConnectionEndReason.MaxRequestBodySizeExceeded);
120+
_context.DisableKeepAlive(ConnectionEndReason.MaxRequestBodySizeExceeded);
122121
KestrelBadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge, maxRequestBodySize.GetValueOrDefault().ToString(CultureInfo.InvariantCulture));
123122
}
124123

@@ -208,6 +207,7 @@ public static MessageBody For(
208207
// Reject with Length Required for HTTP 1.0.
209208
if (httpVersion == HttpVersion.Http10 && (context.Method == HttpMethod.Post || context.Method == HttpMethod.Put))
210209
{
210+
KestrelMetrics.AddConnectionEndReason(context.MetricsContext, ConnectionEndReason.InvalidRequestHeaders);
211211
KestrelBadHttpRequestException.Throw(RequestRejectionReason.LengthRequiredHttp10, context.Method);
212212
}
213213

src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ private void VerifyAndUpdateWrite(int count)
860860
responseHeaders.ContentLength.HasValue &&
861861
_responseBytesWritten + count > responseHeaders.ContentLength.Value)
862862
{
863-
_keepAlive = false;
863+
DisableKeepAlive(ConnectionEndReason.ResponseContentLengthMismatch);
864864
ThrowTooManyBytesWritten(count);
865865
}
866866

@@ -913,7 +913,7 @@ protected bool VerifyResponseContentLength([NotNullWhen(false)] out Exception? e
913913
// cannot be certain of how many bytes it will receive.
914914
if (_responseBytesWritten > 0)
915915
{
916-
_keepAlive = false;
916+
DisableKeepAlive(ConnectionEndReason.ResponseContentLengthMismatch);
917917
}
918918

919919
ex = new InvalidOperationException(
@@ -1392,16 +1392,6 @@ private BadHttpRequestException GetInvalidRequestTargetException(ReadOnlySpan<by
13921392
? target.GetAsciiStringEscaped(Constants.MaxExceptionDetailSize)
13931393
: string.Empty);
13941394

1395-
// This is called during certain bad requests so the automatic Connection: close header gets sent with custom responses.
1396-
// If no response is written, SetBadRequestState(BadHttpRequestException) will later also modify the status code.
1397-
public void DisableHttp1KeepAlive()
1398-
{
1399-
if (_httpVersion == Http.HttpVersion.Http10 || _httpVersion == Http.HttpVersion.Http11)
1400-
{
1401-
_keepAlive = false;
1402-
}
1403-
}
1404-
14051395
public void SetBadRequestState(BadHttpRequestException ex)
14061396
{
14071397
Log.ConnectionBadRequest(ConnectionId, ex);
@@ -1418,6 +1408,12 @@ public void SetBadRequestState(BadHttpRequestException ex)
14181408
WriteDiagnosticEvent(ServiceContext.DiagnosticSource, badRequestEventName, this);
14191409
}
14201410

1411+
// TODO: A specific error should be set. Pass unset here
1412+
DisableKeepAlive(ConnectionEndReason.Unexpected);
1413+
}
1414+
1415+
internal virtual void DisableKeepAlive(ConnectionEndReason reason)
1416+
{
14211417
_keepAlive = false;
14221418
}
14231419

src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelMetrics.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,16 @@ public static void AddConnectionEndReason(ConnectionMetricsContext? context, Con
446446

447447
if (context != null)
448448
{
449+
if (reason == ConnectionEndReason.Unexpected)
450+
{
451+
if (context.ConnectionEndReason == null)
452+
{
453+
Debugger.Launch();
454+
}
455+
456+
return;
457+
}
458+
449459
if (TryGetErrorType(reason, out _))
450460
{
451461
if (context.ConnectionEndReason == null || overwrite)
@@ -512,6 +522,7 @@ internal static bool TryGetErrorType(ConnectionEndReason reason, [NotNullWhen(tr
512522
ConnectionEndReason.MaxRequestBodySizeExceeded => "max_request_body_size_exceeded",
513523
ConnectionEndReason.UnexpectedEndOfRequestContent => "unexpected_end_of_request_content",
514524
ConnectionEndReason.MaxConcurrentConnectionsExceeded => "max_concurrent_connections_exceeded",
525+
ConnectionEndReason.ResponseContentLengthMismatch => "response_content_length_mismatch",
515526
_ => throw new InvalidOperationException($"Unable to calculate whether {reason} resolves to error.type value.")
516527
};
517528

0 commit comments

Comments
 (0)