rust_xfinal/http_parser/
connection.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fs::OpenOptions;
4use std::io::Read;
5use std::net::TcpStream;
6
7use multimap::MultiMap;
8
9use std::sync::Arc;
10
11use std::ops::Range;
12
13use std::rc::Rc;
14
15use std::ffi::OsStr;
16use std::io;
17use std::io::prelude::*;
18
19pub use tera::{Context, Tera};
20
21pub mod mime;
22
23use hmac::Hmac;
24use sha2::Sha256;
25
26use crate::cookie::Cookie;
27
28use serde_json::Value;
29use std::collections::BTreeMap;
30
31pub mod http_response_table {
32    const STATE_TABLE: [(u16, &str); 20] = [
33        (101, "101 Switching Protocals\r\n"),
34        (200, "200 OK\r\n"),
35        (201, "201 Created\r\n"),
36        (202, "202 Accepted\r\n"),
37        (204, "204 No Content\r\n"),
38        (206, "206 Partial Content\r\n"),
39        (300, "300 Multiple Choices\r\n"),
40        (301, "301 Moved Permanently\r\n"),
41        (302, "302 Moved Temporarily\r\n"),
42        (304, "304 Not Modified\r\n"),
43        (400, "400 Bad Request\r\n"),
44        (401, "401 Unauthorized\r\n"),
45        (403, "403 Forbidden\r\n"),
46        (404, "404 Not Found\r\n"),
47        (413, "413 Request Entity Too Large\r\n"),
48        (416, "416 Requested Range Not Satisfiable\r\n"),
49        (500, "500 Internal Server Error\r\n"),
50        (501, "501 Not Implemented\r\n"),
51        (502, "502 Bad Gateway\r\n"),
52        (503, "503 Service Unavailable\r\n"),
53    ];
54
55    pub(super) fn get_httpstatus_from_code(code: u16) -> &'static str {
56        match STATE_TABLE.binary_search_by_key(&code, |&(k, _)| k) {
57            Ok(index) => STATE_TABLE[index].1,
58            Err(_) => panic!("not supporting such a http state code"),
59        }
60    }
61
62    const HTTP_METHODS: [(u8, &str); 9] = [
63        (0, "GET"),
64        (1, "POST"),
65        (2, "OPTIONS"),
66        (3, "DELETE"),
67        (4, "HEAD"),
68        (5, "PUT"),
69        (6, "PATCH"),
70        (7, "CONNECT"),
71        (8, "TRACE"),
72    ];
73    /// > Correspond to http GET
74    pub const GET: u8 = 0;
75    /// > Correspond to http POST
76    pub const POST: u8 = 1;
77    /// > Correspond to http OPTIONS
78    pub const OPTIONS: u8 = 2;
79    /// > Correspond to http DELETE
80    pub const DELETE: u8 = 3;
81    /// > Correspond to http HEAD
82    pub const HEAD: u8 = 4;
83    /// > Correspond to http PUT
84    pub const PUT: u8 = 5;
85    /// > Correspond to http PATCH
86    pub const PATCH: u8 = 6;
87    /// > Correspond to http CONNECT
88    pub const CONNECT: u8 = 7;
89    /// > Correspond to http TRACE
90    pub const TRACE: u8 = 8;
91    pub fn get_httpmethod_from_code(code: u8) -> &'static str {
92        match HTTP_METHODS.binary_search_by_key(&code, |&(k, _)| k) {
93            Ok(index) => HTTP_METHODS[index].1,
94            Err(_) => panic!("not supporting such a http state code"),
95        }
96    }
97}
98pub struct Request<'a> {
99    pub(super) header_pair: HashMap<&'a str, &'a str>,
100    pub(super) url: &'a str,
101    pub(super) method: &'a str,
102    pub(super) version: &'a str,
103    pub(super) body: BodyContent<'a>,
104    pub(super) conn_: Rc<RefCell<&'a mut TcpStream>>,
105    pub(super) secret_key: Arc<Hmac<Sha256>>,
106    pub(super) ctx: RefCell<BTreeMap<String, Value>>,
107}
108
109impl<'a> Request<'a> {
110    /// Get the value of a header pair by specifying the key
111    /// For example, `Content-length: 123`
112    /// get_header("Content-length"), the key is not case senstive
113    pub fn get_header(&self, key: &str) -> Option<&str> {
114        let r = self.header_pair.keys().find(|&&ik| {
115            if ik.to_lowercase() == key.to_lowercase() {
116                true
117            } else {
118                false
119            }
120        });
121        match r {
122            Some(r) => {
123                return Some(self.header_pair.get(*r).unwrap()); // confirm that unwrap() is harmless
124            }
125            None => {
126                return None;
127            }
128        }
129    }
130
131    /// > Get the value of a parameter in the requested url
132    /// # For example
133    /// > `/path?id=1`
134    /// >> - `get_param("id")` returns 1, the key is case senstive
135    pub fn get_param(&self, k: &str) -> Option<&str> {
136        match self.url.split_once("?") {
137            Some((_, v)) => {
138                let r = v.split("&");
139                for e in r {
140                    match e.split_once("=") {
141                        Some((ik, iv)) => {
142                            if ik == k {
143                                return Some(iv);
144                            }
145                        }
146                        None => {}
147                    }
148                }
149                None
150            }
151            None => None,
152        }
153    }
154
155    /// > Get the HashMap of the parameters in the requested url
156    /// # For example
157    /// > `/path?id=1&flag=true`
158    /// >> - `get_params()` returns `{id:1, flag:true }`
159    pub fn get_params(&self) -> Option<HashMap<&str, &str>> {
160        match self.url.split_once("?") {
161            Some((_, v)) => {
162                let r = v.split("&");
163                let mut map = HashMap::new();
164                for e in r {
165                    match e.split_once("=") {
166                        Some((ik, iv)) => {
167                            map.insert(ik, iv);
168                        }
169                        None => {}
170                    }
171                }
172                if map.len() == 0 {
173                    None
174                } else {
175                    Some(map)
176                }
177            }
178            None => None,
179        }
180    }
181
182    /// > Get the complete http headers
183    /// >> - `{"Content-length":"1", "key":"value",...}`
184    pub fn get_headers(&self) -> HashMap<&str, &str> {
185        self.header_pair.clone()
186    }
187    /// > Get the version of http request
188    pub fn get_version(&self) -> &str {
189        self.version
190    }
191
192    /// > Query the value of www-form-urlencoded or the text part of the multipart-form
193    /// >> - The key is not case senstive
194    /// # For example
195    /// > Assume the form has the value `id=1`, then get_query("id") returns Some("1")
196    ///
197    pub fn get_query(&self, k: &str) -> Option<&str> {
198        if let BodyContent::UrlForm(x) = &self.body {
199            let r = x.keys().find(|&&ik| {
200                if ik.to_lowercase() == k.to_lowercase() {
201                    true
202                } else {
203                    false
204                }
205            });
206            match r {
207                Some(r) => {
208                    return Some(x.get(*r).unwrap()); // confirm that unwrap() is harmless
209                }
210                None => {
211                    return None;
212                }
213            }
214        } else if let BodyContent::Multi(x) = &self.body {
215            let r = x.keys().find(|&ik| {
216                if ik.to_lowercase() == k.to_lowercase() {
217                    true
218                } else {
219                    false
220                }
221            });
222            match r {
223                Some(s) => {
224                    let v = x.get(s).unwrap(); // guarantee by above
225                    match v {
226                        MultipleFormData::Text(v) => {
227                            return Some(*v);
228                        }
229                        MultipleFormData::File(_) => return None,
230                    }
231                }
232                None => {
233                    return None;
234                }
235            }
236        } else {
237            None
238        }
239    }
240
241    /// > This method is used to acquire the file in the multipart-form data
242    /// # For example,
243    /// ```
244    /// <form>
245    ///    <input type="file" name="file1" />
246    /// </form>
247    ///
248    ///```
249    /// > - `get_file("file1")` return the file's meta data
250    pub fn get_file(&self, k: &str) -> Option<&'_ MultipleFormFile> {
251        if let BodyContent::Multi(x) = &self.body {
252            let r = x.keys().find(|&ik| {
253                if k.to_lowercase() == ik.to_lowercase() {
254                    true
255                } else {
256                    false
257                }
258            });
259            match r {
260                Some(s) => {
261                    let item = x.get(s).unwrap(); // confirm that unwrap() is harmless
262                    if let MultipleFormData::File(file) = item {
263                        return Some(file);
264                    } else {
265                        return None;
266                    }
267                }
268                None => return None,
269            }
270        } else {
271            None
272        }
273    }
274
275    /// > Return a HashMap that comprises all pairs in the www-form-urlencoded or the text part of the multipart-form
276    /// >> - It is safety called even though the request is `GET`, which returns None
277    pub fn get_queries(&self) -> Option<HashMap<&str, &str>> {
278        if let BodyContent::UrlForm(x) = &self.body {
279            Some(x.clone())
280        } else if let BodyContent::Multi(x) = &self.body {
281            let mut v = HashMap::new();
282            for (k, item) in x {
283                match item {
284                    MultipleFormData::Text(text) => {
285                        v.insert(k.as_str(), *text);
286                    }
287                    MultipleFormData::File(_) => {}
288                }
289            }
290            if v.len() != 0 {
291                return Some(v);
292            } else {
293                return None;
294            }
295        } else {
296            None
297        }
298    }
299
300    /// > Returns an array comprises of all files in the multipart-form data
301    pub fn get_files(&self) -> Option<Vec<&MultipleFormFile>> {
302        if let BodyContent::Multi(x) = &self.body {
303            let mut vec = Vec::new();
304            for (_k, v) in x {
305                match v {
306                    MultipleFormData::Text(_) => {}
307                    MultipleFormData::File(file) => {
308                        vec.push(file);
309                    }
310                }
311            }
312            if vec.len() != 0 {
313                return Some(vec);
314            } else {
315                return None;
316            }
317        } else {
318            None
319        }
320    }
321
322    /// > Returns the body of a request
323    /// >> -  it is used for getting the posted JSON or other plain text body
324    pub fn plain_body(&self) -> Option<&str> {
325        if let BodyContent::PureText(x) = self.body {
326            Some(x)
327        } else {
328            None
329        }
330    }
331
332    /// > Determin whether the request has a body
333    pub fn has_body(&self) -> bool {
334        if let BodyContent::None = self.body {
335            false
336        } else {
337            true
338        }
339    }
340
341    /// > Return the raw instance of TcpStream
342    /// >> - This method should be carefully used,
343    /// It is better to only get some meta information of a connection, such as a peer IP
344    pub fn get_conn(&self) -> Rc<RefCell<&'a mut TcpStream>> {
345        Rc::clone(&self.conn_)
346    }
347
348    /// > Return the requested http method
349    pub fn get_method(&self) -> &str {
350        self.method
351    }
352
353    /// > Return the complete requested url
354    pub fn get_url(&self) -> &str {
355        self.url
356    }
357
358    pub(crate) fn get_secret_key(&self) -> Arc<Hmac<Sha256>> {
359        Arc::clone(&self.secret_key)
360    }
361
362    /// > Return the part of url exclude the parameters(if any)
363    pub fn url_to_path(&self) -> &str {
364        match self.url.find("?") {
365            Some(pos) => &self.url[..pos],
366            None => self.url,
367        }
368    }
369
370    /// > It is used to store user data
371    /// >> - share data between middlwares and routers(if any)
372    ///
373    pub fn get_context(&self) -> &RefCell<BTreeMap<String, Value>> {
374        &self.ctx
375    }
376}
377
378pub struct ResponseConfig<'b, 'a> {
379    res: &'b mut Response<'a>,
380    has_failure: bool,
381}
382
383impl<'b, 'a> ResponseConfig<'b, 'a> {
384    fn get_map_key(map: &MultiMap<String, String>, key: &str) -> Option<String> {
385        let r = map.keys().find(|&ik| {
386            if ik.to_lowercase() == key.to_lowercase() {
387                true
388            } else {
389                false
390            }
391        });
392        Some((r?).clone())
393    }
394
395    /// > Set the transfer type of a response with chunked
396    pub fn chunked(&mut self) -> &mut Self {
397        if self.has_failure {
398            return self;
399        }
400        if self.res.method == "HEAD" {
401            return self;
402        }
403        self.res
404            .add_header(String::from("Transfer-Encoding"), String::from("chunked"));
405        if let Some(key) = Self::get_map_key(&self.res.header_pair, "content-length") {
406            self.res.header_pair.remove(&key);
407        }
408        self.res.chunked.enable = true;
409        self
410    }
411
412    /// > Specify the status of a http response
413    pub fn status(&mut self, code: u16) -> &mut Self {
414        if self.has_failure {
415            return self;
416        }
417        self.res.http_state = code;
418        self
419    }
420
421    /// > This is only used to specify the name when the client downloads a file
422    /// >> - Only works if it follows the write_file()
423    pub fn specify_file_name(&mut self, name: &str) -> &mut Self {
424        if self.has_failure {
425            return self;
426        }
427        match &self.res.body {
428            BodyType::Memory(_, _) => {}
429            BodyType::File(_, _) => {
430                if !self.res.header_exist("Content-Disposition") {
431                    self.res.add_header(
432                        "Content-Disposition".to_string(),
433                        format!("attachment; filename=\"{name}\""),
434                    );
435                }
436            }
437            BodyType::None => {}
438        }
439        self
440    }
441
442    /// > Start a range function for such as `write_file`, `write_string`, or `render_view_xxxx`
443    pub fn enable_range(&mut self) -> &mut Self {
444        if self.has_failure {
445            return self;
446        }
447        self.res
448            .add_header(String::from("Accept-Ranges"), String::from("bytes"));
449        if self.res.method == "HEAD" {
450            match &self.res.body {
451                BodyType::Memory(_, buffs) => {
452                    self.res
453                        .add_header(String::from("Content-length"), buffs.len().to_string());
454                    self.res.http_state = 200;
455                }
456                BodyType::File(path, _) => {
457                    match std::fs::OpenOptions::new().read(true).open(path) {
458                        Ok(file) => {
459                            match file.metadata() {
460                                Ok(meta) => {
461                                    self.res.add_header(
462                                        String::from("Content-length"),
463                                        meta.len().to_string(),
464                                    );
465                                    self.res.http_state = 200;
466                                }
467                                Err(_) => {
468                                    self.has_failure = true;
469                                    self.res.write_state(404);
470                                }
471                            };
472                        }
473                        Err(_) => {
474                            self.has_failure = true;
475                            self.res.write_state(404);
476                        }
477                    }
478                }
479                BodyType::None => {}
480            }
481        } else {
482            match self.res.get_request_header_value("Range") {
483                Some(v) => {
484                    self.res.range = parse_range_content(v);
485                }
486                None => {
487                    self.res.range = ResponseRangeMeta::None;
488                }
489            }
490        }
491        self
492    }
493
494    /// > Specify cookies for the request
495    /// >> - Argument could be a single Cookie
496    /// >> - Or muliple Cookies: [Cookie,Cookie,...]
497    pub fn with_cookies<T: MoreThanOneCookie<Output = Cookie>>(&mut self, v: T) -> &mut Self {
498        if self.has_failure {
499            return self;
500        }
501        for e in v.into_vec() {
502            match e.to_string() {
503                Some(s) => {
504                    self.res.add_header(String::from("set-cookie"), s);
505                }
506                None => {
507                    continue;
508                }
509            }
510        }
511        self
512    }
513
514    pub fn charset(&mut self, v: &str) -> &mut Self {
515        if self.has_failure {
516            return self;
517        }
518        self.res.charset = Some(v.to_string());
519        self
520    }
521}
522
523pub trait MoreThanOneCookie {
524    type Output;
525    fn into_vec(self) -> Vec<Self::Output>;
526}
527
528impl MoreThanOneCookie for Cookie {
529    type Output = Cookie;
530
531    fn into_vec(self) -> Vec<Self::Output> {
532        vec![self]
533    }
534}
535
536impl<const I: usize> MoreThanOneCookie for [Cookie; I] {
537    type Output = Cookie;
538
539    fn into_vec(self) -> Vec<Self::Output> {
540        Vec::from(self)
541    }
542}
543
544fn parse_range_content(v: &str) -> ResponseRangeMeta {
545    match v.trim().split_once("=") {
546        Some(v) => {
547            let v = v.1;
548            match v.trim().split_once("-") {
549                Some(v) => {
550                    let start;
551                    let end;
552                    if v.0 != "" {
553                        let mut exception = false;
554                        let r: u64 = v.0.parse().unwrap_or_else(|_| {
555                            exception = true;
556                            0
557                        });
558                        if r == 0 && exception == true {
559                            start = None;
560                        } else {
561                            start = Some(r);
562                        }
563                    } else {
564                        start = None;
565                    }
566                    if v.1 != "" {
567                        let mut exception = false;
568                        let r: u64 = v.1.parse().unwrap_or_else(|_| {
569                            exception = true;
570                            0
571                        });
572                        if r == 0 && exception == true {
573                            end = None;
574                        } else {
575                            end = Some(r);
576                        }
577                    } else {
578                        end = None;
579                    }
580                    ResponseRangeMeta::Range(start, end)
581                }
582                None => ResponseRangeMeta::Range(None, None),
583            }
584        }
585        None => ResponseRangeMeta::Range(None, None),
586    }
587}
588
589pub struct ResponseChunkMeta {
590    pub(super) enable: bool,
591    pub(super) chunk_size: usize,
592}
593
594impl ResponseChunkMeta {
595    pub(super) fn new(chunk_size: u32) -> Self {
596        ResponseChunkMeta {
597            enable: false,
598            chunk_size: chunk_size as usize,
599        }
600    }
601}
602
603pub enum ResponseRangeMeta {
604    Range(Option<u64>, Option<u64>),
605    None,
606}
607
608pub enum MemoryType {
609    String(String),
610    Binary,
611}
612
613pub enum BodyType {
614    Memory(MemoryType, Vec<u8>),
615    File(String, Option<String>),
616    None,
617}
618
619pub struct Response<'a> {
620    pub(super) header_pair: MultiMap<String, String>,
621    pub(super) version: &'a str,
622    pub(super) method: &'a str,
623    //pub(super) url: &'a str,
624    pub(super) http_state: u16,
625    pub(super) body: BodyType,
626    pub(super) chunked: ResponseChunkMeta,
627    pub(super) conn_: Rc<RefCell<&'a mut TcpStream>>,
628    pub(super) range: ResponseRangeMeta,
629    pub(super) request_header: HashMap<&'a str, &'a str>,
630    pub(super) charset: Option<String>,
631}
632
633impl<'a> Response<'a> {
634    fn get_request_header_value(&mut self, k: &str) -> Option<&str> {
635        match self.request_header.keys().find(|&&ik| {
636            if k.to_lowercase() == ik.to_lowercase() {
637                true
638            } else {
639                false
640            }
641        }) {
642            Some(k) => Some(self.request_header.get(*k).unwrap()), // confirm that unwrap() is harmless
643            None => None,
644        }
645    }
646
647    /// > Remove a pair you have writed to a reponse header
648    /// >> - The key is not case senstive
649    /// # For example
650    /// ```
651    /// add_header(String::from("a"),String::from("b"))
652    /// ```
653    /// > Header: {a:b}
654    /// ```
655    /// remove_header(String::from("a"))
656    /// ```
657    /// > Header: {}
658    pub fn remove_header(&mut self, key: String) {
659        let r = self.header_pair.keys().find(|&ik| {
660            if key.to_lowercase() == ik.to_lowercase() {
661                true
662            } else {
663                false
664            }
665        });
666        match r {
667            Some(k) => {
668                let s = k.clone();
669                let map = &mut self.header_pair;
670                map.remove(&s);
671            }
672            None => {}
673        }
674    }
675
676    /// > Add a pair to the header of the response
677    /// ```
678    /// add_header(String::from("a"),String::from("b"))
679    /// ```
680    /// >  Header:{a:b}
681    pub fn add_header(&mut self, key: String, value: String) {
682        self.header_pair.insert(key, value);
683    }
684
685    fn set_default_content_type(&mut self) {
686        if !self.header_exist("Content-Type") {
687            match &self.body {
688                BodyType::Memory(kind, _) => {
689                    match kind {
690                        MemoryType::String(extension) => match &self.charset {
691                            Some(charset) => {
692                                self.add_header(
693                                    "Content-type".to_string(),
694                                    format!("{}; charset={}", extension, charset),
695                                );
696                            }
697                            None => {
698                                self.add_header(
699                                    "Content-type".to_string(),
700                                    format!("{}; charset=utf-8", extension),
701                                );
702                            }
703                        },
704                        MemoryType::Binary => {}
705                    };
706                }
707                BodyType::File(_, extension) => {
708                    if let Some(x) = extension {
709                        match &self.charset {
710                            Some(charset) => {
711                                self.add_header(
712                                    "Content-type".to_string(),
713                                    format!("{}; charset={}", x, charset),
714                                );
715                            }
716                            None => {
717                                self.add_header(
718                                    "Content-type".to_string(),
719                                    format!("{}; charset=utf-8", x),
720                                );
721                            }
722                        }
723                    }
724                }
725                BodyType::None => {}
726            }
727        }
728    }
729    pub(super) fn header_to_string(&mut self) -> Vec<u8> {
730        //println!("header pairs: {:#?}",self.header_pair);
731        let mut buffs = Vec::new();
732        let state_text = http_response_table::get_httpstatus_from_code(self.http_state);
733        buffs.extend_from_slice(format!("{} {}", self.version, state_text).as_bytes());
734        self.set_default_content_type();
735        for (k, v) in &self.header_pair {
736            for value in v {
737                buffs.extend_from_slice(format!("{}: {}\r\n", k, value).as_bytes());
738            }
739        }
740        buffs.extend_from_slice(b"\r\n");
741        buffs
742    }
743
744    fn take_body_size(&mut self) -> io::Result<u64> {
745        match &self.body {
746            BodyType::Memory(_, buff) => Ok(buff.len() as u64),
747            BodyType::File(path, _) => match std::fs::OpenOptions::new().read(true).open(path) {
748                Ok(file) => Ok(file.metadata()?.len()),
749                Err(e) => Err(e),
750            },
751            BodyType::None => Ok(0),
752        }
753    }
754
755    pub(super) fn take_body_buff(&mut self) -> io::Result<LayzyBuffers> {
756        let body_size = self.take_body_size()?;
757        match self.range {
758            ResponseRangeMeta::Range(start, end) => {
759                let mut beg_pos;
760                let end_pos;
761                let mut lack_beg = false;
762                if let Some(x) = start {
763                    beg_pos = x;
764                } else {
765                    beg_pos = 0;
766                    lack_beg = true;
767                }
768                if let Some(x) = end {
769                    if lack_beg {
770                        end_pos = body_size - 1;
771                        beg_pos = body_size - x;
772                    } else {
773                        end_pos = x;
774                    }
775                } else {
776                    if lack_beg {
777                        self.write_state(416);
778                        return Err(io::Error::new(
779                            io::ErrorKind::InvalidData,
780                            "bad requested range values with form [ - ]",
781                        ));
782                    }
783                    end_pos = body_size - 1;
784                }
785                if beg_pos > end_pos || (beg_pos > (body_size - 1)) || end_pos >= body_size {
786                    self.write_state(416);
787                    return Err(io::Error::new(
788                        io::ErrorKind::InvalidData,
789                        "bad requested range values due to out of range",
790                    ));
791                }
792
793                let v = format!("bytes {}-{}/{}", beg_pos, end_pos, body_size);
794                let len = (end_pos - beg_pos + 1).to_string();
795                self.add_header(String::from("Content-Range"), v);
796                let key = "Content-Length".to_string();
797                self.remove_header(key.clone());
798
799                if !self.chunked.enable {
800                    self.add_header(key, len);
801                }
802                self.http_state = 206;
803
804                match &self.body {
805                    BodyType::Memory(_, buffs) => {
806                        let slice = &buffs[beg_pos as usize..=end_pos as usize];
807                        let mut ret_buff = Vec::new();
808                        ret_buff.extend_from_slice(slice);
809                        return Ok(LayzyBuffers {
810                            buffs: LayzyBuffersType::Memory(ret_buff),
811                            len: slice.len() as u64,
812                        });
813                    }
814                    BodyType::File(path, _) => {
815                        let mut file = std::fs::OpenOptions::new().read(true).open(path)?;
816                        let need_size = end_pos - beg_pos + 1;
817                        file.seek(std::io::SeekFrom::Start(beg_pos))?;
818                        return Ok(LayzyBuffers {
819                            buffs: LayzyBuffersType::File(FileType {
820                                file: Box::new(file),
821                                buffs: Vec::new(),
822                            }),
823                            len: need_size,
824                        });
825                    }
826                    BodyType::None => {
827                        return Ok(LayzyBuffers {
828                            buffs: LayzyBuffersType::None,
829                            len: 0,
830                        });
831                    }
832                };
833            }
834            ResponseRangeMeta::None => match &self.body {
835                BodyType::Memory(_, buffs) => {
836                    return Ok(LayzyBuffers {
837                        buffs: LayzyBuffersType::Memory(buffs.clone()),
838                        len: buffs.len() as u64,
839                    });
840                }
841                BodyType::File(path, _) => {
842                    let file = std::fs::OpenOptions::new().read(true).open(path)?;
843                    return Ok(LayzyBuffers {
844                        buffs: LayzyBuffersType::File(FileType {
845                            file: Box::new(file),
846                            buffs: Vec::new(),
847                        }),
848                        len: body_size as u64,
849                    });
850                }
851                BodyType::None => {
852                    return Ok(LayzyBuffers {
853                        buffs: LayzyBuffersType::None,
854                        len: 0,
855                    });
856                }
857            },
858        }
859    }
860
861    /// > Check whether a pair exists in the header of a reponse
862    /// # For example
863    /// > assume the header is {a:b}
864    ///
865    /// `header_exist("a")` returns true
866    /// > The key is not case senstive
867    pub fn header_exist(&self, s: &str) -> bool {
868        let r = self.header_pair.keys().find(|&k| {
869            if k.to_lowercase() == s.to_lowercase() {
870                true
871            } else {
872                false
873            }
874        });
875        match r {
876            Some(_) => true,
877            None => false,
878        }
879    }
880
881    /// > Get response header
882    /// >> - Return a Vector since a single key can correspond to multiple values in the response header.
883    pub fn get_header(&self, k: &str) -> Option<&Vec<String>> {
884        self.header_pair.get_vec(k)
885    }
886    /// > Write a utf-8 String to client
887    pub fn write_string(&mut self, v: &str) -> ResponseConfig<'_, 'a> {
888        self.add_header(String::from("Content-length"), v.len().to_string());
889        self.body = BodyType::Memory(MemoryType::String("text/plain".to_string()), v.into());
890        ResponseConfig {
891            res: self,
892            has_failure: false,
893        }
894    }
895
896    /// > Write binary data to client
897    pub fn write_binary(&mut self, v: Vec<u8>) -> ResponseConfig<'_, 'a> {
898        self.add_header(String::from("Content-length"), v.len().to_string());
899        self.body = BodyType::Memory(MemoryType::Binary, v);
900        ResponseConfig {
901            res: self,
902            has_failure: false,
903        }
904    }
905
906    /// > Only respond HTTP status to the client
907    pub fn write_state(&mut self, code: u16) {
908        self.http_state = code;
909        self.add_header(String::from("Content-length"), 0.to_string());
910        self.body = BodyType::None;
911    }
912
913    /// > Write file data to the client
914    pub fn write_file(&mut self, path: String) -> ResponseConfig<'_, 'a> {
915        match std::fs::OpenOptions::new().read(true).open(path.clone()) {
916            Ok(file) => {
917                match file.metadata() {
918                    Ok(meta) => {
919                        self.add_header(String::from("Content-length"), meta.len().to_string());
920                    }
921                    Err(_) => {
922                        self.write_string(&format!("{} cannot get file length", path))
923                            .status(404);
924                        return ResponseConfig {
925                            res: self,
926                            has_failure: true,
927                        };
928                    }
929                };
930                let extension = std::path::Path::new(&path)
931                    .extension()
932                    .and_then(OsStr::to_str);
933
934                match extension {
935                    Some(extension) => {
936                        let content_type = mime::extension_to_content_type(extension);
937                        self.body = BodyType::File(path, Some(content_type.to_string()));
938                    }
939                    None => {
940                        self.body = BodyType::File(path, None);
941                    }
942                }
943                return ResponseConfig {
944                    res: self,
945                    has_failure: false,
946                };
947            }
948            Err(_) => {
949                self.write_string(&format!("{} file not found", path))
950                    .status(404);
951                return ResponseConfig {
952                    res: self,
953                    has_failure: true,
954                };
955            }
956        }
957    }
958
959    /// > Render a view to the client
960    /// >> - factory implements Fn() -> tera::Result<String>
961    /// >>> - The factory permits you customize the behavior of the tera engine
962    pub fn render_view(
963        &mut self,
964        factory: impl Fn(&Request) -> tera::Result<String>,
965        context: &Request,
966    ) -> ResponseConfig<'_, 'a> {
967        match factory(context) {
968            Ok(s) => {
969                return self.write_string(&s);
970            }
971            Err(e) => {
972                self.write_string(&format!("Render view error: {}", e.to_string()))
973                    .status(404);
974                return ResponseConfig {
975                    res: self,
976                    has_failure: true,
977                };
978            }
979        }
980    }
981
982    /// > Only use the default configured tera to render a view to the client
983    /// >> - path: path of view file
984    /// >> - context: used in the view
985    pub fn render_view_once(&mut self, path: &str, context: &Context) -> ResponseConfig<'_, 'a> {
986        match OpenOptions::new().read(true).open(path) {
987            Ok(mut file) => {
988                let mut s = String::new();
989                match file.read_to_string(&mut s) {
990                    Ok(_) => match Tera::one_off(&s, &context, true) {
991                        Ok(s) => {
992                            self.add_header(String::from("Content-length"), s.len().to_string());
993                            let extension = std::path::Path::new(&path)
994                                .extension()
995                                .and_then(OsStr::to_str);
996
997                            match extension {
998                                Some(extension) => {
999                                    let content_type = mime::extension_to_content_type(extension);
1000                                    self.body = BodyType::Memory(
1001                                        MemoryType::String(content_type.to_string()),
1002                                        s.into(),
1003                                    );
1004                                }
1005                                None => {
1006                                    self.body = BodyType::Memory(
1007                                        MemoryType::String("text/plain".to_string()),
1008                                        s.into(),
1009                                    );
1010                                }
1011                            }
1012                            return ResponseConfig {
1013                                res: self,
1014                                has_failure: false,
1015                            };
1016                        }
1017                        Err(e) => {
1018                            self.write_string(&format!("Render view error: {}", e.to_string()))
1019                                .status(404);
1020                            return ResponseConfig {
1021                                res: self,
1022                                has_failure: true,
1023                            };
1024                        }
1025                    },
1026                    Err(e) => {
1027                        self.write_string(&format!("Render view error: {}", e.to_string()))
1028                            .status(404);
1029                        return ResponseConfig {
1030                            res: self,
1031                            has_failure: true,
1032                        };
1033                    }
1034                }
1035            }
1036            Err(e) => {
1037                self.write_string(&format!("Render view error: {}", e.to_string()))
1038                    .status(404);
1039                return ResponseConfig {
1040                    res: self,
1041                    has_failure: true,
1042                };
1043            }
1044        }
1045    }
1046
1047    pub fn get_conn(&self) -> Rc<RefCell<&'a mut TcpStream>> {
1048        Rc::clone(&self.conn_)
1049    }
1050}
1051
1052#[derive(Debug)]
1053pub enum BodyContent<'a> {
1054    UrlForm(HashMap<&'a str, &'a str>),
1055    PureText(&'a str),
1056    Multi(HashMap<String, MultipleFormData<'a>>),
1057    None,
1058    Bad,
1059    TooLarge,
1060}
1061
1062#[derive(Debug)]
1063pub struct MultipleFormFile {
1064    pub filename: String,
1065    pub filepath: String,
1066    pub content_type: String,
1067    pub form_indice: String,
1068}
1069
1070#[derive(Debug)]
1071pub enum MultipleFormData<'a> {
1072    Text(&'a str),
1073    File(MultipleFormFile),
1074}
1075
1076pub(super) struct FileType {
1077    file: Box<std::fs::File>,
1078    buffs: Vec<u8>,
1079}
1080
1081pub(super) enum LayzyBuffersType {
1082    Memory(Vec<u8>),
1083    File(FileType),
1084    None,
1085}
1086pub(super) struct LayzyBuffers {
1087    buffs: LayzyBuffersType,
1088    len: u64,
1089}
1090
1091impl LayzyBuffers {
1092    pub fn len(&self) -> usize {
1093        self.len as usize
1094    }
1095
1096    pub fn get_slice_from_range(&mut self, index: Range<usize>) -> Result<&[u8], io::Error> {
1097        match &mut self.buffs {
1098            LayzyBuffersType::Memory(buffs) => Ok(&mut buffs[index]),
1099            LayzyBuffersType::File(file_v) => {
1100                let file = &mut file_v.file;
1101                let need_size = index.end - index.start;
1102                let buffs = &mut file_v.buffs;
1103                buffs.resize(need_size, b'\0');
1104                match file.read(&mut buffs[0..]) {
1105                    Ok(read_size) => {
1106                        if read_size != need_size {
1107                            let msg = format!("cannot read enough bytes from the file, need bytes: {}, actual read bytes: {}",need_size,read_size);
1108                            return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
1109                        }
1110                        return Ok(&buffs[0..read_size]);
1111                    }
1112                    Err(e) => {
1113                        return Err(e);
1114                    }
1115                }
1116            }
1117            LayzyBuffersType::None => unreachable!(),
1118        }
1119    }
1120
1121    // pub fn get_total_slice(& mut self)-> Result<&[u8],io::Error> {
1122    //     match &mut self.buffs {
1123    //         LayzyBuffersType::Memory(buffs) => {
1124    // 			return Ok(buffs);
1125    // 		},
1126    //         LayzyBuffersType::File(file_v) => {
1127    //             let file = &mut file_v.file;
1128    //             let buffs = &mut file_v.buffs;
1129    //             match file.read_to_end(buffs){
1130    //                 Ok(_) => {
1131    // 					return Ok(buffs);
1132    // 				},
1133    //                 Err(e) => {
1134    // 					return Err(e);
1135    // 				},
1136    //             }
1137    //         }
1138    //         LayzyBuffersType::None => unreachable!(),
1139    //     }
1140    // }
1141}
1142
1143// impl Index<Range<usize>> for LayzyBuffers {
1144//     type Output = [u8];
1145
1146//     fn index(&self, _index: Range<usize>) -> &Self::Output {
1147//         unreachable!()
1148//     }
1149// }
1150
1151// impl IndexMut<Range<usize>> for LayzyBuffers {
1152//     fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
1153//         match &mut self.buffs {
1154//             LayzyBuffersType::Memory(buffs) => &mut buffs[index],
1155//             LayzyBuffersType::File(file_v) => {
1156//                 let file = &mut file_v.file;
1157//                 let need_size = index.end - index.start;
1158//                 let buffs = &mut file_v.buffs;
1159//                 buffs.resize(need_size, b'\0');
1160//                 file.read(buffs).unwrap();
1161//                 buffs
1162//             }
1163//             LayzyBuffersType::None => unreachable!(),
1164//         }
1165//     }
1166// }
1167
1168// impl Deref for LayzyBuffers {
1169//     type Target = Vec<u8>;
1170
1171//     fn deref(&self) -> &Self::Target {
1172//         unreachable!()
1173//     }
1174// }
1175
1176// impl DerefMut for LayzyBuffers {
1177//     fn deref_mut(&mut self) -> &mut Self::Target {
1178//         match &mut self.buffs {
1179//             LayzyBuffersType::Memory(buffs) => buffs,
1180//             LayzyBuffersType::File(file_v) => {
1181//                 let file = &mut file_v.file;
1182//                 let buffs = &mut file_v.buffs;
1183//                 file.read_to_end(buffs).unwrap();
1184//                 buffs
1185//             }
1186//             LayzyBuffersType::None => unreachable!(),
1187//         }
1188//     }
1189// }