// Copyright (c) .NET Foundation. All rights reserved. // 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 Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; namespace Microsoft.AspNetCore.Server.HttpSys { 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() }, TODO: https://github.com/aspnet/HttpSysServer/issues/231 { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, { typeof(IHttpMaxRequestBodySizeFeature), _identityFunc }, { typeof(IHttpBodyControlFeature), _identityFunc }, }; private readonly FeatureContext _featureContext; static StandardFeatureCollection() { if (ComNetOS.IsWin8orLater) { // Only add the upgrade feature if it stands a chance of working. // SignalR uses the presence of the feature to detect feature support. // https://github.com/aspnet/HttpSysServer/issues/427 _featureFuncLookup[typeof(IHttpUpgradeFeature)] = _identityFunc; } } 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); } } } public TFeature Get() { return (TFeature)this[typeof(TFeature)]; } public void Set(TFeature instance) { this[typeof(TFeature)] = instance; } } }