[Follow-up] HTTP2 large headers size issue

Hi! this is a follow-up of a networking lab session.

Yes, I managed to reproduce the memory spike with mocked extra large request headers on HTTP2.

My questions are:
  • Does the NSURLSession timeout still apply if running into in that case? Will the request return eventually? What's the error code?

  • In the logs of affected sessions, I can see a few requests timed out longer than 60s( the default timeout in NSURLSession), and the error code is -1001. Also, seems those requests returned right before the app crashed due to out of memory.

  • Is there a good way to estimate the headers size? numberofcharacters * 1 bytes?

  • With HPACK on HTTP2, is the headers size consist of static and dynamic headers?

  • Other than those reserved http headers ("content-length", "accept", " "user-agent", etc), are there any other cases that underlying CFNetworking would add large headers? I assume not

  • A separate API feedback, seems [NSURLSessionConfiguration setHTTPAdditionalHeaders:nil] won't clear up headers. It is a bit confusing imho. :)


Thanks for your time again!



Answered by liangm in 617396022
Sorry, the last one I meant [NSMutableURLRequest setHTTPAdditionalHeaders:nil] after the request already has a bunch of headers are set.

Does the NSURLSession timeout still apply if running into in that case? Will the request return eventually? What's the error code? In the logs of affected sessions, I can see a few requests timed out longer than 60s( the default timeout in NSURLSession), and the error code is -1001. Also, seems those requests returned right before the app crashed due to out of memory.

In my experiment, it does timeout with -1001 error code which stops the retry loop. But as you have mentioned, the app could be killed due to memory pressure so you might want to avoid getting into this state if possible.

Is there a good way to estimate the headers size? numberofcharacters * 1 bytes? With HPACK on HTTP2, is the headers size consist of static and dynamic headers?

HEADERS frame in HTTP/2 can include both literal headers and reference to static or dynamic tables. At worst, every header is encoded as literal headers which makes it as big as HTTP/1 headers.

You can use "header name length + header value length + 32" as a safe estimation. Don't forget that URL is also represented in pseudo headers.

Other than those reserved http headers ("content-length", "accept", " "user-agent", etc), are there any other cases that underlying CFNetworking would add large headers? I assume not

CFNetwork can also add Authorization header if you use HTTP basic auth, which contains the credential your app provided.

A separate API feedback, seems [NSURLSessionConfiguration setHTTPAdditionalHeaders:nil] won't clear up headers. It is a bit confusing imho. :)

I'm unable to reproduce this issue. Are you setting it before NSURLSession is created? NSURLSessionConfiguration is copied by NSURLSession and cannot be changed after NSURLSession creation.
Accepted Answer
Sorry, the last one I meant [NSMutableURLRequest setHTTPAdditionalHeaders:nil] after the request already has a bunch of headers are set.
i meant [NSMutableURLRequest setAllHTTPHeaders:nil]...

In my experiment, it does timeout with -1001 error code which stops the retry loop. But as you have mentioned, the app could be killed due to memory pressure so you might want to avoid getting into this state if possible.

is it the same timeout value set in NSURLSession or NSURLRequest?
another question: I was able to reproduce this issue (XCode shows 10/100 M+ memory increase every a few seconds, depends on how large the header) by mocking super large http headers, with error ( timed out around 60+ secs):


Code Block
finished with error [-1001] Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x60000059bd20 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}


However the XCode doesn't show high memory usage now. After git-bisect, I found that if the code uses

request.HTTPBody instead of request.HTTPBodyStream, the overall memory usage is stable even the request still fails.

Can someone confirm and explain if that is the case? I am skeptical but that's what i'm seeing.
[NSMutableURLRequest setAllHTTPHeaders:nil] is a known issue. It currently can only add headers, not remove them.

If timeoutInterval is set on NSURLRequest, it overrides timeoutIntervalForRequest on NSURLSessionConfiguration.

I cannot confirm that HTTPBodyStream is the cause of memory growth right now, but there is a strong possibility that it is if that's what you are observing.
i've verified the httpbodystream would fix our http oom issues.

btw: does iOS 13.6 include the patch of large http2 request header?
[Follow-up] HTTP2 large headers size issue
 
 
Q