From 2f06c715495b82f644f5556c367af3dd4274aacf Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 7 Jan 2022 08:50:16 +1300 Subject: [PATCH 1/9] Detect HTTP/2 preface on HTTP/1 connection --- .../Core/src/Internal/Http/Http1Connection.cs | 40 ++++++++++++++++++- .../Core/src/Internal/Http/HttpProtocol.cs | 6 ++- .../BadHttpRequestTests.cs | 18 +++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index f088a9973a75..fe5c0cdd8846 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO.Pipelines; using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; @@ -13,6 +14,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpOutputAborter { + internal static ReadOnlySpan Http2GoAwayProtocolErrorBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + private const byte ByteAsterisk = (byte)'*'; private const byte ByteForwardSlash = (byte)'/'; private const string Asterisk = "*"; @@ -618,7 +621,6 @@ protected override void OnReset() _requestTargetForm = HttpRequestTarget.Unknown; _absoluteRequestTarget = null; _remainingRequestHeadersBytesAllowed = ServerOptions.Limits.MaxRequestHeadersTotalSize + 2; - _requestCount++; MinResponseDataRate = ServerOptions.Limits.MinResponseDataRate; @@ -642,6 +644,7 @@ protected override void BeginRequestProcessing() { // Reset the features and timeout. Reset(); + _requestCount++; TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutReason.KeepAlive); } @@ -667,6 +670,14 @@ protected override bool TryParseRequest(ReadResult result, out bool endConnectio } throw; } +#pragma warning disable CS0618 // Type or member is obsolete + catch (BadHttpRequestException ex) + { + DetectHttp2Preface(result.Buffer, ex); + + throw; + } +#pragma warning restore CS0618 // Type or member is obsolete finally { Input.AdvanceTo(reader.Position, isConsumed ? reader.Position : result.Buffer.End); @@ -713,5 +724,32 @@ protected override bool TryParseRequest(ReadResult result, out bool endConnectio } } +#pragma warning disable CS0618 // Type or member is obsolete + private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpRequestException ex) +#pragma warning restore CS0618 // Type or member is obsolete + { + const int PrefaceLineLength = 18; + + if (ConnectionFeatures.Get() == null) + { + // If there is an unrecognized HTTP version, it is the first request on the connection, and the request line + // bytes matches the HTTP/2 preface request line bytes then log and return a HTTP/2 GOAWAY frame. + if (ex.Reason == RequestRejectionReason.UnrecognizedHTTPVersion + && _requestCount == 1 + && requestData.Length >= PrefaceLineLength) + { + var clientPrefaceRequestLine = Http2.Http2Connection.ClientPreface.Slice(0, PrefaceLineLength); + var currentRequestLine = requestData.Slice(0, PrefaceLineLength).ToSpan(); + if (currentRequestLine.SequenceEqual(clientPrefaceRequestLine)) + { + Log.PossibleInvalidHttpVersionDetected(ConnectionId, Http.HttpVersion.Http11, Http.HttpVersion.Http2); + + _context.Transport.Output.Write(Http2GoAwayProtocolErrorBytes); + CancelRequestAbortedToken(); + } + } + } + } + void IRequestProcessor.Tick(DateTimeOffset now) { } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs index fc6508fe0a7c..e04ea1d91683 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs @@ -992,8 +992,10 @@ protected Task TryProduceInvalidRequestResponse() { return ProduceEnd(); } - - return Task.CompletedTask; + else + { + return Output.FlushAsync(CancellationToken.None).GetAsTask(); + } } protected Task ProduceEnd() diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs index b5ae949c60e5..b451aaa20aac 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Text; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.TestTransport; using Microsoft.AspNetCore.Testing; @@ -193,6 +195,22 @@ await client.SendAll( } } + [Fact] + public async Task BadRequestForHttp2() + { + await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory))) + { + using (var client = server.CreateConnection()) + { + await client.Stream.WriteAsync(Core.Internal.Http2.Http2Connection.ClientPreface.ToArray()); + + var data = await client.Stream.ReadAtLeastLengthAsync(17); + + Assert.Equal(Http1Connection.Http2GoAwayProtocolErrorBytes.ToArray(), data); + } + } + } + private class BadRequestEventListener : IObserver>, IDisposable { private IDisposable _subscription; From 6d6806615fb5984e47255fa4afe055da009009e2 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 09:58:41 +1300 Subject: [PATCH 2/9] Change error to HTTP_1_1_REQUIRED --- .../Kestrel/Core/src/Internal/Http/Http1Connection.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index fe5c0cdd8846..9c175acd177b 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpOutputAborter { - internal static ReadOnlySpan Http2GoAwayProtocolErrorBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + internal static ReadOnlySpan Http2GoAwayProtocolErrorBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 }; private const byte ByteAsterisk = (byte)'*'; private const byte ByteForwardSlash = (byte)'/'; @@ -730,6 +730,8 @@ private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpReque { const int PrefaceLineLength = 18; + // Only check for HTTP/2 preface on non-TLS connection. + // When TLS is used then ALPN is used to negotiate correct version. if (ConnectionFeatures.Get() == null) { // If there is an unrecognized HTTP version, it is the first request on the connection, and the request line @@ -745,6 +747,8 @@ private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpReque Log.PossibleInvalidHttpVersionDetected(ConnectionId, Http.HttpVersion.Http11, Http.HttpVersion.Http2); _context.Transport.Output.Write(Http2GoAwayProtocolErrorBytes); + + // Aborting the connection here stops Http1Connection from writing HTTP/1.1 response. CancelRequestAbortedToken(); } } From b757ba3255fd28aefe7af32b03fdd080cde671b4 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 10:02:03 +1300 Subject: [PATCH 3/9] Change error to HTTP_1_1_REQUIRED --- src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs | 4 ++-- .../test/InMemory.FunctionalTests/BadHttpRequestTests.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index 9c175acd177b..bf7544429515 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpOutputAborter { - internal static ReadOnlySpan Http2GoAwayProtocolErrorBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 }; + internal static ReadOnlySpan Http2GoAwayHttp11RequiredBytes => new byte[17] { 0, 0, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 }; private const byte ByteAsterisk = (byte)'*'; private const byte ByteForwardSlash = (byte)'/'; @@ -746,7 +746,7 @@ private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpReque { Log.PossibleInvalidHttpVersionDetected(ConnectionId, Http.HttpVersion.Http11, Http.HttpVersion.Http2); - _context.Transport.Output.Write(Http2GoAwayProtocolErrorBytes); + _context.Transport.Output.Write(Http2GoAwayHttp11RequiredBytes); // Aborting the connection here stops Http1Connection from writing HTTP/1.1 response. CancelRequestAbortedToken(); diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs index b451aaa20aac..f97c7c1d57a9 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs @@ -206,7 +206,7 @@ public async Task BadRequestForHttp2() var data = await client.Stream.ReadAtLeastLengthAsync(17); - Assert.Equal(Http1Connection.Http2GoAwayProtocolErrorBytes.ToArray(), data); + Assert.Equal(Http1Connection.Http2GoAwayHttp11RequiredBytes.ToArray(), data); } } } From 7521aba9a49734cababc1b5c57826313c07b0743 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 12:16:29 +1300 Subject: [PATCH 4/9] Fix trace identifier tests --- .../Core/test/Http1/Http1ConnectionTests.cs | 75 ++++++++++++------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs b/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs index 78d1cb5ac849..28255f6c0d00 100644 --- a/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs +++ b/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Collections; +using System.IO.Pipelines; using System.Text; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Http; @@ -146,21 +147,6 @@ public void ResetResetsScheme() Assert.Equal("http", ((IFeatureCollection)_http1Connection).Get().Scheme); } - [Fact] - public void ResetResetsTraceIdentifier() - { - _http1Connection.TraceIdentifier = "xyz"; - - _http1Connection.Reset(); - - var nextId = ((IFeatureCollection)_http1Connection).Get().TraceIdentifier; - Assert.NotEqual("xyz", nextId); - - _http1Connection.Reset(); - var secondId = ((IFeatureCollection)_http1Connection).Get().TraceIdentifier; - Assert.NotEqual(nextId, secondId); - } - [Fact] public void ResetResetsMinRequestBodyDataRate() { @@ -182,31 +168,73 @@ public void ResetResetsMinResponseDataRate() } [Fact] - public void TraceIdentifierCountsRequestsPerHttp1Connection() + public async Task TraceIdentifierCountsRequestsPerHttp1Connection() { var connectionId = _http1ConnectionContext.ConnectionId; var feature = ((IFeatureCollection)_http1Connection).Get(); - // Reset() is called once in the test ctor + + var requestProcessingTask = _http1Connection.ProcessRequestsAsync(new DummyApplication()); + var count = 1; - void Reset() + async Task SendRequestAsync() { - _http1Connection.Reset(); + var data = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"); + await _application.Output.WriteAsync(data); + + while (true) + { + var read = await _application.Input.ReadAsync(); + SequencePosition consumed = read.Buffer.Start; + SequencePosition examined = read.Buffer.End; + try + { + if (TryReadResponse(read, out consumed, out examined)) + { + break; + } + } + finally + { + _application.Input.AdvanceTo(consumed, examined); + } + } + count++; } var nextId = feature.TraceIdentifier; Assert.Equal($"{connectionId}:00000001", nextId); - Reset(); + await SendRequestAsync(); + var secondId = feature.TraceIdentifier; Assert.Equal($"{connectionId}:00000002", secondId); - var big = 1_000_000; + var big = 10_000; while (big-- > 0) { - Reset(); + await SendRequestAsync(); } Assert.Equal($"{connectionId}:{count:X8}", feature.TraceIdentifier); + + _http1Connection.StopProcessingNextRequest(); + await requestProcessingTask.DefaultTimeout(); + } + + private static bool TryReadResponse(ReadResult read, out SequencePosition consumed, out SequencePosition examined) + { + consumed = read.Buffer.Start; + examined = read.Buffer.End; + + SequenceReader reader = new SequenceReader(read.Buffer); + if (reader.TryReadTo(out ReadOnlySequence _, new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }, advancePastDelimiter: true)) + { + consumed = reader.Position; + examined = reader.Position; + return true; + } + + return false; } [Fact] @@ -216,9 +244,6 @@ public void TraceIdentifierGeneratesWhenNull() var id = _http1Connection.TraceIdentifier; Assert.NotNull(id); Assert.Equal(id, _http1Connection.TraceIdentifier); - - _http1Connection.Reset(); - Assert.NotEqual(id, _http1Connection.TraceIdentifier); } [Fact] From 622995b27577552c1e02c83d6c4457c247288774 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 12:59:45 +1300 Subject: [PATCH 5/9] PR feedback --- .../Core/src/Internal/Http/Http1Connection.cs | 21 +++++++++++++++---- .../Core/src/Internal/Http/HttpProtocol.cs | 15 ++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index bf7544429515..53fcb46ea58e 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; @@ -42,6 +43,9 @@ internal partial class Http1Connection : HttpProtocol, IRequestProcessor, IHttpO private long _remainingRequestHeadersBytesAllowed; + // Tracks whether a HTTP/2 preface was detected during the first request. + private bool _http2PrefaceDetected; + public Http1Connection(HttpConnectionContext context) { Initialize(context); @@ -746,14 +750,23 @@ private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpReque { Log.PossibleInvalidHttpVersionDetected(ConnectionId, Http.HttpVersion.Http11, Http.HttpVersion.Http2); - _context.Transport.Output.Write(Http2GoAwayHttp11RequiredBytes); - - // Aborting the connection here stops Http1Connection from writing HTTP/1.1 response. - CancelRequestAbortedToken(); + // Can't write GOAWAY here. Set flag so TryProduceInvalidRequestResponse writes GOAWAY. + _http2PrefaceDetected = true; } } } } + protected override Task TryProduceInvalidRequestResponse() + { + if (_http2PrefaceDetected) + { + _context.Transport.Output.Write(Http2GoAwayHttp11RequiredBytes); + return _context.Transport.Output.FlushAsync().GetAsTask(); + } + + return base.TryProduceInvalidRequestResponse(); + } + void IRequestProcessor.Tick(DateTimeOffset now) { } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs index e04ea1d91683..178a653d38a1 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs @@ -593,7 +593,10 @@ public async Task ProcessRequestsAsync(IHttpApplication appl { try { - await TryProduceInvalidRequestResponse(); + if (_requestRejectedException != null) + { + await TryProduceInvalidRequestResponse(); + } } catch (Exception ex) { @@ -985,17 +988,15 @@ private void VerifyInitializeState(int firstWriteByteCount) VerifyAndUpdateWrite(firstWriteByteCount); } - protected Task TryProduceInvalidRequestResponse() + protected virtual Task TryProduceInvalidRequestResponse() { // If _requestAborted is set, the connection has already been closed. - if (_requestRejectedException != null && !_connectionAborted) + if (!_connectionAborted) { return ProduceEnd(); } - else - { - return Output.FlushAsync(CancellationToken.None).GetAsTask(); - } + + return Task.CompletedTask; } protected Task ProduceEnd() From 16433f8629e48dce4c6b21821ed5960c40b18d95 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 16:00:29 +1300 Subject: [PATCH 6/9] Update src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs Co-authored-by: Stephen Halter --- src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index 53fcb46ea58e..230cbc3f90f9 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -732,7 +732,7 @@ protected override bool TryParseRequest(ReadResult result, out bool endConnectio private void DetectHttp2Preface(ReadOnlySequence requestData, BadHttpRequestException ex) #pragma warning restore CS0618 // Type or member is obsolete { - const int PrefaceLineLength = 18; + const int PrefaceLineLength = 16; // Only check for HTTP/2 preface on non-TLS connection. // When TLS is used then ALPN is used to negotiate correct version. From 2b5bf804ac7ba4e87a937067d6e1998d49e981ea Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 16:04:03 +1300 Subject: [PATCH 7/9] Update test --- .../test/InMemory.FunctionalTests/BadHttpRequestTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs index f97c7c1d57a9..4bc3117769af 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/BadHttpRequestTests.cs @@ -202,11 +202,12 @@ public async Task BadRequestForHttp2() { using (var client = server.CreateConnection()) { - await client.Stream.WriteAsync(Core.Internal.Http2.Http2Connection.ClientPreface.ToArray()); + await client.Stream.WriteAsync(Core.Internal.Http2.Http2Connection.ClientPreface.ToArray()).DefaultTimeout(); var data = await client.Stream.ReadAtLeastLengthAsync(17); Assert.Equal(Http1Connection.Http2GoAwayHttp11RequiredBytes.ToArray(), data); + Assert.Empty(await client.Stream.ReadUntilEndAsync().DefaultTimeout()); } } } From 8607b3dec5d5e50a40f49df741add217d05839c8 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 16:05:59 +1300 Subject: [PATCH 8/9] Clean up --- src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs index 178a653d38a1..298c16dd8a55 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs @@ -990,7 +990,9 @@ private void VerifyInitializeState(int firstWriteByteCount) protected virtual Task TryProduceInvalidRequestResponse() { - // If _requestAborted is set, the connection has already been closed. + Debug.Assert(_requestRejectedException != null); + + // If _connectionAborted is set, the connection has already been closed. if (!_connectionAborted) { return ProduceEnd(); From 9534326a06cbb44e62da3334dcc5af46543bdac8 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 14 Jan 2022 16:09:38 +1300 Subject: [PATCH 9/9] Clean up --- .../Core/test/Http1/Http1ConnectionTests.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs b/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs index 28255f6c0d00..25d6961a0279 100644 --- a/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs +++ b/src/Servers/Kestrel/Core/test/Http1/Http1ConnectionTests.cs @@ -202,6 +202,22 @@ async Task SendRequestAsync() count++; } + static bool TryReadResponse(ReadResult read, out SequencePosition consumed, out SequencePosition examined) + { + consumed = read.Buffer.Start; + examined = read.Buffer.End; + + SequenceReader reader = new SequenceReader(read.Buffer); + if (reader.TryReadTo(out ReadOnlySequence _, new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }, advancePastDelimiter: true)) + { + consumed = reader.Position; + examined = reader.Position; + return true; + } + + return false; + } + var nextId = feature.TraceIdentifier; Assert.Equal($"{connectionId}:00000001", nextId); @@ -221,22 +237,6 @@ async Task SendRequestAsync() await requestProcessingTask.DefaultTimeout(); } - private static bool TryReadResponse(ReadResult read, out SequencePosition consumed, out SequencePosition examined) - { - consumed = read.Buffer.Start; - examined = read.Buffer.End; - - SequenceReader reader = new SequenceReader(read.Buffer); - if (reader.TryReadTo(out ReadOnlySequence _, new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }, advancePastDelimiter: true)) - { - consumed = reader.Position; - examined = reader.Position; - return true; - } - - return false; - } - [Fact] public void TraceIdentifierGeneratesWhenNull() {