Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ internal partial class RequestContext :
IHttpResetFeature,
IHttpSysRequestDelegationFeature,
IHttpSysRequestPropertyFeature,
IConnectionLifetimeNotificationFeature
IConnectionLifetimeNotificationFeature,
IConnectionEndPointFeature
{
private IFeatureCollection? _features;
private bool _enableResponseCaching;
Expand Down Expand Up @@ -762,4 +763,46 @@ public bool TryGetTlsClientHello(Span<byte> tlsClientHelloBytesDestination, out
{
return TryGetTlsClientHelloMessageBytes(tlsClientHelloBytesDestination, out bytesReturned);
}

EndPoint? IConnectionEndPointFeature.LocalEndPoint
{
get
{
var localIp = ((IHttpConnectionFeature)this).LocalIpAddress;
if (localIp is not null)
{
return new IPEndPoint(localIp, ((IHttpConnectionFeature)this).LocalPort);
}
return null;
}
set
{
if (value is IPEndPoint localIPEndPoint)
{
((IHttpConnectionFeature)this).LocalIpAddress = localIPEndPoint.Address;
((IHttpConnectionFeature)this).LocalPort = localIPEndPoint.Port;
}
}
}

EndPoint? IConnectionEndPointFeature.RemoteEndPoint
{
get
{
var remoteIp = ((IHttpConnectionFeature)this).RemoteIpAddress;
if (remoteIp is not null)
{
return new IPEndPoint(remoteIp, ((IHttpConnectionFeature)this).RemotePort);
}
return null;
}
set
{
if (value is IPEndPoint remoteIPEndPoint)
{
((IHttpConnectionFeature)this).RemoteIpAddress = remoteIPEndPoint.Address;
((IHttpConnectionFeature)this).RemotePort = remoteIPEndPoint.Port;
}
}
}
}
1 change: 1 addition & 0 deletions src/Servers/HttpSys/src/StandardFeatureCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal sealed class StandardFeatureCollection : IFeatureCollection
{ typeof(IHttpResponseTrailersFeature), ctx => ctx.GetResponseTrailersFeature() },
{ typeof(IHttpResetFeature), ctx => ctx.GetResetFeature() },
{ typeof(IConnectionLifetimeNotificationFeature), ctx => ctx.GetConnectionLifetimeNotificationFeature() },
{ typeof(IConnectionEndPointFeature), _identityFunc },
};

private readonly RequestContext _featureContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net;
using System.Text;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.InternalTesting;
using Xunit;

namespace Microsoft.AspNetCore.Server.HttpSys;

public class ConnectionEndPointFeatureTests : LoggedTest
{
[ConditionalFact]
public async Task Request_ProvidesConnectionEndPointFeature()
{
string root;
EndPoint localEndPoint = null;
EndPoint remoteEndPoint = null;
using (Utilities.CreateHttpServerReturnRoot("/", out root, httpContext =>
{
try
{
var endPointFeature = httpContext.Features.Get<IConnectionEndPointFeature>();
localEndPoint = endPointFeature.LocalEndPoint;
remoteEndPoint = endPointFeature.RemoteEndPoint;
}
catch (Exception ex)
{
byte[] body = Encoding.ASCII.GetBytes(ex.ToString());
httpContext.Response.Body.Write(body, 0, body.Length);
}
return Task.FromResult(0);
Comment thread
BrennanConroy marked this conversation as resolved.
}, options => { }, LoggerFactory))
{
string response = await SendRequestAsync(root + "/");
Assert.Equal(string.Empty, response);
}

Assert.NotNull(localEndPoint);
Assert.NotNull(remoteEndPoint);
var localIPEndPoint = Assert.IsType<IPEndPoint>(localEndPoint);
var remoteIPEndPoint = Assert.IsType<IPEndPoint>(remoteEndPoint);
Assert.NotEqual(0, localIPEndPoint.Port);
Assert.NotEqual(0, remoteIPEndPoint.Port);
}

private async Task<string> SendRequestAsync(string uri)
{
using (var client = new System.Net.Http.HttpClient())
{
return await client.GetStringAsync(uri);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections;
using System.Diagnostics;
using System.IO.Pipelines;
using System.Net;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
Expand Down Expand Up @@ -37,6 +38,7 @@ internal partial class IISHttpContext : IFeatureCollection,
IHttpResponseTrailersFeature,
IHttpResetFeature,
IConnectionLifetimeNotificationFeature,
IConnectionEndPointFeature,
IHttpSysRequestInfoFeature,
IHttpSysRequestTimingFeature
{
Expand Down Expand Up @@ -522,4 +524,46 @@ void IConnectionLifetimeNotificationFeature.RequestClose()
ResponseHeaders.Connection = ConnectionClose;
}
}

EndPoint? IConnectionEndPointFeature.LocalEndPoint
{
get
{
var localIp = ((IHttpConnectionFeature)this).LocalIpAddress;
if (localIp is not null)
{
return new IPEndPoint(localIp, ((IHttpConnectionFeature)this).LocalPort);
}
return null;
}
set
{
if (value is IPEndPoint localIPEndPoint)
{
((IHttpConnectionFeature)this).LocalIpAddress = localIPEndPoint.Address;
((IHttpConnectionFeature)this).LocalPort = localIPEndPoint.Port;
}
}
}

EndPoint? IConnectionEndPointFeature.RemoteEndPoint
{
get
{
var remoteIp = ((IHttpConnectionFeature)this).RemoteIpAddress;
if (remoteIp is not null)
{
return new IPEndPoint(remoteIp, ((IHttpConnectionFeature)this).RemotePort);
}
return null;
}
set
{
if (value is IPEndPoint remoteIPEndPoint)
{
((IHttpConnectionFeature)this).RemoteIpAddress = remoteIPEndPoint.Address;
((IHttpConnectionFeature)this).RemotePort = remoteIPEndPoint.Port;
}
}
}
}
16 changes: 16 additions & 0 deletions src/Servers/IIS/IIS/src/Core/IISHttpContext.Features.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal partial class IISHttpContext
private static readonly Type IHttpResponseTrailersFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpResponseTrailersFeature);
private static readonly Type IHttpResetFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpResetFeature);
private static readonly Type IConnectionLifetimeNotificationFeature = typeof(global::Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeNotificationFeature);
private static readonly Type IConnectionEndPointFeature = typeof(global::Microsoft.AspNetCore.Connections.Features.IConnectionEndPointFeature);
private static readonly Type IHttpActivityFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpActivityFeature);
private static readonly Type IHttpSysRequestInfoFeature = typeof(global::Microsoft.AspNetCore.Server.HttpSys.IHttpSysRequestInfoFeature);
private static readonly Type IHttpSysRequestTimingFeature = typeof(global::Microsoft.AspNetCore.Server.HttpSys.IHttpSysRequestTimingFeature);
Expand Down Expand Up @@ -58,6 +59,7 @@ internal partial class IISHttpContext
private object? _currentIHttpResponseTrailersFeature;
private object? _currentIHttpResetFeature;
private object? _currentIConnectionLifetimeNotificationFeature;
private object? _currentIConnectionEndPointFeature;
private object? _currentIHttpActivityFeature;
private object? _currentIHttpSysRequestInfoFeature;
private object? _currentIHttpSysRequestTimingFeature;
Expand All @@ -81,6 +83,7 @@ private void Initialize()
_currentIHttpResponseTrailersFeature = GetResponseTrailersFeature();
_currentIHttpResetFeature = GetResetFeature();
_currentIConnectionLifetimeNotificationFeature = this;
_currentIConnectionEndPointFeature = this;
_currentIHttpSysRequestInfoFeature = this;
_currentIHttpSysRequestTimingFeature = this;

Expand Down Expand Up @@ -189,6 +192,10 @@ private void Initialize()
{
return _currentIConnectionLifetimeNotificationFeature;
}
if (key == IConnectionEndPointFeature)
{
return _currentIConnectionEndPointFeature;
}
if (key == IHttpActivityFeature)
{
return _currentIHttpActivityFeature;
Expand Down Expand Up @@ -337,6 +344,11 @@ internal void FastFeatureSet(Type key, object? feature)
_currentIConnectionLifetimeNotificationFeature = feature;
return;
}
if (key == IConnectionEndPointFeature)
{
_currentIConnectionEndPointFeature = feature;
return;
}
if (key == IHttpSysRequestInfoFeature)
{
_currentIHttpSysRequestInfoFeature = feature;
Expand Down Expand Up @@ -444,6 +456,10 @@ private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{
yield return new KeyValuePair<Type, object>(IHttpResponseTrailersFeature, _currentIHttpResetFeature);
}
if (_currentIConnectionEndPointFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionEndPointFeature, _currentIConnectionEndPointFeature);
}
if (_currentIHttpActivityFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpActivityFeature, _currentIHttpActivityFeature);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.InternalTesting;
using Xunit;

namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;

[SkipIfHostableWebCoreNotAvailable]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "https://github.com/aspnet/IISIntegration/issues/866")]
public class ConnectionEndPointFeatureTests : StrictTestServerTests
{
[ConditionalFact]
public async Task ProvidesLocalAndRemoteEndPoints()
{
EndPoint localEndPoint = null;
EndPoint remoteEndPoint = null;
using (var testServer = await TestServer.Create(ctx =>
{
var endPointFeature = ctx.Features.Get<IConnectionEndPointFeature>();
localEndPoint = endPointFeature.LocalEndPoint;
remoteEndPoint = endPointFeature.RemoteEndPoint;
return Task.CompletedTask;
}, LoggerFactory))
{
await testServer.HttpClient.GetStringAsync("/");
}

Assert.NotNull(localEndPoint);
Assert.NotNull(remoteEndPoint);
var localIPEndPoint = Assert.IsType<IPEndPoint>(localEndPoint);
var remoteIPEndPoint = Assert.IsType<IPEndPoint>(remoteEndPoint);
Assert.NotEqual(0, localIPEndPoint.Port);
Assert.NotEqual(0, remoteIPEndPoint.Port);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Metrics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Security.Authentication;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Shared;

namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;

Expand Down Expand Up @@ -321,43 +320,7 @@ private void TlsHandshakeStopCore(ConnectionMetricsContext metricsContext, long

private static void InitializeConnectionTags(ref TagList tags, in ConnectionMetricsContext metricsContext)
{
var localEndpoint = metricsContext.ConnectionContext.LocalEndPoint;
if (localEndpoint is IPEndPoint localIPEndPoint)
{
tags.Add("server.address", localIPEndPoint.Address.ToString());
tags.Add("server.port", localIPEndPoint.Port);

switch (localIPEndPoint.Address.AddressFamily)
{
case AddressFamily.InterNetwork:
tags.Add("network.type", "ipv4");
break;
case AddressFamily.InterNetworkV6:
tags.Add("network.type", "ipv6");
break;
}

// There isn't an easy way to detect whether QUIC is the underlying transport.
// This code assumes that a multiplexed connection is QUIC.
// Improve in the future if there are additional multiplexed connection types.
var transport = metricsContext.ConnectionContext is not MultiplexedConnectionContext ? "tcp" : "udp";
tags.Add("network.transport", transport);
}
else if (localEndpoint is UnixDomainSocketEndPoint udsEndPoint)
{
tags.Add("server.address", udsEndPoint.ToString());
tags.Add("network.transport", "unix");
}
else if (localEndpoint is NamedPipeEndPoint namedPipeEndPoint)
{
tags.Add("server.address", namedPipeEndPoint.ToString());
tags.Add("network.transport", "pipe");
}
else if (localEndpoint != null)
{
tags.Add("server.address", localEndpoint.ToString());
tags.Add("network.transport", localEndpoint.AddressFamily.ToString());
}
ConnectionEndpointTags.AddConnectionEndpointTags(ref tags, metricsContext.ConnectionContext);
}

public ConnectionMetricsContext CreateContext(BaseConnectionContext connection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<Compile Include="$(SharedSourceRoot)Obsoletions.cs" LinkBase="Shared" />
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Internal\TaskToApm.cs" />
<Compile Include="$(SharedSourceRoot)Metrics\MetricsExtensions.cs" />
<Compile Include="$(SharedSourceRoot)ConnectionEndpointTags.cs" />
<Compile Include="$(RepoRoot)src\Shared\Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
</ItemGroup>

Expand Down
Loading
Loading