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

[HttpClientFactory] Do not log query string by default #103769

Merged
merged 21 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -88,6 +89,8 @@ protected override HttpResponseMessage Send(HttpRequestMessage request, Cancella
// Used in tests.
internal static class Log
{
private static readonly bool s_logQueryString = AppContext.TryGetSwitch("Microsoft.Extensions.Http.LogQueryString", out bool value) && value;
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved

public static class EventIds
{
public static readonly EventId RequestStart = new EventId(100, "RequestStart");
Expand Down Expand Up @@ -144,11 +147,15 @@ public static void RequestEnd(ILogger logger, HttpResponseMessage response, Time
}
}

private static string? GetUriString(Uri? requestUri)
internal static string? GetUriString(Uri? uri)
{
return requestUri?.IsAbsoluteUri == true
? requestUri.AbsoluteUri
: requestUri?.ToString();
if (uri is null)
{
return null;
}

Debug.Assert(uri.IsAbsoluteUri, "HttpClient should not forward relative Uri to its handlers.");
return s_logQueryString ? uri.AbsoluteUri : $"{uri.Scheme}://{uri.Host}{uri.AbsolutePath}";
MihaZupan marked this conversation as resolved.
Show resolved Hide resolved
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ public static class EventIds

public static IDisposable? BeginRequestPipelineScope(ILogger logger, HttpRequestMessage request)
{
return _beginRequestPipelineScope(logger, request.Method, GetUriString(request.RequestUri));
return _beginRequestPipelineScope(logger, request.Method, LoggingHttpMessageHandler.Log.GetUriString(request.RequestUri));
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
}

public static void RequestPipelineStart(ILogger logger, HttpRequestMessage request, Func<string, bool> shouldRedactHeaderValue)
{
_requestPipelineStart(logger, request.Method, GetUriString(request.RequestUri), null);
_requestPipelineStart(logger, request.Method, LoggingHttpMessageHandler.Log.GetUriString(request.RequestUri), null);

if (logger.IsEnabled(LogLevel.Trace))
{
Expand All @@ -145,13 +145,6 @@ public static void RequestPipelineEnd(ILogger logger, HttpResponseMessage respon
(state, ex) => state.ToString());
}
}

private static string? GetUriString(Uri? requestUri)
{
return requestUri?.IsAbsoluteUri == true
? requestUri.AbsoluteUri
: requestUri?.ToString();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Logging;
using Microsoft.Extensions.Logging;
Expand All @@ -16,156 +16,74 @@ namespace Microsoft.Extensions.Http.Tests.Logging
{
public class LoggingUriOutputTests
{
[Fact]
public async Task LoggingHttpMessageHandler_LogsAbsoluteUri()
{
// Arrange
var sink = new TestSink();

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ILoggerFactory>(new TestLoggerFactory(sink, enabled: true));

serviceCollection
.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler(() => new TestMessageHandler());

var services = serviceCollection.BuildServiceProvider();

var client = services.GetRequiredService<IHttpClientFactory>().CreateClient("test");


// Act
var request = new HttpRequestMessage(HttpMethod.Get, "http://api.example.com/search?term=Western%20Australia");

await client.SendAsync(request);

// Assert
var messages = sink.Writes.ToArray();

var message = Assert.Single(messages.Where(m =>
{
return
m.EventId == LoggingHttpMessageHandler.Log.EventIds.RequestStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler";
}));

Assert.Equal("Sending HTTP request GET http://api.example.com/search?term=Western%20Australia", message.Message);
}

[Fact]
public async Task LoggingScopeHttpMessageHandler_LogsAbsoluteUri()
{
// Arrange
var sink = new TestSink();

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ILoggerFactory>(new TestLoggerFactory(sink, enabled: true));

serviceCollection
.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler(() => new TestMessageHandler());

var services = serviceCollection.BuildServiceProvider();

var client = services.GetRequiredService<IHttpClientFactory>().CreateClient("test");


// Act
var request = new HttpRequestMessage(HttpMethod.Get, "http://api.example.com/search?term=Western%20Australia");

await client.SendAsync(request);

// Assert
var messages = sink.Writes.ToArray();

var message = Assert.Single(messages.Where(m =>
{
return
m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.PipelineStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler";
}));

Assert.Equal("Start processing HTTP request GET http://api.example.com/search?term=Western%20Australia", message.Message);
Assert.Equal("HTTP GET http://api.example.com/search?term=Western%20Australia", message.Scope.ToString());
}

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[InlineData(false, false)]
[InlineData(false, true)]
#if NET
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))]
public void LoggingHttpMessageHandler_LogsAbsoluteUri_Sync()
{
// Arrange
var sink = new TestSink();

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ILoggerFactory>(new TestLoggerFactory(sink, enabled: true));

serviceCollection
.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler(() => new TestMessageHandler());

var services = serviceCollection.BuildServiceProvider();

var client = services.GetRequiredService<IHttpClientFactory>().CreateClient("test");


// Act
var request = new HttpRequestMessage(HttpMethod.Get, "http://api.example.com/search?term=Western%20Australia");

client.Send(request);

// Assert
var messages = sink.Writes.ToArray();

var message = Assert.Single(messages.Where(m =>
{
return
m.EventId == LoggingHttpMessageHandler.Log.EventIds.RequestStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler";
}));

Assert.Equal("Sending HTTP request GET http://api.example.com/search?term=Western%20Australia", message.Message);
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))]
public void LoggingScopeHttpMessageHandler_LogsAbsoluteUri_Sync()
[InlineData(true, false)]
[InlineData(true, true)]
#endif
public async Task LogsAbsoluteUrl(bool syncApi, bool logQueryString)
{
// Arrange
var sink = new TestSink();

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ILoggerFactory>(new TestLoggerFactory(sink, enabled: true));

serviceCollection
.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler(() => new TestMessageHandler());

var services = serviceCollection.BuildServiceProvider();

var client = services.GetRequiredService<IHttpClientFactory>().CreateClient("test");


// Act
var request = new HttpRequestMessage(HttpMethod.Get, "http://api.example.com/search?term=Western%20Australia");
const string BaseUri = "http://api.example.com/search";
const string QueryString = "term=Western%20Australia";
const string FullUri = $"{BaseUri}?{QueryString}";

client.Send(request);

// Assert
var messages = sink.Writes.ToArray();

var message = Assert.Single(messages.Where(m =>
await RemoteExecutor.Invoke(static async (syncApiStr, enableQueryStringLoggingStr) =>
{
return
m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.PipelineStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler";
}));

Assert.Equal("Start processing HTTP request GET http://api.example.com/search?term=Western%20Australia", message.Message);
Assert.Equal("HTTP GET http://api.example.com/search?term=Western%20Australia", message.Scope.ToString());
}
bool syncApi = bool.Parse(syncApiStr);
bool enableQueryStringLogging = bool.Parse(enableQueryStringLoggingStr);

if (enableQueryStringLogging)
{
AppContext.SetSwitch("Microsoft.Extensions.Http.LogQueryString", true);
}

var sink = new TestSink();
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ILoggerFactory>(new TestLoggerFactory(sink, enabled: true));
serviceCollection.AddTransient<TestMessageHandler>();
serviceCollection.AddHttpClient("test").ConfigurePrimaryHttpMessageHandler<TestMessageHandler>();

var services = serviceCollection.BuildServiceProvider();
var factory = services.GetRequiredService<IHttpClientFactory>();
var client = factory.CreateClient("test");

using var request = new HttpRequestMessage(HttpMethod.Get, FullUri);
#if NET
if (syncApi)
{
client.Send(request);
await Task.Yield();
}
else
#endif
{
_ = await client.SendAsync(request);
}

var pipelineStartMessage = Assert.Single(sink.Writes.Where(m =>
{
return
m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.PipelineStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler";
}));

var requestStartMessage = Assert.Single(sink.Writes.Where(m =>
{
return
m.EventId == LoggingHttpMessageHandler.Log.EventIds.RequestStart &&
m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler";
}));

string expectedUri = enableQueryStringLogging ? FullUri : BaseUri;

Assert.Equal($"HTTP GET {expectedUri}", pipelineStartMessage.Scope.ToString());
Assert.Equal($"Start processing HTTP request GET {expectedUri}", pipelineStartMessage.Message);
Assert.Equal($"Sending HTTP request GET {expectedUri}", requestStartMessage.Message);

}, syncApi.ToString(), logQueryString.ToString()).DisposeAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
<EnableDefaultItems>true</EnableDefaultItems>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>

<ItemGroup>
Expand All @@ -20,6 +21,8 @@
Link="tests\DI.Common\Common\src\TestLoggerFactory.cs" />
<Compile Include="$(CommonPath)..\tests\Extensions\SingleThreadedSynchronizationContext.cs"
Link="Shared\SingleThreadedSynchronizationContext.cs" />
<Compile Include="$(CommonTestPath)System\Net\RemoteExecutorExtensions.cs"
Link="tests\System\Net\RemoteExecutorExtensions.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading