How to check if HTTP server is ready to send data

Let's imagine that we start an HTTP server and an HTTP request to this server at the same time. It can happen that the first request will successfully connect to the remote server and write data to a stream (headers, body) but will be unable to reading response data (stream.read() will always be 0 even if we retry it). This all works when the HTTP server is started before the request is executed. Note that I'm starting my HTTP server using Docker.

Here's a snippet:

let mut stream = TcpStream::connect(&addr).await?; // CONNECT 
stream.write(b"GET /foo HTTP/1.1.\r\n").await?; // WRITE
stream.write...
...
let mut buff = vec![0u8; 1024];
let len = stream.read(&mut buff).await?; // READ => 0 when server is not ready

How should an HTTP client know when the HTTP server is ready to receive/write data (and retry when the server is not ready yet). I don't want to do an additional request (e.g. HEAD /ready) just to see if I can write data to a stream (so the server will actually receive my messages). Also, I'm pretty positive that this issue is not related just to Rust and you should get the same effect using any other programing language. Any suggestions?

You should simply write the full message and then listen for a response. Note that the plain write method may not write the entire buffer you have provided it, so you should use either write_all or call write in a loop. The read method will only return zero if the connection has been closed.

But if I add stream.flush().await? before I start reading, this should have the same effect as using write_all, right? Replacing write with write_all or adding flush doesn't solve the problem. It looks like the container is up, the network is enabled but the HTTP server within the container is not yet running.

No, flush does not have the same effect as using write_all. You should probably be using both write_all and flush here. I don't know what exactly is wrong with your web-server, but if read returns zero bytes, then the connection is closed.

Strange, I'm getting the same effect with any of these methods. Note that I'm talking only about the first request to the server that's in the progress of becoming ready.

let mut relay = async_std::net::TcpStream::connect(...).await?;
relay.write_all(b"GET / HTTP/1.1\r\n\r\n").await?;
// If I wait here for the webserver to become ready e.g. 1sec, it then works
let mut buff = vec![0u8; 1024];
let len = relay.read(&mut buff).await?; // Zero

Looks like the issue is specifically related to Docker because it works when the server is run directly from the command-line. Docker starts the container, says it's ready, but the HTTP server is not actually ready. I found Github issues describing this problem.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.