add a request handler
This commit is contained in:
		
							parent
							
								
									f7a7cddde5
								
							
						
					
					
						commit
						81d9b0f38d
					
				
							
								
								
									
										3
									
								
								src/handlers/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/handlers/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub mod request; | ||||
| 
 | ||||
| pub use request::handle_request; | ||||
							
								
								
									
										108
									
								
								src/handlers/request.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/handlers/request.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| //! request handles properly the incoming request
 | ||||
| //! it will parse the request according to the HTTP message specifications
 | ||||
| //! see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum HTTPVersion { | ||||
|     HTTP1, | ||||
|     HTTP2, | ||||
| } | ||||
| 
 | ||||
| impl Into<String> for HTTPVersion { | ||||
|     fn into(self) -> String { | ||||
|         match self { | ||||
|             HTTP1 => "HTTP/1.1".to_string(), | ||||
|             HTTP2 => "HTTP/2.2".to_string(), | ||||
|             _ => "UNKNOWN".to_string(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Request defined the HTTP request
 | ||||
| // TODO: method, target, version must be set in new struct : `HTTPStartLine`
 | ||||
| #[derive(Debug)] | ||||
| pub struct HTTPRequest { | ||||
|     pub method: String, | ||||
|     pub target: String, | ||||
|     pub version: HTTPVersion, | ||||
| } | ||||
| 
 | ||||
| impl HTTPRequest { | ||||
|     // associated function to build a new HTTPRequest
 | ||||
|     fn new(method: String, target: String, version: HTTPVersion) -> Self { | ||||
|         HTTPRequest { | ||||
|             method, | ||||
|             target, | ||||
|             version, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn parse(request: &str) -> Result<Self, &str> { | ||||
|         // declare a new `request` var to borrow to &str `request`
 | ||||
|         let request = request.to_string(); | ||||
| 
 | ||||
|         let request_parts: Vec<&str> = request.split(" ").collect(); | ||||
|         if request_parts.len() < 3 { | ||||
|             return Err("unable to parse the request correctly"); | ||||
|         } | ||||
| 
 | ||||
|         Ok(HTTPRequest::new( | ||||
|             request_parts[0].to_string(), | ||||
|             request_parts[1].to_string(), | ||||
|             HTTPVersion::HTTP1, | ||||
|         )) | ||||
|     } | ||||
| 
 | ||||
|     fn is_valid(self) -> bool { | ||||
|         return self.method != "" && self.target != ""; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: to be tested
 | ||||
|     pub fn start_line(self) -> String { | ||||
|         let version: String = self.version.into(); | ||||
|         return format!("{} {} {}", self.method, self.target, version); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Default for HTTPRequest { | ||||
|     fn default() -> Self { | ||||
|         HTTPRequest { | ||||
|             method: "".to_string(), | ||||
|             target: "".to_string(), | ||||
|             version: HTTPVersion::HTTP1, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for HTTPRequest { | ||||
|     fn from(request: &str) -> Self { | ||||
|         match Self::parse(request) { | ||||
|             Ok(v) => v, | ||||
|             Err(v) => { | ||||
|                 eprintln!("{}", format!("[ERR]: {v}")); | ||||
|                 return HTTPRequest::default(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn handle_request(request: &str) -> HTTPRequest { | ||||
|     return HTTPRequest::from(request); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn test_handle_request() { | ||||
|     let test_cases: [(&str, bool); 5] = [ | ||||
|         ("GET / HTTP/1.1", true), | ||||
|         ("POST HTTP/1.1", false), | ||||
|         ("", false), | ||||
|         ("fjlqskjd /oks?id=65 HTTP/2", true), | ||||
|         ("   ", false), | ||||
|     ]; | ||||
| 
 | ||||
|     for (request, is_valid) in test_cases { | ||||
|         let http_request = HTTPRequest::from(request); | ||||
|         println!("{:?}", http_request); | ||||
|         assert_eq!(http_request.is_valid(), is_valid); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -1,3 +1,5 @@ | ||||
| mod handlers; | ||||
| 
 | ||||
| use std::fs; | ||||
| use std::io::prelude::*; | ||||
| use std::net::TcpListener; | ||||
| @ -6,6 +8,8 @@ use std::net::TcpStream; | ||||
| use async_std::task; | ||||
| use std::time::Duration; | ||||
| 
 | ||||
| use handlers::handle_request; | ||||
| 
 | ||||
| // TODO: must be set in a conf file
 | ||||
| const SERVER_URL: &str = "127.0.0.1:9000"; | ||||
| 
 | ||||
| @ -20,15 +24,18 @@ async fn main() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // TODO: must properly handle the request
 | ||||
| async fn handle_connection(mut stream: TcpStream) { | ||||
|     let mut buffer = [0; 1024]; | ||||
|     stream.read(&mut buffer).unwrap(); | ||||
| 
 | ||||
|     let get = b"GET / HTTP/1.1\r\n"; | ||||
| 
 | ||||
|     // TODO: request musy be parsed correctly
 | ||||
|     let status_line = if buffer.starts_with(get) { | ||||
|     // transform buffer bytes array into `String`
 | ||||
|     let buffer_string = String::from_utf8_lossy(&buffer); | ||||
|     let request = handle_request(&buffer_string); | ||||
| 
 | ||||
|     // TODO: `Response` struct must be implemented
 | ||||
|     let status_line = if request.target == "/".to_string() { | ||||
|         "HTTP/1.1 200 OK\r\n" | ||||
|     } else { | ||||
|         "HTTP/1.1 404 NOT FOUND\r\n" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user