Rough implementation of feature collection optimization

This commit is contained in:
Louis DeJardin 2015-10-02 16:09:46 -07:00
parent 0c1b05ce2d
commit dcf591c832
10 changed files with 500 additions and 64 deletions

View File

@ -19,6 +19,9 @@ namespace SampleApp
{ {
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IApplicationEnvironment env) public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IApplicationEnvironment env)
{ {
var ksi = app.ServerFeatures[typeof(IKestrelServerInformation)] as IKestrelServerInformation;
//ksi.ThreadCount = 4;
loggerFactory.MinimumLevel = LogLevel.Debug; loggerFactory.MinimumLevel = LogLevel.Debug;
loggerFactory.AddConsole(LogLevel.Debug); loggerFactory.AddConsole(LogLevel.Debug);
@ -46,6 +49,8 @@ namespace SampleApp
context.Request.Path, context.Request.Path,
context.Request.QueryString); context.Request.QueryString);
foreach (var q in context.Request.Query) { }
context.Response.ContentLength = 11; context.Response.ContentLength = 11;
context.Response.ContentType = "text/plain"; context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello world"); await context.Response.WriteAsync("Hello world");

View File

@ -2,45 +2,44 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Server.Kestrel namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public class ServerRequest : IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature public partial class Frame : IFeatureCollection, IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
{ {
private Frame _frame;
private string _scheme; private string _scheme;
private string _pathBase; private string _pathBase;
private FeatureCollection _features; private int _featureRevision;
public ServerRequest(Frame frame) private Dictionary<Type, object> Extra => MaybeExtra ?? Interlocked.CompareExchange(ref MaybeExtra, new Dictionary<Type, object>(), null);
{ private Dictionary<Type, object> MaybeExtra;
_frame = frame;
_features = new FeatureCollection();
PopulateFeatures();
}
internal IFeatureCollection Features public void ResetFeatureCollection()
{ {
get { return _features; } FastReset();
MaybeExtra?.Clear();
Interlocked.Increment(ref _featureRevision);
} }
string IHttpRequestFeature.Protocol string IHttpRequestFeature.Protocol
{ {
get get
{ {
return _frame.HttpVersion; return HttpVersion;
} }
set set
{ {
_frame.HttpVersion = value; HttpVersion = value;
} }
} }
@ -61,12 +60,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.Method; return Method;
} }
set set
{ {
_frame.Method = value; Method = value;
} }
} }
@ -87,12 +86,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.Path; return Path;
} }
set set
{ {
_frame.Path = value; Path = value;
} }
} }
@ -100,12 +99,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.QueryString; return QueryString;
} }
set set
{ {
_frame.QueryString = value; QueryString = value;
} }
} }
@ -113,12 +112,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.RequestHeaders; return RequestHeaders;
} }
set set
{ {
_frame.RequestHeaders = value; RequestHeaders = value;
} }
} }
@ -126,12 +125,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.RequestBody; return RequestBody;
} }
set set
{ {
_frame.RequestBody = value; RequestBody = value;
} }
} }
@ -139,12 +138,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.StatusCode; return StatusCode;
} }
set set
{ {
_frame.StatusCode = value; StatusCode = value;
} }
} }
@ -152,12 +151,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.ReasonPhrase; return ReasonPhrase;
} }
set set
{ {
_frame.ReasonPhrase = value; ReasonPhrase = value;
} }
} }
@ -165,12 +164,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.ResponseHeaders; return ResponseHeaders;
} }
set set
{ {
_frame.ResponseHeaders = value; ResponseHeaders = value;
} }
} }
@ -178,18 +177,18 @@ namespace Microsoft.AspNet.Server.Kestrel
{ {
get get
{ {
return _frame.ResponseBody; return ResponseBody;
} }
set set
{ {
_frame.ResponseBody = value; ResponseBody = value;
} }
} }
bool IHttpResponseFeature.HasStarted bool IHttpResponseFeature.HasStarted
{ {
get { return _frame.HasResponseStarted; } get { return HasResponseStarted; }
} }
bool IHttpUpgradeFeature.IsUpgradableRequest bool IHttpUpgradeFeature.IsUpgradableRequest
@ -197,7 +196,7 @@ namespace Microsoft.AspNet.Server.Kestrel
get get
{ {
StringValues values; StringValues values;
if (_frame.RequestHeaders.TryGetValue("Connection", out values)) if (RequestHeaders.TryGetValue("Connection", out values))
{ {
return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1); return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1);
} }
@ -205,38 +204,45 @@ namespace Microsoft.AspNet.Server.Kestrel
} }
} }
private void PopulateFeatures() bool IFeatureCollection.IsReadOnly => false;
int IFeatureCollection.Revision => _featureRevision;
object IFeatureCollection.this[Type key]
{ {
_features[typeof(IHttpRequestFeature)] = this; get { return FastFeatureGet(key); }
_features[typeof(IHttpResponseFeature)] = this; set { FastFeatureSet(key, value); }
_features[typeof(IHttpUpgradeFeature)] = this;
} }
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state) void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
{ {
_frame.OnStarting(callback, state); OnStarting(callback, state);
} }
void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state) void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
{ {
_frame.OnCompleted(callback, state); OnCompleted(callback, state);
} }
Task<Stream> IHttpUpgradeFeature.UpgradeAsync() Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
{ {
_frame.StatusCode = 101; StatusCode = 101;
_frame.ReasonPhrase = "Switching Protocols"; ReasonPhrase = "Switching Protocols";
_frame.ResponseHeaders["Connection"] = "Upgrade"; ResponseHeaders["Connection"] = "Upgrade";
if (!_frame.ResponseHeaders.ContainsKey("Upgrade")) if (!ResponseHeaders.ContainsKey("Upgrade"))
{ {
StringValues values; StringValues values;
if (_frame.RequestHeaders.TryGetValue("Upgrade", out values)) if (RequestHeaders.TryGetValue("Upgrade", out values))
{ {
_frame.ResponseHeaders["Upgrade"] = values; ResponseHeaders["Upgrade"] = values;
} }
} }
_frame.ProduceStart(); ProduceStart();
return Task.FromResult(_frame.DuplexStream); return Task.FromResult(DuplexStream);
} }
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
} }
} }

View File

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public partial class Frame
{
private object _currentIHttpRequestFeature;
private object _currentIHttpResponseFeature;
private object _currentIHttpUpgradeFeature;
private object _currentIHttpRequestIdentifierFeature;
private object _currentIHttpConnectionFeature;
private object _currentITlsConnectionFeature;
private object _currentIServiceProvidersFeature;
private object _currentIHttpSendFileFeature;
private object _currentIHttpWebSocketFeature;
private object _currentIQueryFeature;
private object _currentIFormFeature;
private object _currentIItemsFeature;
private object _currentIHttpAuthenticationFeature;
private object _currentIHttpRequestLifetimeFeature;
private object _currentISessionFeature;
private object _currentIResponseCookiesFeature;
private void FastReset()
{
_currentIHttpRequestFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature;
_currentIHttpResponseFeature = this as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature;
_currentIHttpUpgradeFeature = this as global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature;
_currentIHttpRequestIdentifierFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature;
_currentIHttpConnectionFeature = this as global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature;
_currentITlsConnectionFeature = this as global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature;
_currentIServiceProvidersFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature;
_currentIHttpSendFileFeature = this as global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature;
_currentIHttpWebSocketFeature = this as global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature;
_currentIQueryFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature;
_currentIFormFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IFormFeature;
_currentIItemsFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature;
_currentIHttpAuthenticationFeature = this as global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature;
_currentIHttpRequestLifetimeFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature;
_currentISessionFeature = this as global::Microsoft.AspNet.Http.Features.ISessionFeature;
_currentIResponseCookiesFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature;
}
private object FastFeatureGet(Type key)
{
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature))
{
return _currentIHttpRequestFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{
return _currentIHttpResponseFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature))
{
return _currentIHttpUpgradeFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
return _currentIHttpRequestIdentifierFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature))
{
return _currentIHttpConnectionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature))
{
return _currentITlsConnectionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature))
{
return _currentIServiceProvidersFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature))
{
return _currentIHttpSendFileFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature))
{
return _currentIHttpWebSocketFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature))
{
return _currentIQueryFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature))
{
return _currentIFormFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature))
{
return _currentIItemsFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature))
{
return _currentIHttpAuthenticationFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature))
{
return _currentIHttpRequestLifetimeFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature))
{
return _currentISessionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature))
{
return _currentIResponseCookiesFeature;
}
object feature = null;
if (MaybeExtra?.TryGetValue(key, out feature) ?? false)
{
return feature;
}
return null;
}
private void FastFeatureSet(Type key, object feature)
{
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature))
{
_currentIHttpRequestFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{
_currentIHttpResponseFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature))
{
_currentIHttpUpgradeFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
_currentIHttpRequestIdentifierFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature))
{
_currentIHttpConnectionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature))
{
_currentITlsConnectionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature))
{
_currentIServiceProvidersFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature))
{
_currentIHttpSendFileFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature))
{
_currentIHttpWebSocketFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature))
{
_currentIQueryFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature))
{
_currentIFormFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature))
{
_currentIItemsFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature))
{
_currentIHttpAuthenticationFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature))
{
_currentIHttpRequestLifetimeFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature))
{
_currentISessionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature))
{
_currentIResponseCookiesFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
Extra[key] = feature;
}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{
if (_currentIHttpRequestFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature), _currentIHttpRequestFeature);
}
if (_currentIHttpResponseFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature), _currentIHttpResponseFeature);
}
if (_currentIHttpUpgradeFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature), _currentIHttpUpgradeFeature);
}
if (_currentIHttpRequestIdentifierFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature), _currentIHttpRequestIdentifierFeature);
}
if (_currentIHttpConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature), _currentIHttpConnectionFeature);
}
if (_currentITlsConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature), _currentITlsConnectionFeature);
}
if (_currentIServiceProvidersFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature), _currentIServiceProvidersFeature);
}
if (_currentIHttpSendFileFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature), _currentIHttpSendFileFeature);
}
if (_currentIHttpWebSocketFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature), _currentIHttpWebSocketFeature);
}
if (_currentIQueryFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature), _currentIQueryFeature);
}
if (_currentIFormFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature), _currentIFormFeature);
}
if (_currentIItemsFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature), _currentIItemsFeature);
}
if (_currentIHttpAuthenticationFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature), _currentIHttpAuthenticationFeature);
}
if (_currentIHttpRequestLifetimeFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature), _currentIHttpRequestLifetimeFeature);
}
if (_currentISessionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature), _currentISessionFeature);
}
if (_currentIResponseCookiesFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature), _currentIResponseCookiesFeature);
}
if (MaybeExtra != null)
{
foreach(var item in MaybeExtra)
{
yield return item;
}
}
}
}
}

View File

@ -2,12 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -16,7 +18,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public class Frame : FrameContext, IFrameControl public partial class Frame : FrameContext, IFrameControl
{ {
private static readonly Encoding _ascii = Encoding.ASCII; private static readonly Encoding _ascii = Encoding.ASCII;
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n"); private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
@ -80,6 +82,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_requestHeaders.Reset(); _requestHeaders.Reset();
ResetResponseHeaders(); ResetResponseHeaders();
ResetFeatureCollection();
Method = null; Method = null;
RequestUri = null; RequestUri = null;
@ -725,5 +728,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
statusCode != 205 && statusCode != 205 &&
statusCode != 304; statusCode != 304;
} }
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking; using Microsoft.AspNet.Server.Kestrel.Networking;
@ -98,7 +99,7 @@ namespace Microsoft.AspNet.Server.Kestrel
Threads.Clear(); Threads.Clear();
} }
public IDisposable CreateServer(ServerAddress address, Func<Frame, Task> application) public IDisposable CreateServer(ServerAddress address, Func<IFeatureCollection, Task> application)
{ {
var listeners = new List<IDisposable>(); var listeners = new List<IDisposable>();

View File

@ -88,11 +88,7 @@ namespace Microsoft.AspNet.Server.Kestrel
atLeastOneListener = true; atLeastOneListener = true;
disposables.Push(engine.CreateServer( disposables.Push(engine.CreateServer(
parsedAddress, parsedAddress,
async frame => application));
{
var request = new ServerRequest(frame);
await application.Invoke(request.Features).ConfigureAwait(false);
}));
} }
} }

View File

@ -52,7 +52,7 @@
"scripts": { "scripts": {
"prepare": [ "prepare": [
"dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode", "dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode",
"dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs" "dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs Http/Frame.Generated.cs"
], ],
"postrestore": [ "postrestore": [
"dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.LibuvCopier", "dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.LibuvCopier",
@ -65,6 +65,5 @@
"runtimes/win7-x86/native/": "runtimes/win7-x86/native/*", "runtimes/win7-x86/native/": "runtimes/win7-x86/native/*",
"runtimes/win10-arm/native/": "runtimes/win10-arm/native/*", "runtimes/win10-arm/native/": "runtimes/win10-arm/native/*",
"runtimes/osx/native/": "runtimes/osx/native/*" "runtimes/osx/native/": "runtimes/osx/native/*"
} }
} }

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http.Features;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.AspNet.Http.Features.Internal;
using Microsoft.AspNet.Http.Features.Authentication;
namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
{
// This project can output the Class library as a NuGet Package.
// To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build".
public class FrameFeatureCollection : ICompileModule
{
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
{
return values.Select(formatter).Aggregate((a, b) => a + b);
}
public virtual void BeforeCompile(BeforeCompileContext context)
{
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile());
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
}
public static string GeneratedFile()
{
var commonFeatures = new[]
{
typeof(IHttpRequestFeature),
typeof(IHttpResponseFeature),
typeof(IHttpRequestIdentifierFeature),
typeof(IHttpSendFileFeature),
typeof(IServiceProvidersFeature),
typeof(IHttpAuthenticationFeature),
typeof(IHttpRequestLifetimeFeature),
typeof(IQueryFeature),
typeof(IFormFeature),
typeof(IResponseCookiesFeature),
typeof(IItemsFeature),
typeof(IHttpConnectionFeature),
typeof(ITlsConnectionFeature),
typeof(IHttpUpgradeFeature),
typeof(IHttpWebSocketFeature),
typeof(ISessionFeature),
};
return $@"
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Server.Kestrel.Http
{{
public partial class Frame
{{
{Each(commonFeatures, feature => $@"
private object _current{feature.Name};")}
private void FastReset()
{{{Each(commonFeatures, feature => $@"
_current{feature.Name} = this as global::{feature.FullName};")}
}}
private object FastFeatureGet(Type key)
{{{Each(commonFeatures, feature => $@"
if (key == typeof(global::{feature.FullName}))
{{
return _current{feature.Name};
}}")}
object feature = null;
if (MaybeExtra?.TryGetValue(key, out feature) ?? false)
{{
return feature;
}}
return null;
}}
private void FastFeatureSet(Type key, object feature)
{{{Each(commonFeatures, feature => $@"
if (key == typeof(global::{feature.FullName}))
{{
_current{feature.Name} = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}}")}
Extra[key] = feature;
}}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(commonFeatures, feature => $@"
if (_current{feature.Name} != null)
{{
yield return new KeyValuePair<Type, object>(typeof(global::{feature.FullName}), _current{feature.Name});
}}")}
if (MaybeExtra != null)
{{
foreach(var item in MaybeExtra)
{{
yield return item;
}}
}}
}}
}}
}}
";
}
public virtual void AfterCompile(AfterCompileContext context)
{
}
}
}

View File

@ -7,19 +7,34 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
{ {
public int Main(string[] args) public int Main(string[] args)
{ {
var text = KnownHeaders.GeneratedFile(); var text0 = KnownHeaders.GeneratedFile();
var text1 = FrameFeatureCollection.GeneratedFile();
if (args.Length == 1) if (args.Length == 1)
{ {
var existing = File.Exists(args[0]) ? File.ReadAllText(args[0]) : ""; var existing = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
if (!string.Equals(text, existing)) if (!string.Equals(text0, existing))
{ {
File.WriteAllText(args[0], text); File.WriteAllText(args[0], text0);
}
}
else if (args.Length == 2)
{
var existing0 = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
if (!string.Equals(text0, existing0))
{
File.WriteAllText(args[0], text0);
}
var existing1 = File.Exists(args[1]) ? File.ReadAllText(args[1]) : "";
if (!string.Equals(text1, existing1))
{
File.WriteAllText(args[1], text1);
} }
} }
else else
{ {
Console.WriteLine(text); Console.WriteLine(text0);
} }
return 0; return 0;
} }

View File

@ -1,8 +1,10 @@
{ {
"version": "1.0.0-*", "version": "1.0.0-*",
"dependencies": { "dependencies": {
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*" "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
"Microsoft.AspNet.Http.Features": "1.0.0-*",
"Microsoft.AspNet.Hosting": "1.0.0-*"
}, },
"commands": { "commands": {