How would you handle a incoming POST request in a HTTP Server

How would i handle an incoming POST request and get its body, headers, etc.?
I'm trying to make simple API in rust that you send requests to and it does something with the data, but i can't get the body / headers of the request.
I'm also using this as a foundation for the webserver. All i have managed is handling GET requests.

Here is my code:

use std::{
    fs,
    io::{prelude::*, BufReader},
    net::{TcpListener, TcpStream},
};

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

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

        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
  
    let mut buf_reader = BufReader::new(&mut stream);
    
    let request_line = buf_reader.lines().next().unwrap().unwrap();
    println!("{}" ,request_line);
    let (status_line, filename) = if request_line == "GET / HTTP/1.1" {
        ("HTTP/1.1 200 OK", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND", "404.html")
    };

    let contents = fs::read_to_string(filename).unwrap();
    let length = contents.len();

    let response =
        format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");

    stream.write_all(response.as_bytes()).unwrap();
}

What do you mean you can't get the body or headers? You don't appear to be using an HTTP library so you'll have to parse the HTTP messages yourself.

If you're just trying to write a server without worrying about low level HTTP details, you should probably use a mid level library like hyper that handles parsing for you. Alternatively you could go for a higher level web framework like axum or warp that provides nicer building blocks for web servers.

If you're actually interested in parsing HTTP as a learning exercise, could you elaborate on what you're struggling with?

1 Like

okay, thanks!
ill try it out!

In order to read the headers of the request, you will need to keep reading lines from the BufReader.

I tried this and had good success with the headers, but unfortunately I was still stuck reading the actual POST body. I found this other question, that ended up pointing to the fact that the final data sent in the POST request doesn't have new lines at the end, which causes the read to hang.

It's a bit messy (I'm still new to Rust), but the code below should somewhat illustrate.

let mut buf_reader = BufReader::new(&mut stream);

let mut request_line = "".to_string();
buf_reader.read_line(&mut request_line);

let mut header_line = "".to_string();
loop {
    buf_reader.read_line(&mut header_line);

    // The final line is just /r/n
    if header_line.len() == 2 {
        break
    }
    header_line = "".to_string();
}

// This buffer would need to be whatever size Content-Length reports
let mut read_buf = [0u8; 27];
buf_reader.read_exact(&mut read_buf);

let body = String::from_utf8(read_buf.to_vec());
println!("BODY: {}", body.unwrap());

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.