Generate repetitive TransportConnection FeatureCollection code (#2548)
This commit is contained in:
parent
04f2101696
commit
c683316253
|
|
@ -2,8 +2,6 @@
|
||||||
// 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.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -16,8 +14,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
public partial class HttpProtocol : IFeatureCollection,
|
public partial class HttpProtocol : IHttpRequestFeature,
|
||||||
IHttpRequestFeature,
|
|
||||||
IHttpResponseFeature,
|
IHttpResponseFeature,
|
||||||
IHttpConnectionFeature,
|
IHttpConnectionFeature,
|
||||||
IHttpRequestLifetimeFeature,
|
IHttpRequestLifetimeFeature,
|
||||||
|
|
@ -29,53 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
// NOTE: When feature interfaces are added to or removed from this HttpProtocol class implementation,
|
// NOTE: When feature interfaces are added to or removed from this HttpProtocol class implementation,
|
||||||
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||||
// See also: tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/HttpProtocolFeatureCollection.cs
|
// See also: tools/CodeGenerator/HttpProtocolFeatureCollection.cs
|
||||||
|
|
||||||
private int _featureRevision;
|
|
||||||
|
|
||||||
private List<KeyValuePair<Type, object>> MaybeExtra;
|
|
||||||
|
|
||||||
public void ResetFeatureCollection()
|
|
||||||
{
|
|
||||||
FastReset();
|
|
||||||
MaybeExtra?.Clear();
|
|
||||||
_featureRevision++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private object ExtraFeatureGet(Type key)
|
|
||||||
{
|
|
||||||
if (MaybeExtra == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < MaybeExtra.Count; i++)
|
|
||||||
{
|
|
||||||
var kv = MaybeExtra[i];
|
|
||||||
if (kv.Key == key)
|
|
||||||
{
|
|
||||||
return kv.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExtraFeatureSet(Type key, object value)
|
|
||||||
{
|
|
||||||
if (MaybeExtra == null)
|
|
||||||
{
|
|
||||||
MaybeExtra = new List<KeyValuePair<Type, object>>(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < MaybeExtra.Count; i++)
|
|
||||||
{
|
|
||||||
if (MaybeExtra[i].Key == key)
|
|
||||||
{
|
|
||||||
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
string IHttpRequestFeature.Protocol
|
string IHttpRequestFeature.Protocol
|
||||||
{
|
{
|
||||||
|
|
@ -175,9 +126,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
bool IHttpResponseFeature.HasStarted => HasResponseStarted;
|
bool IHttpResponseFeature.HasStarted => HasResponseStarted;
|
||||||
|
|
||||||
bool IFeatureCollection.IsReadOnly => false;
|
|
||||||
|
|
||||||
int IFeatureCollection.Revision => _featureRevision;
|
|
||||||
|
|
||||||
IPAddress IHttpConnectionFeature.RemoteIpAddress
|
IPAddress IHttpConnectionFeature.RemoteIpAddress
|
||||||
{
|
{
|
||||||
|
|
@ -277,10 +225,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
OnCompleted(callback, state);
|
OnCompleted(callback, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
||||||
|
|
||||||
void IHttpRequestLifetimeFeature.Abort()
|
void IHttpRequestLifetimeFeature.Abort()
|
||||||
{
|
{
|
||||||
Abort(new ConnectionAbortedException());
|
Abort(new ConnectionAbortedException());
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// 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 Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
@ -10,7 +11,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
public partial class HttpProtocol
|
public partial class HttpProtocol : IFeatureCollection
|
||||||
{
|
{
|
||||||
private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature);
|
private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature);
|
||||||
private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature);
|
private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature);
|
||||||
|
|
@ -56,6 +57,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private object _currentIHttpBodyControlFeature;
|
private object _currentIHttpBodyControlFeature;
|
||||||
private object _currentIHttpSendFileFeature;
|
private object _currentIHttpSendFileFeature;
|
||||||
|
|
||||||
|
private int _featureRevision;
|
||||||
|
|
||||||
|
private List<KeyValuePair<Type, object>> MaybeExtra;
|
||||||
|
|
||||||
private void FastReset()
|
private void FastReset()
|
||||||
{
|
{
|
||||||
_currentIHttpRequestFeature = this;
|
_currentIHttpRequestFeature = this;
|
||||||
|
|
@ -67,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_currentIHttpMinRequestBodyDataRateFeature = this;
|
_currentIHttpMinRequestBodyDataRateFeature = this;
|
||||||
_currentIHttpMinResponseDataRateFeature = this;
|
_currentIHttpMinResponseDataRateFeature = this;
|
||||||
_currentIHttpBodyControlFeature = this;
|
_currentIHttpBodyControlFeature = this;
|
||||||
|
|
||||||
_currentIServiceProvidersFeature = null;
|
_currentIServiceProvidersFeature = null;
|
||||||
_currentIHttpAuthenticationFeature = null;
|
_currentIHttpAuthenticationFeature = null;
|
||||||
_currentIQueryFeature = null;
|
_currentIQueryFeature = null;
|
||||||
|
|
@ -82,6 +87,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_currentIHttpSendFileFeature = null;
|
_currentIHttpSendFileFeature = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal void ResetFeatureCollection()
|
||||||
|
{
|
||||||
|
FastReset();
|
||||||
|
MaybeExtra?.Clear();
|
||||||
|
_featureRevision++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ExtraFeatureGet(Type key)
|
||||||
|
{
|
||||||
|
if (MaybeExtra == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
||||||
|
{
|
||||||
|
var kv = MaybeExtra[i];
|
||||||
|
if (kv.Key == key)
|
||||||
|
{
|
||||||
|
return kv.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExtraFeatureSet(Type key, object value)
|
||||||
|
{
|
||||||
|
if (MaybeExtra == null)
|
||||||
|
{
|
||||||
|
MaybeExtra = new List<KeyValuePair<Type, object>>(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
||||||
|
{
|
||||||
|
if (MaybeExtra[i].Key == key)
|
||||||
|
{
|
||||||
|
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IFeatureCollection.IsReadOnly => false;
|
||||||
|
|
||||||
|
int IFeatureCollection.Revision => _featureRevision;
|
||||||
|
|
||||||
object IFeatureCollection.this[Type key]
|
object IFeatureCollection.this[Type key]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -182,7 +234,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
|
|
||||||
if (key == IHttpRequestFeatureType)
|
if (key == IHttpRequestFeatureType)
|
||||||
{
|
{
|
||||||
_currentIHttpRequestFeature = value;
|
_currentIHttpRequestFeature = value;
|
||||||
|
|
@ -274,99 +326,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IFeatureCollection.Set<TFeature>(TFeature feature)
|
|
||||||
{
|
|
||||||
_featureRevision++;
|
|
||||||
if (typeof(TFeature) == typeof(IHttpRequestFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpRequestFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpResponseFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpResponseFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpRequestIdentifierFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpRequestIdentifierFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IServiceProvidersFeature))
|
|
||||||
{
|
|
||||||
_currentIServiceProvidersFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpRequestLifetimeFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpRequestLifetimeFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpConnectionFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpAuthenticationFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IQueryFeature))
|
|
||||||
{
|
|
||||||
_currentIQueryFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IFormFeature))
|
|
||||||
{
|
|
||||||
_currentIFormFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpUpgradeFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpUpgradeFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttp2StreamIdFeature))
|
|
||||||
{
|
|
||||||
_currentIHttp2StreamIdFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IResponseCookiesFeature))
|
|
||||||
{
|
|
||||||
_currentIResponseCookiesFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IItemsFeature))
|
|
||||||
{
|
|
||||||
_currentIItemsFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(ITlsConnectionFeature))
|
|
||||||
{
|
|
||||||
_currentITlsConnectionFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpWebSocketFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpWebSocketFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(ISessionFeature))
|
|
||||||
{
|
|
||||||
_currentISessionFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpMaxRequestBodySizeFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpMaxRequestBodySizeFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpMinRequestBodyDataRateFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpMinRequestBodyDataRateFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpMinResponseDataRateFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpMinResponseDataRateFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpBodyControlFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpBodyControlFeature = feature;
|
|
||||||
}
|
|
||||||
else if (typeof(TFeature) == typeof(IHttpSendFileFeature))
|
|
||||||
{
|
|
||||||
_currentIHttpSendFileFeature = feature;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExtraFeatureSet(typeof(TFeature), feature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TFeature IFeatureCollection.Get<TFeature>()
|
TFeature IFeatureCollection.Get<TFeature>()
|
||||||
{
|
{
|
||||||
TFeature feature = default;
|
TFeature feature = default;
|
||||||
|
|
@ -458,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feature == null)
|
if (feature == null)
|
||||||
{
|
{
|
||||||
feature = ConnectionFeatures.Get<TFeature>();
|
feature = ConnectionFeatures.Get<TFeature>();
|
||||||
|
|
@ -467,100 +426,197 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return feature;
|
return feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IFeatureCollection.Set<TFeature>(TFeature feature)
|
||||||
|
{
|
||||||
|
_featureRevision++;
|
||||||
|
if (typeof(TFeature) == typeof(IHttpRequestFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpRequestFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpResponseFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpResponseFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpRequestIdentifierFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpRequestIdentifierFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IServiceProvidersFeature))
|
||||||
|
{
|
||||||
|
_currentIServiceProvidersFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpRequestLifetimeFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpRequestLifetimeFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpConnectionFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpAuthenticationFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IQueryFeature))
|
||||||
|
{
|
||||||
|
_currentIQueryFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IFormFeature))
|
||||||
|
{
|
||||||
|
_currentIFormFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpUpgradeFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpUpgradeFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttp2StreamIdFeature))
|
||||||
|
{
|
||||||
|
_currentIHttp2StreamIdFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IResponseCookiesFeature))
|
||||||
|
{
|
||||||
|
_currentIResponseCookiesFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IItemsFeature))
|
||||||
|
{
|
||||||
|
_currentIItemsFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(ITlsConnectionFeature))
|
||||||
|
{
|
||||||
|
_currentITlsConnectionFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpWebSocketFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpWebSocketFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(ISessionFeature))
|
||||||
|
{
|
||||||
|
_currentISessionFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpMaxRequestBodySizeFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpMaxRequestBodySizeFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpMinRequestBodyDataRateFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpMinRequestBodyDataRateFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpMinResponseDataRateFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpMinResponseDataRateFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpBodyControlFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpBodyControlFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IHttpSendFileFeature))
|
||||||
|
{
|
||||||
|
_currentIHttpSendFileFeature = feature;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExtraFeatureSet(typeof(TFeature), feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
||||||
{
|
{
|
||||||
if (_currentIHttpRequestFeature != null)
|
if (_currentIHttpRequestFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpResponseFeature != null)
|
if (_currentIHttpResponseFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature);
|
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpRequestIdentifierFeature != null)
|
if (_currentIHttpRequestIdentifierFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature);
|
||||||
}
|
}
|
||||||
if (_currentIServiceProvidersFeature != null)
|
if (_currentIServiceProvidersFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature);
|
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpRequestLifetimeFeature != null)
|
if (_currentIHttpRequestLifetimeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpConnectionFeature != null)
|
if (_currentIHttpConnectionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature);
|
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpAuthenticationFeature != null)
|
if (_currentIHttpAuthenticationFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature);
|
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature);
|
||||||
}
|
}
|
||||||
if (_currentIQueryFeature != null)
|
if (_currentIQueryFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as IQueryFeature);
|
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature);
|
||||||
}
|
}
|
||||||
if (_currentIFormFeature != null)
|
if (_currentIFormFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as IFormFeature);
|
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpUpgradeFeature != null)
|
if (_currentIHttpUpgradeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttp2StreamIdFeature != null)
|
if (_currentIHttp2StreamIdFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature);
|
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature);
|
||||||
}
|
}
|
||||||
if (_currentIResponseCookiesFeature != null)
|
if (_currentIResponseCookiesFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature);
|
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature);
|
||||||
}
|
}
|
||||||
if (_currentIItemsFeature != null)
|
if (_currentIItemsFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as IItemsFeature);
|
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature);
|
||||||
}
|
}
|
||||||
if (_currentITlsConnectionFeature != null)
|
if (_currentITlsConnectionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature);
|
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpWebSocketFeature != null)
|
if (_currentIHttpWebSocketFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature);
|
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature);
|
||||||
}
|
}
|
||||||
if (_currentISessionFeature != null)
|
if (_currentISessionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as ISessionFeature);
|
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMaxRequestBodySizeFeature != null)
|
if (_currentIHttpMaxRequestBodySizeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMinRequestBodyDataRateFeature != null)
|
if (_currentIHttpMinRequestBodyDataRateFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMinResponseDataRateFeature != null)
|
if (_currentIHttpMinResponseDataRateFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpBodyControlFeature != null)
|
if (_currentIHttpBodyControlFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature);
|
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpSendFileFeature != null)
|
if (_currentIHttpSendFileFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature);
|
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MaybeExtra != null)
|
if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
foreach(var item in MaybeExtra)
|
foreach (var item in MaybeExtra)
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
// 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.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
{
|
||||||
|
public partial class TransportConnection : IHttpConnectionFeature,
|
||||||
|
IConnectionIdFeature,
|
||||||
|
IConnectionTransportFeature,
|
||||||
|
IConnectionItemsFeature,
|
||||||
|
IMemoryPoolFeature,
|
||||||
|
IApplicationTransportFeature,
|
||||||
|
ITransportSchedulerFeature,
|
||||||
|
IConnectionLifetimeFeature,
|
||||||
|
IBytesWrittenFeature
|
||||||
|
{
|
||||||
|
// NOTE: When feature interfaces are added to or removed from this TransportConnection class implementation,
|
||||||
|
// then the list of `features` in the generated code project MUST also be updated.
|
||||||
|
// See also: tools/CodeGenerator/TransportConnectionFeatureCollection.cs
|
||||||
|
|
||||||
|
string IHttpConnectionFeature.ConnectionId
|
||||||
|
{
|
||||||
|
get => ConnectionId;
|
||||||
|
set => ConnectionId = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress IHttpConnectionFeature.RemoteIpAddress
|
||||||
|
{
|
||||||
|
get => RemoteAddress;
|
||||||
|
set => RemoteAddress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress IHttpConnectionFeature.LocalIpAddress
|
||||||
|
{
|
||||||
|
get => LocalAddress;
|
||||||
|
set => LocalAddress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IHttpConnectionFeature.RemotePort
|
||||||
|
{
|
||||||
|
get => RemotePort;
|
||||||
|
set => RemotePort = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IHttpConnectionFeature.LocalPort
|
||||||
|
{
|
||||||
|
get => LocalPort;
|
||||||
|
set => LocalPort = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPool<byte> IMemoryPoolFeature.MemoryPool => MemoryPool;
|
||||||
|
|
||||||
|
IDuplexPipe IConnectionTransportFeature.Transport
|
||||||
|
{
|
||||||
|
get => Transport;
|
||||||
|
set => Transport = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDuplexPipe IApplicationTransportFeature.Application
|
||||||
|
{
|
||||||
|
get => Application;
|
||||||
|
set => Application = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary<object, object> IConnectionItemsFeature.Items
|
||||||
|
{
|
||||||
|
get => Items;
|
||||||
|
set => Items = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PipeScheduler ITransportSchedulerFeature.InputWriterScheduler => InputWriterScheduler;
|
||||||
|
PipeScheduler ITransportSchedulerFeature.OutputReaderScheduler => OutputReaderScheduler;
|
||||||
|
|
||||||
|
CancellationToken IConnectionLifetimeFeature.ConnectionClosed
|
||||||
|
{
|
||||||
|
get => ConnectionClosed;
|
||||||
|
set => ConnectionClosed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IConnectionLifetimeFeature.Abort() => Abort();
|
||||||
|
|
||||||
|
long IBytesWrittenFeature.TotalBytesWritten => TotalBytesWritten;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,16 @@
|
||||||
using System;
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
using System.Buffers;
|
// 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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using Microsoft.AspNetCore.Connections.Features;
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
{
|
{
|
||||||
public partial class TransportConnection : IFeatureCollection,
|
public partial class TransportConnection : IFeatureCollection
|
||||||
IHttpConnectionFeature,
|
|
||||||
IConnectionIdFeature,
|
|
||||||
IConnectionTransportFeature,
|
|
||||||
IConnectionItemsFeature,
|
|
||||||
IMemoryPoolFeature,
|
|
||||||
IApplicationTransportFeature,
|
|
||||||
ITransportSchedulerFeature,
|
|
||||||
IConnectionLifetimeFeature,
|
|
||||||
IBytesWrittenFeature
|
|
||||||
{
|
{
|
||||||
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
||||||
private static readonly Type IConnectionIdFeatureType = typeof(IConnectionIdFeature);
|
private static readonly Type IConnectionIdFeatureType = typeof(IConnectionIdFeature);
|
||||||
|
|
@ -45,6 +36,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
|
||||||
private List<KeyValuePair<Type, object>> MaybeExtra;
|
private List<KeyValuePair<Type, object>> MaybeExtra;
|
||||||
|
|
||||||
|
private void FastReset()
|
||||||
|
{
|
||||||
|
_currentIHttpConnectionFeature = this;
|
||||||
|
_currentIConnectionIdFeature = this;
|
||||||
|
_currentIConnectionTransportFeature = this;
|
||||||
|
_currentIConnectionItemsFeature = this;
|
||||||
|
_currentIMemoryPoolFeature = this;
|
||||||
|
_currentIApplicationTransportFeature = this;
|
||||||
|
_currentITransportSchedulerFeature = this;
|
||||||
|
_currentIConnectionLifetimeFeature = this;
|
||||||
|
_currentIBytesWrittenFeature = this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal void ResetFeatureCollection()
|
||||||
|
{
|
||||||
|
FastReset();
|
||||||
|
MaybeExtra?.Clear();
|
||||||
|
_featureRevision++;
|
||||||
|
}
|
||||||
|
|
||||||
private object ExtraFeatureGet(Type key)
|
private object ExtraFeatureGet(Type key)
|
||||||
{
|
{
|
||||||
if (MaybeExtra == null)
|
if (MaybeExtra == null)
|
||||||
|
|
@ -84,125 +97,55 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
|
||||||
int IFeatureCollection.Revision => _featureRevision;
|
int IFeatureCollection.Revision => _featureRevision;
|
||||||
|
|
||||||
string IHttpConnectionFeature.ConnectionId
|
|
||||||
{
|
|
||||||
get => ConnectionId;
|
|
||||||
set => ConnectionId = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress IHttpConnectionFeature.RemoteIpAddress
|
|
||||||
{
|
|
||||||
get => RemoteAddress;
|
|
||||||
set => RemoteAddress = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress IHttpConnectionFeature.LocalIpAddress
|
|
||||||
{
|
|
||||||
get => LocalAddress;
|
|
||||||
set => LocalAddress = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int IHttpConnectionFeature.RemotePort
|
|
||||||
{
|
|
||||||
get => RemotePort;
|
|
||||||
set => RemotePort = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int IHttpConnectionFeature.LocalPort
|
|
||||||
{
|
|
||||||
get => LocalPort;
|
|
||||||
set => LocalPort = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryPool<byte> IMemoryPoolFeature.MemoryPool => MemoryPool;
|
|
||||||
|
|
||||||
IDuplexPipe IConnectionTransportFeature.Transport
|
|
||||||
{
|
|
||||||
get => Transport;
|
|
||||||
set => Transport = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDuplexPipe IApplicationTransportFeature.Application
|
|
||||||
{
|
|
||||||
get => Application;
|
|
||||||
set => Application = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDictionary<object, object> IConnectionItemsFeature.Items
|
|
||||||
{
|
|
||||||
get => Items;
|
|
||||||
set => Items = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
CancellationToken IConnectionLifetimeFeature.ConnectionClosed
|
|
||||||
{
|
|
||||||
get => ConnectionClosed;
|
|
||||||
set => ConnectionClosed = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IConnectionLifetimeFeature.Abort() => Abort();
|
|
||||||
|
|
||||||
long IBytesWrittenFeature.TotalBytesWritten => TotalBytesWritten;
|
|
||||||
|
|
||||||
PipeScheduler ITransportSchedulerFeature.InputWriterScheduler => InputWriterScheduler;
|
|
||||||
PipeScheduler ITransportSchedulerFeature.OutputReaderScheduler => OutputReaderScheduler;
|
|
||||||
|
|
||||||
object IFeatureCollection.this[Type key]
|
object IFeatureCollection.this[Type key]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
object feature = null;
|
||||||
if (key == IHttpConnectionFeatureType)
|
if (key == IHttpConnectionFeatureType)
|
||||||
{
|
{
|
||||||
return _currentIHttpConnectionFeature;
|
feature = _currentIHttpConnectionFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionIdFeatureType)
|
||||||
if (key == IConnectionIdFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIConnectionIdFeature;
|
feature = _currentIConnectionIdFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionTransportFeatureType)
|
||||||
if (key == IConnectionTransportFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIConnectionTransportFeature;
|
feature = _currentIConnectionTransportFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionItemsFeatureType)
|
||||||
if (key == IConnectionItemsFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIConnectionItemsFeature;
|
feature = _currentIConnectionItemsFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IMemoryPoolFeatureType)
|
||||||
if (key == IMemoryPoolFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIMemoryPoolFeature;
|
feature = _currentIMemoryPoolFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IApplicationTransportFeatureType)
|
||||||
if (key == IApplicationTransportFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIApplicationTransportFeature;
|
feature = _currentIApplicationTransportFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == ITransportSchedulerFeatureType)
|
||||||
if (key == ITransportSchedulerFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentITransportSchedulerFeature;
|
feature = _currentITransportSchedulerFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IConnectionLifetimeFeatureType)
|
||||||
if (key == IConnectionLifetimeFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIConnectionLifetimeFeature;
|
feature = _currentIConnectionLifetimeFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IBytesWrittenFeatureType)
|
||||||
if (key == IBytesWrittenFeatureType)
|
|
||||||
{
|
{
|
||||||
return _currentIBytesWrittenFeature;
|
feature = _currentIBytesWrittenFeature;
|
||||||
}
|
}
|
||||||
|
else if (MaybeExtra != null)
|
||||||
if (MaybeExtra != null)
|
|
||||||
{
|
{
|
||||||
return ExtraFeatureGet(key);
|
feature = ExtraFeatureGet(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
|
|
@ -252,142 +195,130 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
|
||||||
TFeature IFeatureCollection.Get<TFeature>()
|
TFeature IFeatureCollection.Get<TFeature>()
|
||||||
{
|
{
|
||||||
|
TFeature feature = default;
|
||||||
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIHttpConnectionFeature;
|
feature = (TFeature)_currentIHttpConnectionFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIConnectionIdFeature;
|
feature = (TFeature)_currentIConnectionIdFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIConnectionTransportFeature;
|
feature = (TFeature)_currentIConnectionTransportFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIConnectionItemsFeature;
|
feature = (TFeature)_currentIConnectionItemsFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIMemoryPoolFeature;
|
feature = (TFeature)_currentIMemoryPoolFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIApplicationTransportFeature;
|
feature = (TFeature)_currentIApplicationTransportFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentITransportSchedulerFeature;
|
feature = (TFeature)_currentITransportSchedulerFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIConnectionLifetimeFeature;
|
feature = (TFeature)_currentIConnectionLifetimeFeature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
||||||
{
|
{
|
||||||
return (TFeature)_currentIBytesWrittenFeature;
|
feature = (TFeature)_currentIBytesWrittenFeature;
|
||||||
}
|
}
|
||||||
else if (MaybeExtra != null)
|
else if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
return (TFeature)ExtraFeatureGet(typeof(TFeature));
|
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IFeatureCollection.Set<TFeature>(TFeature instance)
|
void IFeatureCollection.Set<TFeature>(TFeature feature)
|
||||||
{
|
{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
|
|
||||||
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
||||||
{
|
{
|
||||||
_currentIHttpConnectionFeature = instance;
|
_currentIHttpConnectionFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
||||||
{
|
{
|
||||||
_currentIConnectionIdFeature = instance;
|
_currentIConnectionIdFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
||||||
{
|
{
|
||||||
_currentIConnectionTransportFeature = instance;
|
_currentIConnectionTransportFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
||||||
{
|
{
|
||||||
_currentIConnectionItemsFeature = instance;
|
_currentIConnectionItemsFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
||||||
{
|
{
|
||||||
_currentIMemoryPoolFeature = instance;
|
_currentIMemoryPoolFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
||||||
{
|
{
|
||||||
_currentIApplicationTransportFeature = instance;
|
_currentIApplicationTransportFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
||||||
{
|
{
|
||||||
_currentITransportSchedulerFeature = instance;
|
_currentITransportSchedulerFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
||||||
{
|
{
|
||||||
_currentIConnectionLifetimeFeature = instance;
|
_currentIConnectionLifetimeFeature = feature;
|
||||||
}
|
}
|
||||||
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
||||||
{
|
{
|
||||||
_currentIBytesWrittenFeature = instance;
|
_currentIBytesWrittenFeature = feature;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExtraFeatureSet(typeof(TFeature), instance);
|
ExtraFeatureSet(typeof(TFeature), feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
||||||
|
|
||||||
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
||||||
{
|
{
|
||||||
if (_currentIHttpConnectionFeature != null)
|
if (_currentIHttpConnectionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIConnectionIdFeature != null)
|
if (_currentIConnectionIdFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);
|
yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIConnectionTransportFeature != null)
|
if (_currentIConnectionTransportFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);
|
yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIConnectionItemsFeature != null)
|
if (_currentIConnectionItemsFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IConnectionItemsFeatureType, _currentIConnectionItemsFeature);
|
yield return new KeyValuePair<Type, object>(IConnectionItemsFeatureType, _currentIConnectionItemsFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIMemoryPoolFeature != null)
|
if (_currentIMemoryPoolFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IMemoryPoolFeatureType, _currentIMemoryPoolFeature);
|
yield return new KeyValuePair<Type, object>(IMemoryPoolFeatureType, _currentIMemoryPoolFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIApplicationTransportFeature != null)
|
if (_currentIApplicationTransportFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IApplicationTransportFeatureType, _currentIApplicationTransportFeature);
|
yield return new KeyValuePair<Type, object>(IApplicationTransportFeatureType, _currentIApplicationTransportFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentITransportSchedulerFeature != null)
|
if (_currentITransportSchedulerFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(ITransportSchedulerFeatureType, _currentITransportSchedulerFeature);
|
yield return new KeyValuePair<Type, object>(ITransportSchedulerFeatureType, _currentITransportSchedulerFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIConnectionLifetimeFeature != null)
|
if (_currentIConnectionLifetimeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature);
|
yield return new KeyValuePair<Type, object>(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentIBytesWrittenFeature != null)
|
if (_currentIBytesWrittenFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IBytesWrittenFeatureType, _currentIBytesWrittenFeature);
|
yield return new KeyValuePair<Type, object>(IBytesWrittenFeatureType, _currentIBytesWrittenFeature);
|
||||||
|
|
@ -401,5 +332,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
using System.Buffers;
|
// 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.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
|
||||||
|
|
@ -15,26 +15,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
const string httpHeadersGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs";
|
const string httpHeadersGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs";
|
||||||
const string httpProtocolGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs";
|
const string httpProtocolGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs";
|
||||||
const string httpUtilitiesGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Infrastructure/HttpUtilities.Generated.cs";
|
const string httpUtilitiesGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Infrastructure/HttpUtilities.Generated.cs";
|
||||||
|
const string transportConnectionGeneratedPath = "../../../../../src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Generated.cs";
|
||||||
|
|
||||||
var testHttpHeadersGeneratedPath = Path.GetTempFileName();
|
var testHttpHeadersGeneratedPath = Path.GetTempFileName();
|
||||||
var testHttpProtocolGeneratedPath = Path.GetTempFileName();
|
var testHttpProtocolGeneratedPath = Path.GetTempFileName();
|
||||||
var testHttpUtilitiesGeneratedPath = Path.GetTempFileName();
|
var testHttpUtilitiesGeneratedPath = Path.GetTempFileName();
|
||||||
|
var testTransportConnectionGeneratedPath = Path.GetTempFileName();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentHttpHeadersGenerated = File.ReadAllText(httpHeadersGeneratedPath);
|
var currentHttpHeadersGenerated = File.ReadAllText(httpHeadersGeneratedPath);
|
||||||
var currentHttpProtocolGenerated = File.ReadAllText(httpProtocolGeneratedPath);
|
var currentHttpProtocolGenerated = File.ReadAllText(httpProtocolGeneratedPath);
|
||||||
var currentHttpUtilitiesGenerated = File.ReadAllText(httpUtilitiesGeneratedPath);
|
var currentHttpUtilitiesGenerated = File.ReadAllText(httpUtilitiesGeneratedPath);
|
||||||
|
var currentTransportConnectionGenerated = File.ReadAllText(transportConnectionGeneratedPath);
|
||||||
|
|
||||||
CodeGenerator.Program.Run(testHttpHeadersGeneratedPath, testHttpProtocolGeneratedPath, testHttpUtilitiesGeneratedPath);
|
CodeGenerator.Program.Run(testHttpHeadersGeneratedPath, testHttpProtocolGeneratedPath, testHttpUtilitiesGeneratedPath, testTransportConnectionGeneratedPath);
|
||||||
|
|
||||||
var testHttpHeadersGenerated = File.ReadAllText(testHttpHeadersGeneratedPath);
|
var testHttpHeadersGenerated = File.ReadAllText(testHttpHeadersGeneratedPath);
|
||||||
var testHttpProtocolGenerated = File.ReadAllText(testHttpProtocolGeneratedPath);
|
var testHttpProtocolGenerated = File.ReadAllText(testHttpProtocolGeneratedPath);
|
||||||
var testHttpUtilitiesGenerated = File.ReadAllText(testHttpUtilitiesGeneratedPath);
|
var testHttpUtilitiesGenerated = File.ReadAllText(testHttpUtilitiesGeneratedPath);
|
||||||
|
var testTransportConnectionGenerated = File.ReadAllText(testTransportConnectionGeneratedPath);
|
||||||
|
|
||||||
Assert.Equal(currentHttpHeadersGenerated, testHttpHeadersGenerated, ignoreLineEndingDifferences: true);
|
Assert.Equal(currentHttpHeadersGenerated, testHttpHeadersGenerated, ignoreLineEndingDifferences: true);
|
||||||
Assert.Equal(currentHttpProtocolGenerated, testHttpProtocolGenerated, ignoreLineEndingDifferences: true);
|
Assert.Equal(currentHttpProtocolGenerated, testHttpProtocolGenerated, ignoreLineEndingDifferences: true);
|
||||||
Assert.Equal(currentHttpUtilitiesGenerated, testHttpUtilitiesGenerated, ignoreLineEndingDifferences: true);
|
Assert.Equal(currentHttpUtilitiesGenerated, testHttpUtilitiesGenerated, ignoreLineEndingDifferences: true);
|
||||||
|
Assert.Equal(currentTransportConnectionGenerated, testTransportConnectionGenerated, ignoreLineEndingDifferences: true);
|
||||||
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -42,6 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
File.Delete(testHttpHeadersGeneratedPath);
|
File.Delete(testHttpHeadersGeneratedPath);
|
||||||
File.Delete(testHttpProtocolGeneratedPath);
|
File.Delete(testHttpProtocolGeneratedPath);
|
||||||
File.Delete(testHttpUtilitiesGeneratedPath);
|
File.Delete(testHttpUtilitiesGeneratedPath);
|
||||||
|
File.Delete(testTransportConnectionGeneratedPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,10 @@
|
||||||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
||||||
|
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@
|
||||||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
|
||||||
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,6 @@
|
||||||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
|
||||||
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Sockets\Kestrel.Transport.Sockets.csproj" />
|
<ProjectReference Include="..\..\src\Kestrel.Transport.Sockets\Kestrel.Transport.Sockets.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartWorkingDirectory>$(MSBuildThisFileDirectory)..\..\src\Kestrel.Core</StartWorkingDirectory>
|
<StartWorkingDirectory>$(MSBuildThisFileDirectory)..\..\</StartWorkingDirectory>
|
||||||
<StartArguments>Internal/Http/HttpHeaders.Generated.cs Internal/Http/HttpProtocol.Generated.cs Internal/Infrastructure/HttpUtilities.Generated.cs</StartArguments>
|
<StartArguments>src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs src/Kestrel.Core/Internal/Infrastructure/HttpUtilities.Generated.cs src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Generated.cs</StartArguments>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
public static class FeatureCollectionGenerator
|
||||||
|
{
|
||||||
|
public static string GenerateFile(string namespaceName, string className, string[] allFeatures, string[] implementedFeatures, string extraUsings, string fallbackFeatures)
|
||||||
|
{
|
||||||
|
// NOTE: This list MUST always match the set of feature interfaces implemented by TransportConnection.
|
||||||
|
// See also: src/Kestrel/Http/TransportConnection.FeatureCollection.cs
|
||||||
|
var features = allFeatures.Select((type, index) => new KnownFeature
|
||||||
|
{
|
||||||
|
Name = type,
|
||||||
|
Index = index
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
{extraUsings}
|
||||||
|
|
||||||
|
namespace {namespaceName}
|
||||||
|
{{
|
||||||
|
public partial class {className} : IFeatureCollection
|
||||||
|
{{{Each(features, feature => $@"
|
||||||
|
private static readonly Type {feature.Name}Type = typeof({feature.Name});")}
|
||||||
|
{Each(features, feature => $@"
|
||||||
|
private object _current{feature.Name};")}
|
||||||
|
|
||||||
|
private int _featureRevision;
|
||||||
|
|
||||||
|
private List<KeyValuePair<Type, object>> MaybeExtra;
|
||||||
|
|
||||||
|
private void FastReset()
|
||||||
|
{{{Each(implementedFeatures, feature => $@"
|
||||||
|
_current{feature} = this;")}
|
||||||
|
{Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@"
|
||||||
|
_current{feature} = null;")}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal void ResetFeatureCollection()
|
||||||
|
{{
|
||||||
|
FastReset();
|
||||||
|
MaybeExtra?.Clear();
|
||||||
|
_featureRevision++;
|
||||||
|
}}
|
||||||
|
|
||||||
|
private object ExtraFeatureGet(Type key)
|
||||||
|
{{
|
||||||
|
if (MaybeExtra == null)
|
||||||
|
{{
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
||||||
|
{{
|
||||||
|
var kv = MaybeExtra[i];
|
||||||
|
if (kv.Key == key)
|
||||||
|
{{
|
||||||
|
return kv.Value;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
|
||||||
|
private void ExtraFeatureSet(Type key, object value)
|
||||||
|
{{
|
||||||
|
if (MaybeExtra == null)
|
||||||
|
{{
|
||||||
|
MaybeExtra = new List<KeyValuePair<Type, object>>(2);
|
||||||
|
}}
|
||||||
|
|
||||||
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
||||||
|
{{
|
||||||
|
if (MaybeExtra[i].Key == key)
|
||||||
|
{{
|
||||||
|
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
|
||||||
|
}}
|
||||||
|
|
||||||
|
bool IFeatureCollection.IsReadOnly => false;
|
||||||
|
|
||||||
|
int IFeatureCollection.Revision => _featureRevision;
|
||||||
|
|
||||||
|
object IFeatureCollection.this[Type key]
|
||||||
|
{{
|
||||||
|
get
|
||||||
|
{{
|
||||||
|
object feature = null;{Each(features, feature => $@"
|
||||||
|
{(feature.Index != 0 ? "else " : "")}if (key == {feature.Name}Type)
|
||||||
|
{{
|
||||||
|
feature = _current{feature.Name};
|
||||||
|
}}")}
|
||||||
|
else if (MaybeExtra != null)
|
||||||
|
{{
|
||||||
|
feature = ExtraFeatureGet(key);
|
||||||
|
}}
|
||||||
|
|
||||||
|
return feature{(string.IsNullOrEmpty(fallbackFeatures) ? "" : $" ?? {fallbackFeatures}[key]")};
|
||||||
|
}}
|
||||||
|
|
||||||
|
set
|
||||||
|
{{
|
||||||
|
_featureRevision++;
|
||||||
|
{Each(features, feature => $@"
|
||||||
|
{(feature.Index != 0 ? "else " : "")}if (key == {feature.Name}Type)
|
||||||
|
{{
|
||||||
|
_current{feature.Name} = value;
|
||||||
|
}}")}
|
||||||
|
else
|
||||||
|
{{
|
||||||
|
ExtraFeatureSet(key, value);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
TFeature IFeatureCollection.Get<TFeature>()
|
||||||
|
{{
|
||||||
|
TFeature feature = default;{Each(features, 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)));
|
||||||
|
}}{(string.IsNullOrEmpty(fallbackFeatures) ? "" : $@"
|
||||||
|
|
||||||
|
if (feature == null)
|
||||||
|
{{
|
||||||
|
feature = {fallbackFeatures}.Get<TFeature>();
|
||||||
|
}}")}
|
||||||
|
|
||||||
|
return feature;
|
||||||
|
}}
|
||||||
|
|
||||||
|
void IFeatureCollection.Set<TFeature>(TFeature feature)
|
||||||
|
{{
|
||||||
|
_featureRevision++;{Each(features, feature => $@"
|
||||||
|
{(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name}))
|
||||||
|
{{
|
||||||
|
_current{feature.Name} = feature;
|
||||||
|
}}")}
|
||||||
|
else
|
||||||
|
{{
|
||||||
|
ExtraFeatureSet(typeof(TFeature), feature);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
||||||
|
{{{Each(features, feature => $@"
|
||||||
|
if (_current{feature.Name} != null)
|
||||||
|
{{
|
||||||
|
yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name});
|
||||||
|
}}")}
|
||||||
|
|
||||||
|
if (MaybeExtra != null)
|
||||||
|
{{
|
||||||
|
foreach (var item in MaybeExtra)
|
||||||
|
{{
|
||||||
|
yield return item;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
||||||
|
{
|
||||||
|
return values.Any() ? values.Select(formatter).Aggregate((a, b) => a + b) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KnownFeature
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public int Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,28 +1,13 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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;
|
using System.Linq;
|
||||||
|
|
||||||
namespace CodeGenerator
|
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
|
public class HttpProtocolFeatureCollection
|
||||||
{
|
{
|
||||||
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
public static string GenerateFile()
|
||||||
{
|
|
||||||
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[]
|
var alwaysFeatures = new[]
|
||||||
{
|
{
|
||||||
|
|
@ -65,14 +50,10 @@ namespace CodeGenerator
|
||||||
.Concat(commonFeatures)
|
.Concat(commonFeatures)
|
||||||
.Concat(sometimesFeatures)
|
.Concat(sometimesFeatures)
|
||||||
.Concat(rareFeatures)
|
.Concat(rareFeatures)
|
||||||
.Select((type, index) => new KnownFeature
|
.ToArray();
|
||||||
{
|
|
||||||
Name = type,
|
|
||||||
Index = index
|
|
||||||
});
|
|
||||||
|
|
||||||
// NOTE: This list MUST always match the set of feature interfaces implemented by HttpProtocol.
|
// NOTE: This list MUST always match the set of feature interfaces implemented by HttpProtocol.
|
||||||
// See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs
|
// See also: src/Kestrel.Core/Internal/Http/HttpProtocol.FeatureCollection.cs
|
||||||
var implementedFeatures = new[]
|
var implementedFeatures = new[]
|
||||||
{
|
{
|
||||||
"IHttpRequestFeature",
|
"IHttpRequestFeature",
|
||||||
|
|
@ -86,114 +67,18 @@ namespace CodeGenerator
|
||||||
"IHttpBodyControlFeature",
|
"IHttpBodyControlFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
return $@"// Copyright (c) .NET Foundation. All rights reserved.
|
var usings = $@"
|
||||||
// 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;
|
||||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;";
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
return FeatureCollectionGenerator.GenerateFile(
|
||||||
{{
|
namespaceName: "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http",
|
||||||
public partial class {className}
|
className: "HttpProtocol",
|
||||||
{{{Each(allFeatures, feature => $@"
|
allFeatures: allFeatures,
|
||||||
private static readonly Type {feature.Name}Type = typeof({feature.Name});")}
|
implementedFeatures: implementedFeatures,
|
||||||
{Each(allFeatures, feature => $@"
|
extraUsings: usings,
|
||||||
private object _current{feature.Name};")}
|
fallbackFeatures: "ConnectionFeatures");
|
||||||
|
|
||||||
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;
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@ using System.Text;
|
||||||
|
|
||||||
namespace CodeGenerator
|
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 KnownHeaders
|
public class KnownHeaders
|
||||||
{
|
{
|
||||||
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
||||||
|
|
@ -18,11 +16,6 @@ namespace CodeGenerator
|
||||||
return values.Any() ? values.Select(formatter).Aggregate((a, b) => a + b) : "";
|
return values.Any() ? values.Select(formatter).Aggregate((a, b) => a + b) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static string If(bool condition, Func<string> formatter)
|
|
||||||
{
|
|
||||||
return condition ? formatter() : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
static string AppendSwitch(IEnumerable<IGrouping<int, KnownHeader>> values, string className) =>
|
static string AppendSwitch(IEnumerable<IGrouping<int, KnownHeader>> values, string className) =>
|
||||||
$@"var pUL = (ulong*)pUB;
|
$@"var pUL = (ulong*)pUB;
|
||||||
var pUI = (uint*)pUB;
|
var pUI = (uint*)pUB;
|
||||||
|
|
|
||||||
|
|
@ -25,17 +25,27 @@ namespace CodeGenerator
|
||||||
Console.Error.WriteLine("Missing path to HttpUtilities.Generated.cs");
|
Console.Error.WriteLine("Missing path to HttpUtilities.Generated.cs");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if (args.Length < 4)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Missing path to TransportConnection.Generated.cs");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Run(args[0], args[1], args[2]);
|
Run(args[0], args[1], args[2], args[3]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath)
|
public static void Run(
|
||||||
|
string knownHeadersPath,
|
||||||
|
string httpProtocolFeatureCollectionPath,
|
||||||
|
string httpUtilitiesPath,
|
||||||
|
string transportConnectionFeatureCollectionPath)
|
||||||
{
|
{
|
||||||
var knownHeadersContent = KnownHeaders.GeneratedFile();
|
var knownHeadersContent = KnownHeaders.GeneratedFile();
|
||||||
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile("HttpProtocol");
|
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GenerateFile();
|
||||||
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
|
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
|
||||||
|
var transportConnectionFeatureCollectionContent = TransportConnectionFeatureCollection.GenerateFile();
|
||||||
|
|
||||||
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";
|
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";
|
||||||
if (!string.Equals(knownHeadersContent, existingKnownHeaders))
|
if (!string.Equals(knownHeadersContent, existingKnownHeaders))
|
||||||
|
|
@ -54,6 +64,12 @@ namespace CodeGenerator
|
||||||
{
|
{
|
||||||
File.WriteAllText(httpUtilitiesPath, httpUtilitiesContent);
|
File.WriteAllText(httpUtilitiesPath, httpUtilitiesContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var existingTransportConnectionFeatureCollection = File.Exists(transportConnectionFeatureCollectionPath) ? File.ReadAllText(transportConnectionFeatureCollectionPath) : "";
|
||||||
|
if (!string.Equals(transportConnectionFeatureCollectionContent, existingTransportConnectionFeatureCollection))
|
||||||
|
{
|
||||||
|
File.WriteAllText(transportConnectionFeatureCollectionPath, transportConnectionFeatureCollectionContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace CodeGenerator
|
||||||
|
{
|
||||||
|
public class TransportConnectionFeatureCollection
|
||||||
|
{
|
||||||
|
public static string GenerateFile()
|
||||||
|
{
|
||||||
|
// NOTE: This list MUST always match the set of feature interfaces implemented by TransportConnection.
|
||||||
|
// See also: src/Kestrel.Transport.Abstractions/Internal/TransportConnection.FeatureCollection.cs
|
||||||
|
var features = new[]
|
||||||
|
{
|
||||||
|
"IHttpConnectionFeature",
|
||||||
|
"IConnectionIdFeature",
|
||||||
|
"IConnectionTransportFeature",
|
||||||
|
"IConnectionItemsFeature",
|
||||||
|
"IMemoryPoolFeature",
|
||||||
|
"IApplicationTransportFeature",
|
||||||
|
"ITransportSchedulerFeature",
|
||||||
|
"IConnectionLifetimeFeature",
|
||||||
|
"IBytesWrittenFeature",
|
||||||
|
};
|
||||||
|
|
||||||
|
var usings = $@"
|
||||||
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;";
|
||||||
|
|
||||||
|
return FeatureCollectionGenerator.GenerateFile(
|
||||||
|
namespaceName: "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal",
|
||||||
|
className: "TransportConnection",
|
||||||
|
allFeatures: features,
|
||||||
|
implementedFeatures: features,
|
||||||
|
extraUsings: usings,
|
||||||
|
fallbackFeatures: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue