Generate repetitive TransportConnection FeatureCollection code (#2548)

This commit is contained in:
Stephen Halter 2018-05-14 17:20:48 -07:00 committed by GitHub
parent 04f2101696
commit c683316253
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 627 additions and 468 deletions

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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" />

View File

@ -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" />

View File

@ -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" />

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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");
}
}
}

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}