mini_async_http/request/
request.rs

1use crate::http::parser::BuildError;
2use crate::http::Headers;
3use crate::http::Method;
4use crate::http::Version;
5
6use std::convert::TryFrom;
7use std::fmt;
8
9/// Represent an http request.  
10#[derive(Debug, PartialEq)]
11pub struct Request {
12    method: Method,
13    path: String,
14    version: Version,
15    headers: Headers,
16    body: Option<Vec<u8>>,
17}
18
19impl Request {
20    /// Return the request Method
21    pub fn method(&self) -> &Method {
22        &self.method
23    }
24
25    /// Return the target path of the request
26    pub fn path(&self) -> &String {
27        &self.path
28    }
29
30    /// Return the HTTP version of the request
31    pub fn version(&self) -> &Version {
32        &self.version
33    }
34
35    /// Return the headers of the request
36    pub fn headers(&self) -> &Headers {
37        &self.headers
38    }
39
40    /// Return the body of the request as byte vector
41    pub fn body(&self) -> Option<&Vec<u8>> {
42        self.body.as_ref()
43    }
44
45    /// Return the body of the request interpreted as utf 8 string
46    pub fn body_as_string(&self) -> Option<String> {
47        match self.body.as_ref() {
48            Some(val) => match String::from_utf8(val.to_vec()) {
49                Ok(body) => Some(body),
50                Err(_) => None,
51            },
52            None => None,
53        }
54    }
55}
56
57impl fmt::Display for Request {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        let mut buf = String::new();
60
61        buf.push_str(
62            format!(
63                "{} {} {}\r\n",
64                self.method.as_str(),
65                self.path,
66                self.version.as_str()
67            )
68            .as_str(),
69        );
70
71        self.headers
72            .iter()
73            .for_each(|(key, value)| buf.push_str(format!("{}: {}\r\n", key, value).as_str()));
74
75        buf.push_str("\r\n");
76
77        match &self.body_as_string() {
78            Some(body) => buf.push_str(body.as_str()),
79            None => {}
80        };
81
82        write!(f, "{}", buf)
83    }
84}
85
86impl TryFrom<&[u8]> for Request {
87    type Error = crate::http::parser::ParseError;
88
89    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
90        let parser = crate::request::request_parser::RequestParser::new();
91
92        match parser.parse_u8(slice) {
93            Ok((request, _)) => Ok(request),
94            Err(e) => Err(e),
95        }
96    }
97}
98
99/// Build a request
100pub struct RequestBuilder {
101    method: Option<Method>,
102    path: Option<String>,
103    version: Option<Version>,
104    headers: Headers,
105    body: Option<Vec<u8>>,
106}
107
108impl RequestBuilder {
109    pub fn new() -> RequestBuilder {
110        RequestBuilder {
111            method: Option::None,
112            path: Option::None,
113            version: Option::None,
114            headers: Headers::new(),
115            body: Option::None,
116        }
117    }
118
119    /// Provide the method for the request
120    pub fn method(mut self, method: Method) -> Self {
121        self.method = Option::Some(method);
122        self
123    }
124
125    /// Provide the path for the request
126    pub fn path(mut self, path: String) -> Self {
127        self.path = Option::Some(path);
128        self
129    }
130
131    /// Provide the version for the request
132    pub fn version(mut self, version: Version) -> Self {
133        self.version = Option::Some(version);
134        self
135    }
136
137    /// Provide the headers for the request
138    pub fn headers(mut self, headers: Headers) -> Self {
139        self.headers = headers;
140        self
141    }
142
143    /// Provide the body for the request
144    pub fn body(mut self, body: &[u8]) -> Self {
145        self.body = Option::Some(body.to_vec());
146        self
147    }
148
149    /// Build the request with provided informations.
150    /// If some informations are missing, BuildError will occur
151    pub fn build(self) -> Result<Request, BuildError> {
152        let method = match self.method {
153            Some(val) => val,
154            None => return Result::Err(BuildError::Incomplete),
155        };
156
157        let path = match self.path {
158            Some(val) => val,
159            None => return Result::Err(BuildError::Incomplete),
160        };
161
162        let version = match self.version {
163            Some(val) => val,
164            None => return Result::Err(BuildError::Incomplete),
165        };
166
167        Result::Ok(Request {
168            method,
169            path,
170            version,
171            headers: self.headers,
172            body: self.body,
173        })
174    }
175}
176
177impl Default for RequestBuilder {
178    fn default() -> Self {
179        RequestBuilder::new()
180    }
181}