Initial commit
This commit is contained in:
commit
012ef02a8e
9 changed files with 1068 additions and 0 deletions
123
src/server.rs
Normal file
123
src/server.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue