From 546af5ddee99ead0f1d667f0034ddb5e5266e8fb Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 24 Mar 2014 09:44:12 -0700 Subject: [PATCH] Rename Prefix to UrlPrefix. Seperate IServerInformation to its own implementation. --- .../OwinWebListener.cs | 18 +++--- .../PumpLimits.cs | 28 --------- .../RequestProcessing/Request.cs | 2 +- .../ServerFactory.cs | 12 ++-- .../ServerInformation.cs | 37 ++++++++++++ .../{Prefix.cs => UrlPrefix.cs} | 14 ++--- .../WebListenerWrapper.cs | 60 +++++++------------ .../RequestTests.cs | 8 +-- .../ServerTests.cs | 12 ++-- .../Utilities.cs | 10 ++-- 10 files changed, 95 insertions(+), 106 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs rename src/Microsoft.AspNet.Server.WebListener/{Prefix.cs => UrlPrefix.cs} (91%) diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 28deb59011..cc76380f53 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener private object _internalLock; - private List _uriPrefixes = new List(); + private List _urlPrefixes = new List(); // The native request queue private long? _requestQueueLength; @@ -105,9 +105,9 @@ namespace Microsoft.AspNet.Server.WebListener get { return _logger; } } - public List UriPrefixes + public List UrlPrefixes { - get { return _uriPrefixes; } + get { return _urlPrefixes; } } internal SafeHandle RequestQueueHandle @@ -247,12 +247,12 @@ namespace Microsoft.AspNet.Server.WebListener { CheckDisposed(); // go through the uri list and unregister for each one of them - if (_uriPrefixes.Count > 0) + if (_urlPrefixes.Count > 0) { LogHelper.LogInfo(_logger, "RemoveAll"); if (_state == State.Started) { - foreach (Prefix registeredPrefix in _uriPrefixes) + foreach (UrlPrefix registeredPrefix in _urlPrefixes) { // ignore possible failures InternalRemovePrefix(registeredPrefix.Whole); @@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Server.WebListener if (clear) { - _uriPrefixes.Clear(); + _urlPrefixes.Clear(); } } } @@ -605,12 +605,12 @@ namespace Microsoft.AspNet.Server.WebListener private void AddAllPrefixes() { // go through the uri list and register for each one of them - if (_uriPrefixes.Count > 0) + if (_urlPrefixes.Count > 0) { - for (int i = 0; i < _uriPrefixes.Count; i++) + for (int i = 0; i < _urlPrefixes.Count; i++) { // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - Prefix registeredPrefix = _uriPrefixes[i]; + UrlPrefix registeredPrefix = _urlPrefixes[i]; uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { diff --git a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs deleted file mode 100644 index 438de700e8..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright 2011-2012 Katana contributors -// -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Microsoft.AspNet.Server.WebListener -{ - internal struct PumpLimits - { - internal PumpLimits(int maxAccepts) - { - MaxOutstandingAccepts = maxAccepts; - } - - internal readonly int MaxOutstandingAccepts; - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 78049af54a..2136b96bae 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } - Prefix prefix = httpContext.Server.UriPrefixes[(int)_contextId]; + UrlPrefix prefix = httpContext.Server.UrlPrefixes[(int)_contextId]; string orriginalPath = RequestPath; // These paths are both unescaped already. diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 2d134135f2..b0d1b819c4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener { OwinWebListener listener = new OwinWebListener(); ParseAddresses(configuration, listener); - return new WebListenerWrapper(listener, _loggerFactory); + return new ServerInformation(new WebListenerWrapper(listener, _loggerFactory)); } /// @@ -70,16 +70,16 @@ namespace Microsoft.AspNet.Server.WebListener throw new ArgumentNullException("app"); } - WebListenerWrapper wrapper = server as WebListenerWrapper; - if (wrapper == null) + var serverInfo = server as ServerInformation; + if (serverInfo == null) { throw new ArgumentException("server"); } // TODO: var capabilities = new Dictionary(); - wrapper.Start(app); - return wrapper; + serverInfo.Wrapper.Start(app); + return serverInfo.Wrapper; } private void ParseAddresses(IConfiguration config, OwinWebListener listener) @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener { foreach (var value in urls.Split(';')) { - listener.UriPrefixes.Add(Prefix.Create(value)); + listener.UrlPrefixes.Add(UrlPrefix.Create(value)); } } // TODO: look for just a port option? diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs new file mode 100644 index 0000000000..6e514819c4 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using Microsoft.AspNet.Abstractions; + +namespace Microsoft.AspNet.Server.WebListener +{ + public class ServerInformation : IServerInformation + { + private WebListenerWrapper _webListenerWrapper; + + internal ServerInformation(WebListenerWrapper webListenerWrapper) + { + _webListenerWrapper = webListenerWrapper; + } + + internal WebListenerWrapper Wrapper + { + get { return _webListenerWrapper; } + } + + // Microsoft.AspNet.Server.WebListener + public string Name + { + get { return GetType().GetTypeInfo().Assembly.GetName().Name; } + } + + public OwinWebListener Listener + { + get { return _webListenerWrapper.Listener; } + } + + public int MaxAccepts + { + get { return _webListenerWrapper.MaxAccepts; } + set { _webListenerWrapper.MaxAccepts = value; } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs b/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs similarity index 91% rename from src/Microsoft.AspNet.Server.WebListener/Prefix.cs rename to src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs index a9c7d642d1..7a6e36e1ee 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs +++ b/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ @@ -9,9 +9,9 @@ using System.Globalization; namespace Microsoft.AspNet.Server.WebListener { - public class Prefix + public class UrlPrefix { - private Prefix(bool isHttps, string scheme, string host, string port, int portValue, string path) + private UrlPrefix(bool isHttps, string scheme, string host, string port, int portValue, string path) { IsHttps = isHttps; Scheme = scheme; @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Server.WebListener /// +, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead. /// If empty, the default port for the given scheme will be used (80 or 443). /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. - public static Prefix Create(string scheme, string host, string port, string path) + public static UrlPrefix Create(string scheme, string host, string port, string path) { bool isHttps; if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase)) @@ -73,10 +73,10 @@ namespace Microsoft.AspNet.Server.WebListener path += "/"; } - return new Prefix(isHttps, scheme, host, port, portValue, path); + return new UrlPrefix(isHttps, scheme, host, port, portValue, path); } - public static Prefix Create(string prefix) + public static UrlPrefix Create(string prefix) { string scheme = null; string host = null; @@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Server.WebListener } path = whole.Substring(delimiterStart3); - return Prefix.Create(scheme, host, port, path); + return UrlPrefix.Create(scheme, host, port, path); } public bool IsHttps { get; private set; } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 3785978504..1986d8d3de 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -1,18 +1,14 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; -using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - public class WebListenerWrapper : IServerInformation, IDisposable + internal class WebListenerWrapper : IDisposable { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; @@ -21,7 +17,7 @@ namespace Microsoft.AspNet.Server.WebListener private AppFunc _appFunc; - private PumpLimits _pumpLimits; + private int _maxAccepts; private int _acceptorCounts; private Action _processRequest; @@ -34,18 +30,28 @@ namespace Microsoft.AspNet.Server.WebListener _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); _processRequest = new Action(ProcessRequestAsync); - _pumpLimits = new PumpLimits(DefaultMaxAccepts); + _maxAccepts = DefaultMaxAccepts; } - public OwinWebListener Listener + internal OwinWebListener Listener { get { return _listener; } } - // Microsoft.AspNet.Server.WebListener - public string Name + internal int MaxAccepts { - get { return GetType().GetTypeInfo().Assembly.GetName().Name; } + get + { + return _maxAccepts; + } + set + { + _maxAccepts = value; + if (_listener.IsListening) + { + ActivateRequestProcessingLimits(); + } + } } internal void Start(AppFunc app) @@ -57,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener _appFunc = app; - if (_listener.UriPrefixes.Count == 0) + if (_listener.UrlPrefixes.Count == 0) { throw new InvalidOperationException("No address prefixes were defined."); } @@ -69,40 +75,14 @@ namespace Microsoft.AspNet.Server.WebListener ActivateRequestProcessingLimits(); } - /// - /// These are merged as one operation because they should be swapped out atomically. - /// This controls how many requests the server attempts to process concurrently. - /// - /// The maximum number of pending accepts. - public void SetRequestProcessingLimits(int maxAccepts) - { - _pumpLimits = new PumpLimits(maxAccepts); - - if (_listener.IsListening) - { - ActivateRequestProcessingLimits(); - } - } - private void ActivateRequestProcessingLimits() { - for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) + for (int i = _acceptorCounts; i < MaxAccepts; i++) { ProcessRequestsWorker(); } } - /// - /// Gets the request processing limits. - /// - /// The maximum number of pending accepts. - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] - public void GetRequestProcessingLimits(out int maxAccepts) - { - PumpLimits limits = _pumpLimits; - maxAccepts = limits.MaxOutstandingAccepts; - } - // The message pump. // When we start listening for the next request on one thread, we may need to be sure that the // completion continues on another thread as to not block the current request processing. @@ -110,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener private async void ProcessRequestsWorker() { int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) + while (_listener.IsListening && workerIndex <= MaxAccepts) { // Receive a request RequestContext requestContext; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index be4ec471b1..c95292bbcf 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -150,15 +150,15 @@ namespace Microsoft.AspNet.Server.WebListener.Test private IDisposable CreateServer(AppFunc app) { - var factory = new ServerFactory(null); - var wrapper = (WebListenerWrapper)factory.Initialize(null); + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - wrapper.Listener.UriPrefixes.Add(Prefix.Create("http", "localhost", "8080", path)); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http", "localhost", "8080", path)); } - return factory.Start(wrapper, app); + return factory.Start(serverInfo, app); } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index db6497f4b1..c3632fa4c3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test requestTasks.Add(requestTask); } - bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(5)); + bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(10)); if (!success) { Console.WriteLine(); @@ -191,13 +191,13 @@ namespace Microsoft.AspNet.Server.WebListener.Test [Fact] public async Task Server_SetQueueLimit_Success() { - var factory = new ServerFactory(null); - var wrapper = (WebListenerWrapper)factory.Initialize(null); - wrapper.Listener.UriPrefixes.Add(Prefix.Create("http://localhost:8080")); + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); - wrapper.Listener.SetRequestQueueLimit(1001); + serverInfo.Listener.SetRequestQueueLimit(1001); - using (factory.Start(wrapper, env => Task.FromResult(0))) + using (factory.Start(serverInfo, env => Task.FromResult(0))) { string response = await SendRequestAsync(Address); Assert.Equal(string.Empty, response); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs index abc80060dd..eba2edfd9e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -32,12 +32,12 @@ namespace Microsoft.AspNet.Server.WebListener.Test internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app) { - ServerFactory factory = new ServerFactory(null); - WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); - wrapper.Listener.UriPrefixes.Add(Prefix.Create(scheme, host, port, path)); - wrapper.Listener.AuthenticationManager.AuthenticationTypes = authType; + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType; - return factory.Start(wrapper, app); + return factory.Start(serverInfo, app); } } }