Why Your Mobile App Can Time Out on Responses With an Empty Body

While testing an Android app, one of our QA engineers noticed something odd: after stripping the response body from a request using a MITM proxy, the app didn’t just return an empty result. Instead, it kept waiting… and waiting… until finally throwing a timeout error. On the UI, the loader animation spun endlessly before failing.
At first glance, this looks like a bug. After all, the server sent back a 200 OK
; shouldn’t the app consider that a valid response? The answer lies deep in how HTTP/1.1 handles response bodies.
The Core Issue
The problem is not that the app ignores the HTTP status code, but that it expects not only a response header, but also a properly defined body.
\
When the server says “I’ll send you a body”, the client (your app) trusts that promise. If the body never arrives, the client keeps waiting until a timeout occurs.
Why It Happens
1. Transfer-Encoding: chunked
\
In the failing case, the response contained this header: Transfer-Encoding: chunked
\
This header tells the client: “Don’t worry about the total size, I’ll send the body in chunks.”
\
Per RFC 7230:
The chunked transfer coding wraps the payload body in order to transfer it as a series of chunks […] Chunked enables content streams of unknown size to be transferred as a sequence of length-delimited buffers, which enables the sender to retain connection persistence and the recipient to know when it has received the entire message.
\
Since the server promised chunks but sent none, the client keeps waiting for data that will never come. Eventually, it times out.
2. Missing Content-Length
If the server did not use Transfer-Encoding
, the next expectation would be an explicit Content-Length
.
\
RFC 7230 (HTTP/1.1) Content-Length
\
For a truly empty body, the correct header would be: Content-Length: 0
\
Without it, the client cannot know for sure that the body is absent.
Why the Example Was Wrong
In our test setup, the response was stripped incorrectly. To signal a deliberately empty body in compliance with HTTP/1.1, the response must:
- Not include
Transfer-Encoding: chunked
- Include
Content-Length: 0
\
Only then will the client immediately understand: “Nobody is coming, I can stop waiting.”
How to Reproduce the Correct Case in Charles Proxy
If you want to simulate this behavior correctly, here’s how to configure Charles Proxy:
\
On the request:
- Replace the
Accept-Encoding
header withIdentity
. This disables compression (otherwise you’ll hit SSL errors).
\
On the response:
- Remove the body entirely
- Add
Content-Length: 0
- Remove the
Transfer-Encoding
header
\
Now, your app will immediately recognize the empty response and behave accordingly.
Takeaways
- HTTP responses with
Transfer-Encoding: chunked
imply that a body is coming. - If the body is missing, clients will wait until a timeout.
- To signal a truly empty response, use
Content-Length: 0
and dropTransfer-Encoding
. - When testing with tools like Charles Proxy, make sure you’re simulating the protocol correctly, not just stripping content.
👉 This little quirk reminds us how much apps rely on strict adherence to HTTP standards. A missing or misconfigured header can completely change how the client interprets the response.