rust_web_server/extract/
mod.rs1#[cfg(test)]
2mod tests;
3
4use std::collections::HashMap;
5
6use crate::header::Header;
7use crate::mime_type::MimeType;
8use crate::range::Range;
9use crate::request::Request;
10use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
11use crate::url::URL;
12
13pub trait FromRequest: Sized {
33 fn from_request(request: &Request) -> Result<Self, Response>;
35}
36
37#[derive(Debug)]
41pub struct Body(pub Vec<u8>);
42
43impl FromRequest for Body {
44 fn from_request(request: &Request) -> Result<Self, Response> {
45 Ok(Body(request.body.clone()))
46 }
47}
48
49impl Body {
50 pub fn into_bytes(self) -> Vec<u8> {
51 self.0
52 }
53}
54
55#[derive(Debug)]
59pub struct BodyText(pub String);
60
61impl FromRequest for BodyText {
62 fn from_request(request: &Request) -> Result<Self, Response> {
63 String::from_utf8(request.body.clone())
64 .map(BodyText)
65 .map_err(|_| bad_request(request, "request body is not valid UTF-8"))
66 }
67}
68
69impl BodyText {
70 pub fn as_str(&self) -> &str {
71 &self.0
72 }
73}
74
75#[derive(Debug)]
79pub struct Query(pub HashMap<String, String>);
92
93impl FromRequest for Query {
94 fn from_request(request: &Request) -> Result<Self, Response> {
95 let query_str = request.request_uri
96 .splitn(2, '?')
97 .nth(1)
98 .unwrap_or("");
99 Ok(Query(URL::parse_query(query_str)))
100 }
101}
102
103impl Query {
104 pub fn get(&self, key: &str) -> Option<&String> {
105 self.0.get(key)
106 }
107}
108
109#[derive(Debug)]
111pub struct RequestHeaders(pub Vec<Header>);
112
113impl FromRequest for RequestHeaders {
114 fn from_request(request: &Request) -> Result<Self, Response> {
115 Ok(RequestHeaders(request.headers.clone()))
116 }
117}
118
119impl RequestHeaders {
120 pub fn get(&self, name: &str) -> Option<&str> {
122 let lower = name.to_lowercase();
123 self.0.iter()
124 .find(|h| h.name.to_lowercase() == lower)
125 .map(|h| h.value.as_str())
126 }
127}
128
129fn bad_request(request: &Request, msg: &str) -> Response {
130 let header_list = Header::get_header_list(request);
131 let cr = Range::get_content_range(msg.as_bytes().to_vec(), MimeType::TEXT_PLAIN.to_string());
132 Response::get_response(
133 STATUS_CODE_REASON_PHRASE.n400_bad_request,
134 Some(header_list),
135 Some(vec![cr]),
136 )
137}