After my last attempt, I started to learn Rust again. This time I wrote a simple HTTP router. I would appreciate it if you could help me to fix my mistakes.
Here is the link of the repository
main.rs
fn main() {
let mut router = Router::new();
router.get("/home", home);
Server::new(router).run("127.0.0.1:8989");
}
fn home(req: request::Request) -> Response {
let res = format!("Welcome Home: {}", req.get("name"));
Response::html(String::from(res), 200)
}
src/router.rs
pub type Handler = fn(Request) -> Response;
pub struct Route {
pub pattern: String,
pub method: String,
pub callback: Handler,
}
pub struct Router {
pub routes: Vec<Route>,
}
impl Router {
pub fn new() -> Router {
Router {
routes: Vec::new(),
}
}
fn route(&mut self, method: &str, pattern: &str, f: Handler) {
let r = Route{method: String::from(method), pattern: String::from(pattern), callback: f} ;
self.routes.push(r);
}
pub fn get(&mut self, pattern: &str, f: Handler) {
self.route(Method::GET, pattern, f)
}
pub fn post(&mut self, pattern: &str, f: Handler) {
self.route(Method::POST, pattern, f)
}
}
src/request.rs
pub mod method{
pub const GET: &str = "GET";
pub const POST: &str = "POST";
}
pub struct Request {
path: String,
method: String,
params: HashMap<String, String>,
}
impl Request {
pub fn parse(stream:&mut TcpStream) -> Request {
let mut lines = String::new();
let mut reader = BufReader::new(stream);
let _ = reader.read_line(&mut lines);
let mut line = lines.split_whitespace();
let method = match line.nth(0) {
Some(e) => e,
None => "GET",
};
let path = match line.nth(0) {
Some(e) => e,
None => "/",
};
let parts = Request::parse_path(path);
let req_path = parts[0];
let query_string = match parts.get(1).or(None) {
Some(q) => {
let tags: HashMap<String, String> = q.split('&')
.map(|kv| kv.split('=').collect::<Vec<&str>>())
.map(|vec| {
assert_eq!(vec.len(), 2);
(vec[0].to_string(), vec[1].to_string())
})
.collect();
tags
},
None => HashMap::new(),
};
Request {
method: method.to_string(),
path: req_path.to_string(),
params: query_string,
}
}
fn parse_path(line: &str) -> Vec<&str> {
let parts: Vec<&str> = line.split("?").collect();
parts
}
pub fn get(&self, key: &str) -> &str {
match self.params.get(key) {
Some(e) => e,
None => "",
}
}
pub fn method(&self) -> String {
self.method.to_string()
}
pub fn path(&self) -> String {
self.path.to_string()
}
}
src/response.rs
pub struct Server {
router: Router,
}
impl Server {
pub fn new(router: Router) -> Server {
Server{ router: router}
}
pub fn run(&self, addr: &str) {
let listener = TcpListener::bind(addr).unwrap();
println!("Listening to {}", addr);
for stream in listener.incoming() {
self.handle(&mut stream.unwrap());
}
}
fn handle(&self, stream: &mut TcpStream) {
let req = Request::parse(stream);
for r in &self.router.routes {
if r.method == req.method() && r.pattern == req.path() {
self.dispatch(stream, r.callback, req);
break;
}
}
}
fn dispatch(&self, stream:&mut TcpStream, handler: Handler, req: Request) {
let response = (handler)(req);
response.result(stream);
}
}