Does NSURLSession data tasks buffer the first 512 bytes before it calls URLSession:dataTask:didReceiveResponse:completionHandler: as well as URLSession:dataTask:didReceiveData:? And is the buffering disabled when the Content-Type is application/json?
I was experimenting with NSURLSession and was hoping to make it possible for my app to do something as soon as the HTTP header is received or as the first batch of raw data is received. I wrote a simple server to test, but what I described below can also be tested with services like httpbin.org. I noticed that:
- URLSession:dataTask:didReceiveResponse:completionHandler: is only called before URLSession:dataTask:didReceiveData: is called, though the doc says the former "[tells] the delegate that the data task received the initial reply (headers) from the server", and I thought it meant that the delegate method would be called as soon as the header is received even if the response body is not yet seen, but that doesn't seem to be the case.
- URLSession:dataTask:didReceiveData: is only called for the first time when the server sends 512 bytes in total (or closes the connection if the total content length is less than that). After the first 512 bytes, the delegate method is called as soon as a new batch of data is received. If Transfer-Encoding is used for chunking, the 512 bytes apply to the decoded bytes, not the raw bytes over the wire.
- However, if Content-Type is application/json, URLSession:dataTask:didReceiveData: will be called as soon as one byte is received. This Stack Overflow discussion mentioned this seemingly undocumented behavior.
One can see the buffering in action with a simple HTTP server, or just use httpbin.org, for example with https://httpbin.org/drip?numbytes=1024&duration=8; if you use "curl -N" to fetch that URL, you'll see some characters received soon after the the request started, but if you use a data task to fetch it, it'll be a few seconds until the two delegate methods mentioned above are called, and the first batch of data is always >= 512 bytes long.
The thing about this is that they don't seem to be documented anywhere, and I appreciate if there are some clarifications on the API contract. Thanks!