Fix User Agent on .NET Client (#13298)
This commit is contained in:
parent
e0f95cfa6f
commit
5c05b9288a
|
|
@ -1414,6 +1414,118 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserAgentIsSet()
|
||||
{
|
||||
using (StartServer<Startup>(out var server))
|
||||
{
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithLoggerFactory(LoggerFactory)
|
||||
.WithUrl(server.Url + "/default", HttpTransportType.LongPolling, options =>
|
||||
{
|
||||
options.Headers["X-test"] = "42";
|
||||
options.Headers["X-42"] = "test";
|
||||
})
|
||||
.Build();
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
var headerValues = await hubConnection.InvokeAsync<string[]>(nameof(TestHub.GetHeaderValues), new[] { "User-Agent" }).OrTimeout();
|
||||
Assert.NotNull(headerValues);
|
||||
Assert.Single(headerValues);
|
||||
|
||||
var userAgent = headerValues[0];
|
||||
|
||||
Assert.StartsWith("Microsoft SignalR/", userAgent);
|
||||
|
||||
var majorVersion = typeof(HttpConnection).Assembly.GetName().Version.Major;
|
||||
var minorVersion = typeof(HttpConnection).Assembly.GetName().Version.Minor;
|
||||
|
||||
Assert.Contains($"{majorVersion}.{minorVersion}", userAgent);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserAgentCanBeCleared()
|
||||
{
|
||||
using (StartServer<Startup>(out var server))
|
||||
{
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithLoggerFactory(LoggerFactory)
|
||||
.WithUrl(server.Url + "/default", HttpTransportType.LongPolling, options =>
|
||||
{
|
||||
options.Headers["User-Agent"] = "";
|
||||
})
|
||||
.Build();
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
var headerValues = await hubConnection.InvokeAsync<string[]>(nameof(TestHub.GetHeaderValues), new[] { "User-Agent" }).OrTimeout();
|
||||
Assert.NotNull(headerValues);
|
||||
Assert.Single(headerValues);
|
||||
|
||||
var userAgent = headerValues[0];
|
||||
|
||||
Assert.Null(userAgent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserAgentCanBeSet()
|
||||
{
|
||||
using (StartServer<Startup>(out var server))
|
||||
{
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithLoggerFactory(LoggerFactory)
|
||||
.WithUrl(server.Url + "/default", HttpTransportType.LongPolling, options =>
|
||||
{
|
||||
options.Headers["User-Agent"] = "User Value";
|
||||
})
|
||||
.Build();
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
var headerValues = await hubConnection.InvokeAsync<string[]>(nameof(TestHub.GetHeaderValues), new[] { "User-Agent" }).OrTimeout();
|
||||
Assert.NotNull(headerValues);
|
||||
Assert.Single(headerValues);
|
||||
|
||||
var userAgent = headerValues[0];
|
||||
|
||||
Assert.Equal("User Value", userAgent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[WebSocketsSupportedCondition]
|
||||
public async Task WebSocketOptionsAreApplied()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.IO.Pipelines;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
|
|
@ -113,16 +114,17 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
testHttpHandler.OnRequest(async (request, next, token) =>
|
||||
{
|
||||
var userAgentHeaderCollection = request.Headers.UserAgent;
|
||||
var userAgentHeader = Assert.Single(userAgentHeaderCollection);
|
||||
Assert.Equal("Microsoft.AspNetCore.Http.Connections.Client", userAgentHeader.Product.Name);
|
||||
var userAgentHeader = request.Headers.UserAgent.ToString();
|
||||
|
||||
Assert.NotNull(userAgentHeader);
|
||||
Assert.StartsWith("Microsoft SignalR/", userAgentHeader);
|
||||
|
||||
// user agent version should come from version embedded in assembly metadata
|
||||
var assemblyVersion = typeof(Constants)
|
||||
.Assembly
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
|
||||
Assert.Equal(assemblyVersion.InformationalVersion, userAgentHeader.Product.Version);
|
||||
Assert.Contains(assemblyVersion.InformationalVersion, userAgentHeader);
|
||||
|
||||
requestsExecuted = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -551,14 +551,34 @@ namespace Microsoft.AspNetCore.Http.Connections.Client
|
|||
httpClient.Timeout = HttpClientTimeout;
|
||||
|
||||
// Start with the user agent header
|
||||
httpClient.DefaultRequestHeaders.UserAgent.Add(Constants.UserAgentHeader);
|
||||
httpClient.DefaultRequestHeaders.Add(Constants.UserAgent, Constants.UserAgentHeader);
|
||||
|
||||
// Apply any headers configured on the HttpConnectionOptions
|
||||
if (_httpConnectionOptions?.Headers != null)
|
||||
{
|
||||
foreach (var header in _httpConnectionOptions.Headers)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
// Check if the key is User-Agent and remove if empty string then replace if it exists.
|
||||
if (string.Equals(header.Key, Constants.UserAgent, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (string.IsNullOrEmpty(header.Value))
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Remove(header.Key);
|
||||
}
|
||||
else if (httpClient.DefaultRequestHeaders.Contains(header.Key))
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Remove(header.Key);
|
||||
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,19 +3,18 @@
|
|||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
public static readonly ProductInfoHeaderValue UserAgentHeader;
|
||||
public const string UserAgent = "User-Agent";
|
||||
public static readonly string UserAgentHeader;
|
||||
|
||||
static Constants()
|
||||
{
|
||||
var userAgent = "Microsoft.AspNetCore.Http.Connections.Client";
|
||||
|
||||
var assemblyVersion = typeof(Constants)
|
||||
.Assembly
|
||||
.GetCustomAttributes<AssemblyInformationalVersionAttribute>()
|
||||
|
|
@ -23,14 +22,22 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
|||
|
||||
Debug.Assert(assemblyVersion != null);
|
||||
|
||||
var majorVersion = typeof(Constants).Assembly.GetName().Version.Major;
|
||||
var minorVersion = typeof(Constants).Assembly.GetName().Version.Minor;
|
||||
var os = RuntimeInformation.OSDescription;
|
||||
var runtime = ".NET";
|
||||
var runtimeVersion = RuntimeInformation.FrameworkDescription;
|
||||
|
||||
// assembly version attribute should always be present
|
||||
// but in case it isn't then don't include version in user-agent
|
||||
if (assemblyVersion != null)
|
||||
{
|
||||
userAgent += "/" + assemblyVersion.InformationalVersion;
|
||||
UserAgentHeader = $"Microsoft SignalR/{majorVersion}.{minorVersion} ({assemblyVersion.InformationalVersion}; {os}; {runtime}; {runtimeVersion})";
|
||||
}
|
||||
else
|
||||
{
|
||||
UserAgentHeader = $"Microsoft SignalR/{majorVersion}.{minorVersion} ({os}; {runtime}; {runtimeVersion})";
|
||||
}
|
||||
|
||||
UserAgentHeader = ProductInfoHeaderValue.Parse(userAgent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.Http.Connections.Client;
|
||||
using Xunit;
|
||||
using Constants = Microsoft.AspNetCore.Http.Connections.Client.Internal.Constants;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||
{
|
||||
public class UserAgentHeaderTest
|
||||
{
|
||||
[Fact]
|
||||
public void UserAgentHeaderIsAccurate()
|
||||
{
|
||||
var majorVersion = typeof(HttpConnection).Assembly.GetName().Version.Major;
|
||||
var minorVersion = typeof(HttpConnection).Assembly.GetName().Version.Minor;
|
||||
var version = typeof(HttpConnection).Assembly.GetName().Version;
|
||||
var os = RuntimeInformation.OSDescription;
|
||||
var runtime = ".NET";
|
||||
var runtimeVersion = RuntimeInformation.FrameworkDescription;
|
||||
var assemblyVersion = typeof(Constants)
|
||||
.Assembly
|
||||
.GetCustomAttributes<AssemblyInformationalVersionAttribute>()
|
||||
.FirstOrDefault();
|
||||
var userAgent = Constants.UserAgentHeader;
|
||||
var expectedUserAgent = $"Microsoft SignalR/{majorVersion}.{minorVersion} ({assemblyVersion.InformationalVersion}; {os}; {runtime}; {runtimeVersion})";
|
||||
|
||||
Assert.Equal(expectedUserAgent, userAgent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue