| use std::{io::Result, collections::HashMap}; |
| use tokio::{net::{TcpListener, TcpStream}, io::{AsyncReadExt, AsyncWriteExt}}; |
| |
| |
| use itertools::Itertools; |
| use nom::AsChar; |
| |
| async fn process_socket(mut stream: TcpStream) { |
| println!("accepted new connection"); |
| |
| let mut request: HashMap<String, String> = HashMap::new(); |
| let mut line_num: usize = 0; |
| loop { |
| let mut line = String::default(); |
| |
| loop { |
| let mut buf: [u8; 1] = [0; 1]; |
| stream.read_exact(&mut buf).await.unwrap(); |
| |
| let character = buf[0].as_char(); |
| if character == '\n' { |
| break |
| } else if character != '\r' { |
| line.push(character); |
| } |
| } |
| |
| if line_num == 0 { |
| let mut splits = line.split(' '); |
| request.insert("method".to_owned(), splits.next().unwrap().to_owned()); |
| request.insert("path".to_owned(), splits.next().unwrap().to_owned()); |
| } else { |
| let mut splits = line.split(":"); |
| let key = splits.next().unwrap(); |
| let value = splits.next().unwrap_or_default().trim(); |
| request.insert(key.to_owned(), value.to_owned()); |
| } |
| |
| if request.get("path").unwrap() != "/user-agent" || request.contains_key("User-Agent") { break }; |
| line_num += 1; |
| } |
| |
| // println!("{:?}", request); |
| |
| let mut path = request.get("path").unwrap().split("/"); |
| |
| let response_status: String; |
| let mut response_headers: Vec<String> = vec![]; |
| let response_body: String; |
| |
| // println!("{:?}", path); |
| |
| path.next().unwrap(); |
| |
| match path.next().unwrap() { |
| "" => { |
| response_status = "200 OK".into(); |
| response_body = "".into(); |
| }, |
| "echo" => { |
| response_status = "200 OK".into(); |
| response_body = path.join("/"); |
| response_headers.push("Content-Type: text/plain".into()); |
| }, |
| "user-agent" => { |
| response_status = "200 OK".into(); |
| response_body = request.get("User-Agent").unwrap().into(); |
| response_headers.push("Content-Type: text/plain".into()); |
| }, |
| _ => { |
| response_status = "404 Not Found".into(); |
| response_body = "".into(); |
| } |
| } |
| |
| if response_body.len() > 0 { |
| response_headers.push(format!("Content-Length: {}", response_body.len())); |
| } |
| |
| stream.write(format!("HTTP/1.1 {response_status}\r\n{}\r\n\r\n{response_body}", response_headers.join("\r\n")).as_bytes()).await.unwrap(); |
| |
| } |
| |
| #[tokio::main] |
| async fn main() -> Result<()> { |
| let listener = TcpListener::bind("127.0.0.1:4221").await?; |
| let mut futures = vec![]; |
| |
| loop { |
| let (socket, _) = listener.accept().await?; |
| futures.push(tokio::spawn(process_socket(socket))); |
| } |
| } |