123 lines
3.5 KiB
Rust
123 lines
3.5 KiB
Rust
use crate::http;
|
|
use crate::schemas;
|
|
|
|
use clap::Parser;
|
|
use http::{HttpError, HttpMethod, HttpRequest, parse_method};
|
|
use schemas::{Args, State};
|
|
use std::error::Error;
|
|
use std::sync::Mutex;
|
|
use std::thread;
|
|
use std::{
|
|
collections::HashMap,
|
|
io::{BufReader, prelude::*},
|
|
net::{TcpListener, TcpStream},
|
|
sync::Arc,
|
|
};
|
|
use std::{path::PathBuf, str::FromStr};
|
|
|
|
type AppState = Arc<Mutex<State>>;
|
|
|
|
fn parse_http_request(mut buf: BufReader<&TcpStream>) -> Result<HttpRequest, HttpError> {
|
|
let mut request_method: Option<HttpMethod> = None;
|
|
let mut uri: Option<PathBuf> = None;
|
|
let mut headers: Vec<String> = Vec::new();
|
|
let mut header_map: HashMap<String, String> = HashMap::new();
|
|
let mut method_line: String = String::new();
|
|
|
|
for (i, line_result) in buf.by_ref().lines().enumerate() {
|
|
let line = line_result.unwrap();
|
|
if i == 0 {
|
|
method_line.push_str(&line);
|
|
let http_args = method_line.split(" ").collect::<Vec<&str>>();
|
|
if http_args.len() == 3 {
|
|
match parse_method(http_args[0]) {
|
|
Ok(m) => request_method = Some(m),
|
|
Err(e) => return Err(e),
|
|
}
|
|
match PathBuf::from_str(http_args[1]) {
|
|
Ok(b) => uri = Some(b),
|
|
Err(_) => return Err(HttpError::InternalServerError),
|
|
}
|
|
} else {
|
|
return Err(HttpError::InternalServerError);
|
|
}
|
|
}
|
|
if line.is_empty() {
|
|
break;
|
|
}
|
|
headers.push(line.clone());
|
|
if let Some((key, value)) = line.split_once(": ") {
|
|
header_map.insert(key.to_string().to_lowercase(), value.to_string());
|
|
}
|
|
}
|
|
|
|
let conten_length = header_map
|
|
.get("content-length")
|
|
.and_then(|v| v.parse::<usize>().ok())
|
|
.unwrap_or(0);
|
|
|
|
println!("Content length: {conten_length:?}");
|
|
|
|
let mut body: Vec<u8> = vec![0 as u8; conten_length];
|
|
let res = match buf.read_exact(&mut body) {
|
|
Ok(_) => body,
|
|
Err(_) => return Err(HttpError::InternalServerError),
|
|
};
|
|
|
|
if uri.is_none() || request_method.is_none() {
|
|
return Err(HttpError::InternalServerError);
|
|
}
|
|
|
|
Ok(HttpRequest {
|
|
method: request_method.unwrap(),
|
|
uri: uri.unwrap(),
|
|
headers: header_map,
|
|
body: res,
|
|
})
|
|
}
|
|
|
|
fn dispatch_connection(mut stream: TcpStream, state: &AppState) -> Result<(), HttpError> {
|
|
loop {
|
|
let buf_reader = BufReader::new(&stream);
|
|
match parse_http_request(buf_reader) {
|
|
Ok(request) => {
|
|
println!("Request: {:?}", &request);
|
|
|
|
if request.uri == PathBuf::from("/healthcheck") {
|
|
} else {
|
|
}
|
|
|
|
let response = "HTTP/1.1 200 OK\r\nContent-length: 0\r\n\r\n";
|
|
|
|
stream.write_all(response.as_bytes()).unwrap();
|
|
}
|
|
Err(_) => {
|
|
println!("Closing connection due to error or client disconnect.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub struct HttpServer {
|
|
listener: TcpListener,
|
|
}
|
|
|
|
impl HttpServer {
|
|
pub fn new(port: &u32) -> Self {
|
|
Self {
|
|
listener: TcpListener::bind(format!("[::]:{}", port)).unwrap(),
|
|
}
|
|
}
|
|
|
|
pub fn listen(&self, state: &AppState) {
|
|
println!("Listening on port 7878");
|
|
|
|
for stream in self.listener.incoming() {
|
|
let stream = stream.unwrap();
|
|
|
|
let _ = dispatch_connection(stream, &state);
|
|
}
|
|
}
|
|
}
|