blob: eb6b198411e2d9ea1199260dd627d9237b206c15 [file] [log] [blame]
Samuel Shuert2ecef062024-01-10 16:31:55 -05001use std::{io::Result, collections::HashMap};
2use tokio::{net::{TcpListener, TcpStream}, io::{AsyncReadExt, AsyncWriteExt}};
3
codecrafters-bot67061582024-01-10 17:35:39 +00004
Samuel Shuert62c526f2024-01-10 15:30:45 -05005use itertools::Itertools;
Samuel Shuertf2efffb2024-01-10 16:14:01 -05006use nom::AsChar;
Samuel Shuert62c526f2024-01-10 15:30:45 -05007
Samuel Shuert2ecef062024-01-10 16:31:55 -05008async fn process_socket(mut stream: TcpStream) {
9 println!("accepted new connection");
Samuel Shuert3d880f72024-01-10 14:48:08 -050010
Samuel Shuert2ecef062024-01-10 16:31:55 -050011 let mut request: HashMap<String, String> = HashMap::new();
12 let mut line_num: usize = 0;
13 loop {
14 let mut line = String::default();
Samuel Shuerte4ee8732024-01-10 14:42:09 -050015
Samuel Shuert2ecef062024-01-10 16:31:55 -050016 loop {
17 let mut buf: [u8; 1] = [0; 1];
18 stream.read_exact(&mut buf).await.unwrap();
Samuel Shuert3d880f72024-01-10 14:48:08 -050019
Samuel Shuert2ecef062024-01-10 16:31:55 -050020 let character = buf[0].as_char();
21 if character == '\n' {
22 break
23 } else if character != '\r' {
24 line.push(character);
Samuel Shuertf10dce92024-01-10 14:31:46 -050025 }
26 }
Samuel Shuert2ecef062024-01-10 16:31:55 -050027
28 if line_num == 0 {
29 let mut splits = line.split(' ');
30 request.insert("method".to_owned(), splits.next().unwrap().to_owned());
31 request.insert("path".to_owned(), splits.next().unwrap().to_owned());
32 } else {
33 let mut splits = line.split(": ");
34 let key = splits.next().unwrap();
35 let value = splits.next().unwrap();
36 request.insert(key.to_owned(), value.to_owned());
37 }
38
39 if request.contains_key("User-Agent") { break };
40 line_num += 1;
41 }
42
43 println!("{:?}", request);
44
45 let mut path = request.get("path").unwrap().split("/");
46
47 let response_status: String;
48 let mut response_headers: Vec<String> = vec![];
49 let response_body: String;
50
51 // println!("{:?}", path);
52
53 path.next().unwrap();
54
55 match path.next().unwrap() {
56 "" => {
57 response_status = "200 OK".into();
58 response_body = "".into();
59 },
60 "echo" => {
61 response_status = "200 OK".into();
62 response_body = path.join("/");
63 response_headers.push("Content-Type: text/plain".into());
64 },
65 "user-agent" => {
66 response_status = "200 OK".into();
67 response_body = request.get("User-Agent").unwrap().into();
68 response_headers.push("Content-Type: text/plain".into());
69 },
70 _ => {
71 response_status = "404 Not Found".into();
72 response_body = "".into();
73 }
74 }
75
76 if response_body.len() > 0 {
77 response_headers.push(format!("Content-Length: {}", response_body.len()));
78 }
79
80 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();
81
82}
83
84#[tokio::main]
85async fn main() -> Result<()> {
86 let listener = TcpListener::bind("127.0.0.1:4221").await?;
87 let mut futures = vec![];
88
89 loop {
90 let (socket, _) = listener.accept().await?;
91 futures.push(process_socket(socket));
Samuel Shuertf10dce92024-01-10 14:31:46 -050092 }
codecrafters-bot67061582024-01-10 17:35:39 +000093}