ECONNRESET When Benchmarking HTTP Server

Hello, im writing a basic http server, but when I benchmark it, the results are very underwhelming and im getting a whole bunch of errors (50% of the requests are errors) and I was curious if anyone could help me out on what i might be doing wrong?

// src/http/server.rs
pub struct Server<'a> {
    pub resources: Vec<Resource::Resource>,
    pub options: &'a HttpOptions
}

impl Server<'_> {

    pub fn run(&self) {
        let port_str: &String = &self.options.port.to_string();
        let address = format!("{}:{}", &self.options.hostname, port_str);
        let listener = TcpListener::bind(address).unwrap();

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

    fn handle_http_request (&self, mut stream: TcpStream) {
        println!("Connection established!");
        let mut buffer = [0; 1024];
        stream.read(&mut buffer).unwrap();
        let request_data = String::from_utf8_lossy(&buffer[..]);
        println!("Request: {}", request_data);
        'outer: for resource in &self.resources {
            for path in &resource.paths {
                let formatted = format!(r"{} HTTP/1.1", path);
                let regex = Regex::new(formatted.as_str()).unwrap();
                if regex.is_match(&request_data) {
                    println!("match!");
                    for method in &resource.methods {
                        // TODO if matched method:
                        let request = Request::Request {
                            stream: &stream
                        };
                        let response = Http::Response::Response;
                        let true_response = method(request, response);
                        Http::Response::Response::write_response(&stream, true_response);
                        break 'outer;
                    }
                }
            }
        }
    }
}

Contents of Http::Response::Response::write_response is:

let contents = String::from("hello");

let response = format!(
   "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
    contents.len(),
    contents
);

stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();

I start the server, and run: $ autocannon -d 1 -c 10 http://localhost:1334

Your issue is likely that you ignore the results of stream.read and stream.write. TCP is a stream oriented protocols, and the typical APIs allow everything from 1 byte up to N bytes (the size of your buffer) to be transmitted within one call.

That means:

  • Your read call might not read the full request - parsing will fail and some bytes might stay "on the wire"
  • Your write call is not guaranteed to write everything.

You can likely fix the last issue by using stream.write_all(response.as_bytes()).

Thanks :slight_smile: Your suggestion does indeed fix the second issue (getting less error responses now). Just need to ensure im reading all the bytes from the request now

I should note, i get the same problems when using a bare basic http server - benchmarking results in 50% of the requests erroring