diff --git a/samples/SampleApp/Startup.cs b/samples/SampleApp/Startup.cs index 2f18d72aed..61840db407 100644 --- a/samples/SampleApp/Startup.cs +++ b/samples/SampleApp/Startup.cs @@ -19,6 +19,9 @@ namespace SampleApp { 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.AddConsole(LogLevel.Debug); @@ -46,6 +49,8 @@ namespace SampleApp context.Request.Path, context.Request.QueryString); + foreach (var q in context.Request.Query) { } + context.Response.ContentLength = 11; context.Response.ContentType = "text/plain"; await context.Response.WriteAsync("Hello world"); diff --git a/src/Microsoft.AspNet.Server.Kestrel/ServerRequest.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.FeatureCollection.cs similarity index 58% rename from src/Microsoft.AspNet.Server.Kestrel/ServerRequest.cs rename to src/Microsoft.AspNet.Server.Kestrel/Http/Frame.FeatureCollection.cs index 559b7bb525..bb9f2928ff 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/ServerRequest.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.FeatureCollection.cs @@ -2,45 +2,44 @@ // 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.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Kestrel.Http; 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 _pathBase; - private FeatureCollection _features; + private int _featureRevision; - public ServerRequest(Frame frame) - { - _frame = frame; - _features = new FeatureCollection(); - PopulateFeatures(); - } + private Dictionary Extra => MaybeExtra ?? Interlocked.CompareExchange(ref MaybeExtra, new Dictionary(), null); + private Dictionary MaybeExtra; - internal IFeatureCollection Features + public void ResetFeatureCollection() { - get { return _features; } + FastReset(); + MaybeExtra?.Clear(); + Interlocked.Increment(ref _featureRevision); } string IHttpRequestFeature.Protocol { get { - return _frame.HttpVersion; + return HttpVersion; } set { - _frame.HttpVersion = value; + HttpVersion = value; } } @@ -61,12 +60,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.Method; + return Method; } set { - _frame.Method = value; + Method = value; } } @@ -87,12 +86,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.Path; + return Path; } set { - _frame.Path = value; + Path = value; } } @@ -100,12 +99,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.QueryString; + return QueryString; } set { - _frame.QueryString = value; + QueryString = value; } } @@ -113,12 +112,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.RequestHeaders; + return RequestHeaders; } set { - _frame.RequestHeaders = value; + RequestHeaders = value; } } @@ -126,12 +125,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.RequestBody; + return RequestBody; } set { - _frame.RequestBody = value; + RequestBody = value; } } @@ -139,12 +138,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.StatusCode; + return StatusCode; } set { - _frame.StatusCode = value; + StatusCode = value; } } @@ -152,12 +151,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.ReasonPhrase; + return ReasonPhrase; } set { - _frame.ReasonPhrase = value; + ReasonPhrase = value; } } @@ -165,12 +164,12 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.ResponseHeaders; + return ResponseHeaders; } set { - _frame.ResponseHeaders = value; + ResponseHeaders = value; } } @@ -178,18 +177,18 @@ namespace Microsoft.AspNet.Server.Kestrel { get { - return _frame.ResponseBody; + return ResponseBody; } set { - _frame.ResponseBody = value; + ResponseBody = value; } } bool IHttpResponseFeature.HasStarted { - get { return _frame.HasResponseStarted; } + get { return HasResponseStarted; } } bool IHttpUpgradeFeature.IsUpgradableRequest @@ -197,7 +196,7 @@ namespace Microsoft.AspNet.Server.Kestrel get { 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); } @@ -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; - _features[typeof(IHttpResponseFeature)] = this; - _features[typeof(IHttpUpgradeFeature)] = this; + get { return FastFeatureGet(key); } + set { FastFeatureSet(key, value); } } void IHttpResponseFeature.OnStarting(Func callback, object state) { - _frame.OnStarting(callback, state); + OnStarting(callback, state); } void IHttpResponseFeature.OnCompleted(Func callback, object state) { - _frame.OnCompleted(callback, state); + OnCompleted(callback, state); } Task IHttpUpgradeFeature.UpgradeAsync() { - _frame.StatusCode = 101; - _frame.ReasonPhrase = "Switching Protocols"; - _frame.ResponseHeaders["Connection"] = "Upgrade"; - if (!_frame.ResponseHeaders.ContainsKey("Upgrade")) + StatusCode = 101; + ReasonPhrase = "Switching Protocols"; + ResponseHeaders["Connection"] = "Upgrade"; + if (!ResponseHeaders.ContainsKey("Upgrade")) { StringValues values; - if (_frame.RequestHeaders.TryGetValue("Upgrade", out values)) + if (RequestHeaders.TryGetValue("Upgrade", out values)) { - _frame.ResponseHeaders["Upgrade"] = values; + ResponseHeaders["Upgrade"] = values; } } - _frame.ProduceStart(); - return Task.FromResult(_frame.DuplexStream); + ProduceStart(); + return Task.FromResult(DuplexStream); } + + IEnumerator> IEnumerable>.GetEnumerator() => FastEnumerable().GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator(); } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs new file mode 100644 index 0000000000..afe65ec80a --- /dev/null +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs @@ -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> FastEnumerable() + { + if (_currentIHttpRequestFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature), _currentIHttpRequestFeature); + } + if (_currentIHttpResponseFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature), _currentIHttpResponseFeature); + } + if (_currentIHttpUpgradeFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature), _currentIHttpUpgradeFeature); + } + if (_currentIHttpRequestIdentifierFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature), _currentIHttpRequestIdentifierFeature); + } + if (_currentIHttpConnectionFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature), _currentIHttpConnectionFeature); + } + if (_currentITlsConnectionFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature), _currentITlsConnectionFeature); + } + if (_currentIServiceProvidersFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature), _currentIServiceProvidersFeature); + } + if (_currentIHttpSendFileFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature), _currentIHttpSendFileFeature); + } + if (_currentIHttpWebSocketFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature), _currentIHttpWebSocketFeature); + } + if (_currentIQueryFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature), _currentIQueryFeature); + } + if (_currentIFormFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature), _currentIFormFeature); + } + if (_currentIItemsFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature), _currentIItemsFeature); + } + if (_currentIHttpAuthenticationFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature), _currentIHttpAuthenticationFeature); + } + if (_currentIHttpRequestLifetimeFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature), _currentIHttpRequestLifetimeFeature); + } + if (_currentISessionFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature), _currentISessionFeature); + } + if (_currentIResponseCookiesFeature != null) + { + yield return new KeyValuePair(typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature), _currentIResponseCookiesFeature); + } + if (MaybeExtra != null) + { + foreach(var item in MaybeExtra) + { + yield return item; + } + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index e70d1bd6fc..7e813bfb11 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -2,12 +2,14 @@ // 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.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; @@ -16,7 +18,7 @@ using Microsoft.Extensions.Primitives; 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 ArraySegment _endChunkBytes = CreateAsciiByteArraySegment("\r\n"); @@ -80,6 +82,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http _requestHeaders.Reset(); ResetResponseHeaders(); + ResetFeatureCollection(); Method = null; RequestUri = null; @@ -725,5 +728,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http statusCode != 205 && statusCode != 304; } - } + } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs b/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs index aa02efa35f..dec15232f7 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/KestrelEngine.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Kestrel.Http; using Microsoft.AspNet.Server.Kestrel.Infrastructure; using Microsoft.AspNet.Server.Kestrel.Networking; @@ -98,7 +99,7 @@ namespace Microsoft.AspNet.Server.Kestrel Threads.Clear(); } - public IDisposable CreateServer(ServerAddress address, Func application) + public IDisposable CreateServer(ServerAddress address, Func application) { var listeners = new List(); diff --git a/src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs b/src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs index ed441bc95d..c804e4c233 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/ServerFactory.cs @@ -88,11 +88,7 @@ namespace Microsoft.AspNet.Server.Kestrel atLeastOneListener = true; disposables.Push(engine.CreateServer( parsedAddress, - async frame => - { - var request = new ServerRequest(frame); - await application.Invoke(request.Features).ConfigureAwait(false); - })); + application)); } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/project.json b/src/Microsoft.AspNet.Server.Kestrel/project.json index 221a1ab18b..f726255872 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/project.json +++ b/src/Microsoft.AspNet.Server.Kestrel/project.json @@ -52,7 +52,7 @@ "scripts": { "prepare": [ "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": [ "dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.LibuvCopier", @@ -65,6 +65,5 @@ "runtimes/win7-x86/native/": "runtimes/win7-x86/native/*", "runtimes/win10-arm/native/": "runtimes/win10-arm/native/*", "runtimes/osx/native/": "runtimes/osx/native/*" - } } diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs new file mode 100644 index 0000000000..fe12bc9b7b --- /dev/null +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs @@ -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(IEnumerable values, Func 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> FastEnumerable() + {{{Each(commonFeatures, feature => $@" + if (_current{feature.Name} != null) + {{ + yield return new KeyValuePair(typeof(global::{feature.FullName}), _current{feature.Name}); + }}")} + if (MaybeExtra != null) + {{ + foreach(var item in MaybeExtra) + {{ + yield return item; + }} + }} + }} + }} +}} +"; + } + + public virtual void AfterCompile(AfterCompileContext context) + { + } + } +} diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs index 2a77e2542e..3727772c03 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/Program.cs @@ -7,19 +7,34 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode { public int Main(string[] args) { - var text = KnownHeaders.GeneratedFile(); + var text0 = KnownHeaders.GeneratedFile(); + var text1 = FrameFeatureCollection.GeneratedFile(); if (args.Length == 1) { 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 { - Console.WriteLine(text); + Console.WriteLine(text0); } return 0; } diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json index 75adb1ec73..465bd1b866 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/project.json @@ -1,8 +1,10 @@ -{ +{ "version": "1.0.0-*", "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": {