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::fs; | ||||||
| use std::io::prelude::*; | use std::io::prelude::*; | ||||||
| use std::net::TcpListener; | use std::net::TcpListener; | ||||||
| @ -6,6 +8,8 @@ use std::net::TcpStream; | |||||||
| use async_std::task; | use async_std::task; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
|  | use handlers::handle_request; | ||||||
|  | 
 | ||||||
| // TODO: must be set in a conf file
 | // TODO: must be set in a conf file
 | ||||||
| const SERVER_URL: &str = "127.0.0.1:9000"; | 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) { | async fn handle_connection(mut stream: TcpStream) { | ||||||
|     let mut buffer = [0; 1024]; |     let mut buffer = [0; 1024]; | ||||||
|     stream.read(&mut buffer).unwrap(); |     stream.read(&mut buffer).unwrap(); | ||||||
| 
 | 
 | ||||||
|     let get = b"GET / HTTP/1.1\r\n"; |     let get = b"GET / HTTP/1.1\r\n"; | ||||||
| 
 | 
 | ||||||
|     // TODO: request musy be parsed correctly
 |     // transform buffer bytes array into `String`
 | ||||||
|     let status_line = if buffer.starts_with(get) { |     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" |         "HTTP/1.1 200 OK\r\n" | ||||||
|     } else { |     } else { | ||||||
|         "HTTP/1.1 404 NOT FOUND\r\n" |         "HTTP/1.1 404 NOT FOUND\r\n" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user