// 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. using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Http; using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNetCore.Server.KestrelTests { public class FrameResponseHeadersTests { [Theory] [InlineData(true)] [InlineData(false)] public void InitialDictionaryContainsServerAndDate(bool addServerHeader) { var serverOptions = new KestrelServerOptions { AddServerHeader = addServerHeader }; var connectionContext = new ConnectionContext { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), ServerOptions = serverOptions, }; var frame = new Frame(application: null, context: connectionContext); frame.InitializeHeaders(); IDictionary headers = frame.ResponseHeaders; 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]); } else { Assert.Equal(1, headers.Count); StringValues serverHeader; Assert.False(headers.TryGetValue("Server", out serverHeader)); } StringValues dateHeader; DateTime date; Assert.True(headers.TryGetValue("Date", out dateHeader)); Assert.Equal(1, dateHeader.Count); Assert.True(DateTime.TryParse(dateHeader[0], out date)); Assert.True(DateTime.Now - date <= TimeSpan.FromMinutes(1)); Assert.False(headers.IsReadOnly); } [Fact] public void InitialEntriesCanBeCleared() { var serverOptions = new KestrelServerOptions(); var connectionContext = new ConnectionContext { DateHeaderValueManager = new DateHeaderValueManager(), ServerAddress = ServerAddress.FromUrl("http://localhost:5000"), ServerOptions = serverOptions, }; var frame = new Frame(application: null, context: connectionContext); frame.InitializeHeaders(); Assert.True(frame.ResponseHeaders.Count > 0); frame.ResponseHeaders.Clear(); Assert.Equal(0, frame.ResponseHeaders.Count); Assert.False(frame.ResponseHeaders.ContainsKey("Server")); Assert.False(frame.ResponseHeaders.ContainsKey("Date")); } [Theory] [InlineData("Server", "\r\nData")] [InlineData("Server", "\0Data")] [InlineData("Server", "Data\r")] [InlineData("Server", "Da\0ta")] [InlineData("Server", "Da\u001Fta")] [InlineData("Unknown-Header", "\r\nData")] [InlineData("Unknown-Header", "\0Data")] [InlineData("Unknown-Header", "Data\0")] [InlineData("Unknown-Header", "Da\nta")] [InlineData("\r\nServer", "Data")] [InlineData("Server\r", "Data")] [InlineData("Ser\0ver", "Data")] [InlineData("Server\r\n", "Data")] [InlineData("\u001FServer", "Data")] [InlineData("Unknown-Header\r\n", "Data")] [InlineData("\0Unknown-Header", "Data")] [InlineData("Unknown\r-Header", "Data")] [InlineData("Unk\nown-Header", "Data")] public void AddingControlCharactersToHeadersThrows(string key, string value) { var responseHeaders = new FrameResponseHeaders(); Assert.Throws(() => { ((IHeaderDictionary)responseHeaders)[key] = value; }); Assert.Throws(() => { ((IHeaderDictionary)responseHeaders)[key] = new StringValues(new[] { "valid", value }); }); Assert.Throws(() => { ((IDictionary)responseHeaders)[key] = value; }); Assert.Throws(() => { var kvp = new KeyValuePair(key, value); ((ICollection>)responseHeaders).Add(kvp); }); Assert.Throws(() => { var kvp = new KeyValuePair(key, value); ((IDictionary)responseHeaders).Add(key, value); }); } } }