\$\begingroup\$
\$\endgroup\$
3
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);
}
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 4, 2019 at 13:01
-
\$\begingroup\$ By mistakes, do you mean the code isn’t working and you want us to fix it or you want advice on how to make it better? If it’s the latter you should change your wording to reflect such. \$\endgroup\$Ben A– Ben A2019年05月04日 15:15:51 +00:00Commented May 4, 2019 at 15:15
-
\$\begingroup\$ @DavidWhite: It's working fine. I posted here because I want to make it better. The Codereview exists for this purpose, right? \$\endgroup\$Saeed M.– Saeed M.2019年05月04日 16:06:45 +00:00Commented May 4, 2019 at 16:06
-
\$\begingroup\$ Correct, but some could view "mistakes" as code that doesn’t work. Wording means a lot when asking a good question \$\endgroup\$Ben A– Ben A2019年05月04日 20:04:13 +00:00Commented May 4, 2019 at 20:04
lang-rust