http_mini_lib/utils/
http_request.rs1use crate::traits::stream_trait::StreamTrait;
2use std::fmt::Display;
3use std::io::{BufRead, BufReader};
4use std::net::TcpStream;
5
6const REQUEST_METHODS: [&str; 6] = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"];
8
9#[derive(Debug, PartialEq)]
11pub enum ParseHttpRequestError {
12 BadLen,
13 NoMethod,
14 UnknownMethod,
15 NoPath,
16 NoProtocol,
17 UnknownProtocol,
18}
19
20impl Display for ParseHttpRequestError {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(
23 f,
24 "{}",
25 match self {
26 ParseHttpRequestError::BadLen => "Invalid request format",
27 ParseHttpRequestError::NoMethod => "Missing request method",
28 ParseHttpRequestError::UnknownMethod => "Unknown request method",
29 ParseHttpRequestError::NoPath => "Missing request path",
30 ParseHttpRequestError::NoProtocol => "Missing request protocol",
31 ParseHttpRequestError::UnknownProtocol => "Unknown request protocol",
32 }
33 )
34 }
35}
36
37#[derive(Debug, PartialEq)]
38pub struct HttpRequest {
39 pub method: Option<String>,
40 pub protocol: Option<String>,
41 pub path: Option<String>,
42 pub headers: Vec<(String, String)>,
43 pub body: Option<String>,
44}
45
46impl StreamTrait for TcpStream {
47 fn parse(&self) -> Result<HttpRequest, ParseHttpRequestError> {
49 let buf_reader = BufReader::new(self);
50 let mut lines_iterator = buf_reader.lines();
51
52 let mut request = HttpRequest {
53 method: None,
54 protocol: None,
55 path: None,
56 headers: vec![],
57 body: None,
58 };
59
60 let mut first_line_vector: Vec<&str>;
61 let mut has_first_line = false;
62 let mut request_line;
63 loop {
64 request_line = lines_iterator.next();
65 if request_line.is_none() {
66 break;
67 }
68
69 let line_content = request_line.unwrap().unwrap();
70 if line_content.is_empty() {
71 break;
72 }
73
74 if has_first_line {
75 let line_content_iterator = line_content.splitn(2, ": ").collect::<Vec<&str>>();
77 request.headers.push((
78 line_content_iterator[0].to_string(),
79 line_content_iterator[1].to_string(),
80 ));
81 } else {
82 first_line_vector = line_content.splitn(3, ' ').collect::<Vec<&str>>();
83 let init_result = init_request(&mut request, &first_line_vector);
84 if init_result.is_err() {
85 return Err(init_result.err().unwrap());
86 }
87
88 has_first_line = true;
89 }
90 }
91
92 Ok(request)
93 }
94}
95
96fn init_request(
98 http_request: &mut HttpRequest,
99 first_line_vector: &[&str],
100) -> Result<(), ParseHttpRequestError> {
101 if first_line_vector.len() != 3 {
102 return Err(ParseHttpRequestError::BadLen);
103 }
104
105 if first_line_vector[0].is_empty() {
107 return Err(ParseHttpRequestError::NoMethod);
108 }
109 if !REQUEST_METHODS.contains(&first_line_vector[0]) {
110 return Err(ParseHttpRequestError::UnknownMethod);
111 }
112 http_request.method = Option::from(first_line_vector[0].to_string());
113
114 if !first_line_vector[1].is_empty() {
116 http_request.path = Option::from(first_line_vector[1].to_string());
117 } else {
118 return Err(ParseHttpRequestError::NoPath);
119 }
120
121 if first_line_vector[2].is_empty() {
123 return Err(ParseHttpRequestError::NoProtocol);
124 }
125 if !first_line_vector[2].contains("HTTP") {
126 return Err(ParseHttpRequestError::UnknownProtocol);
127 }
128 http_request.protocol = Option::from(first_line_vector[2].to_string());
129
130 Ok(())
131}