thruster_context/
basic_context.rs1use std::collections::HashMap;
2use std::str;
3
4use thruster_core::context::Context;
5use thruster_core::response::Response;
6use thruster_core::request::Request;
7
8use thruster_middleware::query_params::HasQueryParams;
9use thruster_middleware::cookies::{Cookie, HasCookies, CookieOptions, SameSite};
10
11pub fn generate_context(request: Request) -> BasicContext {
12 let mut ctx = BasicContext::new();
13 ctx.params = request.params().clone();
14 ctx.request = request;
15
16 ctx
17}
18
19#[derive(Default)]
20pub struct BasicContext {
21 response: Response,
22 pub cookies: Vec<Cookie>,
23 pub params: HashMap<String, String>,
24 pub query_params: HashMap<String, String>,
25 pub request: Request,
26 pub status: u32,
27 pub headers: HashMap<String, String>,
28}
29
30impl BasicContext {
31 pub fn new() -> BasicContext {
32 let mut ctx = BasicContext {
33 response: Response::new(),
34 cookies: Vec::new(),
35 params: HashMap::new(),
36 query_params: HashMap::new(),
37 request: Request::new(),
38 headers: HashMap::new(),
39 status: 200
40 };
41
42 ctx.set("Server", "Thruster");
43
44 ctx
45 }
46
47 pub fn body(&mut self, body_string: &str) {
51 self.response.body_bytes_from_vec(body_string.as_bytes().to_vec());
52 }
53
54 pub fn get_body(&self) -> String {
55 str::from_utf8(&self.response.response).unwrap_or("").to_owned()
56 }
57
58 pub fn set(&mut self, key: &str, value: &str) {
62 self.response.header(key, value);
63 }
64
65 pub fn remove(&mut self, key: &str) {
69 self.headers.remove(key);
70 }
71
72 pub fn status(&mut self, code: u32) {
76 self.status = code;
77 }
78
79 pub fn content_type(&mut self, c_type: &str) {
87 self.set("Content-Type", c_type);
88 }
89
90 pub fn redirect(&mut self, destination: &str) {
100 self.status(302);
101
102 self.set("Location", destination);
103 }
104
105 pub fn cookie(&mut self, name: &str, value: &str, options: &CookieOptions) {
109 let cookie_value = match self.headers.get("Set-Cookie") {
110 Some(val) => format!("{}, {}", val, self.cookify_options(name, value, &options)),
111 None => self.cookify_options(name, value, &options)
112 };
113
114 self.set("Set-Cookie", &cookie_value);
115 }
116
117 fn cookify_options(&self, name: &str, value: &str, options: &CookieOptions) -> String {
118 let mut pieces = vec![format!("Path={}", options.path)];
119
120 if options.expires > 0 {
121 pieces.push(format!("Expires={}", options.expires));
122 }
123
124 if options.max_age > 0 {
125 pieces.push(format!("Max-Age={}", options.max_age));
126 }
127
128 if !options.domain.is_empty() {
129 pieces.push(format!("Domain={}", options.domain));
130 }
131
132 if options.secure {
133 pieces.push("Secure".to_owned());
134 }
135
136 if options.http_only {
137 pieces.push("HttpOnly".to_owned());
138 }
139
140 if let Some(ref same_site) = options.same_site {
141 match same_site {
142 SameSite::Strict => pieces.push("SameSite=Strict".to_owned()),
143 SameSite::Lax => pieces.push("SameSite=Lax".to_owned())
144 };
145 }
146
147 format!("{}={}; {}", name, value, pieces.join(", "))
148 }
149}
150
151impl Context for BasicContext {
152 type Response = Response;
153
154 fn get_response(mut self) -> Self::Response {
155 self.response.status_code(self.status, "");
156
157 self.response
158 }
159
160 fn set_body(&mut self, body: Vec<u8>) {
161 self.response.body_bytes_from_vec(body);
162 }
163}
164
165impl HasQueryParams for BasicContext {
166 fn set_query_params(&mut self, query_params: HashMap<String, String>) {
167 self.query_params = query_params;
168 }
169
170 fn route(&self) -> &str {
171 self.request.path()
172 }
173}
174
175impl HasCookies for BasicContext {
176 fn set_cookies(&mut self, cookies: Vec<Cookie>) {
177 self.cookies = cookies;
178 }
179
180 fn headers(&self) -> HashMap<String, String> {
181 self.request.headers()
182 }
183}