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)
}
ほう…