From aa34e5e46e69dbb9850131ce85bf5f091bd064a0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 29 Jul 2015 15:29:43 -0700 Subject: [PATCH] React to IFeatureCollection changes. Use a static feature collection. --- .../FeatureContext.cs | 45 +++----- .../StandardFeatureCollection.cs | 105 ++++++++++++++++++ 2 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index dc47ee71d6..2ba8740c6f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Server.WebListener private static Func OnStartDelegate = OnStart; private RequestContext _requestContext; - private FeatureCollection _features; + private IFeatureCollection _features; private bool _enableResponseCaching; private Stream _requestBody; @@ -76,11 +76,10 @@ namespace Microsoft.AspNet.Server.WebListener internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { _requestContext = requestContext; - _features = new FeatureCollection(); + _features = new StandardFeatureCollection(this); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; requestContext.Response.OnStarting(OnStartDelegate, this); - PopulateFeatures(); } internal IFeatureCollection Features @@ -88,6 +87,11 @@ namespace Microsoft.AspNet.Server.WebListener get { return _features; } } + internal object RequestContext + { + get { return _requestContext; } + } + private Request Request { get { return _requestContext.Request; } @@ -98,31 +102,6 @@ namespace Microsoft.AspNet.Server.WebListener get { return _requestContext.Response; } } - private void PopulateFeatures() - { - _features.Add(typeof(IHttpRequestFeature), this); - _features.Add(typeof(IHttpConnectionFeature), this); - _features.Add(typeof(IHttpResponseFeature), this); - _features.Add(typeof(IHttpSendFileFeature), this); - _features.Add(typeof(IHttpBufferingFeature), this); - _features.Add(typeof(IHttpRequestLifetimeFeature), this); - _features.Add(typeof(IHttpAuthenticationFeature), this); - _features.Add(typeof(IHttpRequestIdentifierFeature), this); - - if (Request.IsSecureConnection) - { - _features.Add(typeof(ITlsConnectionFeature), this); - _features.Add(typeof(ITlsTokenBindingFeature), this); - } - - // Win8+ - if (WebSocketHelpers.AreWebSocketsSupported) - { - _features.Add(typeof(IHttpUpgradeFeature), this); - _features.Add(typeof(IHttpWebSocketFeature), this); - } - } - Stream IHttpRequestFeature.Body { get @@ -326,6 +305,11 @@ namespace Microsoft.AspNet.Server.WebListener return _clientCert; } + internal ITlsConnectionFeature GetTlsConnectionFeature() + { + return Request.IsSecureConnection ? this : null; + } + byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() { return Request.GetProvidedTokenBindingId(); @@ -336,6 +320,11 @@ namespace Microsoft.AspNet.Server.WebListener return Request.GetReferredTokenBindingId(); } + internal ITlsTokenBindingFeature GetTlsTokenBindingFeature() + { + return Request.IsSecureConnection ? this : null; + } + void IHttpBufferingFeature.DisableRequestBuffering() { // There is no request buffering. diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs new file mode 100644 index 0000000000..a8b735accb --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs @@ -0,0 +1,105 @@ +// Copyright (c) .NET Foundation. +// All Rights Reserved +// +// 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 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.Net.Http.Server; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class StandardFeatureCollection : IFeatureCollection + { + private static readonly Func _identityFunc = ReturnIdentity; + private static readonly Dictionary> _featureFuncLookup = new Dictionary>() + { + { typeof(IHttpRequestFeature), _identityFunc }, + { typeof(IHttpConnectionFeature), _identityFunc }, + { typeof(IHttpResponseFeature), _identityFunc }, + { typeof(IHttpSendFileFeature), _identityFunc }, + { typeof(ITlsConnectionFeature), ctx => ctx.GetTlsConnectionFeature() }, + { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, + { typeof(IHttpBufferingFeature), _identityFunc }, + { typeof(IHttpRequestLifetimeFeature), _identityFunc }, + { typeof(IHttpUpgradeFeature), _identityFunc }, + { typeof(IHttpWebSocketFeature), _identityFunc }, + { typeof(IHttpAuthenticationFeature), _identityFunc }, + { typeof(IHttpRequestIdentifierFeature), _identityFunc }, + { typeof(RequestContext), ctx => ctx.RequestContext }, + }; + + private readonly FeatureContext _featureContext; + + public StandardFeatureCollection(FeatureContext featureContext) + { + _featureContext = featureContext; + } + + public bool IsReadOnly + { + get { return true; } + } + + public int Revision + { + get { return 0; } + } + + public object this[Type key] + { + get + { + Func lookupFunc; + _featureFuncLookup.TryGetValue(key, out lookupFunc); + return lookupFunc?.Invoke(_featureContext); + } + set + { + throw new InvalidOperationException("The collection is read-only"); + } + } + + private static object ReturnIdentity(FeatureContext featureContext) + { + return featureContext; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable>)this).GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + foreach (var featureFunc in _featureFuncLookup) + { + var feature = featureFunc.Value(_featureContext); + if (feature != null) + { + yield return new KeyValuePair(featureFunc.Key, feature); + } + } + } + + void IDisposable.Dispose() + { + // nothing to dispose of + } + } +}