starberry_core/
context.rs

1use std::io::BufReader;
2use std::pin::Pin;
3use std::{collections::HashMap, sync::Arc}; 
4use std::net::TcpStream; 
5use std::future::{ready, Ready}; 
6use std::any::{Any, TypeId}; 
7
8use akari::Object;
9use once_cell::sync::Lazy;
10
11use crate::app::{application::App, urls::Url};
12use crate::http::response::HttpResponse;
13use crate::http::{http_value::{HttpMethod, MultiForm, UrlEncodedForm}, request::{HttpMeta, HttpRequestBody}}; 
14
15pub trait SendResponse { 
16    fn send(&self, stream: &mut TcpStream); 
17} 
18
19/// The `RequestContext` struct is used to hold the context of a request. 
20pub struct Rc { 
21    pub meta: HttpMeta, 
22    pub body: HttpRequestBody, 
23    pub reader: BufReader<TcpStream>, 
24    pub app: Arc<App>, 
25    pub endpoint: Arc<Url>, 
26    pub response: HttpResponse, 
27
28    /// Type-based extension storage, typically used by middleware
29    /// Each type can have exactly one value
30    params: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
31    
32    /// String-based extension storage, typically used by application code
33    /// Multiple values of the same type can be stored with different keys
34    locals: HashMap<String, Box<dyn Any + Send + Sync>>,
35} 
36
37impl Rc  { 
38    pub fn new(
39        meta: HttpMeta,
40        body: HttpRequestBody,
41        reader: BufReader<TcpStream>,
42        app: Arc<App>,
43        endpoint: Arc<Url>, 
44    ) -> Self {
45        Self {
46            meta,
47            body,
48            reader,
49            app,
50            endpoint, 
51            response: HttpResponse::default(), 
52            params: HashMap::new(),
53            locals: HashMap::new(), 
54        }
55    } 
56
57    pub async fn handle(app: Arc<App>, stream: TcpStream) -> Self {
58        // Create one BufReader up-front, pass this throughout.
59        let mut reader = BufReader::new(stream);
60        let meta = HttpMeta::from_request_stream(&mut reader, &app.connection_config)
61            .await
62            .unwrap_or_default();
63
64        let body = HttpRequestBody::Unparsed;
65        let endpoint = app
66            .root_url
67            .clone()
68            .walk_str(meta.path())
69            .await; 
70
71        Rc::new(meta, body, reader, app.clone(), endpoint.clone())
72    } 
73
74    pub async fn run(mut self) { 
75        let endpoint = self.endpoint.clone(); 
76        if !endpoint.clone().request_check(&mut self).await { 
77            self.response.send(self.reader.get_mut()); 
78            return; 
79        }
80        let parsed = endpoint.run(self); 
81        parsed.await.send_response(); 
82    } 
83
84    pub fn send_response(mut self) { 
85        self.response.send(self.reader.get_mut());
86    } 
87
88    pub fn meta(&self) -> &HttpMeta { 
89        &self.meta 
90    } 
91
92    pub fn app(&self) -> Arc<App> { 
93        self.app.clone() 
94    } 
95
96    pub fn endpoint(&self) -> Arc<Url> { 
97        self.endpoint.clone() 
98    } 
99
100    pub fn parse_body(&mut self) {
101        if let HttpRequestBody::Unparsed = self.body {
102            self.body = HttpRequestBody::parse(
103                &mut self.reader,
104                self.endpoint.get_max_body_size().unwrap_or(self.app.get_max_body_size()),
105                &mut self.meta.header,
106            );
107        }
108    } 
109
110    pub fn get_path(&mut self, part: usize) -> String { 
111        self.meta.get_path(part) 
112    }
113
114    pub fn path(&self) -> &str { 
115        self.meta.path() 
116    } 
117
118    /// Returns the method of the request. 
119    pub fn method(&mut self) -> &HttpMethod { 
120        self.meta.method() 
121    } 
122
123    pub fn get_cookies(&mut self) -> &HashMap<String, String> { 
124        self.meta.get_cookies() 
125    } 
126
127    pub fn get_cookie(&mut self, key: &str) -> Option<String> { 
128        self.meta.get_cookie(key) 
129    } 
130
131    pub fn get_cookie_or_default(&mut self, key: &str) -> String { 
132        self.meta.get_cookie_or_default(key) 
133    } 
134
135    pub fn form(&mut self) -> Option<&UrlEncodedForm> {
136        self.parse_body();
137        if let HttpRequestBody::Form(ref data) = self.body {
138            Some(data)
139        } else {
140            None
141        }
142    }
143
144    pub fn form_or_default(&mut self) -> &UrlEncodedForm {
145        self.form().unwrap_or_else(|| {
146            static EMPTY: Lazy<UrlEncodedForm> = Lazy::new(|| HashMap::new().into());
147            &EMPTY
148        })
149    }
150
151    pub fn files(&mut self) -> Option<&MultiForm> {
152        self.parse_body(); 
153        if let HttpRequestBody::Files(ref data) = self.body {
154            Some(data)
155        } else {
156            None
157        }
158    }
159
160    pub fn files_or_default(&mut self) -> &MultiForm {
161        self.files().unwrap_or_else(|| {
162            static EMPTY: Lazy<MultiForm> = Lazy::new(|| HashMap::new().into());
163            &EMPTY
164        })
165    }
166
167    pub fn json(&mut self) -> Option<&Object> {
168        self.parse_body();  
169        if let HttpRequestBody::Json(ref data) = self.body {
170            Some(data)
171        } else {
172            None
173        }
174    }
175
176    pub fn json_or_default(&mut self) -> &Object {
177        self.json().unwrap_or_else(|| {
178            static EMPTY: Lazy<Object> = Lazy::new(|| Object::new(""));
179            &EMPTY
180        })
181    } 
182
183        //
184    // Type-based params methods (for middleware)
185    //
186    
187    /// Stores a value in the type-based params storage.
188    /// Any previous value of the same type will be replaced.
189    /// 
190    /// # Examples
191    ///
192    /// ```rust
193    /// let mut req = HttpRequest::default();
194    /// 
195    /// // Store authentication information
196    /// req.set_param(User { id: 123, name: "Alice".to_string() });
197    /// 
198    /// // Store timing information
199    /// req.set_param(RequestTimer::start());
200    /// ```
201    pub fn set_param<T: 'static + Send + Sync>(&mut self, value: T) {
202        self.params.insert(TypeId::of::<T>(), Box::new(value));
203    }
204    
205    /// Retrieves a reference to a value from the type-based params storage.
206    /// Returns `None` if no value of this type has been stored.
207    ///
208    /// # Examples
209    ///
210    /// ```rust
211    /// // In an authentication middleware
212    /// if let Some(user) = req.param::<User>() {
213    ///     println!("Request by: {}", user.name);
214    ///     // Proceed with authenticated user
215    /// } else {
216    ///     return HttpResponse::unauthorized();
217    /// }
218    /// ```
219    pub fn param<T: 'static + Send + Sync>(&self) -> Option<&T> {
220        self.params
221            .get(&TypeId::of::<T>())
222            .and_then(|boxed| boxed.downcast_ref::<T>())
223    }
224    
225    /// Retrieves a mutable reference to a value from the type-based params storage.
226    /// Returns `None` if no value of this type has been stored.
227    ///
228    /// # Examples
229    ///
230    /// ```rust
231    /// // Update a request timer
232    /// if let Some(timer) = req.param_mut::<RequestTimer>() {
233    ///     timer.mark("after_db_query");
234    /// }
235    /// ```
236    pub fn param_mut<T: 'static + Send + Sync>(&mut self) -> Option<&mut T> {
237        self.params
238            .get_mut(&TypeId::of::<T>())
239            .and_then(|boxed| boxed.downcast_mut::<T>())
240    }
241    
242    /// Removes a value from the type-based params storage and returns it.
243    /// Returns `None` if no value of this type has been stored.
244    ///
245    /// # Examples
246    ///
247    /// ```rust
248    /// // Take ownership of a value
249    /// if let Some(token) = req.take_param::<AuthToken>() {
250    ///     // Use and consume the token
251    ///     validate_token(token);
252    /// }
253    /// ```
254    pub fn take_param<T: 'static + Send + Sync>(&mut self) -> Option<T> {
255        self.params
256            .remove(&TypeId::of::<T>())
257            .and_then(|boxed| boxed.downcast::<T>().ok())
258            .map(|boxed| *boxed)
259    }
260    
261    //
262    // String-based locals methods (for application code)
263    //
264    
265    /// Stores a value in the string-based locals storage with the given key.
266    /// Any previous value with the same key will be replaced.
267    ///
268    /// # Examples
269    ///
270    /// ```rust
271    /// let mut req = HttpRequest::default();
272    ///
273    /// // Store various data with descriptive keys
274    /// req.set_local("user_id", 123);
275    /// req.set_local("is_premium", true);
276    /// req.set_local("cart_items", vec!["item1", "item2"]);
277    /// ```
278    pub fn set_local<T: 'static + Send + Sync>(&mut self, key: impl Into<String>, value: T) {
279        self.locals.insert(key.into(), Box::new(value));
280    }
281    
282    /// Retrieves a reference to a value from the string-based locals storage by key.
283    /// Returns `None` if no value with this key exists or if the type doesn't match.
284    ///
285    /// # Examples
286    ///
287    /// ```rust
288    /// // In a request handler
289    /// if let Some(is_premium) = req.local::<bool>("is_premium") {
290    ///     if *is_premium {
291    ///         // Show premium content
292    ///     }
293    /// }
294    ///
295    /// // With different types
296    /// let user_id = req.local::<i32>("user_id");
297    /// let items = req.local::<Vec<String>>("cart_items");
298    /// ```
299    pub fn local<T: 'static + Send + Sync>(&self, key: &str) -> Option<&T> {
300        self.locals
301            .get(key)
302            .and_then(|boxed| boxed.downcast_ref::<T>())
303    }
304    
305    /// Retrieves a mutable reference to a value from the string-based locals storage by key.
306    /// Returns `None` if no value with this key exists or if the type doesn't match.
307    ///
308    /// # Examples
309    ///
310    /// ```rust
311    /// // Modify a list of items
312    /// if let Some(items) = req.local_mut::<Vec<String>>("cart_items") {
313    ///     items.push("new_item".to_string());
314    /// }
315    /// ```
316    pub fn local_mut<T: 'static + Send + Sync>(&mut self, key: &str) -> Option<&mut T> {
317        self.locals
318            .get_mut(key)
319            .and_then(|boxed| boxed.downcast_mut::<T>())
320    }
321    
322    /// Removes a value from the string-based locals storage and returns it.
323    /// Returns `None` if no value with this key exists or if the type doesn't match.
324    ///
325    /// # Examples
326    ///
327    /// ```rust
328    /// // Take ownership of a value
329    /// if let Some(token) = req.take_local::<String>("session_token") {
330    ///     // Use and consume the token
331    ///     validate_and_destroy_token(token);
332    /// }
333    /// ```
334    pub fn take_local<T: 'static + Send + Sync>(&mut self, key: &str) -> Option<T> {
335        self.locals
336            .remove(key)
337            .and_then(|boxed| boxed.downcast::<T>().ok())
338            .map(|boxed| *boxed)
339    }
340    
341    /// Returns all keys currently stored in the locals map
342    ///
343    /// # Examples
344    ///
345    /// ```rust
346    /// // Inspect what data is attached to the request
347    /// for key in req.local_keys() {
348    ///     println!("Request has data with key: {}", key);
349    /// }
350    /// ```
351    pub fn local_keys(&self) -> Vec<&str> {
352        self.locals.keys().map(|s| s.as_str()).collect()
353    }
354    
355    //
356    // Utility bridging methods
357    //
358    
359    /// Exports a param value to the locals storage with the given key.
360    /// The value must implement Clone. Does nothing if the param doesn't exist.
361    ///
362    /// # Examples
363    ///
364    /// ```rust
365    /// // Make the authenticated user available in locals for convenience
366    /// req.export_param_to_local::<User>("current_user");
367    /// ```
368    pub fn export_param_to_local<T: 'static + Clone + Send + Sync>(&mut self, key: impl Into<String>) {
369        if let Some(value) = self.param::<T>() {
370            let cloned = value.clone();
371            self.set_local(key, cloned);
372        }
373    }
374    
375    /// Imports a local value into the params storage.
376    /// The value must implement Clone. Does nothing if the local doesn't exist.
377    ///
378    /// # Examples
379    ///
380    /// ```rust
381    /// // Make a manually set user available to middleware expecting it in params
382    /// req.import_local_to_param::<User>("manual_user");
383    /// ```
384    pub fn import_local_to_param<T: 'static + Clone + Send + Sync>(&mut self, key: &str) {
385        if let Some(value) = self.local::<T>(key) {
386            let cloned = value.clone();
387            self.set_param(cloned);
388        }
389    } 
390
391    /// Converts this response into a Future that resolves to itself.
392    /// Useful for middleware functions that need to return a Future<Output = HttpResponse>.
393    pub fn future(self) -> impl Future<Output = Rc> + Send {
394        ready(self)
395    }
396
397    /// Creates a boxed future from this response (useful for trait objects).
398    pub fn boxed_future(self) -> Pin<Box<dyn Future<Output = Rc> + Send>> {
399        Box::pin(self.future())
400    }  
401}