czh_http_server/
lib.rs

1//!
2//! # czh_http_server
3//!
4//! czh_http_server is a simple http server
5//! # Example
6//! ```
7//! let mut server  = HttpServer::create_server("localhost", 3000);
8//!    // server.listen();
9//!    server.filter("/home",|req,res| {
10//!        println!("{:#?}","hello i am filterb");
11//!        if req.url() == "/home/abc" {
12//!            res.json("GLALALALALALA");
13//!            return None
14//!        }
15//!        Some((req,res))
16//!    });
17//!    server.map("/file","/Users/dadigua/Desktop/lifetime/app/nextjs-static/dist");
18//!
19//!    server.get("/home",|req,mut res| {
20//!        println!("{:#?}",req.url());
21//!        // println!("{:#?}",req.headers());
22//!        println!("{:#?}",req.cookies());
23//!        res.set_cookie("cooooooo", "this is cookie setted by server");
24//!        res.json("hello fetch");
25//!    });
26//!    server.get("/home/abc",|req,res| {
27//!        println!("{:#?}",req.url());
28//!        res.json("hello fetch/ home/abc");
29//!    });
30//!    
31//!    server.post("/post",|mut req,res| {
32//!        match req.json::<Student>() {
33//!            Ok(stu) => {
34//!                println!("{:#?}",stu);
35//!            },
36//!            Err(_) => {
37//!                res.json("error parse json");
38//!                return;
39//!            },
40//!        }
41//!        println!("{:#?}",req.url());
42//!        res.json("hello post");
43//!    });
44//!
45//!    let mut route = Route::new();
46//!
47//!    route.get("/sayhello", |req, res| {
48//!        // req.url()
49//!        println!("{:#?}",req.url());
50//!        res.json(Student{
51//!            name:"dadigua".to_string(),
52//!            age:18
53//!        });
54//!    });
55//!
56//!    server.router("/route",route);
57//!    server.listen();
58//! ```
59//!
60use std::{
61    cell::RefCell, fs::File, mem, net::{TcpListener, TcpStream}, path::{Path, PathBuf}, rc::Rc, sync::Arc
62};
63
64use controller::Controller;
65use filter::{Filter, FilterChain};
66use request::HttpRequest;
67use response::{ContentType, HttpResponse};
68mod controller;
69pub mod request;
70pub mod response;
71pub mod route;
72pub mod filter;
73type ControllerHandler = Box<dyn Fn(HttpRequest, HttpResponse) + Sync + Send + 'static>;
74pub trait HttpHander {
75    fn get<T>(&mut self, url: &str, controller: T)
76    where
77        T: Fn(HttpRequest, HttpResponse) + Sync + Send + 'static;
78
79    fn post<T>(&mut self, url: &str, controller: T)
80    where
81        T: Fn(HttpRequest, HttpResponse) + Sync + Send + 'static;
82    fn router(&mut self, url: &str, route: route::Route);
83}
84
85
86///
87/// # HttpServer
88/// used to create a HTTP_SERVER
89/// 
90/// # Example
91/// ```
92/// let mut server  = HttpServer::create_server("localhost", 3000);
93/// server.get("/hello",|req,mut res| {
94///     println!("{:#?}","hello i am filterb");
95///     res.json("hello fetch");    
96/// })
97/// server.listen();
98/// ```
99pub struct HttpServer {
100    listener: TcpListener,
101    // port: u16,
102    controller: Option<Controller>,
103    filter_chain:FilterChain
104}
105impl HttpServer {
106    pub fn create_server(host: &str, port: u16) -> Self {
107        let listener = TcpListener::bind(format!("{}:{}", host, port)).unwrap();
108        HttpServer {
109            listener,
110            controller: Some(Controller::new()),
111            filter_chain: FilterChain::new()
112        }
113    }
114    /// start listen request
115    /// 
116    /// # Example
117    /// ```
118    ///  let mut server  = HttpServer::create_server("localhost", 3000);
119    ///  server.listen();
120    /// ```
121    pub fn listen(mut self) {
122        let controller = Arc::new(self.controller.take().unwrap());
123        let filter  = Arc::new(self.filter_chain);
124        let pool = czhmt::ThreadPool::new(4);
125        for client in self.listener.incoming() {
126            print!("hello");
127            match client {
128                Ok(stream) => {
129                    let controller = controller.clone();
130                    let filter = filter.clone();
131                    pool.exec(|| {
132                        handle_stream(stream, controller,filter);
133                    });
134                }
135                Err(_) => {
136                    println!("Something wrong!")
137                }
138            }
139        }
140    }
141
142    ///
143    /// url prefix
144    /// absolute path
145    /// say
146    /// `
147    /// map("/path","/file")
148    /// `
149    /// the url /path/a would be mapped to /file/a which is a fs path
150    pub fn map(&mut self, url: &str, path: &str) {
151        let path = path.to_string();
152        self.controller
153            .as_mut()
154            .unwrap()
155            .add_static_handler(url, move |req, res| {
156                // println!("map {:#?} to ",url,path);
157                println!("map {} to {:#?}", req.url(), path);
158                let root = PathBuf::from(path.as_str());
159                let mut start = 1;
160                loop {
161                    if start >= req.url().len() {
162                        break;
163                    }
164                    if req.url().as_bytes()[start] == b'/' {
165                        start += 1;
166                        break;
167                    }
168                    start += 1;
169                }
170                let mut path = root.join(req.url()[start..].to_string());
171                println!("{:#?}", path);
172                if let Ok(file) = File::open(&path) {
173                    if file.metadata().unwrap().is_dir() {
174                        path.push("index.html");
175                        if let Ok(file) = File::open(&path) {
176                            let filename = path.file_name().as_ref().unwrap().to_str().unwrap();
177                            let ext = Path::new(filename).extension().unwrap().to_str().unwrap();
178                            res.file(file, ContentType::from(ext));
179                        } else {
180                            res.json("no such file");
181                        }
182                    } else {
183                        let filename = path.file_name().as_ref().unwrap().to_str().unwrap();
184                        let ext = Path::new(filename).extension().unwrap().to_str().unwrap();
185                        res.file(file, ContentType::from(ext));
186                    }
187                } else {
188                    res.json("no such file");
189                }
190            });
191    }
192    
193    pub fn filter(&mut self, url: &str, filter: impl Fn(HttpRequest,HttpResponse) -> Option<(HttpRequest,HttpResponse)> + Send + Sync + 'static) {
194        self.filter_chain.add_filter(Filter::new(filter),url);
195    }
196
197}
198
199impl HttpHander for HttpServer {
200    fn post<T>(&mut self, url: &str, controller: T)
201    where
202        T: Fn(HttpRequest, HttpResponse) + Sync + Send + 'static,
203    {
204        self.controller
205            .as_mut()
206            .unwrap()
207            .add_handler("POST", url, Box::new(controller));
208    }
209    fn get<T>(&mut self, url: &str, controller: T)
210    where
211        T: Fn(HttpRequest, HttpResponse) + Sync + Send + 'static,
212    {
213        self.controller
214            .as_mut()
215            .unwrap()
216            .add_handler("GET", url, Box::new(controller));
217    }
218    fn router(&mut self, url: &str, route: route::Route) {
219        let self_controller = self.controller.as_mut().unwrap();
220        let controller = route.get_controller();
221        let mut handlers: std::collections::HashMap<String, std::collections::HashMap<String, Box<dyn Fn(HttpRequest, HttpResponse) + Send + Sync>>> = controller.take();
222        let methods = handlers.keys().map(|key| key.to_string()).collect::<Vec<String>>();
223        for method in methods{
224            let mut handers_inner = handlers.remove(method.as_str()).unwrap();
225            let url_inner = handers_inner.keys().map(|key| key.to_string()).collect::<Vec<String>>();
226            for handler_inner in url_inner {
227                let handler: Box<dyn Fn(HttpRequest, HttpResponse) + Send + Sync> = handers_inner.remove(handler_inner.as_str()).unwrap();
228                self_controller.add_handler(method.as_str(), format!("{}{}",url,handler_inner).as_str(), handler);
229            }
230        }
231    }
232}
233pub fn handle_stream(stream: TcpStream, controller: Arc<Controller>,filter:Arc<FilterChain>) {
234    let rc = Rc::new(RefCell::new(stream));
235    let request = match HttpRequest::build(rc.clone()) {
236        Ok(req) => req,
237        Err(e) => {
238            println!("Error: {}", e);
239            let response = HttpResponse::init(rc.clone(), "HTTP/1.1");
240            controller.handle_not_found(response);
241            return;
242        }
243    };
244    let response = HttpResponse::init(rc.clone(), request.version());
245    if let Some((request, response)) = filter.exec(request, response)  {
246        controller.handle_request(request, response);
247    }else {
248
249    }
250
251    
252}