diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs index 467b841fd6..d50aa1b613 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs @@ -610,10 +610,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http var responseHeaders = _frameHeaders.ResponseHeaders; responseHeaders.Reset(); var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues(); + responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes); - responseHeaders.SetRawServer("Kestrel", Headers.BytesServer); responseHeaders.SetRawContentLength("0", _bytesContentLengthZero); + if (ServerOptions.AddServerHeader) + { + responseHeaders.SetRawServer(Constants.ServerName, Headers.BytesServer); + } + ResponseHeaders = responseHeaders; } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/Constants.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/Constants.cs index b7dcc01a41..3031b022dc 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/Constants.cs @@ -23,6 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure /// public const string RFC1123DateFormat = "r"; + public const string ServerName = "Kestrel"; + private static int? GetECONNRESET() { switch (PlatformServices.Default.Runtime.OperatingSystemPlatform) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs index 4d647e2caa..baeb975233 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/HttpComponentFactory.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure if (!_headerPool.TryDequeue(out headers)) { - headers = new Headers(); + headers = new Headers(ServerOptions); } headers.Initialize(dateValueManager); @@ -76,11 +76,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure public readonly FrameRequestHeaders RequestHeaders = new FrameRequestHeaders(); public readonly FrameResponseHeaders ResponseHeaders = new FrameResponseHeaders(); + private readonly KestrelServerOptions _options; + + public Headers(KestrelServerOptions options) + { + _options = options; + } + public void Initialize(DateHeaderValueManager dateValueManager) { var dateHeaderValues = dateValueManager.GetDateHeaderValues(); + ResponseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes); - ResponseHeaders.SetRawServer("Kestrel", BytesServer); + + if (_options.AddServerHeader) + { + ResponseHeaders.SetRawServer(Constants.ServerName, BytesServer); + } } public void Uninitialize() diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerOptions.cs b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerOptions.cs index ddf85f9a27..708eb240b2 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerOptions.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerOptions.cs @@ -32,6 +32,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel public bool NoDelay { get; set; } = true; + /// + /// Gets or sets whether the Server header should be included in each response. + /// + public bool AddServerHeader { get; set; } = true; + /// /// The amount of time after the server begins shutting down before connections will be forcefully closed. /// By default, Kestrel will wait 5 seconds for any ongoing requests to complete before terminating diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs index 07be384d2c..097d4dac9a 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameResponseHeadersTests.cs @@ -15,10 +15,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { public class FrameResponseHeadersTests { - [Fact] - public void InitialDictionaryContainsServerAndDate() + [Theory] + [InlineData(true)] + [InlineData(false)] + public void InitialDictionaryContainsServerAndDate(bool addServerHeader) { - var serverOptions = new KestrelServerOptions(); + var serverOptions = new KestrelServerOptions { AddServerHeader = addServerHeader }; + var connectionContext = new ConnectionContext { DateHeaderValueManager = new DateHeaderValueManager(), @@ -31,12 +34,22 @@ namespace Microsoft.AspNetCore.Server.KestrelTests IDictionary headers = frame.ResponseHeaders; - Assert.Equal(2, headers.Count); + if (addServerHeader) + { + Assert.Equal(2, headers.Count); - StringValues serverHeader; - Assert.True(headers.TryGetValue("Server", out serverHeader)); - Assert.Equal(1, serverHeader.Count); - Assert.Equal("Kestrel", serverHeader[0]); + StringValues serverHeader; + Assert.True(headers.TryGetValue("Server", out serverHeader)); + Assert.Equal(1, serverHeader.Count); + Assert.Equal("Kestrel", serverHeader[0]); + } + else + { + Assert.Equal(1, headers.Count); + + StringValues serverHeader; + Assert.False(headers.TryGetValue("Server", out serverHeader)); + } StringValues dateHeader; DateTime date;