lava_http/server/
server.rs1use std::{
2 net::{
3 TcpListener,
4 TcpStream
5 },
6 io::{
7 Read,
8 Write, SeekFrom
9 },
10 fmt::format, string
11};
12
13use crate::{
14 request::parse::parse_request_header,
15 request::req::Request,
16 server::route::Route,
17 response::res::Response
18};
19
20use crate::server::servefile::send_static_file;
21
22pub struct Server{
23 pub host: &'static str,
24 pub port: i32,
25 pub routes: Vec<Route>
26}
27
28impl Server{
29 fn bind(&self) -> TcpListener{
30
31 let (
32 port_min,
33 port_max
34 ) = (1023, 65535);
35
36 if self.port < port_min || self.port > port_max{
37 panic!("Invalid port");
38 }
39
40 let addr: String = format!(
41 "{}:{}", self.host, self.port
42 );
43
44 let bind: TcpListener = TcpListener::bind(
45 addr
46 ).expect(
47 "Error binding socket"
48 );
49
50 const VOLCANO_EMOJI: char = '\u{1F30B}';
51 println!("\r\n\r\nThe volcano is live on port {}! {VOLCANO_EMOJI} {VOLCANO_EMOJI} {VOLCANO_EMOJI}\r\n\r\n", self.port);
52
53 return bind;
54 }
55
56 pub fn erupt(&self){
67 let listener: TcpListener = self.bind();
68
69 loop {
70 let mut stream: TcpStream;
71
72 match listener.accept(){
73 Ok(conn) => {
74 stream = conn.0;
75 }
76 Err(err) => { panic!("{}", err) }
77 };
78
79 let request: Request = parse_request_header(
80 read_connection(&stream)
81 );
82
83 let mut res: Response = Response {
84 status: (200),
85 body: (String::from("")),
86 headers: (String::from(""))
87 };
88
89 if request.path.ends_with(".css") || request.path.ends_with(".js"){
90 res = send_static_file(request.path);
91 }
92 else{
93 res = handle_connection(request, &self.routes);
94 }
95
96 let response_header: String = format!(
97 "HTTP/1.1 {}\r\n{}\r\n\r\n{}",
98 res.get_status(),
99 res.get_header(),
100 res.get_body()
101 );
102
103 match stream.write_all(response_header.as_bytes()){
104 Ok(_) => {}
105 Err(err) => { panic!("{}", err) }
106 }
107
108 match stream.flush(){
109 Ok(_) => {}
110 Err(err) => { panic!("{}", err) }
111 }
112 }
113 }
114}
115
116fn read_connection(mut stream: &TcpStream) -> String{
117 const BUFFER_SIZE: usize = 4096;
118 let mut buffer: [u8; 4096] = [0; BUFFER_SIZE];
119
120 let mut data: Vec<u8> = vec![];
121
122 loop{
123
124 let bytes_read: usize = stream.read(&mut buffer).unwrap();
125
126 data.extend_from_slice(&buffer[..bytes_read]);
127
128 if bytes_read < BUFFER_SIZE{
129 break;
130 }
131 }
132
133 let request_header: String = String::from(
134 core::str::from_utf8(&data).unwrap()
135 );
136
137 return request_header;
138}
139
140fn handle_connection(
141 req: Request,
142 routes: &Vec<Route>
143) -> Response{
144
145 let mut res: Response = Response{
146 status: 200,
147 body: String::from(""),
148 headers: String::from("")
149 };
150
151 for route in routes{
152 if req.path != route.path{
153 continue;
154 }
155 else if req.method != route.method{
156 continue;
157 }
158 res = route.get_func()(res, &req);
159 }
160
161 return res;
162}
163
164