feat: #1 rework on http request parser and include HTTPBody in HTTPRequest
This commit is contained in:
parent
e0d72b08cf
commit
ce7e49af47
@ -5,6 +5,8 @@
|
||||
|
||||
use json;
|
||||
|
||||
type RequestParts = (String, String, String);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HTTPVersion {
|
||||
Http1,
|
||||
@ -76,7 +78,8 @@ impl Into<String> for HTTPStartLine {
|
||||
}
|
||||
|
||||
/// HTTPBody represents http request body
|
||||
/// for simplicity, only json body are accepted
|
||||
/// for simplicity, only json body is accepted
|
||||
#[derive(Debug)]
|
||||
pub struct HTTPBody {
|
||||
data: json::JsonValue,
|
||||
}
|
||||
@ -87,10 +90,10 @@ impl HTTPBody {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for HTTPBody {
|
||||
impl TryFrom<String> for HTTPBody {
|
||||
type Error = String;
|
||||
fn try_from(body: &str) -> Result<HTTPBody, Self::Error> {
|
||||
match json::parse(body) {
|
||||
fn try_from(body: String) -> Result<HTTPBody, Self::Error> {
|
||||
match json::parse(&body) {
|
||||
Ok(v) => Ok(HTTPBody::new(v)),
|
||||
Err(e) => Err(format!(
|
||||
"error occurred during request body parsing err={}",
|
||||
@ -104,35 +107,86 @@ impl TryFrom<&str> for HTTPBody {
|
||||
#[derive(Debug)]
|
||||
pub struct HTTPRequest {
|
||||
pub start_line: HTTPStartLine,
|
||||
pub body: Option<HTTPBody>,
|
||||
}
|
||||
|
||||
impl HTTPRequest {
|
||||
// associated function to build a new HTTPRequest
|
||||
fn new(start_line: HTTPStartLine) -> Self {
|
||||
HTTPRequest { start_line }
|
||||
fn new(start_line: HTTPStartLine, body: Option<HTTPBody>) -> Self {
|
||||
HTTPRequest { start_line, body }
|
||||
}
|
||||
|
||||
/// get mandatory request informations :
|
||||
/// * start_line
|
||||
/// * headers
|
||||
fn get_request_mandats(request_parts: Vec<&str>) -> Result<(String, String), String> {
|
||||
let headers_sline: Vec<&str> = request_parts[0].split("\r\n").collect();
|
||||
match headers_sline.len() {
|
||||
0 => return Err("request does not contain start_line or headers".to_string()),
|
||||
1 => return Ok((headers_sline[0].to_string(), "".to_string())),
|
||||
// TODO: check if in the spec it must be 2 or 3 !
|
||||
2 | 3 => return Ok((headers_sline[0].to_string(), headers_sline[1].to_string())),
|
||||
_ => return Err("bad start_line headers parsing".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// split correctly the incoming request in order to get :
|
||||
/// * start_line
|
||||
/// * headers
|
||||
/// * data (if exists)
|
||||
fn get_request_parts(request: &str) -> Result<RequestParts, String> {
|
||||
// separate the body part from the start_line and the headers
|
||||
let request_parts: Vec<&str> = request.split("\r\n\r\n").collect();
|
||||
if request_parts.len() == 0 {
|
||||
return Err("request has no enough informations to be correctly parsed".to_string());
|
||||
}
|
||||
|
||||
match request_parts.len() {
|
||||
0 => {
|
||||
return Err("request has no enough informations to be correctly parsed".to_string())
|
||||
}
|
||||
1 => match HTTPRequest::get_request_mandats(request_parts) {
|
||||
Ok(v) => return Ok((v.0, v.1, "".to_string())),
|
||||
Err(e) => return Err(e),
|
||||
},
|
||||
2 => {
|
||||
let body = request_parts[1];
|
||||
match HTTPRequest::get_request_mandats(request_parts) {
|
||||
Ok(v) => return Ok((v.0, v.1, body.to_string())),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
_ => return Err("bad incoming request, impossible to parse".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// parse parses the request by spliting the incoming request with the separator `\r\n`
|
||||
fn parse(request: &str) -> Result<HTTPRequest, &str> {
|
||||
fn parse(request: &str) -> Result<HTTPRequest, String> {
|
||||
// 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");
|
||||
match HTTPRequest::get_request_parts(&request) {
|
||||
Ok(rp) => {
|
||||
let mut request = HTTPRequest::default();
|
||||
|
||||
let start_line = HTTPStartLine::parse(&rp.0);
|
||||
match start_line {
|
||||
Ok(v) => request.start_line = v,
|
||||
Err(e) => eprintln!("error occurred while parsing start_line err={}", e),
|
||||
}
|
||||
|
||||
let body = HTTPBody::try_from(rp.2);
|
||||
match body {
|
||||
Ok(v) => request.body = Some(v),
|
||||
Err(e) => eprintln!("error occurred during body parsing err={}", e),
|
||||
}
|
||||
|
||||
return Ok(request);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format!("error occurred getting request parts err={}", e));
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -144,6 +198,7 @@ impl Default for HTTPRequest {
|
||||
fn default() -> Self {
|
||||
HTTPRequest {
|
||||
start_line: HTTPStartLine::default(),
|
||||
body: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,16 +221,17 @@ pub fn handle_request(request: &str) -> HTTPRequest {
|
||||
|
||||
#[test]
|
||||
fn test_handle_request() {
|
||||
let test_cases: [(&str, bool); 6] = [
|
||||
("GET / HTTP/1.1", true),
|
||||
let test_cases: [(&str, bool); 7] = [
|
||||
("GET / HTTP/1.1\r\n\r\n", true),
|
||||
(
|
||||
"OPTIONS /admin/2 HTTP/\r\nContent-Type: application/json",
|
||||
"OPTIONS /admin/2 HTTP/\r\nContent-Type: application/json\r\n",
|
||||
true,
|
||||
), // intentionally add HTTP with no version number
|
||||
("POST HTTP/1.1", false),
|
||||
("", false),
|
||||
("fjlqskjd /oks?id=65 HTTP/2", true),
|
||||
("fjlqskjd /oks?id=65 HTTP/2\r\n\r\n", true),
|
||||
(" ", false),
|
||||
("lm //// skkss\r\ndkldklkdl\r\n", true),
|
||||
];
|
||||
|
||||
for (request, is_valid) in test_cases {
|
||||
@ -197,7 +253,7 @@ fn test_http_body() {
|
||||
];
|
||||
|
||||
for (body, is_valid) in test_cases {
|
||||
match HTTPBody::try_from(body) {
|
||||
match HTTPBody::try_from(body.to_string()) {
|
||||
Ok(_) => assert!(is_valid),
|
||||
Err(_) => assert!(!is_valid),
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user