From adea477824c68d54e3ae6e1612b8c22500945aaa Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 5 Apr 2017 10:09:31 -0700 Subject: [PATCH] Re-write commented out tests in RequestHeaderLimitsTests as Frame tests (#1583). --- .../RequestHeaderLimitsTests.cs | 153 +----------------- .../FrameTests.cs | 128 +++++++++++++++ 2 files changed, 130 insertions(+), 151 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestHeaderLimitsTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestHeaderLimitsTests.cs index 65b4eaaef8..d5087cc23f 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestHeaderLimitsTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestHeaderLimitsTests.cs @@ -1,15 +1,11 @@ // 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; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests @@ -80,108 +76,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } - //[Theory] - //[InlineData(1, 1)] - //[InlineData(5, 5)] - //[InlineData(100, 100)] - //[InlineData(600, 100)] - //[InlineData(700, 1)] - //[InlineData(1, 700)] - //public async Task ServerAcceptsHeadersAcrossSends(int header0Count, int header1Count) - //{ - // var headers0 = MakeHeaders(header0Count); - // var headers1 = MakeHeaders(header1Count, header0Count); - - // using (var server = CreateServer(maxRequestHeaderCount: header0Count + header1Count)) - // { - // using (var connection = new TestConnection(server.Port)) - // { - // await connection.SendAll("GET / HTTP/1.1\r\n"); - // // Wait for parsing to start - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame?.RequestHeaders != null); - - // Assert.Equal(0, server.Frame.RequestHeaders.Count); - - // await connection.SendAll(headers0); - // // Wait for headers to be parsed - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame.RequestHeaders.Count >= header0Count); - - // Assert.Equal(header0Count, server.Frame.RequestHeaders.Count); - - // await connection.SendAll(headers1); - // // Wait for headers to be parsed - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame.RequestHeaders.Count >= header0Count + header1Count); - - // Assert.Equal(header0Count + header1Count, server.Frame.RequestHeaders.Count); - - // await connection.SendAll("\r\n"); - // await connection.ReceiveEnd( - // "HTTP/1.1 200 OK", - // $"Date: {server.Context.DateHeaderValue}", - // "Transfer-Encoding: chunked", - // "", - // "c", - // "hello, world", - // "0", - // "", - // ""); - // } - // } - //} - - //[Theory] - //[InlineData(1, 1)] - //[InlineData(5, 5)] - //public async Task ServerKeepsSameHeaderCollectionAcrossSends(int header0Count, int header1Count) - //{ - // var headers0 = MakeHeaders(header0Count); - // var headers1 = MakeHeaders(header0Count, header1Count); - - // using (var server = CreateServer(maxRequestHeaderCount: header0Count + header1Count)) - // { - // using (var connection = new TestConnection(server.Port)) - // { - // await connection.SendAll("GET / HTTP/1.1\r\n"); - // // Wait for parsing to start - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame?.RequestHeaders != null); - - // Assert.Equal(0, server.Frame.RequestHeaders.Count); - - // var newRequestHeaders = new RequestHeadersWrapper(server.Frame.RequestHeaders); - // server.Frame.RequestHeaders = newRequestHeaders; - - // Assert.Same(newRequestHeaders, server.Frame.RequestHeaders); - - // await connection.SendAll(headers0); - // // Wait for headers to be parsed - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame.RequestHeaders.Count >= header0Count); - - // Assert.Same(newRequestHeaders, server.Frame.RequestHeaders); - // Assert.Equal(header0Count, server.Frame.RequestHeaders.Count); - - // await connection.SendAll(headers1); - // // Wait for headers to be parsed - // await WaitForCondition(TimeSpan.FromSeconds(1), () => server.Frame.RequestHeaders.Count >= header0Count + header1Count); - - // Assert.Equal(header0Count + header1Count, server.Frame.RequestHeaders.Count); - - // Assert.Same(newRequestHeaders, server.Frame.RequestHeaders); - - // await connection.SendAll("\r\n"); - // await connection.ReceiveEnd( - // "HTTP/1.1 200 OK", - // $"Date: {server.Context.DateHeaderValue}", - // "Transfer-Encoding: chunked", - // "", - // "c", - // "hello, world", - // "0", - // "", - // ""); - // } - // } - //} - [Theory] [InlineData(1)] [InlineData(5)] @@ -229,26 +123,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } - private static async Task WaitForCondition(TimeSpan timeout, Func condition) - { - const int MaxWaitLoop = 150; - - var delay = (int)Math.Ceiling(timeout.TotalMilliseconds / MaxWaitLoop); - - var waitLoop = 0; - while (waitLoop < MaxWaitLoop && !condition()) - { - // Wait for parsing condition to trigger - await Task.Delay(delay); - waitLoop++; - } - } - - private static string MakeHeaders(int count, int startAt = 0) + private static string MakeHeaders(int count) { return string.Join("", Enumerable .Range(0, count) - .Select(i => $"Header-{startAt + i}: value{startAt + i}\r\n")); + .Select(i => $"Header-{i}: value{i}\r\n")); } private TestServer CreateServer(int? maxRequestHeaderCount = null, int? maxRequestHeadersTotalSize = null) @@ -270,33 +149,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests ServerOptions = options }); } - - private class RequestHeadersWrapper : IHeaderDictionary - { - IHeaderDictionary _innerHeaders; - - public RequestHeadersWrapper(IHeaderDictionary headers) - { - _innerHeaders = headers; - } - - public StringValues this[string key] { get => _innerHeaders[key]; set => _innerHeaders[key] = value; } - public long? ContentLength { get => _innerHeaders.ContentLength; set => _innerHeaders.ContentLength = value; } - public ICollection Keys => _innerHeaders.Keys; - public ICollection Values => _innerHeaders.Values; - public int Count => _innerHeaders.Count; - public bool IsReadOnly => _innerHeaders.IsReadOnly; - public void Add(string key, StringValues value) => _innerHeaders.Add(key, value); - public void Add(KeyValuePair item) => _innerHeaders.Add(item); - public void Clear() => _innerHeaders.Clear(); - public bool Contains(KeyValuePair item) => _innerHeaders.Contains(item); - public bool ContainsKey(string key) => _innerHeaders.ContainsKey(key); - public void CopyTo(KeyValuePair[] array, int arrayIndex) => _innerHeaders.CopyTo(array, arrayIndex); - public IEnumerator> GetEnumerator() => _innerHeaders.GetEnumerator(); - public bool Remove(string key) => _innerHeaders.Remove(key); - public bool Remove(KeyValuePair item) => _innerHeaders.Remove(item); - public bool TryGetValue(string key, out StringValues value) => _innerHeaders.TryGetValue(key, out value); - IEnumerator IEnumerable.GetEnumerator() => _innerHeaders.GetEnumerator(); - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs index 45949cb5f2..2f7ac31e61 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs @@ -2,9 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.IO.Pipelines; +using System.Linq; using System.Net; using System.Text; using System.Threading; @@ -20,6 +22,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using Moq; using Xunit; @@ -640,6 +643,103 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } + [Theory] + [InlineData(1, 1)] + [InlineData(5, 5)] + [InlineData(100, 100)] + [InlineData(600, 100)] + [InlineData(700, 1)] + [InlineData(1, 700)] + public async Task AcceptsHeadersAcrossSends(int header0Count, int header1Count) + { + _serviceContext.ServerOptions.Limits.MaxRequestHeaderCount = header0Count + header1Count; + + var headers0 = MakeHeaders(header0Count); + var headers1 = MakeHeaders(header1Count, header0Count); + + var requestProcessingTask = _frame.RequestProcessingAsync(); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n")); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders != null); + Assert.Equal(0, _frame.RequestHeaders.Count); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes(headers0)); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders.Count >= header0Count); + Assert.Equal(header0Count, _frame.RequestHeaders.Count); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes(headers1)); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders.Count >= header0Count + header1Count); + Assert.Equal(header0Count + header1Count, _frame.RequestHeaders.Count); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes("\r\n")); + Assert.Equal(header0Count + header1Count, _frame.RequestHeaders.Count); + + await requestProcessingTask.TimeoutAfter(TimeSpan.FromSeconds(10)); + } + + [Theory] + [InlineData(1, 1)] + [InlineData(5, 5)] + [InlineData(100, 100)] + [InlineData(600, 100)] + [InlineData(700, 1)] + [InlineData(1, 700)] + public async Task KeepsSameHeaderCollectionAcrossSends(int header0Count, int header1Count) + { + _serviceContext.ServerOptions.Limits.MaxRequestHeaderCount = header0Count + header1Count; + + var headers0 = MakeHeaders(header0Count); + var headers1 = MakeHeaders(header1Count, header0Count); + + var requestProcessingTask = _frame.RequestProcessingAsync(); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.0\r\n")); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders != null); + Assert.Equal(0, _frame.RequestHeaders.Count); + + var newRequestHeaders = new RequestHeadersWrapper(_frame.RequestHeaders); + _frame.RequestHeaders = newRequestHeaders; + Assert.Same(newRequestHeaders, _frame.RequestHeaders); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes(headers0)); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders.Count >= header0Count); + Assert.Same(newRequestHeaders, _frame.RequestHeaders); + Assert.Equal(header0Count, _frame.RequestHeaders.Count); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes(headers1)); + await WaitForCondition(TimeSpan.FromSeconds(1), () => _frame.RequestHeaders.Count >= header0Count + header1Count); + Assert.Same(newRequestHeaders, _frame.RequestHeaders); + Assert.Equal(header0Count + header1Count, _frame.RequestHeaders.Count); + + await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes("\r\n")); + Assert.Same(newRequestHeaders, _frame.RequestHeaders); + Assert.Equal(header0Count + header1Count, _frame.RequestHeaders.Count); + + await requestProcessingTask.TimeoutAfter(TimeSpan.FromSeconds(10)); + } + + private static async Task WaitForCondition(TimeSpan timeout, Func condition) + { + const int MaxWaitLoop = 150; + + var delay = (int)Math.Ceiling(timeout.TotalMilliseconds / MaxWaitLoop); + + var waitLoop = 0; + while (waitLoop < MaxWaitLoop && !condition()) + { + // Wait for parsing condition to trigger + await Task.Delay(delay); + waitLoop++; + } + } + + private static string MakeHeaders(int count, int startAt = 0) + { + return string.Join("", Enumerable + .Range(0, count) + .Select(i => $"Header-{startAt + i}: value{startAt + i}\r\n")); + } + public static IEnumerable RequestLineValidData => HttpParsingData.RequestLineValidData; public static IEnumerable RequestLineDotSegmentData => HttpParsingData.RequestLineDotSegmentData; @@ -719,5 +819,33 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public IScheduler OutputReaderScheduler { get; } public ITimeoutControl TimeoutControl { get; set; } = Mock.Of(); } + + private class RequestHeadersWrapper : IHeaderDictionary + { + IHeaderDictionary _innerHeaders; + + public RequestHeadersWrapper(IHeaderDictionary headers) + { + _innerHeaders = headers; + } + + public StringValues this[string key] { get => _innerHeaders[key]; set => _innerHeaders[key] = value; } + public long? ContentLength { get => _innerHeaders.ContentLength; set => _innerHeaders.ContentLength = value; } + public ICollection Keys => _innerHeaders.Keys; + public ICollection Values => _innerHeaders.Values; + public int Count => _innerHeaders.Count; + public bool IsReadOnly => _innerHeaders.IsReadOnly; + public void Add(string key, StringValues value) => _innerHeaders.Add(key, value); + public void Add(KeyValuePair item) => _innerHeaders.Add(item); + public void Clear() => _innerHeaders.Clear(); + public bool Contains(KeyValuePair item) => _innerHeaders.Contains(item); + public bool ContainsKey(string key) => _innerHeaders.ContainsKey(key); + public void CopyTo(KeyValuePair[] array, int arrayIndex) => _innerHeaders.CopyTo(array, arrayIndex); + public IEnumerator> GetEnumerator() => _innerHeaders.GetEnumerator(); + public bool Remove(string key) => _innerHeaders.Remove(key); + public bool Remove(KeyValuePair item) => _innerHeaders.Remove(item); + public bool TryGetValue(string key, out StringValues value) => _innerHeaders.TryGetValue(key, out value); + IEnumerator IEnumerable.GetEnumerator() => _innerHeaders.GetEnumerator(); + } } }