I'm using the following code to test how many seconds an HTTP connection can be kept alive:
start_time = time.time()
try:
r = requests.get(BIG_FILE_URL, stream=True)
total_length = r.headers['Content-length']
for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
time.sleep(1)
# ... except and more logic to report total time and percentage downloaded
To be sure Python doesn't just download everything at once and creates a generator, I've used tcpdump. It does send one packet per second (approximately) but I didn't find what makes the server send one block at a time and how does the requests library does that.
I've checked several SOF questions and looked at the requests library documentation, but all resources explain how to use the library to download large files, and none of them explain the internals of the stream=True option.
My question is: what in the tcp protocol or HTTP request headers, makes the server send one block at a time and not the whole file at once?
EDIT + possible answer:
After working with Wireshark, I found out Python implements it using the TCP's sliding window. Meaning, it won't send an ack while the next chunk is not called.
That might cause some unexpected behavior as the sliding window might be a lot bigger than the chunk, and the chunks in the code might not represent actual packets.
Example: if you set the chunk to 1000 bytes, a default sliding window of 64K (my default on Ubuntu 18) will cause 64 chunks to be sent immediately. If the body size is less than 64K the connection might close immediately. So this is not a good idea for keeping connection online.