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.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
|
@ -16,8 +14,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||
{
|
||||
public partial class HttpProtocol : IFeatureCollection,
|
||||
IHttpRequestFeature,
|
||||
public partial class HttpProtocol : IHttpRequestFeature,
|
||||
IHttpResponseFeature,
|
||||
IHttpConnectionFeature,
|
||||
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,
|
||||
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||
// See also: tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/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));
|
||||
}
|
||||
// See also: tools/CodeGenerator/HttpProtocolFeatureCollection.cs
|
||||
|
||||
string IHttpRequestFeature.Protocol
|
||||
{
|
||||
|
|
@ -175,9 +126,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
bool IHttpResponseFeature.HasStarted => HasResponseStarted;
|
||||
|
||||
bool IFeatureCollection.IsReadOnly => false;
|
||||
|
||||
int IFeatureCollection.Revision => _featureRevision;
|
||||
|
||||
IPAddress IHttpConnectionFeature.RemoteIpAddress
|
||||
{
|
||||
|
|
@ -277,10 +225,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
OnCompleted(callback, state);
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||
|
||||
void IHttpRequestLifetimeFeature.Abort()
|
||||
{
|
||||
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.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
|
@ -10,7 +11,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
|||
|
||||
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 IHttpResponseFeatureType = typeof(IHttpResponseFeature);
|
||||
|
|
@ -56,6 +57,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
private object _currentIHttpBodyControlFeature;
|
||||
private object _currentIHttpSendFileFeature;
|
||||
|
||||
private int _featureRevision;
|
||||
|
||||
private List<KeyValuePair<Type, object>> MaybeExtra;
|
||||
|
||||
private void FastReset()
|
||||
{
|
||||
_currentIHttpRequestFeature = this;
|
||||
|
|
@ -67,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
_currentIHttpMinRequestBodyDataRateFeature = this;
|
||||
_currentIHttpMinResponseDataRateFeature = this;
|
||||
_currentIHttpBodyControlFeature = this;
|
||||
|
||||
|
||||
_currentIServiceProvidersFeature = null;
|
||||
_currentIHttpAuthenticationFeature = null;
|
||||
_currentIQueryFeature = null;
|
||||
|
|
@ -82,6 +87,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
_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]
|
||||
{
|
||||
get
|
||||
|
|
@ -182,7 +234,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
set
|
||||
{
|
||||
_featureRevision++;
|
||||
|
||||
|
||||
if (key == IHttpRequestFeatureType)
|
||||
{
|
||||
_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 feature = default;
|
||||
|
|
@ -458,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
{
|
||||
feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
|
||||
}
|
||||
|
||||
|
||||
if (feature == null)
|
||||
{
|
||||
feature = ConnectionFeatures.Get<TFeature>();
|
||||
|
|
@ -467,100 +426,197 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
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()
|
||||
{
|
||||
if (_currentIHttpRequestFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature);
|
||||
}
|
||||
if (_currentIHttpResponseFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature);
|
||||
}
|
||||
if (_currentIHttpRequestIdentifierFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature);
|
||||
}
|
||||
if (_currentIServiceProvidersFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature);
|
||||
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature);
|
||||
}
|
||||
if (_currentIHttpRequestLifetimeFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature);
|
||||
}
|
||||
if (_currentIHttpConnectionFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
||||
}
|
||||
if (_currentIHttpAuthenticationFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature);
|
||||
}
|
||||
if (_currentIQueryFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as IQueryFeature);
|
||||
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature);
|
||||
}
|
||||
if (_currentIFormFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as IFormFeature);
|
||||
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature);
|
||||
}
|
||||
if (_currentIHttpUpgradeFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature);
|
||||
}
|
||||
if (_currentIHttp2StreamIdFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature);
|
||||
}
|
||||
if (_currentIResponseCookiesFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature);
|
||||
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature);
|
||||
}
|
||||
if (_currentIItemsFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as IItemsFeature);
|
||||
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature);
|
||||
}
|
||||
if (_currentITlsConnectionFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature);
|
||||
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature);
|
||||
}
|
||||
if (_currentIHttpWebSocketFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature);
|
||||
}
|
||||
if (_currentISessionFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as ISessionFeature);
|
||||
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature);
|
||||
}
|
||||
if (_currentIHttpMaxRequestBodySizeFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature);
|
||||
}
|
||||
if (_currentIHttpMinRequestBodyDataRateFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature);
|
||||
}
|
||||
if (_currentIHttpMinResponseDataRateFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature);
|
||||
}
|
||||
if (_currentIHttpBodyControlFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature);
|
||||
}
|
||||
if (_currentIHttpSendFileFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature);
|
||||
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature);
|
||||
}
|
||||
|
||||
if (MaybeExtra != null)
|
||||
{
|
||||
foreach(var item in MaybeExtra)
|
||||
foreach (var item in MaybeExtra)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
using System.Collections;
|
||||
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 : IFeatureCollection,
|
||||
IHttpConnectionFeature,
|
||||
IConnectionIdFeature,
|
||||
IConnectionTransportFeature,
|
||||
IConnectionItemsFeature,
|
||||
IMemoryPoolFeature,
|
||||
IApplicationTransportFeature,
|
||||
ITransportSchedulerFeature,
|
||||
IConnectionLifetimeFeature,
|
||||
IBytesWrittenFeature
|
||||
public partial class TransportConnection : IFeatureCollection
|
||||
{
|
||||
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
||||
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 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)
|
||||
{
|
||||
if (MaybeExtra == null)
|
||||
|
|
@ -84,125 +97,55 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
|||
|
||||
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]
|
||||
{
|
||||
get
|
||||
{
|
||||
object feature = null;
|
||||
if (key == IHttpConnectionFeatureType)
|
||||
{
|
||||
return _currentIHttpConnectionFeature;
|
||||
feature = _currentIHttpConnectionFeature;
|
||||
}
|
||||
|
||||
if (key == IConnectionIdFeatureType)
|
||||
else if (key == IConnectionIdFeatureType)
|
||||
{
|
||||
return _currentIConnectionIdFeature;
|
||||
feature = _currentIConnectionIdFeature;
|
||||
}
|
||||
|
||||
if (key == IConnectionTransportFeatureType)
|
||||
else if (key == IConnectionTransportFeatureType)
|
||||
{
|
||||
return _currentIConnectionTransportFeature;
|
||||
feature = _currentIConnectionTransportFeature;
|
||||
}
|
||||
|
||||
if (key == IConnectionItemsFeatureType)
|
||||
else if (key == IConnectionItemsFeatureType)
|
||||
{
|
||||
return _currentIConnectionItemsFeature;
|
||||
feature = _currentIConnectionItemsFeature;
|
||||
}
|
||||
|
||||
if (key == IMemoryPoolFeatureType)
|
||||
else if (key == IMemoryPoolFeatureType)
|
||||
{
|
||||
return _currentIMemoryPoolFeature;
|
||||
feature = _currentIMemoryPoolFeature;
|
||||
}
|
||||
|
||||
if (key == IApplicationTransportFeatureType)
|
||||
else if (key == IApplicationTransportFeatureType)
|
||||
{
|
||||
return _currentIApplicationTransportFeature;
|
||||
feature = _currentIApplicationTransportFeature;
|
||||
}
|
||||
|
||||
if (key == ITransportSchedulerFeatureType)
|
||||
else if (key == ITransportSchedulerFeatureType)
|
||||
{
|
||||
return _currentITransportSchedulerFeature;
|
||||
feature = _currentITransportSchedulerFeature;
|
||||
}
|
||||
|
||||
if (key == IConnectionLifetimeFeatureType)
|
||||
else if (key == IConnectionLifetimeFeatureType)
|
||||
{
|
||||
return _currentIConnectionLifetimeFeature;
|
||||
feature = _currentIConnectionLifetimeFeature;
|
||||
}
|
||||
|
||||
if (key == IBytesWrittenFeatureType)
|
||||
else if (key == IBytesWrittenFeatureType)
|
||||
{
|
||||
return _currentIBytesWrittenFeature;
|
||||
feature = _currentIBytesWrittenFeature;
|
||||
}
|
||||
|
||||
if (MaybeExtra != null)
|
||||
else if (MaybeExtra != null)
|
||||
{
|
||||
return ExtraFeatureGet(key);
|
||||
feature = ExtraFeatureGet(key);
|
||||
}
|
||||
|
||||
return null;
|
||||
return feature;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_featureRevision++;
|
||||
|
|
@ -252,142 +195,130 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
|||
|
||||
TFeature IFeatureCollection.Get<TFeature>()
|
||||
{
|
||||
TFeature feature = default;
|
||||
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
||||
{
|
||||
return (TFeature)_currentIHttpConnectionFeature;
|
||||
feature = (TFeature)_currentIHttpConnectionFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
||||
{
|
||||
return (TFeature)_currentIConnectionIdFeature;
|
||||
feature = (TFeature)_currentIConnectionIdFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
||||
{
|
||||
return (TFeature)_currentIConnectionTransportFeature;
|
||||
feature = (TFeature)_currentIConnectionTransportFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
||||
{
|
||||
return (TFeature)_currentIConnectionItemsFeature;
|
||||
feature = (TFeature)_currentIConnectionItemsFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
||||
{
|
||||
return (TFeature)_currentIMemoryPoolFeature;
|
||||
feature = (TFeature)_currentIMemoryPoolFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
||||
{
|
||||
return (TFeature)_currentIApplicationTransportFeature;
|
||||
feature = (TFeature)_currentIApplicationTransportFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
||||
{
|
||||
return (TFeature)_currentITransportSchedulerFeature;
|
||||
feature = (TFeature)_currentITransportSchedulerFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
||||
{
|
||||
return (TFeature)_currentIConnectionLifetimeFeature;
|
||||
feature = (TFeature)_currentIConnectionLifetimeFeature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
||||
{
|
||||
return (TFeature)_currentIBytesWrittenFeature;
|
||||
feature = (TFeature)_currentIBytesWrittenFeature;
|
||||
}
|
||||
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++;
|
||||
|
||||
if (typeof(TFeature) == typeof(IHttpConnectionFeature))
|
||||
{
|
||||
_currentIHttpConnectionFeature = instance;
|
||||
_currentIHttpConnectionFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionIdFeature))
|
||||
{
|
||||
_currentIConnectionIdFeature = instance;
|
||||
_currentIConnectionIdFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionTransportFeature))
|
||||
{
|
||||
_currentIConnectionTransportFeature = instance;
|
||||
_currentIConnectionTransportFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionItemsFeature))
|
||||
{
|
||||
_currentIConnectionItemsFeature = instance;
|
||||
_currentIConnectionItemsFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IMemoryPoolFeature))
|
||||
{
|
||||
_currentIMemoryPoolFeature = instance;
|
||||
_currentIMemoryPoolFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IApplicationTransportFeature))
|
||||
{
|
||||
_currentIApplicationTransportFeature = instance;
|
||||
_currentIApplicationTransportFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(ITransportSchedulerFeature))
|
||||
{
|
||||
_currentITransportSchedulerFeature = instance;
|
||||
_currentITransportSchedulerFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))
|
||||
{
|
||||
_currentIConnectionLifetimeFeature = instance;
|
||||
_currentIConnectionLifetimeFeature = feature;
|
||||
}
|
||||
else if (typeof(TFeature) == typeof(IBytesWrittenFeature))
|
||||
{
|
||||
_currentIBytesWrittenFeature = instance;
|
||||
_currentIBytesWrittenFeature = feature;
|
||||
}
|
||||
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()
|
||||
{
|
||||
if (_currentIHttpConnectionFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
||||
}
|
||||
|
||||
if (_currentIConnectionIdFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);
|
||||
}
|
||||
|
||||
if (_currentIConnectionTransportFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);
|
||||
}
|
||||
|
||||
if (_currentIConnectionItemsFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IConnectionItemsFeatureType, _currentIConnectionItemsFeature);
|
||||
}
|
||||
|
||||
if (_currentIMemoryPoolFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IMemoryPoolFeatureType, _currentIMemoryPoolFeature);
|
||||
}
|
||||
|
||||
if (_currentIApplicationTransportFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IApplicationTransportFeatureType, _currentIApplicationTransportFeature);
|
||||
}
|
||||
|
||||
if (_currentITransportSchedulerFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(ITransportSchedulerFeatureType, _currentITransportSchedulerFeature);
|
||||
}
|
||||
|
||||
if (_currentIConnectionLifetimeFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature);
|
||||
}
|
||||
|
||||
if (_currentIBytesWrittenFeature != null)
|
||||
{
|
||||
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.IO.Pipelines;
|
||||
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 httpProtocolGeneratedPath = "../../../../../src/Kestrel.Core/Internal/Http/HttpProtocol.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 testHttpProtocolGeneratedPath = Path.GetTempFileName();
|
||||
var testHttpUtilitiesGeneratedPath = Path.GetTempFileName();
|
||||
var testTransportConnectionGeneratedPath = Path.GetTempFileName();
|
||||
|
||||
try
|
||||
{
|
||||
var currentHttpHeadersGenerated = File.ReadAllText(httpHeadersGeneratedPath);
|
||||
var currentHttpProtocolGenerated = File.ReadAllText(httpProtocolGeneratedPath);
|
||||
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 testHttpProtocolGenerated = File.ReadAllText(testHttpProtocolGeneratedPath);
|
||||
var testHttpUtilitiesGenerated = File.ReadAllText(testHttpUtilitiesGeneratedPath);
|
||||
var testTransportConnectionGenerated = File.ReadAllText(testTransportConnectionGeneratedPath);
|
||||
|
||||
Assert.Equal(currentHttpHeadersGenerated, testHttpHeadersGenerated, ignoreLineEndingDifferences: true);
|
||||
Assert.Equal(currentHttpProtocolGenerated, testHttpProtocolGenerated, ignoreLineEndingDifferences: true);
|
||||
Assert.Equal(currentHttpUtilitiesGenerated, testHttpUtilitiesGenerated, ignoreLineEndingDifferences: true);
|
||||
Assert.Equal(currentTransportConnectionGenerated, testTransportConnectionGenerated, ignoreLineEndingDifferences: true);
|
||||
|
||||
}
|
||||
finally
|
||||
|
|
@ -42,6 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
File.Delete(testHttpHeadersGeneratedPath);
|
||||
File.Delete(testHttpProtocolGeneratedPath);
|
||||
File.Delete(testHttpUtilitiesGeneratedPath);
|
||||
File.Delete(testTransportConnectionGeneratedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,10 @@
|
|||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
||||
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@
|
|||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
||||
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@
|
|||
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
|
||||
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||
<ProjectReference Include="..\..\src\Kestrel.Transport.Sockets\Kestrel.Transport.Sockets.csproj" />
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<StartWorkingDirectory>$(MSBuildThisFileDirectory)..\..\src\Kestrel.Core</StartWorkingDirectory>
|
||||
<StartArguments>Internal/Http/HttpHeaders.Generated.cs Internal/Http/HttpProtocol.Generated.cs Internal/Infrastructure/HttpUtilities.Generated.cs</StartArguments>
|
||||
<StartWorkingDirectory>$(MSBuildThisFileDirectory)..\..\</StartWorkingDirectory>
|
||||
<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>
|
||||
|
||||
</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.
|
||||
// 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)
|
||||
public static string GenerateFile()
|
||||
{
|
||||
var alwaysFeatures = new[]
|
||||
{
|
||||
|
|
@ -65,14 +50,10 @@ namespace CodeGenerator
|
|||
.Concat(commonFeatures)
|
||||
.Concat(sometimesFeatures)
|
||||
.Concat(rareFeatures)
|
||||
.Select((type, index) => new KnownFeature
|
||||
{
|
||||
Name = type,
|
||||
Index = index
|
||||
});
|
||||
.ToArray();
|
||||
|
||||
// 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[]
|
||||
{
|
||||
"IHttpRequestFeature",
|
||||
|
|
@ -86,114 +67,18 @@ namespace CodeGenerator
|
|||
"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;
|
||||
|
||||
var usings = $@"
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
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
|
||||
{{
|
||||
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;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
";
|
||||
return FeatureCollectionGenerator.GenerateFile(
|
||||
namespaceName: "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http",
|
||||
className: "HttpProtocol",
|
||||
allFeatures: allFeatures,
|
||||
implementedFeatures: implementedFeatures,
|
||||
extraUsings: usings,
|
||||
fallbackFeatures: "ConnectionFeatures");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ using System.Text;
|
|||
|
||||
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
|
||||
{
|
||||
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) : "";
|
||||
}
|
||||
|
||||
static string If(bool condition, Func<string> formatter)
|
||||
{
|
||||
return condition ? formatter() : "";
|
||||
}
|
||||
|
||||
static string AppendSwitch(IEnumerable<IGrouping<int, KnownHeader>> values, string className) =>
|
||||
$@"var pUL = (ulong*)pUB;
|
||||
var pUI = (uint*)pUB;
|
||||
|
|
|
|||
|
|
@ -25,17 +25,27 @@ namespace CodeGenerator
|
|||
Console.Error.WriteLine("Missing path to HttpUtilities.Generated.cs");
|
||||
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;
|
||||
}
|
||||
|
||||
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 httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile("HttpProtocol");
|
||||
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GenerateFile();
|
||||
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
|
||||
var transportConnectionFeatureCollectionContent = TransportConnectionFeatureCollection.GenerateFile();
|
||||
|
||||
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";
|
||||
if (!string.Equals(knownHeadersContent, existingKnownHeaders))
|
||||
|
|
@ -54,6 +64,12 @@ namespace CodeGenerator
|
|||
{
|
||||
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