Skip to content

Commit

Permalink
fix AspNet productInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
terencefan committed Feb 26, 2025
1 parent 8984d22 commit 827676f
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ public ConnectionFactory(IServerNameProvider nameProvider, ILoggerFactory logger
{
}

protected override void SetInternalUserAgent(IDictionary<string, string> headers)
{
// Fix issue: https://github.com/Azure/azure-signalr/issues/198
// .NET Framework has restriction about reserved string as the header name like "User-Agent"
headers[Constants.AsrsUserAgent] = ProductInfo.GetProductInfo();
}

protected override void SetCustomHeaders(IDictionary<string, string> headers)
{
return;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,35 +73,35 @@ internal IDictionary<string, string> GetRequestHeaders()
{
var headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
SetCustomHeaders(headers);
CheckHeaders(headers, Constants.Headers.AsrsHeaderPrefix);
CheckHeaders(headers, Constants.Headers.AsrsInternalHeaderPrefix);
SetInternalHeaders(headers);
CheckHeadersPrefix(headers, Constants.Headers.AsrsHeaderPrefix);
CheckHeadersPrefix(headers, Constants.Headers.AsrsInternalHeaderPrefix);
SetInternalUserAgent(headers);
SetServerId(headers);
return headers;
}

internal virtual void SetInternalHeaders(IDictionary<string, string> headers)
internal virtual void SetServerId(IDictionary<string, string> headers)
{
// Fix issue: https://github.com/Azure/azure-signalr/issues/198
// .NET Framework has restriction about reserved string as the header name like "User-Agent"
headers[Constants.AsrsUserAgent] = ProductInfo.GetProductInfo();

if (!string.IsNullOrEmpty(_serverId) && !headers.ContainsKey(Constants.Headers.AsrsServerId))
{
headers.Add(Constants.Headers.AsrsServerId, _serverId);
}
}

protected abstract void SetInternalUserAgent(IDictionary<string, string> headers);

protected abstract void SetCustomHeaders(IDictionary<string, string> headers);

private static void CheckHeaders(IDictionary<string, string> headers, string forbidPrefix)
private static void CheckHeadersPrefix(IDictionary<string, string> headers, string forbidPrefix)
{
var item = headers.Where(x => x.Key.StartsWith(forbidPrefix, StringComparison.InvariantCultureIgnoreCase));
if (item.Any())
var item = headers.Where(x => x.Key.StartsWith(forbidPrefix, StringComparison.InvariantCultureIgnoreCase)).ToArray();
if (item.Length > 0)
{
var key = item.First().Key;
var key = item[0].Key;
throw new ArgumentException($"Invalid header {key}, custom header cannot startwith '{forbidPrefix}'");
}
}

private static Uri GetServiceUrl(IServiceEndpointProvider provider, string hubName, string connectionId, string target)
{
var baseUri = new UriBuilder(provider.GetServerEndpoint(hubName));
Expand Down Expand Up @@ -150,6 +150,7 @@ public void Dispose()
{
_inner.Dispose();
}

private sealed class GracefulLogger : ILogger
{
private readonly ILogger _inner;
Expand All @@ -160,10 +161,12 @@ public GracefulLogger(ILogger inner)
}

#nullable disable

public IDisposable BeginScope<TState>(TState state)
{
return _inner.BeginScope(state);
}

#nullable enable

public bool IsEnabled(LogLevel logLevel)
Expand Down Expand Up @@ -191,4 +194,4 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,13 @@ internal class ManagementConnectionFactory(IOptions<ServiceManagerOptions> conte
{
private readonly string? _productInfo = context.Value.ProductInfo;

internal override void SetInternalHeaders(IDictionary<string, string> headers)
protected override void SetCustomHeaders(IDictionary<string, string> headers)
{
base.SetInternalHeaders(headers);

if (_productInfo != null)
{
headers[Constants.AsrsUserAgent] = _productInfo;
}
return;
}

protected override void SetCustomHeaders(IDictionary<string, string> headers)
protected override void SetInternalUserAgent(IDictionary<string, string> headers)
{
return;
headers[Constants.AsrsUserAgent] = _productInfo ?? ProductInfo.GetProductInfo();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ public ConnectionFactory(IServerNameProvider nameProvider,
_options = options;
}

protected override void SetInternalUserAgent(IDictionary<string, string> headers)
{
// Fix issue: https://github.com/Azure/azure-signalr/issues/198
// .NET Framework has restriction about reserved string as the header name like "User-Agent"
headers[Constants.AsrsUserAgent] = ProductInfo.GetProductInfo();
}

protected override void SetCustomHeaders(IDictionary<string, string> headers)
{
_options.Value.CustomHeaderProvider?.Invoke(headers);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Extensions.Logging.Abstractions;

using Xunit;

namespace Microsoft.Azure.SignalR.AspNet.Tests;

#nullable enable

public class ConnectionFactoryTests
{
[Fact]
public void TestGetRequestHeaders()
{
var nameProvider = new DefaultServerNameProvider();

var loggerFactory = NullLoggerFactory.Instance;

var factory = new ConnectionFactory(nameProvider, loggerFactory);

var headers = factory.GetRequestHeaders();
Assert.True(headers.TryGetValue(Constants.AsrsUserAgent, out var productInfo));
Assert.StartsWith("Microsoft.Azure.SignalR.AspNet/", productInfo);

Assert.True(headers.TryGetValue(Constants.Headers.AsrsServerId, out var serverId));
Assert.Equal(nameProvider.GetName(), serverId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.Azure.SignalR.Management.Tests;

public class ManagementConnectionFactoryTests
{
private const string OptionsAsrsUserAgent = $"Microsoft.Azure.SignalR.Management.123456";
private const string OptionsAsrsUserAgent = $"Microsoft.Azure.SignalR.Foo/123456";

[Theory]
[InlineData(true)]
Expand All @@ -39,11 +39,11 @@ public void TestGetRequestHeaders(bool setManagementProductInfo)

if (setManagementProductInfo)
{
Assert.StartsWith("Microsoft.Azure.SignalR.Management", productInfo);
Assert.StartsWith("Microsoft.Azure.SignalR.Foo/", productInfo);
}
else
{
Assert.StartsWith("Microsoft.Azure.SignalR.Common", productInfo);
Assert.StartsWith("Microsoft.Azure.SignalR.Management/", productInfo);
}
}
}
6 changes: 4 additions & 2 deletions test/Microsoft.Azure.SignalR.Tests/ConnectionFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void TestSetCustomHeaders(string? key, string? val)

var headers = factory.GetRequestHeaders();
Assert.True(headers.TryGetValue(Constants.AsrsUserAgent, out var productInfo));
Assert.StartsWith("Microsoft.Azure.SignalR.Common", productInfo);
Assert.StartsWith("Microsoft.Azure.SignalR/", productInfo);

Assert.True(headers.TryGetValue(Constants.Headers.AsrsServerId, out var serverId));
Assert.Equal(nameProvider.GetName(), serverId);
Expand All @@ -52,8 +52,10 @@ public void TestSetCustomHeaders(string? key, string? val)
[Theory]
[InlineData(Constants.AsrsUserAgent, "bar")]
[InlineData(Constants.Headers.AsrsServerId, "bar")]
[InlineData("asrs-x", "bar")]
[InlineData("asrs-foo", "bar")]
[InlineData("ASRS-bar", "bar")]
[InlineData("x-asrs-foo", "bar")]
[InlineData("x-ASRS-bar", "bar")]
public void TestSetCustomHeadersThrows(string key, string val)
{
var nameProvider = new DefaultServerNameProvider();
Expand Down

0 comments on commit 827676f

Please sign in to comment.