Can't write to TcpStream without reading from it?


#1

I’m encountering a bizarre issue while following the multithreaded web server project guide:

https://doc.rust-lang.org/book/second-edition/ch20-00-final-project-a-web-server.html

In the step where we add a way to respond to /sleep , I realized my browser would always say Connection Reset when trying to load /sleep but everything else worked.

I realized this was happening apparently due to the length of the URL. /s, /sl, and /sle all worked, but /slee did not work. Here is my full code:

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::fs::File;

fn main() {
	let listener = TcpListener::bind("127.0.0.1:8080").unwrap();

	for stream in listener.incoming() {
		let stream = stream.unwrap();

		handle_connection(stream);
	}
}

fn handle_connection(mut stream: TcpStream){
	let mut buffer = [0; 512];
	stream.read(&mut buffer).unwrap();

	let (status_line, filename) = ("HTTP/1.1 200 OK\r\n\r\n", "index.html");

	let mut file = File::open(filename).unwrap();
	let mut contents = String::new();
	file.read_to_string(&mut contents).unwrap();

	let response = format!("{}{}", status_line, contents);

	let written = stream.write(response.as_bytes()).unwrap();
	stream.flush().unwrap();	

	println!("Wrote {:?} bytes", written);
}

If I change the line:

let mut buffer = [0; 512];

To

let mut buffer = [0;1000];

The problem goes away (presumably until the URL gets long enough). Furthermore, removing the read makes the browser always say Connection Reset. This is despite the fact that I am printing out the number of bytes returned from the write call at the end, and it is always writing the same number of bytes.

I’m on Windows 10, testing with Firefox (same problem in Chrome, just with a longer URL length).

So my question is: Does writing to the stream depend on reading from it first? Is the socket blocked and waiting for its message to be received before it can receive anything? If so, we should probably add something about that to the guide.


#2

I don’t seem to get this behavior (Linux here). It would also make no sense, since the write and read halves of the socket are independent (full duplex).

However, you’re closing the stream after writing your response. So possibly on Windows, send() (at least to loopback) doesn’t actually consider data sent until the other end has recv()d it completely?

Does the server behave differently when you bind and connect to an external interface?


#3

You have to read the entire request or else the client blocks and then fails as soon as you close the socket. It never actually tries to read your response before it has sent the request completely.

The code is problematic because it relies on OS buffering on the client or server side.
Without buffering, a peer can only send if the other peer is reading and vice versa. With buffering, the same problem exists but only if the buffers are full.