feat: #1 add HTTPStartLine struct to parse request start line + some fixes
This commit is contained in:
		
							parent
							
								
									2e097bbedb
								
							
						
					
					
						commit
						3afe437143
					
				| @ -4,72 +4,118 @@ | |||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum HTTPVersion { | pub enum HTTPVersion { | ||||||
|     HTTP1, |     Http1, | ||||||
|     HTTP2, |     //http2,
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Into<String> for HTTPVersion { | impl Into<String> for HTTPVersion { | ||||||
|     fn into(self) -> String { |     fn into(self) -> String { | ||||||
|         match self { |         match self { | ||||||
|             HTTP1 => "HTTP/1.1".to_string(), |             Self::Http1 => "HTTP/1.1".to_string(), | ||||||
|             HTTP2 => "HTTP/2.2".to_string(), |             //Self::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)] | #[derive(Debug)] | ||||||
| pub struct HTTPRequest { | pub struct HTTPStartLine { | ||||||
|     pub method: String, |     pub method: String, | ||||||
|     pub target: String, |     pub target: String, | ||||||
|     pub version: HTTPVersion, |     pub version: HTTPVersion, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl HTTPRequest { | impl HTTPStartLine { | ||||||
|     // associated function to build a new HTTPRequest
 |  | ||||||
|     fn new(method: String, target: String, version: HTTPVersion) -> Self { |     fn new(method: String, target: String, version: HTTPVersion) -> Self { | ||||||
|         HTTPRequest { |         HTTPStartLine { | ||||||
|             method, |             method, | ||||||
|             target, |             target, | ||||||
|             version, |             version, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn parse(request: &str) -> Result<Self, &str> { |     fn parse(start_line: &str) -> Result<Self, &str> { | ||||||
|         // declare a new `request` var to borrow to &str `request`
 |         // declare a new `start_line` var to borrow to &str `start_line`
 | ||||||
|         let request = request.to_string(); |         let start_line = start_line.to_string(); | ||||||
| 
 | 
 | ||||||
|         let request_parts: Vec<&str> = request.split(" ").collect(); |         let parts: Vec<&str> = start_line.split(" ").collect(); | ||||||
|         if request_parts.len() < 3 { |         if parts.len() < 3 { | ||||||
|             return Err("unable to parse the request correctly"); |             return Err("unable to parse the start correctly"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Ok(HTTPRequest::new( |         // TODO: parse correctly the different parts (using regex ?)
 | ||||||
|             request_parts[0].to_string(), |         Ok(HTTPStartLine::new( | ||||||
|             request_parts[1].to_string(), |             parts[0].to_string(), | ||||||
|             HTTPVersion::HTTP1, |             parts[1].to_string(), | ||||||
|  |             HTTPVersion::Http1, | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_valid(self) -> bool { |     fn is_valid(self) -> bool { | ||||||
|         return self.method != "" && self.target != ""; |         return self.method != "" && self.target != ""; | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     // TODO: to be tested
 | impl Default for HTTPStartLine { | ||||||
|     pub fn start_line(self) -> String { |     fn default() -> Self { | ||||||
|  |         HTTPStartLine { | ||||||
|  |             method: "".to_string(), | ||||||
|  |             target: "".to_string(), | ||||||
|  |             version: HTTPVersion::Http1, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Into<String> for HTTPStartLine { | ||||||
|  |     fn into(self) -> String { | ||||||
|         let version: String = self.version.into(); |         let version: String = self.version.into(); | ||||||
|         return format!("{} {} {}", self.method, self.target, version); |         return format!("{} {} {}", self.method, self.target, version); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Request defined the HTTP request
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct HTTPRequest { | ||||||
|  |     pub start_line: HTTPStartLine, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl HTTPRequest { | ||||||
|  |     // associated function to build a new HTTPRequest
 | ||||||
|  |     fn new(start_line: HTTPStartLine) -> Self { | ||||||
|  |         HTTPRequest { start_line } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// parse parses the request by spliting the incoming request with the separator `\r\n`
 | ||||||
|  |     fn parse(request: &str) -> Result<HTTPRequest, &str> { | ||||||
|  |         // declare a new `request` var to borrow to &str `request`
 | ||||||
|  |         let request = request.to_string(); | ||||||
|  | 
 | ||||||
|  |         let request_parts: Vec<&str> = request.split("\r\n").collect(); | ||||||
|  |         println!("request part : {:?}", request_parts); | ||||||
|  |         // TODO: increase the check to 3 to match the request (for now only the start_line)
 | ||||||
|  |         if request_parts.len() < 1 { | ||||||
|  |             return Err("unable to parse the request correctly"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut request = HTTPRequest::default(); | ||||||
|  | 
 | ||||||
|  |         let start_line = HTTPStartLine::parse(request_parts[0]); | ||||||
|  |         match start_line { | ||||||
|  |             Ok(v) => request.start_line = v, | ||||||
|  |             Err(e) => eprintln!("error occured while parsing start_line err={}", e), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return Ok(request); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn is_valid(self) -> bool { | ||||||
|  |         return self.start_line.is_valid(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl Default for HTTPRequest { | impl Default for HTTPRequest { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         HTTPRequest { |         HTTPRequest { | ||||||
|             method: "".to_string(), |             start_line: HTTPStartLine::default(), | ||||||
|             target: "".to_string(), |  | ||||||
|             version: HTTPVersion::HTTP1, |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -92,8 +138,12 @@ pub fn handle_request(request: &str) -> HTTPRequest { | |||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_handle_request() { | fn test_handle_request() { | ||||||
|     let test_cases: [(&str, bool); 5] = [ |     let test_cases: [(&str, bool); 6] = [ | ||||||
|         ("GET / HTTP/1.1", true), |         ("GET / HTTP/1.1", true), | ||||||
|  |         ( | ||||||
|  |             "OPTIONS /admin/2 HTTP/\r\nContent-Type: application/json", | ||||||
|  |             true, | ||||||
|  |         ), // intentionally add HTTP with no version number
 | ||||||
|         ("POST HTTP/1.1", false), |         ("POST HTTP/1.1", false), | ||||||
|         ("", false), |         ("", false), | ||||||
|         ("fjlqskjd /oks?id=65 HTTP/2", true), |         ("fjlqskjd /oks?id=65 HTTP/2", true), | ||||||
|  | |||||||
| @ -1,13 +1,9 @@ | |||||||
| mod handlers; | mod handlers; | ||||||
| 
 | 
 | ||||||
| use std::fs; |  | ||||||
| use std::io::prelude::*; | use std::io::prelude::*; | ||||||
| use std::net::TcpListener; | use std::net::TcpListener; | ||||||
| use std::net::TcpStream; | use std::net::TcpStream; | ||||||
| 
 | 
 | ||||||
| use async_std::task; |  | ||||||
| use std::time::Duration; |  | ||||||
| 
 |  | ||||||
| use handlers::handle_request; | use handlers::handle_request; | ||||||
| 
 | 
 | ||||||
| // TODO: must be set in a conf file
 | // TODO: must be set in a conf file
 | ||||||
| @ -28,14 +24,12 @@ 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"; |  | ||||||
| 
 |  | ||||||
|     // transform buffer bytes array into `String`
 |     // transform buffer bytes array into `String`
 | ||||||
|     let buffer_string = String::from_utf8_lossy(&buffer); |     let buffer_string = String::from_utf8_lossy(&buffer); | ||||||
|     let request = handle_request(&buffer_string); |     let request = handle_request(&buffer_string); | ||||||
| 
 | 
 | ||||||
|     // TODO: `Response` struct must be implemented
 |     // TODO: `Response` struct must be implemented
 | ||||||
|     let status_line = if request.target == "/".to_string() { |     let status_line = if request.start_line.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