Rename Prefix to UrlPrefix. Seperate IServerInformation to its own implementation.

This commit is contained in:
Chris Ross 2014-03-24 09:44:12 -07:00
parent eb27892470
commit 546af5ddee
10 changed files with 95 additions and 106 deletions

View File

@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener
private object _internalLock; private object _internalLock;
private List<Prefix> _uriPrefixes = new List<Prefix>(); private List<UrlPrefix> _urlPrefixes = new List<UrlPrefix>();
// The native request queue // The native request queue
private long? _requestQueueLength; private long? _requestQueueLength;
@ -105,9 +105,9 @@ namespace Microsoft.AspNet.Server.WebListener
get { return _logger; } get { return _logger; }
} }
public List<Prefix> UriPrefixes public List<UrlPrefix> UrlPrefixes
{ {
get { return _uriPrefixes; } get { return _urlPrefixes; }
} }
internal SafeHandle RequestQueueHandle internal SafeHandle RequestQueueHandle
@ -247,12 +247,12 @@ namespace Microsoft.AspNet.Server.WebListener
{ {
CheckDisposed(); CheckDisposed();
// go through the uri list and unregister for each one of them // go through the uri list and unregister for each one of them
if (_uriPrefixes.Count > 0) if (_urlPrefixes.Count > 0)
{ {
LogHelper.LogInfo(_logger, "RemoveAll"); LogHelper.LogInfo(_logger, "RemoveAll");
if (_state == State.Started) if (_state == State.Started)
{ {
foreach (Prefix registeredPrefix in _uriPrefixes) foreach (UrlPrefix registeredPrefix in _urlPrefixes)
{ {
// ignore possible failures // ignore possible failures
InternalRemovePrefix(registeredPrefix.Whole); InternalRemovePrefix(registeredPrefix.Whole);
@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Server.WebListener
if (clear) if (clear)
{ {
_uriPrefixes.Clear(); _urlPrefixes.Clear();
} }
} }
} }
@ -605,12 +605,12 @@ namespace Microsoft.AspNet.Server.WebListener
private void AddAllPrefixes() private void AddAllPrefixes()
{ {
// go through the uri list and register for each one of them // 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. // 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); uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i);
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
{ {

View File

@ -1,28 +0,0 @@
// <copyright file="PumpLimits.cs" company="Katana contributors">
// Copyright 2011-2012 Katana contributors
// </copyright>
//
// 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;
}
}

View File

@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener
_cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); _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; string orriginalPath = RequestPath;
// These paths are both unescaped already. // These paths are both unescaped already.

View File

@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener
{ {
OwinWebListener listener = new OwinWebListener(); OwinWebListener listener = new OwinWebListener();
ParseAddresses(configuration, listener); ParseAddresses(configuration, listener);
return new WebListenerWrapper(listener, _loggerFactory); return new ServerInformation(new WebListenerWrapper(listener, _loggerFactory));
} }
/// <summary> /// <summary>
@ -70,16 +70,16 @@ namespace Microsoft.AspNet.Server.WebListener
throw new ArgumentNullException("app"); throw new ArgumentNullException("app");
} }
WebListenerWrapper wrapper = server as WebListenerWrapper; var serverInfo = server as ServerInformation;
if (wrapper == null) if (serverInfo == null)
{ {
throw new ArgumentException("server"); throw new ArgumentException("server");
} }
// TODO: var capabilities = new Dictionary<string, object>(); // TODO: var capabilities = new Dictionary<string, object>();
wrapper.Start(app); serverInfo.Wrapper.Start(app);
return wrapper; return serverInfo.Wrapper;
} }
private void ParseAddresses(IConfiguration config, OwinWebListener listener) private void ParseAddresses(IConfiguration config, OwinWebListener listener)
@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener
{ {
foreach (var value in urls.Split(';')) 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? // TODO: look for just a port option?

View File

@ -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; }
}
}
}

View File

@ -1,5 +1,5 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <copyright file="HttpListener.cs" company="Microsoft"> // <copyright file="UrlPrefix.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright> // </copyright>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -9,9 +9,9 @@ using System.Globalization;
namespace Microsoft.AspNet.Server.WebListener 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; IsHttps = isHttps;
Scheme = scheme; Scheme = scheme;
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Server.WebListener
/// <param name="host">+, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead.</param> /// <param name="host">+, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead.</param>
/// <param name="port">If empty, the default port for the given scheme will be used (80 or 443).</param> /// <param name="port">If empty, the default port for the given scheme will be used (80 or 443).</param>
/// <param name="path">Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped.</param> /// <param name="path">Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped.</param>
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; bool isHttps;
if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase)) if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase))
@ -73,10 +73,10 @@ namespace Microsoft.AspNet.Server.WebListener
path += "/"; 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 scheme = null;
string host = null; string host = null;
@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Server.WebListener
} }
path = whole.Substring(delimiterStart3); path = whole.Substring(delimiterStart3);
return Prefix.Create(scheme, host, port, path); return UrlPrefix.Create(scheme, host, port, path);
} }
public bool IsHttps { get; private set; } public bool IsHttps { get; private set; }

View File

@ -1,18 +1,14 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts; using System.Diagnostics.Contracts;
using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Logging; using Microsoft.AspNet.Logging;
namespace Microsoft.AspNet.Server.WebListener namespace Microsoft.AspNet.Server.WebListener
{ {
using AppFunc = Func<object, Task>; using AppFunc = Func<object, Task>;
public class WebListenerWrapper : IServerInformation, IDisposable internal class WebListenerWrapper : IDisposable
{ {
private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
@ -21,7 +17,7 @@ namespace Microsoft.AspNet.Server.WebListener
private AppFunc _appFunc; private AppFunc _appFunc;
private PumpLimits _pumpLimits; private int _maxAccepts;
private int _acceptorCounts; private int _acceptorCounts;
private Action<object> _processRequest; private Action<object> _processRequest;
@ -34,18 +30,28 @@ namespace Microsoft.AspNet.Server.WebListener
_logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper));
_processRequest = new Action<object>(ProcessRequestAsync); _processRequest = new Action<object>(ProcessRequestAsync);
_pumpLimits = new PumpLimits(DefaultMaxAccepts); _maxAccepts = DefaultMaxAccepts;
} }
public OwinWebListener Listener internal OwinWebListener Listener
{ {
get { return _listener; } get { return _listener; }
} }
// Microsoft.AspNet.Server.WebListener internal int MaxAccepts
public string Name
{ {
get { return GetType().GetTypeInfo().Assembly.GetName().Name; } get
{
return _maxAccepts;
}
set
{
_maxAccepts = value;
if (_listener.IsListening)
{
ActivateRequestProcessingLimits();
}
}
} }
internal void Start(AppFunc app) internal void Start(AppFunc app)
@ -57,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener
_appFunc = app; _appFunc = app;
if (_listener.UriPrefixes.Count == 0) if (_listener.UrlPrefixes.Count == 0)
{ {
throw new InvalidOperationException("No address prefixes were defined."); throw new InvalidOperationException("No address prefixes were defined.");
} }
@ -69,40 +75,14 @@ namespace Microsoft.AspNet.Server.WebListener
ActivateRequestProcessingLimits(); ActivateRequestProcessingLimits();
} }
/// <summary>
/// These are merged as one operation because they should be swapped out atomically.
/// This controls how many requests the server attempts to process concurrently.
/// </summary>
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
public void SetRequestProcessingLimits(int maxAccepts)
{
_pumpLimits = new PumpLimits(maxAccepts);
if (_listener.IsListening)
{
ActivateRequestProcessingLimits();
}
}
private void ActivateRequestProcessingLimits() private void ActivateRequestProcessingLimits()
{ {
for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) for (int i = _acceptorCounts; i < MaxAccepts; i++)
{ {
ProcessRequestsWorker(); ProcessRequestsWorker();
} }
} }
/// <summary>
/// Gets the request processing limits.
/// </summary>
/// <param name="maxAccepts">The maximum number of pending accepts.</param>
[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. // The message pump.
// When we start listening for the next request on one thread, we may need to be sure that the // 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. // 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() private async void ProcessRequestsWorker()
{ {
int workerIndex = Interlocked.Increment(ref _acceptorCounts); int workerIndex = Interlocked.Increment(ref _acceptorCounts);
while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) while (_listener.IsListening && workerIndex <= MaxAccepts)
{ {
// Receive a request // Receive a request
RequestContext requestContext; RequestContext requestContext;

View File

@ -150,15 +150,15 @@ namespace Microsoft.AspNet.Server.WebListener.Test
private IDisposable CreateServer(AppFunc app) private IDisposable CreateServer(AppFunc app)
{ {
var factory = new ServerFactory(null); var factory = new ServerFactory(loggerFactory: null);
var wrapper = (WebListenerWrapper)factory.Initialize(null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null);
foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) 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<string> SendRequestAsync(string uri) private async Task<string> SendRequestAsync(string uri)

View File

@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test
requestTasks.Add(requestTask); requestTasks.Add(requestTask);
} }
bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(5)); bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(10));
if (!success) if (!success)
{ {
Console.WriteLine(); Console.WriteLine();
@ -191,13 +191,13 @@ namespace Microsoft.AspNet.Server.WebListener.Test
[Fact] [Fact]
public async Task Server_SetQueueLimit_Success() public async Task Server_SetQueueLimit_Success()
{ {
var factory = new ServerFactory(null); var factory = new ServerFactory(loggerFactory: null);
var wrapper = (WebListenerWrapper)factory.Initialize(null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null);
wrapper.Listener.UriPrefixes.Add(Prefix.Create("http://localhost:8080")); 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); string response = await SendRequestAsync(Address);
Assert.Equal(string.Empty, response); Assert.Equal(string.Empty, response);

View File

@ -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) internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app)
{ {
ServerFactory factory = new ServerFactory(null); var factory = new ServerFactory(loggerFactory: null);
WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null);
wrapper.Listener.UriPrefixes.Add(Prefix.Create(scheme, host, port, path)); serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path));
wrapper.Listener.AuthenticationManager.AuthenticationTypes = authType; serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType;
return factory.Start(wrapper, app); return factory.Start(serverInfo, app);
} }
} }
} }