rust_web_server/extract/
mod.rs1#[cfg(test)]
2mod tests;
3
4use std::collections::HashMap;
5
6use crate::header::Header;
7use crate::request::Request;
8use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
9use crate::url::URL;
10
11pub trait FromRequest: Sized {
31 fn from_request(request: &Request) -> Result<Self, Response>;
33}
34
35#[derive(Debug)]
39pub struct Body(pub Vec<u8>);
40
41impl FromRequest for Body {
42 fn from_request(request: &Request) -> Result<Self, Response> {
43 Ok(Body(request.body.to_vec()))
44 }
45}
46
47impl Body {
48 pub fn into_bytes(self) -> Vec<u8> {
49 self.0
50 }
51}
52
53#[derive(Debug)]
57pub struct BodyText(pub String);
58
59impl FromRequest for BodyText {
60 fn from_request(request: &Request) -> Result<Self, Response> {
61 String::from_utf8(request.body.to_vec())
62 .map(BodyText)
63 .map_err(|_| bad_request(request, "request body is not valid UTF-8"))
64 }
65}
66
67impl BodyText {
68 pub fn as_str(&self) -> &str {
69 &self.0
70 }
71}
72
73#[derive(Debug)]
77pub struct Query(pub HashMap<String, String>);
90
91impl FromRequest for Query {
92 fn from_request(request: &Request) -> Result<Self, Response> {
93 let query_str = request.request_uri
94 .splitn(2, '?')
95 .nth(1)
96 .unwrap_or("");
97 Ok(Query(URL::parse_query(query_str)))
98 }
99}
100
101impl Query {
102 pub fn get(&self, key: &str) -> Option<&String> {
103 self.0.get(key)
104 }
105}
106
107#[derive(Debug)]
109pub struct RequestHeaders(pub Vec<Header>);
110
111impl FromRequest for RequestHeaders {
112 fn from_request(request: &Request) -> Result<Self, Response> {
113 Ok(RequestHeaders(request.headers.clone()))
114 }
115}
116
117impl RequestHeaders {
118 pub fn get(&self, name: &str) -> Option<&str> {
120 let lower = name.to_lowercase();
121 self.0.iter()
122 .find(|h| h.name.to_lowercase() == lower)
123 .map(|h| h.value.as_ref())
124 }
125}
126
127#[derive(Debug, Clone)]
134pub struct RequestId(pub String);
135
136impl FromRequest for RequestId {
137 fn from_request(request: &Request) -> Result<Self, Response> {
138 Ok(RequestId(
139 (request
140 .get_header(crate::request_id::DEFAULT_HEADER.to_string())
141 .map(|h| h.value.clone())
142 .unwrap_or_default()).into_owned(),
143 ))
144 }
145}
146
147impl RequestId {
148 pub fn as_str(&self) -> &str {
150 &self.0
151 }
152}
153
154fn bad_request(request: &Request, msg: &str) -> Response {
155 let header_list = Header::get_header_list(request);
156 crate::error::problem::with_headers(STATUS_CODE_REASON_PHRASE.n400_bad_request, msg, msg, Some(header_list))
157}