-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[WinHTTP] Certificate caching on WinHttpHandler to eliminate extra call to Custom Certificate Validation #111791
base: main
Are you sure you want to change the base?
Conversation
…om Certificate Validation
Tagging subscribers to this area: @dotnet/ncl |
/azp run runtime-libraries-coreclr outerloop-windows |
Azure Pipelines successfully started running 1 pipeline(s). |
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
AddressFamily.InterNetwork => new IPAddress(BinaryPrimitives.ReadUInt32LittleEndian(RemoteAddressSpan.Slice(4))), | ||
AddressFamily.InterNetworkV6 => new IPAddress(RemoteAddressSpan.Slice(8, 16).ToArray()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is running per-request, can we try to avoid the IPAddress
allocations (eg. by using a custom struct as a dictionary key), or if we think they are insignificant, run some benchmarks to prove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really think it's worth it? Usage of IPAddress simplifies the written code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usage of IPAddress simplifies the written code
I'm not sure. Since the addresses are only used as keys in platform-specific logic, we don't even need to parse them or have any logic distinguishing InterNetwork
and InterNetworkV6
. It's enough to copy the relevant bytes of the span into a struct containing a buffer big enough for both IPv4 and IPv6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've discussed this in our offline chat, do you still believe we need to change this into some other structure @antonfirsov ?
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very nice for Prove of concept, but there are few things which needs to be considered before we decide on feasibility of this approach:
- decide if unbounded cache can be an memory leak issue (I have hard time to imagine use where it would)
- consider different cache key to handle virtual servers infra
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
/azp run runtime-libraries-coreclr outerloop-windows |
Azure Pipelines successfully started running 1 pipeline(s). |
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
@@ -56,6 +62,14 @@ private static void RequestCallback( | |||
{ | |||
switch (internetStatus) | |||
{ | |||
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: | |||
if (CertificateCachingAppContextSwitchEnabled) | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the null-forgiving operator '!' assumes that Marshal.PtrToStringUni(statusInformation) is never null. Consider adding an explicit null check to prevent a potential exception if the pointer is unexpectedly null.
{ | |
{ | |
if (statusInformation == IntPtr.Zero) | |
{ | |
throw new InvalidOperationException("statusInformation pointer is null."); | |
} |
Copilot is powered by AI, so mistakes are possible. Review output carefully before use.
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
ipAddress = addressFamily switch | ||
{ | ||
AddressFamily.InterNetwork => new IPAddress(BinaryPrimitives.ReadUInt32LittleEndian(remoteAddressSpan.Slice(4))), | ||
AddressFamily.InterNetworkV6 => new IPAddress(remoteAddressSpan.Slice(8, 16).ToArray()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit.
I think we should also try to get ScopeID for IPv6 to be 100% correct. LLA are rare but possible.
/azp run runtime-libraries-coreclr outerloop-windows |
Azure Pipelines successfully started running 1 pipeline(s). |
…ficate_experiment
/azp run runtime-libraries-coreclr outerloop-windows |
Azure Pipelines successfully started running 1 pipeline(s). |
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/CachedCertificateValue.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
/azp run runtime-libraries-coreclr outerloop-windows |
Azure Pipelines successfully started running 1 pipeline(s). |
src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/CachedCertificateValue.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming we get validation that this saves enough perf to justify the added complexity, this looks reasonable to me.
AddressFamily.InterNetwork => new IPAddress(BinaryPrimitives.ReadUInt32LittleEndian(remoteAddressSpan.Slice(4))), | ||
AddressFamily.InterNetworkV6 => new IPAddress(remoteAddressSpan.Slice(8, 16).ToArray()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth leaving a link to the relevant docs here for where these offset numbers are coming from.
src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Miha Zupan <[email protected]>
…ficate_experiment
public override bool Equals(object? obj) | ||
{ | ||
throw new Exception("Unreachable"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: | ||
if (WinHttpHandler.CertificateCachingAppContextSwitchEnabled) | ||
{ | ||
IPAddress connectedToIPAddress = IPAddress.Parse(Marshal.PtrToStringUni(statusInformation)!); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use IPAddress.Parse(ReadOnlySpan<char>)
here? Moreover: are we confident this will work well for both IPv4 and IPv6?
This PR goal is improving performance around CustomCertificateValidationCallback.