Skip to content

Commit

Permalink
Validate Windows version when using WinHttpHandler (#2229)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed Aug 4, 2023
1 parent 6420a8c commit cec98b2
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
12 changes: 12 additions & 0 deletions src/Grpc.Net.Client/GrpcChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@ internal GrpcChannel(Uri address, GrpcChannelOptions channelOptions) : base(addr
{
Log.AddressPathUnused(Logger, Address.OriginalString);
}

// Validate the Windows version can support WinHttpHandler.
const int WinServer2022BuildVersion = 20348;
if (HttpHandlerType == HttpHandlerType.WinHttpHandler &&

This comment has been minimized.

Copy link
@danielgindi

danielgindi Nov 28, 2023

This commit blocks .NET 6 apps on Windows 2019. It is supposed to allow it on .NET >= 6.0

This comment has been minimized.

Copy link
@JamesNK

JamesNK Nov 28, 2023

Author Member

Are you using WinHttpHandler + Grpc.Net.Client on Windows 2019? I was under the impression that it wasn't supported.

This comment has been minimized.

Copy link
@danielgindi

danielgindi Jan 10, 2024

Yes, for a long time now, and it is supported :)

This comment has been minimized.

Copy link
@JamesNK

JamesNK Jan 11, 2024

Author Member

Are you only using unary gRPC calls from Windows 2019? There might be some limited support for unary calls in that OS version.

This comment has been minimized.

Copy link
@danielgindi

danielgindi Jan 16, 2024

Are you only using unary gRPC calls from Windows 2019? There might be some limited support for unary calls in that OS version.

I believe so. And for a long time it works, currently with a version behind this specific commit.

This comment has been minimized.

Copy link
@danielgindi

danielgindi Jan 16, 2024

Microsoft updated the documentation for 2022 support, but this is actually breaking support for Windows 2019 without a Major version release, which is kind of against the rules.
There were issues opened in the past about streaming not being supported with winhttphandler+grpc, which was always the case.

This comment has been minimized.

Copy link
@JamesNK

JamesNK Jan 16, 2024

Author Member

This comment has been minimized.

Copy link
@JamesNK

JamesNK Jan 18, 2024

Author Member

I merged a change to allow 2019: #2362

I don't have 2019 setup to test it but I believe it should work. It would be great if you could try out the next preview to double check it works in the real world.

This comment has been minimized.

Copy link
@danielgindi

danielgindi Jan 21, 2024

Thank you! I will test the preview and let you know!

OperatingSystem.IsWindows &&
OperatingSystem.OSVersion.Build < WinServer2022BuildVersion)
{
throw new InvalidOperationException("The channel configuration isn't valid on this operating system. " +
"The channel is configured to use WinHttpHandler and the current version of Windows " +
"doesn't support HTTP/2 features required by gRPC. Windows Server 2022 or Windows 11 or later is required. " +
"For more information, see https://aka.ms/aspnet/grpc/netframework.");
}
}

private void ResolveCredentials(GrpcChannelOptions channelOptions, out bool isSecure, out List<CallCredentials>? callCredentials)
Expand Down
8 changes: 7 additions & 1 deletion src/Grpc.Net.Client/Internal/OperatingSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
Expand All @@ -24,6 +24,8 @@ internal interface IOperatingSystem
{
bool IsBrowser { get; }
bool IsAndroid { get; }
bool IsWindows { get; }
Version OSVersion { get; }
}

internal sealed class OperatingSystem : IOperatingSystem
Expand All @@ -32,6 +34,8 @@ internal sealed class OperatingSystem : IOperatingSystem

public bool IsBrowser { get; }
public bool IsAndroid { get; }
public bool IsWindows { get; }
public Version OSVersion { get; }

private OperatingSystem()
{
Expand All @@ -41,5 +45,7 @@ private OperatingSystem()
#else
IsAndroid = false;
#endif
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
OSVersion = Environment.OSVersion.Version;
}
}
4 changes: 3 additions & 1 deletion test/Grpc.Net.Client.Tests/GetStatusTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
Expand Down Expand Up @@ -214,6 +214,8 @@ private class TestOperatingSystem : IOperatingSystem
{
public bool IsBrowser { get; set; }
public bool IsAndroid { get; set; }
public bool IsWindows { get; set; }
public Version OSVersion { get; set; } = new Version(1, 2, 3, 4);
}

[Test]
Expand Down
60 changes: 60 additions & 0 deletions test/Grpc.Net.Client.Tests/GrpcChannelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,66 @@ private class TestOperatingSystem : IOperatingSystem
{
public bool IsBrowser { get; set; }
public bool IsAndroid { get; set; }
public bool IsWindows { get; set; }
public Version OSVersion { get; set; } = new Version(1, 2, 3, 4);
}

[Test]
public void WinHttpHandler_UnsupportedWindows_Throw()
{
// Arrange
var services = new ServiceCollection();
services.AddSingleton<IOperatingSystem>(new TestOperatingSystem
{
IsWindows = true,
OSVersion = new Version(1, 2, 3, 4)
});

#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior.
var winHttpHandler = new WinHttpHandler(new TestHttpMessageHandler());
#pragma warning restore CS0436

// Act
var ex = Assert.Throws<InvalidOperationException>(() =>
{
GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions
{
HttpHandler = winHttpHandler,
ServiceProvider = services.BuildServiceProvider()
});
});

// Assert
Assert.AreEqual(ex!.Message, "The channel configuration isn't valid on this operating system. " +
"The channel is configured to use WinHttpHandler and the current version of Windows " +
"doesn't support HTTP/2 features required by gRPC. Windows Server 2022 or Windows 11 or later is required. " +
"For more information, see https://aka.ms/aspnet/grpc/netframework.");
}

[Test]
public void WinHttpHandler_SupportedWindows_Success()
{
// Arrange
var services = new ServiceCollection();
services.AddSingleton<IOperatingSystem>(new TestOperatingSystem
{
IsWindows = true,
OSVersion = Version.Parse("10.0.20348.169")
});

#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior.
var winHttpHandler = new WinHttpHandler(new TestHttpMessageHandler());
#pragma warning restore CS0436

// Act
var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions
{
HttpHandler = winHttpHandler,
ServiceProvider = services.BuildServiceProvider()
});

// Assert
Assert.AreEqual(HttpHandlerType.WinHttpHandler, channel.HttpHandlerType);
}

#if SUPPORT_LOAD_BALANCING
Expand Down

0 comments on commit cec98b2

Please sign in to comment.