diff --git a/src/ApplicationInsights.AspNet/TelemetryInitializers/WebClientIpHeaderTelemetryInitializer.cs b/src/ApplicationInsights.AspNet/TelemetryInitializers/WebClientIpHeaderTelemetryInitializer.cs index 7ac2086..e51a92a 100644 --- a/src/ApplicationInsights.AspNet/TelemetryInitializers/WebClientIpHeaderTelemetryInitializer.cs +++ b/src/ApplicationInsights.AspNet/TelemetryInitializers/WebClientIpHeaderTelemetryInitializer.cs @@ -16,10 +16,8 @@ /// This telemetry initializer extracts client IP address and populates telemetry.Context.Location.Ip property. /// Lot's of code reuse from Microsoft.ApplicationInsights.Extensibility.Web.TelemetryInitializers.WebClientIpHeaderTelemetryInitializer /// - public class WebClientIpHeaderTelemetryInitializer : ITelemetryInitializer + public class WebClientIpHeaderTelemetryInitializer : TelemetryInitializerBase { - private IServiceProvider serviceProvider; - private readonly char[] HeaderValuesSeparatorDefault = new char[] { ',' }; private const string HeaderNameDefault = "X-Forwarded-For"; @@ -29,8 +27,8 @@ public WebClientIpHeaderTelemetryInitializer(IServiceProvider serviceProvider) + : base(serviceProvider) { - this.serviceProvider = serviceProvider; this.headerNames = new List(); this.HeaderNames.Add(HeaderNameDefault); this.UseFirstIp = true; @@ -72,48 +70,6 @@ /// public bool UseFirstIp { get; set; } - public void Initialize(ITelemetry telemetry) - { - var request = this.serviceProvider.GetService(); - if (!string.IsNullOrEmpty(request.Context.Location.Ip)) - { - telemetry.Context.Location.Ip = request.Context.Location.Ip; - } - else - { - var context = this.serviceProvider.GetService().Context; - - string resultIp = null; - foreach (var name in this.HeaderNames) - { - var headerValue = context.Request.Headers[name]; - if (!string.IsNullOrEmpty(headerValue)) - { - var ip = GetIpFromHeader(headerValue); - ip = CutPort(ip); - if (IsCorrectIpAddress(ip)) - { - resultIp = ip; - break; - } - } - } - - if (string.IsNullOrEmpty(resultIp)) - { - var connectionFeature = context.GetFeature(); - - if (connectionFeature != null) - { - resultIp = connectionFeature.RemoteIpAddress.ToString(); - } - } - - request.Context.Location.Ip = resultIp; - telemetry.Context.Location.Ip = resultIp; - } - } - private static string CutPort(string address) { // For Web sites in Azure header contains ip address with port e.g. 50.47.87.223:54464 @@ -151,5 +107,45 @@ return this.UseFirstIp ? ips[0].Trim() : ips[ips.Length - 1].Trim(); } + protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry) + { + if (!string.IsNullOrEmpty(telemetry.Context.Location.Ip)) + { + //already populated + return; + } + + if (string.IsNullOrEmpty(requestTelemetry.Context.Location.Ip)) + { + string resultIp = null; + foreach (var name in this.HeaderNames) + { + var headerValue = platformContext.Request.Headers[name]; + if (!string.IsNullOrEmpty(headerValue)) + { + var ip = GetIpFromHeader(headerValue); + ip = CutPort(ip); + if (IsCorrectIpAddress(ip)) + { + resultIp = ip; + break; + } + } + } + + if (string.IsNullOrEmpty(resultIp)) + { + var connectionFeature = platformContext.GetFeature(); + + if (connectionFeature != null) + { + resultIp = connectionFeature.RemoteIpAddress.ToString(); + } + } + + requestTelemetry.Context.Location.Ip = resultIp; + } + telemetry.Context.Location.Ip = requestTelemetry.Context.Location.Ip; + } } } \ No newline at end of file diff --git a/test/ApplicationInsights.AspNet.Tests/TelemetryInitializers/WebClientIpHeaderTelemetryInitializerTests.cs b/test/ApplicationInsights.AspNet.Tests/TelemetryInitializers/WebClientIpHeaderTelemetryInitializerTests.cs new file mode 100644 index 0000000..1e67aa5 --- /dev/null +++ b/test/ApplicationInsights.AspNet.Tests/TelemetryInitializers/WebClientIpHeaderTelemetryInitializerTests.cs @@ -0,0 +1,93 @@ +namespace Microsoft.ApplicationInsights.AspNet.Tests.TelemetryInitializers +{ + using Microsoft.ApplicationInsights.AspNet.Implementation; + using Microsoft.ApplicationInsights.AspNet.TelemetryInitializers; + using Microsoft.ApplicationInsights.AspNet.Tests.Helpers; + using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.AspNet.Http.Core; + using System; + using System.Collections.Generic; + using Xunit; + + public class WebClientIpHeaderTelemetryInitializerTests + { + [Fact] + public void InitializeDoesNotThrowIfHttpContextHolderIsUnavailable() + { + var initializer = new WebClientIpHeaderTelemetryInitializer(new TestServiceProvider()); + + initializer.Initialize(new RequestTelemetry()); + } + + [Fact] + public void InitializeDoesNotThrowIfHttpContextIsUnavailable() + { + var serviceProvider = new TestServiceProvider(new List() { new HttpContextHolder() }); + var initializer = new WebClientIpHeaderTelemetryInitializer(serviceProvider); + + initializer.Initialize(new RequestTelemetry()); + } + + [Fact] + public void InitializeDoesNotThrowIfRequestTelemetryIsUnavailable() + { + var contextHolder = new HttpContextHolder(); + contextHolder.Context = new DefaultHttpContext(); + var serviceProvider = new TestServiceProvider(new List() { contextHolder }); + var initializer = new WebClientIpHeaderTelemetryInitializer(serviceProvider); + + initializer.Initialize(new RequestTelemetry()); + } + + [Fact] + public void InitializeSetsIPFromStandardHeader() + { + var requestTelemetry = new RequestTelemetry(); + var contextHolder = new HttpContextHolder(); + contextHolder.Context = new DefaultHttpContext(); + contextHolder.Context.Request.Headers.Add("X-Forwarded-For", new string[] { "127.0.0.3" }); + var serviceProvider = new TestServiceProvider(new List() { contextHolder, requestTelemetry }); + var initializer = new WebClientIpHeaderTelemetryInitializer(serviceProvider); + + initializer.Initialize(requestTelemetry); + + Assert.Equal("127.0.0.3", requestTelemetry.Context.Location.Ip); + } + + [Fact] + public void InitializeSetsIPFromCustomHeader() + { + var requestTelemetry = new RequestTelemetry(); + var contextHolder = new HttpContextHolder(); + contextHolder.Context = new DefaultHttpContext(); + contextHolder.Context.Request.Headers.Add("HEADER", new string[] { "127.0.0.3;127.0.0.4" }); + var serviceProvider = new TestServiceProvider(new List() { contextHolder, requestTelemetry }); + var initializer = new WebClientIpHeaderTelemetryInitializer(serviceProvider); + initializer.HeaderNames.Add("HEADER"); + initializer.HeaderValueSeparators = ",;"; + + initializer.Initialize(requestTelemetry); + + Assert.Equal("127.0.0.3", requestTelemetry.Context.Location.Ip); + } + + [Fact] + public void InitializeDoesNotOverrideIPProvidedInline() + { + var requestTelemetry = new RequestTelemetry(); + requestTelemetry.Context.Location.Ip = "127.0.0.4"; + var contextHolder = new HttpContextHolder(); + contextHolder.Context = new DefaultHttpContext(); + contextHolder.Context.Request.Headers.Add("X-Forwarded-For", new string[] { "127.0.0.3" }); + var serviceProvider = new TestServiceProvider(new List() { contextHolder, requestTelemetry }); + var initializer = new WebClientIpHeaderTelemetryInitializer(serviceProvider); + + + initializer.Initialize(requestTelemetry); + + Assert.Equal("127.0.0.4", requestTelemetry.Context.Location.Ip); + } + + + } +} \ No newline at end of file