Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added AspNet-Request-ConnectionId and AspNet-Response-Has-Started #796

Merged
merged 14 commits into from
Jun 11, 2022
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using NLog.LayoutRenderers;
using NLog.Web.Internal;
using System.Text;

namespace NLog.Web.LayoutRenderers
{
/// <summary>
/// ASP.NET request connection id
/// </summary>
/// <remarks>
/// ${aspnet-request-connection-id}
/// </remarks>
[LayoutRenderer("aspnet-request-connection-id")]
public class AspNetRequestConnectionIdLayoutRenderer : AspNetLayoutRendererBase
{
/// <summary>
/// Renders the ASP.NET connection ID
/// </summary>
/// <param name="builder">The <see cref="StringBuilder" /> to append the rendered data to.</param>
/// <param name="logEvent">Logging event.</param>
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var connection = HttpContextAccessor.HttpContext.TryGetConnection();
if (connection == null)
{
return;
}

var id = connection.Id;
if(!string.IsNullOrEmpty(id))
{
builder.Append(id);
}
}
}
}
16 changes: 16 additions & 0 deletions src/Shared/Internal/HttpContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ internal static HttpResponseBase TryGetResponse(this HttpContextBase context)
}
}
#else
internal static WebSocketManager TryGetWebSocket(this HttpContext context)
{
var websocket = context?.WebSockets;
if (websocket == null)
InternalLogger.Debug("HttpContext WebSocket Lookup returned null");
return websocket;
}

internal static ConnectionInfo TryGetConnection(this HttpContext context)
{
var connection = context?.Connection;
if (connection == null)
InternalLogger.Debug("HttpContext Connection Lookup returned null");
return connection;
}

internal static HttpRequest TryGetRequest(this HttpContext context)
{
var request = context?.Request;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ namespace NLog.Web.LayoutRenderers
/// ASP.NET Client Certificate of the Connection
/// </summary>
/// <remarks>
/// ${aspnet-request-client certificate}
/// ${aspnet-request-client-certificate}
/// ${aspnet-request-client-certificate:Verbose=True}
/// </remarks>
[LayoutRenderer("aspnet-request-client-certificate")]
public class AspNetRequestClientCertificateLayoutRenderer : AspNetLayoutRendererBase
{
/// <summary>
/// This is passed to the X509Certificate2.ToString(bool) method
/// </summary>
public bool Verbose { get; set; }

/// <summary>
/// Render Remote Port
/// </summary>
Expand All @@ -30,7 +36,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
return;
}
builder.Append(connection.ClientCertificate);
builder.Append(connection.ClientCertificate?.ToString(Verbose));
#else
var certificate = httpContext.Request.ClientCertificate;
if (certificate == null)
Expand All @@ -39,7 +45,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
}
// Convert to an X509Certificate2, which does have the proper overridden ToString() method.
// HttpClientCertificate class only use object.ToString() which is useless.
builder.Append(new X509Certificate2(certificate.Certificate));
builder.Append(new X509Certificate2(certificate.Certificate)?.ToString(Verbose));
#endif
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text;
using NLog.LayoutRenderers;
using NLog.Web.Internal;

namespace NLog.Web.LayoutRenderers
{
Expand All @@ -21,7 +22,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
// Not available on .NET 3.5
#if ASP_NET_CORE
var websockets = HttpContextAccessor.HttpContext?.WebSockets;
var websockets = HttpContextAccessor.HttpContext.TryGetWebSocket();
builder.Append(websockets?.IsWebSocketRequest == true ? '1' : '0');
#elif NET46_OR_GREATER
var httpContext = HttpContextAccessor.HttpContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
var httpContext = HttpContextAccessor.HttpContext;

#if ASP_NET_CORE
var connection = httpContext.Connection;
var connection = httpContext.TryGetConnection();
if (connection == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var httpContext = HttpContextAccessor.HttpContext;
#if ASP_NET_CORE
var connection = httpContext.Connection;
var connection = httpContext.TryGetConnection();
if (connection == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
var httpContext = HttpContextAccessor.HttpContext;

#if ASP_NET_CORE
var connection = httpContext.Connection;
var connection = httpContext.TryGetConnection();
if (connection == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text;
using NLog.LayoutRenderers;
using NLog.Web.Internal;

namespace NLog.Web.LayoutRenderers
{
Expand Down Expand Up @@ -28,7 +29,7 @@ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
// Not available on .NET 3.5
#if ASP_NET_CORE
var websockets = HttpContextAccessor.HttpContext?.WebSockets;
var websockets = HttpContextAccessor.HttpContext.TryGetWebSocket();
if (websockets == null)
{
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using NLog.LayoutRenderers;
using NLog.Web.Internal;
using System.Text;

namespace NLog.Web.LayoutRenderers
{
/// <summary>
/// ASP.NET response headers already sent
/// </summary>
/// <remarks>
/// ${aspnet-response-headers-written}
/// </remarks>
[LayoutRenderer("aspnet-response-headers-written")]
public class AspNetResponseHeadersWrittenLayoutRenderer : AspNetLayoutRendererBase
snakefoot marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Renders the ASP.NET HttpResponse HasStarted property in ASP.NET Core and the HttpResponse HeadersWritten in .NET Framework
/// </summary>
/// <param name="builder">The <see cref="StringBuilder" /> to append the rendered data to.</param>
/// <param name="logEvent">Logging event.</param>
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var response = HttpContextAccessor.HttpContext.TryGetResponse();
#if ASP_NET_CORE
builder.Append(response?.HasStarted == true ? '1' : '0');
#elif NET46
builder.Append(response?.HeadersWritten == true ? '1' : '0');
#endif
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using NLog.Web.LayoutRenderers;
using NSubstitute;
using NSubstitute.ReturnsExtensions;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace NLog.Web.Tests.LayoutRenderers
{
public class AspNetRequestConnectionIdLayoutRendererTests : LayoutRenderersTestBase<AspNetRequestConnectionIdLayoutRenderer>
{
[Fact]
public void SuccessTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();

httpContext.Connection.Id.Returns("My Connection Id");
// Act
string result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("My Connection Id", result);
}

[Fact]
public void EmptyTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();

httpContext.Connection.Id.Returns("");
// Act
string result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("", result);
}

[Fact]
public void NullTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();

httpContext.Connection.Id.ReturnsNull();
// Act
string result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("", result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ public void SuccessTest()
Assert.Equal(certificate.ToString(), result);
}

[Fact]
public void SuccessVerboseTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Verbose = true;

var certificate = new X509Certificate2(
Convert.FromBase64String(
"MIIC7DCCAdSgAwIBAgIQJq2oGnSgP79FVWGrezYIBDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjIwMzExMDQyOTI4WhcNMjcwMzEwMDAwMDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfSpPySBJetaQdagcgNMs6owXj6QwDv4BKB/qRG4AM5myL3T+7cTiUUOaHywIR+79k2K+LVOLKzfXLJvrzYZSj3yd02ScmM4BEJEcbauY7wCYjgFfB6K9Klh87UAP6+gUUHjIVfzI/Go3883c9D29S3PbO3z5Yz1hTVS0Hes5ZE0d7TDevVSXm2ZpUZSPz7W50+FBq2z3uI3pSBg2oZYHhUvbFIhMI0VIFAPSiyU9XIo+RCv3eN27Fq8g3Qo0z+8wnk7zSldncVEZko5WGKNL781U/TDuhBigkvEme9goaRPRW8oNjm//v+vyJwo/WDzghSwc6jCIdjTXUIqxw4THBAgMBAAGjOjA4MAsGA1UdDwQEAwIEsDATBgNVHSUEDDAKBggrBgEFBQcDATAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAEqAzHpQgeiW1abdOj4LClM+8uU813tvFhepneLL59yvtZ2NT6ruSd7Fa15CT8bIKACgxzUOaB7N/KseORqLFrNiwvu2A1vvEkhueH0TLC2KJt7SvlEKw5QooiLdOIfNBaL8h/YE/TK9hXCdTgmsPuXuc47vxSyLUUzMGFlW4olFkOEHOP0havplJvPabLY/WpPTV0+mKUe+CKKEKNduH8il9heXguak06XGufP8UQP1fE+GVDFJDqX0S2TMcaoohxL2lV4VqNnadGJ/VA97ZDTWKFteDdTNwZYyb0KvxLtUCc6cHak9ZRs1E7+SZyNx/pcB4vgpnWPXKX8WDr3VGw0="));

httpContext.Connection.ClientCertificate.Returns(certificate);

// Act
string result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal(certificate.ToString(true), result);
}

[Fact]
public void NullTest()
{
Expand Down Expand Up @@ -77,6 +96,45 @@ public void SuccessTest()
//Assert.Equal(certificate.ToString(), result);
Assert.Equal(string.Empty, result);
}

[Fact]
public void SuccessVerboseTest()
{
var httpContext = Substitute.For<HttpContextBase>();
var renderer = new AspNetRequestClientCertificateLayoutRenderer();
renderer.Verbose = true;
renderer.HttpContextAccessor = new FakeHttpContextAccessor(httpContext);

// Arrange
var byteArray = Convert.FromBase64String(
"MIIC7DCCAdSgAwIBAgIQJq2oGnSgP79FVWGrezYIBDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjIwMzExMDQyOTI4WhcNMjcwMzEwMDAwMDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfSpPySBJetaQdagcgNMs6owXj6QwDv4BKB/qRG4AM5myL3T+7cTiUUOaHywIR+79k2K+LVOLKzfXLJvrzYZSj3yd02ScmM4BEJEcbauY7wCYjgFfB6K9Klh87UAP6+gUUHjIVfzI/Go3883c9D29S3PbO3z5Yz1hTVS0Hes5ZE0d7TDevVSXm2ZpUZSPz7W50+FBq2z3uI3pSBg2oZYHhUvbFIhMI0VIFAPSiyU9XIo+RCv3eN27Fq8g3Qo0z+8wnk7zSldncVEZko5WGKNL781U/TDuhBigkvEme9goaRPRW8oNjm//v+vyJwo/WDzghSwc6jCIdjTXUIqxw4THBAgMBAAGjOjA4MAsGA1UdDwQEAwIEsDATBgNVHSUEDDAKBggrBgEFBQcDATAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAEqAzHpQgeiW1abdOj4LClM+8uU813tvFhepneLL59yvtZ2NT6ruSd7Fa15CT8bIKACgxzUOaB7N/KseORqLFrNiwvu2A1vvEkhueH0TLC2KJt7SvlEKw5QooiLdOIfNBaL8h/YE/TK9hXCdTgmsPuXuc47vxSyLUUzMGFlW4olFkOEHOP0havplJvPabLY/WpPTV0+mKUe+CKKEKNduH8il9heXguak06XGufP8UQP1fE+GVDFJDqX0S2TMcaoohxL2lV4VqNnadGJ/VA97ZDTWKFteDdTNwZYyb0KvxLtUCc6cHak9ZRs1E7+SZyNx/pcB4vgpnWPXKX8WDr3VGw0=");

var certificate = new X509Certificate2(byteArray);

// We need Microsoft Fakes here, but we only have Visual Studio 2022 Community, not Enterprise
// and we also cannot require NLog.Web community of developer to have Enterprise edition
//httpContext.Request.ClientCertificate = new HttpClientCertificate(byteArray);

// This throws NullReferenceException
//httpContext.Request.ClientCertificate.Certificate.Returns(byteArray);

var httpRequest = Substitute.For<HttpRequestBase>();
httpContext.Request.Returns(httpRequest);

// This throws NotSupportedException due to no public constructors, from Castle.DynamicProxy.Generators
//var clientCertificate = Substitute.For<HttpClientCertificate>();

//clientCertificate.Certificate.Returns(byteArray);
//httpRequest.ClientCertificate.Returns(clientCertificate);

// Act
string result = renderer.Render(new LogEventInfo());

// Assert
//Assert.Equal(certificate.ToString(true), result);
Assert.Equal(string.Empty, result);
}

[Fact]
public void NullTest()
{
Expand Down
Loading