Skip to content

Interactions between different UAP HttpClient SSL tests causes failures #22657

@davidsh

Description

@davidsh

While working on PR dotnet/corefx#21905, I discovered some test failures on UAP. The failures occur in two different tests, but only if both tests are enabled. Running each test separately while disabling the other makes the tests pass.

The problem is actually due to a known issue in WinRT Windows.Web.Http.HttpClient layer. The WinRT layer uses native WinInet and there are some things that WinInet caches per-process and not per-session handle. That means that there is unintended sharing of some state between separate HttpClient objects.

In particular, this shared state is about TCP connections and specifically if SSL connections were made using cert error ignore flags.

We have two tests were the tests are testing against connecting to servers with bad certificates.

public static readonly object[][] CertificateValidationServers = 
{
    new object[] { Configuration.Http.ExpiredCertRemoteServer },
    new object[] { Configuration.Http.SelfSignedCertRemoteServer },
    new object[] { Configuration.Http.WrongHostNameCertRemoteServer },
};

[OuterLoop] // TODO: Issue dotnet/runtime#18406
[ConditionalTheory(nameof(ClientSupportsDHECipherSuites))]
[MemberData(nameof(CertificateValidationServers))]
public async Task NoCallback_BadCertificate_ThrowsException(string url)
{
    using (var client = new HttpClient())
    {
        await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
    }
}

[OuterLoop] // TODO: Issue dotnet/runtime#18406
[ConditionalTheory(nameof(BackendSupportsCustomCertificateHandlingAndClientSupportsDHECipherSuites))]
[MemberData(nameof(CertificateValidationServersAndExpectedPolicies))]
public async Task UseCallback_BadCertificate_ExpectedPolicyErrors(string url, SslPolicyErrors expectedErrors)

In one test, we use no callback and expect to get errors. In another test, we connect to the same servers and pass it a callback. We use the callback to analyze the certificate errors from the X509Chain we get back.

The problem occurs in the no_callback test where we expect to get an HttpRequestException back. But we don't because the other test which ran in parallel or just before already used ignore flags, made good connections at the TCP/SSL layer, so Wininet caches those connections for later use. So, the no_callback test fails because the connections are already there.

One way to work around this problem in the tests is to isolate each of the two tests into separate processes using the RemoteExecutor.

In a previous release of Windows 10, the WinRT HttpClient APIs added a new method to the HttpBaseProtocolFilter:
https://docs.microsoft.com/en-us/uwp/api/windows.web.http.filters.httpbaseprotocolfilter

That new method

public void ClearAuthenticationCache()

allows developers to clear out any cached connection information if their app is running long-term and they need to do "log off" scenarios. However, at the System.Net.Http layer, we don't have that control, nor do we expect it since the assumption is that connections are cached per HttpClient. So, this is a difference in behaviors, unfortunately, for now.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions