URLSession for HTTP/2

I'm confused on how to initiate an HTTP/2 session. I keep seeing that URLSession supports it, but I don't know what that means. I'm on a mac (not iOS) and I've got all the code already to encode/decode the frames that the spec describes. Now I want to make a connection to the APNS server. I'm assuming I need to call the streamTask(withHostName:port:) method to get the bidirectional data stream?


Right after the streamTask constructor I called startSecureConnection() but it doesn't look like the session delegate's challenge method was ever called.


Let's assume that was working though. Would I then call captureStreams() at that point to get the InputStream and OutputStream items to then read and write to?

NSURLSession
will automatically use HTTP/2 for HTTPS requests if the server supports it. This isn’t something you have to configure. Rather, when you run an HTTPS task in the session it will, on opening the connection to the server, detect that it supports HTTP/2, set up an HTTP/2 connection, and then issue that task over that HTTP/2 connection.

Now I want to make a connection to the APNS server.

NSURLSession
is not a good match for APNS. APNS wants the push provider to open an HTTP/2 connection and keep it open indefinitely.
NSURLSession
was designed for typically client applications and doesn’t support that model. Specifically, it will automatically close the HTTP/2 connection after it’s been idle for a short period of time (last I checked that was one minute) and that’s exactly what you shouldn’t do in an APNS push provider because it can trigger the APNS denial of service attack checker.

I'm assuming I need to call the

streamTask(withHostName:port:)
method to get the bidirectional data stream?

You could do that, but then you’re just talking raw TCP with, optionally, TLS layered on top. You’d then have to implement HTTP/2 on top of that channel, which is a lot of work. You could use a third-party library to help with that, but at that point you might as well not use

NSURLSession
at all.

If you’d like

NSURLSession
to better support APNS, my recommendation is that you file an enhancement request along those lines (s. 637853075). Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the explanation, Quinn. Suggestions on what I should use instead then to make the connection to the APNS server?

Suggestions on what I should use instead then to make the connection to the APNS server?

You should use whatever HTTP/2 client is supported by the platform on which your push provider is running. On UNIX-y platforms a common choice is libcurl but I’ve not used it personally.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

NSURLSession uses HTTP/2 automatically for HTTP2 SSL server.

But NSURLSession uses HTTP/1.1 for HTTP/2 HTTP server(Not SSL).

Is there an option for NSURLSession to use HTTP/2 for HTTP/2 HTTP server?

Because it uses HTTP/1.1 and failed.

@eskimo We are having some intermittent and random SSL Handsake Errors with an HTTPS request:

Connection 5: received failure notification
Connection 5: failed to connect 3:18,446,744,073,709,541,800, reason 18,446,744,073,709,551,615
Connection 5: encountered error(3:18,446,744,073,709,541,800)
Task <2B22A105-33BD-4291-8749-40EEF62C50EC>.<1> HTTP load failed, 0/0 bytes (error code: 18,446,744,073,709,550,416 [3:18,446,744,073,709,541,800])
Task <2B22A105-33BD-4291-8749-40EEF62C50EC>.<1> finished with error [18,446,744,073,709,550,416] Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
    "<cert(0x11482c000) s: *.xxxxx.com i: GeoTrust TLS RSA CA G1>",
    "<cert(0x1128bac00) s: GeoTrust TLS RSA CA G1 i: DigiCert Global Root G2>"

One of our engineers is seeing TLS 1.0 requests but we are using URLSession with iOS 16 or 17. From what I can see, this should result in TLS 1.2+ request. In fact, the proxy captures and network package captures are showing TLS 1.2+ requests. Also, I saw this posting that has the same error codes saying it was an HTTP/1.1 vs. HTTP/2.0 problem with the server:

https://forums.developer.apple.com/forums/thread/709042

So what would be the best way to track this down and is there any documentation about the "dance" that URLSession goes thru to determine what protocol versions of HTTP and TLS to use when making an HTTPS request? Is there utilities to query the web server to see what versions of HTTP/1.1 or HTTP/2.0 are supported?

BTW - I am not seeing any low level networking calls that would bypass ATS minimum TLS version of 1.2.

URLSession for HTTP/2
 
 
Q