aspnetcore/tools/CodeGenerator/HttpProtocolFeatureCollecti...

200 lines
6.5 KiB
C#

// 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.Generic;
using System.Linq;
namespace CodeGenerator
{
// 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 HttpProtocolFeatureCollection
{
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
{
return values.Select(formatter).Aggregate((a, b) => a + b);
}
public class KnownFeature
{
public string Name;
public int Index;
}
public static string GeneratedFile(string className)
{
var alwaysFeatures = new[]
{
"IHttpRequestFeature",
"IHttpResponseFeature",
"IHttpRequestIdentifierFeature",
"IServiceProvidersFeature",
"IHttpRequestLifetimeFeature",
"IHttpConnectionFeature",
};
var commonFeatures = new[]
{
"IHttpAuthenticationFeature",
"IQueryFeature",
"IFormFeature",
};
var sometimesFeatures = new[]
{
"IHttpUpgradeFeature",
"IHttp2StreamIdFeature",
"IResponseCookiesFeature",
"IItemsFeature",
"ITlsConnectionFeature",
"IHttpWebSocketFeature",
"ISessionFeature",
"IHttpMaxRequestBodySizeFeature",
"IHttpMinRequestBodyDataRateFeature",
"IHttpMinResponseDataRateFeature",
"IHttpBodyControlFeature",
};
var rareFeatures = new[]
{
"IHttpSendFileFeature",
};
var allFeatures = alwaysFeatures
.Concat(commonFeatures)
.Concat(sometimesFeatures)
.Concat(rareFeatures)
.Select((type, index) => new KnownFeature
{
Name = type,
Index = index
});
// NOTE: This list MUST always match the set of feature interfaces implemented by HttpProtocol.
// See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs
var implementedFeatures = new[]
{
"IHttpRequestFeature",
"IHttpResponseFeature",
"IHttpRequestIdentifierFeature",
"IHttpRequestLifetimeFeature",
"IHttpConnectionFeature",
"IHttpMaxRequestBodySizeFeature",
"IHttpMinRequestBodyDataRateFeature",
"IHttpMinResponseDataRateFeature",
"IHttpBodyControlFeature",
};
return $@"// 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.Generic;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{{
public partial class {className}
{{{Each(allFeatures, feature => $@"
private static readonly Type {feature.Name}Type = typeof({feature.Name});")}
{Each(allFeatures, feature => $@"
private object _current{feature.Name};")}
private void FastReset()
{{{Each(implementedFeatures, feature => $@"
_current{feature} = this;")}
{Each(allFeatures.Where(f => !implementedFeatures.Contains(f.Name)), feature => $@"
_current{feature.Name} = null;")}
}}
object IFeatureCollection.this[Type key]
{{
get
{{
object feature = null;{Each(allFeatures, feature => $@"
{(feature.Index != 0 ? "else " : "")}if (key == {feature.Name}Type)
{{
feature = _current{feature.Name};
}}")}
else if (MaybeExtra != null)
{{
feature = ExtraFeatureGet(key);
}}
return feature ?? ConnectionFeatures[key];
}}
set
{{
_featureRevision++;
{Each(allFeatures, feature => $@"
{(feature.Index != 0 ? "else " : "")}if (key == {feature.Name}Type)
{{
_current{feature.Name} = value;
}}")}
else
{{
ExtraFeatureSet(key, value);
}}
}}
}}
void IFeatureCollection.Set<TFeature>(TFeature feature)
{{
_featureRevision++;{Each(allFeatures, feature => $@"
{(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name}))
{{
_current{feature.Name} = feature;
}}")}
else
{{
ExtraFeatureSet(typeof(TFeature), feature);
}}
}}
TFeature IFeatureCollection.Get<TFeature>()
{{
TFeature feature = default;{Each(allFeatures, feature => $@"
{(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name}))
{{
feature = (TFeature)_current{feature.Name};
}}")}
else if (MaybeExtra != null)
{{
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
}}
if (feature == null)
{{
feature = ConnectionFeatures.Get<TFeature>();
}}
return feature;
}}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(allFeatures, feature => $@"
if (_current{feature.Name} != null)
{{
yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name} as {feature.Name});
}}")}
if (MaybeExtra != null)
{{
foreach(var item in MaybeExtra)
{{
yield return item;
}}
}}
}}
}}
}}
";
}
}
}