aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/http_types.rs77
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs187
-rw-r--r--src/request.rs43
-rw-r--r--src/response.rs40
5 files changed, 176 insertions, 174 deletions
diff --git a/src/http_types.rs b/src/http_types.rs
new file mode 100644
index 0000000..a652e6c
--- /dev/null
+++ b/src/http_types.rs
@@ -0,0 +1,77 @@
+use itertools::Itertools;
+use std::collections::HashMap;
+
+pub enum StatusCode {
+ // 2xx Success
+ Ok,
+
+ // 4xx Client Error
+ BadRequest,
+ NotFound,
+}
+
+type Endpoint = String;
+type Target = String;
+
+#[derive(Debug)]
+pub enum HTTPMethod {
+ Get((Endpoint, Target)),
+ Post((Endpoint, Target)),
+ Put((Endpoint, Target)),
+}
+
+impl From<StatusCode> for String {
+ fn from(val: StatusCode) -> Self {
+ use StatusCode::*;
+ match val {
+ Ok => "200 OK".to_string(),
+ BadRequest => "400 Bad Request".to_string(),
+ NotFound => "404 Not Found".to_string(),
+ }
+ }
+}
+
+impl From<HTTPMethod> for String {
+ fn from(val: HTTPMethod) -> Self {
+ use HTTPMethod::*;
+ match val {
+ Get((endpoint, target)) => "GET".to_string() + &endpoint + &target,
+ Post((endpoint, target)) => "POST".to_string() + &endpoint + &target,
+ Put((endpoint, target)) => "PUT".to_string() + &endpoint + &target,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Headers(pub HashMap<String, String>);
+
+impl From<&[&str]> for Headers {
+ fn from(value: &[&str]) -> Self {
+ let mut header_map = HashMap::new();
+ for header in value.iter().filter(|val| !val.is_empty()) {
+ let (key, val) = header
+ .split_once(": ")
+ .expect("Should be splitable by :<space>");
+ header_map.insert(key.to_string(), val.to_string());
+ }
+ Headers(header_map)
+ }
+}
+
+impl From<&str> for HTTPMethod {
+ fn from(val: &str) -> Self {
+ use HTTPMethod::*;
+ let request_line = val.split(' ').collect_vec();
+ let (method, info) = (request_line[0], request_line[1]);
+ let info = info.chars().skip(1).collect::<String>() + &"/";
+ let (endpoint, target) = info.split_once("/").expect("Should be splitable by /");
+ match method {
+ "GET" => Get((endpoint.to_string(), target.to_string())),
+ "POST" => Post((endpoint.to_string(), target.to_string())),
+ _ => {
+ eprintln!("{method} Not Supported Yet");
+ unreachable!()
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..4667e1d
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,3 @@
+pub mod http_types;
+pub mod request;
+pub mod response;
diff --git a/src/main.rs b/src/main.rs
index 2f61490..1ad6f26 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,171 +1,13 @@
+#![allow(unused)]
+use itertools::Itertools;
use std::collections::HashMap;
-use std::fmt::format;
-use std::io::{Read, Write};
+use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
-use std::str;
+use std::{str, thread};
-use itertools::{join, Itertools};
-
-enum StatusCode {
- // 2xx Success
- Ok,
- // Created = 201,
- // Accepted = 202,
- // NonAuthoritative = 203,
- // NoContent = 204,
- // ResetContent = 205,
- // PartialContent = 206,
-
- // 4xx Client Error
- BadRequest,
- NotFound,
-}
-
-type Endpoint = String;
-type Target = String;
-
-#[derive(Debug)]
-enum HTTPMethod {
- Get((Endpoint, Target)),
- Post((Endpoint, Target)),
- Put((Endpoint, Target)),
-}
-
-impl From<StatusCode> for String {
- fn from(val: StatusCode) -> Self {
- use StatusCode::*;
- match val {
- Ok => "200 OK".to_string(),
- BadRequest => "400 Bad Request".to_string(),
- NotFound => "404 Not Found".to_string(),
- }
- }
-}
-
-impl From<HTTPMethod> for String {
- fn from(val: HTTPMethod) -> Self {
- use HTTPMethod::*;
- match val {
- Get((endpoint, target)) => "GET".to_string() + &endpoint + &target,
- Post((endpoint, target)) => "POST".to_string() + &endpoint + &target,
- Put((endpoint, target)) => "PUT".to_string() + &endpoint + &target,
- }
- }
-}
-
-#[derive(Debug)]
-struct Headers(HashMap<String, String>);
-
-impl From<&[&str]> for Headers {
- fn from(value: &[&str]) -> Self {
- let mut header_map = HashMap::new();
- for header in value.iter().filter(|val| !val.is_empty()) {
- let (key, val) = header
- .split_once(": ")
- .expect("Should be splitable by :<space>");
- header_map.insert(key.to_string(), val.to_string());
- }
- Headers(header_map)
- }
-}
-
-impl From<&str> for HTTPMethod {
- fn from(val: &str) -> Self {
- use HTTPMethod::*;
- let request_line = val.split(' ').collect_vec();
- let (method, info) = (request_line[0], request_line[1]);
- let info = info.chars().skip(1).collect::<String>() + &"/";
- let (endpoint, target) = info.split_once("/").expect("Should be splitable by /");
- match method {
- "GET" => Get((endpoint.to_string(), target.to_string())),
- "POST" => Post((endpoint.to_string(), target.to_string())),
- _ => {
- eprintln!("{method} Not Supported Yet");
- unreachable!()
- }
- }
- }
-}
-
-#[derive(Debug)]
-struct Request {
- method: HTTPMethod,
- headers: Option<Headers>,
- body: Option<String>,
-}
-
-impl Request {
- fn new(method: HTTPMethod, headers: Headers, body: String) -> Self {
- let headers = if headers.0.len() == 0 {
- None
- } else {
- Some(headers)
- };
- let body = if body.is_empty() { None } else { Some(body) };
- Request {
- method,
- headers,
- body,
- }
- }
-}
-
-impl From<&str> for Request {
- fn from(val: &str) -> Self {
- let request: Vec<&str> = val.split("\r\n").collect();
- match &request[..] {
- [request_line, headers @ .., body] => {
- let (method, headers, body) = (
- HTTPMethod::from(*request_line),
- Headers::from(headers),
- body.to_string(),
- );
- Request::new(method, headers, body)
- }
- _ => {
- unreachable!();
- }
- }
- }
-}
-
-struct Response {
- version: String,
- status: StatusCode,
- headers: Option<Headers>,
- body: Option<String>,
-}
-
-impl Response {
- fn new(
- version: String,
- status: StatusCode,
- headers: Option<Headers>,
- body: Option<String>,
- ) -> Self {
- Response {
- version,
- headers,
- status,
- body,
- }
- }
-}
-
-impl Into<String> for Response {
- fn into(self) -> String {
- let status_line = format!("HTTP/{} {}", self.version, String::from(self.status));
- let headers = self
- .headers
- .unwrap_or(Headers(HashMap::new()))
- .0
- .iter()
- .map(|(key, value)| format!("{key}: {value}\r\n"))
- .collect::<String>();
- let body = self.body.unwrap_or("".to_string());
- format!("{status_line}\r\n{headers}\r\n{body}")
- }
-}
+use http_server_starter_rust::http_types::*;
+use http_server_starter_rust::request::*;
+use http_server_starter_rust::response::*;
fn handle_client(mut stream: TcpStream) {
// Buffer to store the data received from the client
@@ -258,14 +100,10 @@ fn handle_client(mut stream: TcpStream) {
},
}
}
- HTTPMethod::Post(target) => todo!(),
- HTTPMethod::Put(target) => todo!(),
+ HTTPMethod::Post(_target) => todo!(),
+ HTTPMethod::Put(_target) => todo!(),
}
}
-
- // Prepare a response
- // let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello, world!";
- //
}
Err(e) => {
eprintln!("Failed to read from stream: {}", e);
@@ -273,18 +111,19 @@ fn handle_client(mut stream: TcpStream) {
}
}
-fn main() {
+fn main() -> io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:4221").unwrap();
for stream in listener.incoming() {
match stream {
Ok(stream) => {
- // println!("accepted new connection");
- handle_client(stream)
+ thread::spawn(move || handle_client(stream));
}
Err(e) => {
eprintln!("error: {}", e);
}
}
}
+
+ Ok(())
}
diff --git a/src/request.rs b/src/request.rs
new file mode 100644
index 0000000..8728e79
--- /dev/null
+++ b/src/request.rs
@@ -0,0 +1,43 @@
+use crate::http_types::*;
+
+#[derive(Debug)]
+pub struct Request {
+ pub method: HTTPMethod,
+ pub headers: Option<Headers>,
+ body: Option<String>,
+}
+
+impl Request {
+ fn new(method: HTTPMethod, headers: Headers, body: String) -> Self {
+ let headers = if headers.0.len() == 0 {
+ None
+ } else {
+ Some(headers)
+ };
+ let body = if body.is_empty() { None } else { Some(body) };
+ Request {
+ method,
+ headers,
+ body,
+ }
+ }
+}
+
+impl From<&str> for Request {
+ fn from(val: &str) -> Self {
+ let request: Vec<&str> = val.split("\r\n").collect();
+ match &request[..] {
+ [request_line, headers @ .., body] => {
+ let (method, headers, body) = (
+ HTTPMethod::from(*request_line),
+ Headers::from(headers),
+ body.to_string(),
+ );
+ Request::new(method, headers, body)
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ }
+}
diff --git a/src/response.rs b/src/response.rs
new file mode 100644
index 0000000..4219afd
--- /dev/null
+++ b/src/response.rs
@@ -0,0 +1,40 @@
+use crate::http_types::*;
+use std::collections::HashMap;
+
+pub struct Response {
+ version: String,
+ status: StatusCode,
+ headers: Option<Headers>,
+ body: Option<String>,
+}
+
+impl Response {
+ pub fn new(
+ version: String,
+ status: StatusCode,
+ headers: Option<Headers>,
+ body: Option<String>,
+ ) -> Self {
+ Response {
+ version,
+ headers,
+ status,
+ body,
+ }
+ }
+}
+
+impl Into<String> for Response {
+ fn into(self) -> String {
+ let status_line = format!("HTTP/{} {}", self.version, String::from(self.status));
+ let headers = self
+ .headers
+ .unwrap_or(Headers(HashMap::new()))
+ .0
+ .iter()
+ .map(|(key, value)| format!("{key}: {value}\r\n"))
+ .collect::<String>();
+ let body = self.body.unwrap_or("".to_string());
+ format!("{status_line}\r\n{headers}\r\n{body}")
+ }
+}