actori_http/
httpmessage.rs1use std::cell::{Ref, RefMut};
2use std::str;
3
4use encoding_rs::{Encoding, UTF_8};
5use http::header;
6use mime::Mime;
7
8use crate::cookie::Cookie;
9use crate::error::{ContentTypeError, CookieParseError, ParseError};
10use crate::extensions::Extensions;
11use crate::header::{Header, HeaderMap};
12use crate::payload::Payload;
13
14struct Cookies(Vec<Cookie<'static>>);
15
16pub trait HttpMessage: Sized {
18 type Stream;
20
21 fn headers(&self) -> &HeaderMap;
23
24 fn take_payload(&mut self) -> Payload<Self::Stream>;
26
27 fn extensions(&self) -> Ref<'_, Extensions>;
29
30 fn extensions_mut(&self) -> RefMut<'_, Extensions>;
32
33 #[doc(hidden)]
34 fn get_header<H: Header>(&self) -> Option<H>
36 where
37 Self: Sized,
38 {
39 if self.headers().contains_key(H::name()) {
40 H::parse(self).ok()
41 } else {
42 None
43 }
44 }
45
46 fn content_type(&self) -> &str {
49 if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
50 if let Ok(content_type) = content_type.to_str() {
51 return content_type.split(';').next().unwrap().trim();
52 }
53 }
54 ""
55 }
56
57 fn encoding(&self) -> Result<&'static Encoding, ContentTypeError> {
61 if let Some(mime_type) = self.mime_type()? {
62 if let Some(charset) = mime_type.get_param("charset") {
63 if let Some(enc) =
64 Encoding::for_label_no_replacement(charset.as_str().as_bytes())
65 {
66 Ok(enc)
67 } else {
68 Err(ContentTypeError::UnknownEncoding)
69 }
70 } else {
71 Ok(UTF_8)
72 }
73 } else {
74 Ok(UTF_8)
75 }
76 }
77
78 fn mime_type(&self) -> Result<Option<Mime>, ContentTypeError> {
80 if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
81 if let Ok(content_type) = content_type.to_str() {
82 return match content_type.parse() {
83 Ok(mt) => Ok(Some(mt)),
84 Err(_) => Err(ContentTypeError::ParseError),
85 };
86 } else {
87 return Err(ContentTypeError::ParseError);
88 }
89 }
90 Ok(None)
91 }
92
93 fn chunked(&self) -> Result<bool, ParseError> {
95 if let Some(encodings) = self.headers().get(header::TRANSFER_ENCODING) {
96 if let Ok(s) = encodings.to_str() {
97 Ok(s.to_lowercase().contains("chunked"))
98 } else {
99 Err(ParseError::Header)
100 }
101 } else {
102 Ok(false)
103 }
104 }
105
106 #[inline]
108 fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
109 if self.extensions().get::<Cookies>().is_none() {
110 let mut cookies = Vec::new();
111 for hdr in self.headers().get_all(header::COOKIE) {
112 let s =
113 str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
114 for cookie_str in s.split(';').map(|s| s.trim()) {
115 if !cookie_str.is_empty() {
116 cookies.push(Cookie::parse_encoded(cookie_str)?.into_owned());
117 }
118 }
119 }
120 self.extensions_mut().insert(Cookies(cookies));
121 }
122 Ok(Ref::map(self.extensions(), |ext| {
123 &ext.get::<Cookies>().unwrap().0
124 }))
125 }
126
127 fn cookie(&self, name: &str) -> Option<Cookie<'static>> {
129 if let Ok(cookies) = self.cookies() {
130 for cookie in cookies.iter() {
131 if cookie.name() == name {
132 return Some(cookie.to_owned());
133 }
134 }
135 }
136 None
137 }
138}
139
140impl<'a, T> HttpMessage for &'a mut T
141where
142 T: HttpMessage,
143{
144 type Stream = T::Stream;
145
146 fn headers(&self) -> &HeaderMap {
147 (**self).headers()
148 }
149
150 fn take_payload(&mut self) -> Payload<Self::Stream> {
152 (**self).take_payload()
153 }
154
155 fn extensions(&self) -> Ref<'_, Extensions> {
157 (**self).extensions()
158 }
159
160 fn extensions_mut(&self) -> RefMut<'_, Extensions> {
162 (**self).extensions_mut()
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use bytes::Bytes;
169 use encoding_rs::ISO_8859_2;
170 use mime;
171
172 use super::*;
173 use crate::test::TestRequest;
174
175 #[test]
176 fn test_content_type() {
177 let req = TestRequest::with_header("content-type", "text/plain").finish();
178 assert_eq!(req.content_type(), "text/plain");
179 let req =
180 TestRequest::with_header("content-type", "application/json; charset=utf=8")
181 .finish();
182 assert_eq!(req.content_type(), "application/json");
183 let req = TestRequest::default().finish();
184 assert_eq!(req.content_type(), "");
185 }
186
187 #[test]
188 fn test_mime_type() {
189 let req = TestRequest::with_header("content-type", "application/json").finish();
190 assert_eq!(req.mime_type().unwrap(), Some(mime::APPLICATION_JSON));
191 let req = TestRequest::default().finish();
192 assert_eq!(req.mime_type().unwrap(), None);
193 let req =
194 TestRequest::with_header("content-type", "application/json; charset=utf-8")
195 .finish();
196 let mt = req.mime_type().unwrap().unwrap();
197 assert_eq!(mt.get_param(mime::CHARSET), Some(mime::UTF_8));
198 assert_eq!(mt.type_(), mime::APPLICATION);
199 assert_eq!(mt.subtype(), mime::JSON);
200 }
201
202 #[test]
203 fn test_mime_type_error() {
204 let req = TestRequest::with_header(
205 "content-type",
206 "applicationadfadsfasdflknadsfklnadsfjson",
207 )
208 .finish();
209 assert_eq!(Err(ContentTypeError::ParseError), req.mime_type());
210 }
211
212 #[test]
213 fn test_encoding() {
214 let req = TestRequest::default().finish();
215 assert_eq!(UTF_8.name(), req.encoding().unwrap().name());
216
217 let req = TestRequest::with_header("content-type", "application/json").finish();
218 assert_eq!(UTF_8.name(), req.encoding().unwrap().name());
219
220 let req = TestRequest::with_header(
221 "content-type",
222 "application/json; charset=ISO-8859-2",
223 )
224 .finish();
225 assert_eq!(ISO_8859_2, req.encoding().unwrap());
226 }
227
228 #[test]
229 fn test_encoding_error() {
230 let req = TestRequest::with_header("content-type", "applicatjson").finish();
231 assert_eq!(Some(ContentTypeError::ParseError), req.encoding().err());
232
233 let req = TestRequest::with_header(
234 "content-type",
235 "application/json; charset=kkkttktk",
236 )
237 .finish();
238 assert_eq!(
239 Some(ContentTypeError::UnknownEncoding),
240 req.encoding().err()
241 );
242 }
243
244 #[test]
245 fn test_chunked() {
246 let req = TestRequest::default().finish();
247 assert!(!req.chunked().unwrap());
248
249 let req =
250 TestRequest::with_header(header::TRANSFER_ENCODING, "chunked").finish();
251 assert!(req.chunked().unwrap());
252
253 let req = TestRequest::default()
254 .header(
255 header::TRANSFER_ENCODING,
256 Bytes::from_static(b"some va\xadscc\xacas0xsdasdlue"),
257 )
258 .finish();
259 assert!(req.chunked().is_err());
260 }
261}