httpageboy/
server_base.rs1use std::collections::HashMap;
2use std::io::prelude::Write;
3use std::net::{TcpListener, TcpStream};
4use std::sync::{Arc, Mutex};
5
6pub use crate::threadpool::ThreadPool;
7pub use crate::request_type::Rt;
8pub use crate::request_handler::Rh;
9use crate::request::{ Request, stream_to_request, handle_request};
10use crate::response::Response;
11use crate::utils::absolutize_path;
12
13
14pub struct ServerBase {
15 listener: TcpListener,
16 pool: Arc<Mutex<ThreadPool>>,
17 routes: HashMap<String, Rh>,
18 files_sources: Vec<String>
19}
20
21impl ServerBase {
22 pub fn new(
23 serving_url: &str,
24 pool_size: u8,
25 routes_list: Option<HashMap<String, Rh>>)
26 -> Result<ServerBase, std::io::Error>{
27 let listener = TcpListener::bind(serving_url)?;
28 let pool = Arc::new(Mutex::new(ThreadPool::new(pool_size as usize)));
29 let routes: HashMap<String, Rh>;
30
31 if let Some(routes_list) = routes_list {
32 routes = routes_list;
33 }
34 else {
35 routes = HashMap::new();
36 }
37
38 return Ok(ServerBase {
39 listener,
40 routes,
41 pool,
42 files_sources: Vec::new()
43 });
44 }
45
46 pub fn add_route(&mut self, path: &str, rt: Rt, rh: fn(&Request) -> Response) {
47 let key = format!("{}|{}", path, rt.to_string());
48 let handler = Rh { handler: rh};
49 self.routes.insert(key, handler);
50 }
51
52 pub fn add_files_source(&mut self, path: String) {
53 let local_path = absolutize_path(&path);
54 self.files_sources.push(local_path);
55 }
56
57 pub fn run (&self) {
58 for stream in self.listener.incoming(){
59 match stream {
60 Ok(stream) => {
61 let routes_local = self.routes.clone();
62 let sources_local = self.files_sources.clone();
63 let pool = Arc::clone(&self.pool);
64 pool.lock().unwrap().run(move || {
65 let request: Request = stream_to_request(&stream);
66 let answer: Option<Response> = handle_request(&request, &routes_local, &sources_local);
67 match answer {
68 Some(response) => {
69 send_response(stream, &response);
70 }
71 None => {
72 send_response(stream, &Response::new());
73 }
74 }
75 });
76 }
77 Err(err) => {
78 println!("Error: {}", err);
79 }
80 }
81 }
82 }
83
84 pub fn stop(&self) {
85 let mut pool = self.pool.lock().unwrap();
86 println!("server_base stop");
87 pool.stop();
88 }
89}
90
91fn send_response(mut stream: TcpStream, response: &Response) {
92 let header = format!(
93 "HTTP/1.1 {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n",
94 response.status,
95 response.content_type,
96 response.content.len()
97 );
98 stream.write(header.as_bytes()).unwrap();
99 if response.content_type.starts_with("image/") {
100 stream.write(&response.content).unwrap();
101 }
102 else {
103 stream.write(String::from_utf8_lossy(&response.content).as_bytes()).unwrap();
104 }
105 stream.flush().unwrap();
106}