getとpostを分ける
use std::fs; use std::io; use std::io::prelude::*; use std::net::{TcpListener, TcpStream}; use std::collections::HashMap; use crate::main; pub struct Router { get_routes: HashMap<String, String>, post_routes: HashMap<String, fn(String) -> String>, } impl Router { pub fn new() -> Self { Router { get_routes: HashMap::new(), post_routes: HashMap::new(), } } pub fn add_get(&mut self, path: &str, f: fn()-> Option<HashMap<&'static str, &'static str>>){ let mut content: Option<HashMap<&str, &str>> = Some(HashMap::new()); content = f(); let temp_path = format!("./templates/{}.html", path); let mut html = fs::read_to_string(temp_path).unwrap(); match content { Some(data) => { for (key, value) in data { let k = format!("{{{{ {} }}}}", key); html = html.replace(&k, value); } }, None => {}, } let route_path = format!("/{}", path); self.get_routes.insert(route_path, html); } pub fn add_post(&mut self, path: &str, handler: fn(String) -> String) { self.post_routes.insert(format!("/{}", path), handler); } pub fn up(&self, ip: &str) { let listenr = TcpListener::bind(ip).unwrap(); for stream in listenr.incoming() { match stream { Ok(stream) => { let _ = handle_connection( stream, self.get_routes.clone(), self.post_routes.clone(), ); } Err(e) => { println!("Connection failed: {}", e); } } } } } fn handle_connection(mut stream: TcpStream, get_routes: HashMap<String, String>, post_routes: HashMap<String, fn(String) -> String>) { let mut buffer = [0; 1024]; stream.read(&mut buffer).unwrap(); let request = String::from_utf8_lossy(&buffer); let request_line = request.lines().next().unwrap_or(""); let mut parts = request_line.split_whitespace(); let method = parts.next().unwrap_or(""); let path = parts.next().unwrap_or("/"); println!("Received {} request for {}", method, path); let response_body = match method { "GET" => get_routes.get(path).cloned().unwrap_or_else(|| "<h1>404 Not Found</h1>".to_string()), "POST" => { let body = request.split("\r\n\r\n").nth(1).unwrap_or("").to_string(); match post_routes.get(path) { Some(handler) => handler(body), None => "<h1>404 Not Found</h1>".to_string(), } } _ => "<h1>405 Method Not Allowed</h1>".to_string(), }; let response = http_response(200, "text/html", &response_body); stream.write_all(response.as_bytes()).unwrap(); stream.flush().unwrap(); } fn http_response(status_code: u16, content_type: &str, body: &str) -> String { format!( "HTTP/1.1 {} {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n{}", status_code, get_status_text(status_code), content_type, body.len(), body ) } fn get_status_text(code: u16) -> &'static str { match code { 200 => "OK", 404 => "Not Found", _ => "Unknown", } }
### 利用側
use std::collections::HashMap; mod ares; fn main() { let mut router = ares::Router::new(); router.add_get("index", handle_index); router.add_get("hello", handle_hello); router.add_get("world", handle_world); router.add_post("submit", handle_post); router.up("192.168.33.10:8000"); } fn handle_index() -> Option<HashMap<&'static str, &'static str>> { let mut content1 = HashMap::new(); content1.insert( "title", "index page", ); return Some(content1); } fn handle_hello() -> Option<HashMap<&'static str, &'static str>> { return None; } fn handle_world() -> Option<HashMap<&'static str, &'static str>> { return None; } fn handle_post(body: String) -> String { println!("{}", body); format!("<h1>POST 受信しました</h1><p>内容: {}</p>", body) }
ほう…