aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoromagdy7 <omar.professional8777@gmail.com>2024-06-03 20:11:42 +0300
committeromagdy7 <omar.professional8777@gmail.com>2024-06-03 20:11:42 +0300
commitb542d2e744e8fbd5b0c0eb1d55ce491c37f9419d (patch)
tree32694b07cdff2aaf5ec8d44eaf652e0f18fae969 /src
parent989413ebc3692fe7ccfa02c2460404c618b5635c (diff)
downloadtiny-server-b542d2e744e8fbd5b0c0eb1d55ce491c37f9419d.tar.xz
tiny-server-b542d2e744e8fbd5b0c0eb1d55ce491c37f9419d.zip
codecrafters submit [skip ci]
Diffstat (limited to 'src')
-rw-r--r--src/main.rs107
1 files changed, 78 insertions, 29 deletions
diff --git a/src/main.rs b/src/main.rs
index bbae91e..0ea01c5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,10 @@
use std::collections::HashMap;
+use std::fmt::format;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::str;
-use itertools::Itertools;
+use itertools::{join, Itertools};
enum StatusCode {
// 2xx Success
@@ -20,11 +21,14 @@ enum StatusCode {
NotFound,
}
+type Endpoint = String;
+type Target = String;
+
#[derive(Debug)]
enum HTTPMethod {
- Get(String),
- Post(String),
- Put(String),
+ Get((Endpoint, Target)),
+ Post((Endpoint, Target)),
+ Put((Endpoint, Target)),
}
impl From<StatusCode> for String {
@@ -42,9 +46,9 @@ impl From<HTTPMethod> for String {
fn from(val: HTTPMethod) -> Self {
use HTTPMethod::*;
match val {
- Get(target) => "GET".to_string() + &target,
- Post(target) => "POST".to_string() + &target,
- Put(target) => "PUT".to_string() + &target,
+ Get((endpoint, target)) => "GET".to_string() + &endpoint + &target,
+ Post((endpoint, target)) => "POST".to_string() + &endpoint + &target,
+ Put((endpoint, target)) => "PUT".to_string() + &endpoint + &target,
}
}
}
@@ -67,10 +71,12 @@ impl From<&str> for HTTPMethod {
fn from(val: &str) -> Self {
use HTTPMethod::*;
let request_line = val.split(' ').collect_vec();
- let (method, target) = (request_line[0], request_line[1]);
+ 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(target.to_string()),
- "POST" => Post(target.to_string()),
+ "GET" => Get((endpoint.to_string(), target.to_string())),
+ "POST" => Post((endpoint.to_string(), target.to_string())),
_ => {
eprintln!("{method} Not Supported Yet");
unreachable!()
@@ -124,13 +130,20 @@ impl From<&str> for Request {
struct Response {
version: String,
status: StatusCode,
+ headers: Option<Headers>,
body: Option<String>,
}
impl Response {
- fn new(version: String, status: StatusCode, body: Option<String>) -> Self {
+ fn new(
+ version: String,
+ status: StatusCode,
+ headers: Option<Headers>,
+ body: Option<String>,
+ ) -> Self {
Response {
version,
+ headers,
status,
body,
}
@@ -139,12 +152,16 @@ impl Response {
impl Into<String> for Response {
fn into(self) -> String {
- format!(
- "HTTP/{} {}\r\n{}\r\n",
- self.version,
- String::from(self.status),
- self.body.unwrap_or("".to_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}")
}
}
@@ -160,24 +177,56 @@ fn handle_client(mut stream: TcpStream) {
println!("Received request: {}", request);
let request = Request::from(request);
println!("Request after parsing: {:?}", request);
- let succses: String = Response::new("1.1".to_string(), StatusCode::Ok, None).into();
+ let succses: String =
+ Response::new("1.1".to_string(), StatusCode::Ok, None, None).into();
let succses = succses.as_bytes();
let not_found: String =
- Response::new("1.1".to_string(), StatusCode::NotFound, None).into();
+ Response::new("1.1".to_string(), StatusCode::NotFound, None, None).into();
let not_found = not_found.as_bytes();
match request.method {
- HTTPMethod::Get(target) => match target.as_str() {
- "/" => match stream.write(succses) {
- Ok(_) => println!("Response sent successfully"),
- Err(e) => eprintln!("Failed to send response: {}", e),
- },
- _ => match stream.write(not_found) {
- Ok(_) => println!("Response sent successfully"),
- Err(e) => eprintln!("Failed to send response: {}", e),
- },
- },
+ HTTPMethod::Get((endpoint, target)) => {
+ match (endpoint.as_str(), target.as_str()) {
+ ("", "") => match stream.write(succses) {
+ Ok(_) => {
+ println!("Response sent successfully");
+ }
+ Err(e) => eprintln!("Failed to send response: {}", e),
+ },
+ ("echo", target) => {
+ let mut headers = HashMap::new();
+ headers
+ .insert("Content-Type".to_string(), "text/plain".to_string());
+ headers.insert(
+ "Content-Length".to_string(),
+ (target.len() - 1).to_string(),
+ );
+ let body = target[0..target.len() - 1].to_string();
+ let response: String = Response::new(
+ "1.1".to_string(),
+ StatusCode::Ok,
+ Some(Headers(headers)),
+ Some(body),
+ )
+ .into();
+ dbg!(&response);
+ let response = response.as_bytes();
+
+ match stream.write(response) {
+ Ok(_) => {
+ println!("Response sent successfully");
+ println!("Hello echo");
+ }
+ Err(e) => eprintln!("Failed to send response: {}", e),
+ }
+ }
+ _ => match stream.write(not_found) {
+ Ok(_) => println!("Response sent successfully"),
+ Err(e) => eprintln!("Failed to send response: {}", e),
+ },
+ }
+ }
HTTPMethod::Post(target) => todo!(),
HTTPMethod::Put(target) => todo!(),
}