I just wanted to ask if this is a reliable/good way to get the body of an http request.
Is there a better way of doing it? Maybe an example or a existing crate?
Thanks!
use std::{io::Read, net::TcpStream};
pub fn parse_request(stream: &mut TcpStream) -> (String, String) {
let mut buffer = [0; 2048];
stream.read(&mut buffer).unwrap();
let request_str = std::str::from_utf8(&buffer).unwrap();
let lines: Vec<String> = request_str.lines().map(|line| line.to_string()).collect();
let request_line = lines.first().unwrap().to_string();
// get body
let mut collect = false;
let mut body = String::from("");
for line in &lines {
if collect {
body.push_str(line);
}
if line.is_empty() {
collect = true;
}
}
body = body.trim_matches(char::from(0)).to_string();
(request_line, body)
}
The best way to handle parsing an HTTP request will depend on what your goal is.
Are you just interested in building an HTTP server and don't care about the details? You probably want an HTTP server framework, of which there are quite a few. axum is my personal favorite at the moment, warp and rocket are generally well regarded. https://www.arewewebyet.org/ has a list of many more, plus utility crates.
If you're interested in learning how to write an HTTP server without a framework, but don't want to deal with parsing HTTP yourself hyper may be a good option, since it handles most of the low level stuff but doesn't do things like routing.
If you want to control everything except the parsing, I believe hyper uses httparse for parsing HTTP 1.X requests. Handling HTTP 2 is a bit more complicated, I'm not sure it's really feasible to offer a pure parsing crate for it, but the h2 crate provides HTTP 2 support.
As for the code you've written, I'm not an HTTP expert but a couple things jumped out at me:
You aren't using the return value from stream.read to check how much data was actually read, so unless the request is exactly 2048 bytes long you're going to have problems. You also aren't handling the case where the request is larger than that
body probably shouldn't be a string. HTTP bodies can contain arbitrary bytes which strings can't always represent in Rust.