diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs index ad73c82d45..df750a344a 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs @@ -11,7 +11,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Exceptions; using Microsoft.Extensions.Logging; @@ -217,13 +216,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { if (FrameRequestHeaders == null) { - RequestHeaders = FrameRequestHeaders = new FrameRequestHeaders(); + FrameRequestHeaders = new FrameRequestHeaders(); } + RequestHeaders = FrameRequestHeaders; + if (FrameResponseHeaders == null) { - ResponseHeaders = FrameResponseHeaders = new FrameResponseHeaders(); + FrameResponseHeaders = new FrameResponseHeaders(); } + + ResponseHeaders = FrameResponseHeaders; } public void InitializeStreams(MessageBody messageBody) @@ -646,8 +649,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { responseHeaders.SetRawServer(Constants.ServerName, _bytesServer); } - - ResponseHeaders = responseHeaders; } if (!HasResponseStarted) diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs index 1ff2116bb7..d90c38ad6c 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/EngineTests.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel; +using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.AspNetCore.Server.Kestrel.Infrastructure; using Xunit; @@ -1057,9 +1058,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [MemberData(nameof(ConnectionFilterData))] public async Task NoResponseSentWhenConnectionIsClosedByServerBeforeClientFinishesSendingRequest(TestServiceContext testContext) { - var testLogger = new TestApplicationErrorLogger(); - testContext.Log = new KestrelTrace(testLogger); - using (var server = new TestServer(httpContext => { httpContext.Abort(); @@ -1077,5 +1075,99 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } } + + [Theory] + [MemberData(nameof(ConnectionFilterData))] + public async Task RequestHeadersAreResetOnEachRequest(TestServiceContext testContext) + { + IHeaderDictionary originalRequestHeaders = null; + var firstRequest = true; + + using (var server = new TestServer(httpContext => + { + var requestFeature = httpContext.Features.Get(); + + if (firstRequest) + { + originalRequestHeaders = requestFeature.Headers; + requestFeature.Headers = new FrameRequestHeaders(); + firstRequest = false; + } + else + { + Assert.Same(originalRequestHeaders, requestFeature.Headers); + } + + return TaskUtilities.CompletedTask; + }, testContext)) + { + using (var connection = server.CreateConnection()) + { + await connection.SendEnd( + "GET / HTTP/1.1", + "", + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + "HTTP/1.1 200 OK", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + } + } + + [Theory] + [MemberData(nameof(ConnectionFilterData))] + public async Task ResponseHeadersAreResetOnEachRequest(TestServiceContext testContext) + { + IHeaderDictionary originalResponseHeaders = null; + var firstRequest = true; + + using (var server = new TestServer(httpContext => + { + var responseFeature = httpContext.Features.Get(); + + if (firstRequest) + { + originalResponseHeaders = responseFeature.Headers; + responseFeature.Headers = new FrameResponseHeaders(); + firstRequest = false; + } + else + { + Assert.Same(originalResponseHeaders, responseFeature.Headers); + } + + return TaskUtilities.CompletedTask; + }, testContext)) + { + using (var connection = server.CreateConnection()) + { + await connection.SendEnd( + "GET / HTTP/1.1", + "", + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + "HTTP/1.1 200 OK", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + } + } } } diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs index 809dde54ab..5146a9040e 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Text; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Http; @@ -115,5 +116,51 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Assert.True(frame.HasResponseStarted); Assert.Throws(() => ((IHttpResponseFeature)frame).ReasonPhrase = "Reason phrase"); } + + [Fact] + public void InitializeHeadersResetsRequestHeaders() + { + // Arrange + var connectionContext = new ConnectionContext() + { + DateHeaderValueManager = new DateHeaderValueManager(), + ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), + ServerOptions = new KestrelServerOptions(), + SocketOutput = new MockSocketOuptut() + }; + var frame = new Frame(application: null, context: connectionContext); + frame.InitializeHeaders(); + + // Act + var originalRequestHeaders = frame.RequestHeaders; + frame.RequestHeaders = new FrameRequestHeaders(); + frame.InitializeHeaders(); + + // Assert + Assert.Same(originalRequestHeaders, frame.RequestHeaders); + } + + [Fact] + public void InitializeHeadersResetsResponseHeaders() + { + // Arrange + var connectionContext = new ConnectionContext() + { + DateHeaderValueManager = new DateHeaderValueManager(), + ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), + ServerOptions = new KestrelServerOptions(), + SocketOutput = new MockSocketOuptut() + }; + var frame = new Frame(application: null, context: connectionContext); + frame.InitializeHeaders(); + + // Act + var originalResponseHeaders = frame.ResponseHeaders; + frame.ResponseHeaders = new FrameResponseHeaders(); + frame.InitializeHeaders(); + + // Assert + Assert.Same(originalResponseHeaders, frame.ResponseHeaders); + } } }