@DTS Engineer
Thanks Quinn - the sysdiagnose is now attached to FB24062619.
It was captured on 2026-08-03 with the CFNetwork debug profile installed, right after a
reproduction. I noted the process name and host to look for in the Feedback itself. The
frame-level trace was very helpful: in that window our app logged 119 "sent HEADERS frame"
entries against 41 "sent DATA frame" entries, which matches what we had been seeing through
URLSessionTaskMetrics.
What the trace confirms is narrower than what I first posted. Under the classic loader,
exactly two of the concurrent upload tasks transmit their request body, and the rest stay
at countOfRequestBodyBytesSent = 0 until they are cut off. That number stayed at two across
six runs while we varied the session type, HTTPMaximumConnectionsPerHost (2 and 6), and how
many tasks were queued (4 and 12). The streams that never sent a body still received HTTP
responses, so the server had accepted their HEADERS and its advertised stream limit was
above two.
Setting usesClassicLoadingMode = NO changes it - all four then transmit, at 1.80 / 1.46 /
1.79 MB/s. Since only a client-side flag changed, the limit does not appear to come from
the server.
So the question I am still stuck on is where that "2" comes from. Is there a limit on
concurrent request bodies per HTTP/2 connection in the classic loader, and is it something
an app can influence? I got an answer on the Feedback that stream scheduling is not
controllable and that the server determines the stream count, but that does not seem to
explain the behavior above, so I may well be misreading something.
This still matters to us even with the new loader available: our minimum deployment target
is iOS 17.0, so a portion of our users cannot get that flag at all, and I would like to
understand what we are working around before choosing a fallback for them.
Topic:
App & System Services
SubTopic:
Networking
Tags: