Rustでフレームワークを自作したい

ルーティングが一つの場合、TcpListener::bindでlistenerを作ってあげれば良い
ただ、フレームワークの場合、ルーティングが複数でないと意味がない…

use std::fs;
use std::io;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};

fn main() {

   let path = "./data/index.html";
   
   let listenr = TcpListener::bind("192.168.33.10:8000").unwrap();
   println!("Listening on http://192.168.33.10:8000");

   for stream in listenr.incoming() {
      match stream {
         Ok(stream) => {
            let _ = handle_connection(stream, path);
         }
         Err(e) => {
            println!("Connection failed: {}", e);
         }
      }
   }
}

fn handle_connection(mut stream: TcpStream, path: &str) -> io::Result<()>  {
   let mut buffer = [0; 1024];
   stream.read(&mut buffer).unwrap();

   let request = String::from_utf8_lossy(&buffer);
   println!("Received request:\n{}", request);

   let header = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n";

   
   let contents = fs::read_to_string(path)?;
   println!("File contents:\n{}", contents);

   let response = format!("{}{}", header, contents);
   stream.write_all(response.as_bytes()).unwrap();
   stream.flush().unwrap();

   Ok(())
}

index.html

<p>This is framework!</p>

### ルーティングが複数の場合

use std::fs;
use std::io;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};

fn main() {

   let path = "./data/index.html";
   
   let listenr = TcpListener::bind("192.168.33.10:8000").unwrap();
   println!("Listening on http://192.168.33.10:8000");

   for stream in listenr.incoming() {
      match stream {
         Ok(stream) => {
            let _ = handle_connection(stream);
         }
         Err(e) => {
            println!("Connection failed: {}", e);
         }
      }
   }
}

fn handle_connection(mut stream: TcpStream)  {
   let mut buffer = [0; 1024];
   stream.read(&mut buffer).unwrap();

   let request = String::from_utf8_lossy(&buffer);
   println!("Received request:\n{}", request);

   let response = if request.starts_with("GET /hello ") {
      http_response(200, "text/html", "<h1>Hello from Rust!</h1>")
   } else if request.starts_with("GET / ") {
      http_response(200, "text/html", "<h1>Welcome to the Rust server!</h1>")
   } else {
      http_response(404, "text/html", "<h1>404 Not Found</h1>")
   };
   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",
   }
}

ルートとコンテンツをhashmapにした場合

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("");
   println!("Received request:\n{}", request);

   let mut routes = HashMap::new();
   routes.insert (
      "/hello",
      "<h1>Hello from Rust!</h1>",
   );

   routes.insert (
      "/",
      "<h1>Welcome to the Rust server!</h1>",
   );

   let path = request_line
        .split_whitespace()
        .nth(1)
        .unwrap_or("/");
   
   let response_body = routes.get(path)
        .cloned()
        .unwrap_or_else(|| "<h1>404 Not Found</h1>");

   let response = http_response(200, "text/html", &response_body);