The problem
We have built a Windows 10 app which sends push notifications to iOS devices. While load testing, we discovered a pretty severe bug with UWP's HttpClient classes that is seemingly-impossible to diagnose.
Our UWP app sends push notifications to Apple's APN servers. We can send HTTP/2 TLS requests and everything works fine as long as we send a message every few seconds.
But if we wait a minute or so between HTTP/2 requests, HttpClient completely breaks down, returning a COMException with error code 0x80072efd and the COM error text "A connection with the server could not be established".
We have tested this scenario against our own web-based HTTP/2 servers (ASP.NET Core HTTPS behind Nginx) using the same payload and appropriate client certificates. Everything works fine there--so this problem seems to be isolated to HttpClient interoperability with either the Apple APN client certificates or Apple's HTTP/2 frontend.
Attempts to diagnose
To diagnose the issue, we installed mitmproxy (with HTTP/2 and client certificate support) but the HTTP/2 implementation that mitmproxy uses behaves perfectly and does not exhibit the same issues as UWP's HttpClient classes so we were unable to debug the issue there.
We also tried using Fiddler, but Fiddler (and Fiddler Core which Microsoft's message analyzer uses) only has early HTTP/2 support and corrupts HTTP/2 streams.
And of course we looked at diagnostics with SSLSPLIT and similar solutions but could not find any diagnostic tool that could handle HTTP/2 and client certificates.
Code, for reference
/* code called during app startup */
Certificate clientCertificate = [apns certificate omitted for security];
string deviceToken = "[omitted for security]";
string appBundleId = "[omitted for security]";
//
Windows.Web.Http.Filters.HttpBaseProtocolFilter filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
filter.ClientCertificate = clientCertificate;
var client = new Windows.Web.Http.HttpClient(filter);
/* code called every time a push notification needs to be sent */
string messageUuid = Guid.NewGuid().ToString("D");
//
var request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, new Uri("https://api.development.push.apple.com:443/3/device/" + deviceToken));
//
request.Headers.Add("apns-id", messageUuid);
request.Headers.Add("apns-expiration", "0");
request.Headers.Add("apns-priority", "10");
request.Headers.Add("apns-topic", appBundleId);
// sample notification content for testing purposes only
request.Content = new Windows.Web.Http.HttpStringContent("{ \"aps\" : { \"alert\" : \" -- test message " + messageUuid + " -- \" } }");
//
try
{
// this next line of code works fine if called a few seconds after the last message--but throws a COMException if a minute has passed
var response = await client.SendRequestAsync(request);
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
Questions
What if any options are available to diagnose WinInet/HttpClient failures on Windows 10? With HTTP/2, TLS and Client Certificates in the mix?
Is there anything special about Apple's selected HTTP/2 implementation which is known to cause issues with UWP's HttpClient--with a known workaround?
User contributions licensed under CC BY-SA 3.0