~jeffa/jeffa.io

1adae7139c3dcd7f9cb6384492a92a9b6a7918ed — Jeff a month ago 9945bac
Write homegrown http server
4 files changed, 123 insertions(+), 10 deletions(-)

M src/server/Cargo.lock
M src/server/Cargo.toml
M src/server/src/main.rs
A src/server/src/request.rs
M src/server/Cargo.lock => src/server/Cargo.lock +1 -1
@@ 1,5 1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "server"
name = "jeffaio-server"
version = "0.1.0"

M src/server/Cargo.toml => src/server/Cargo.toml +1 -2
@@ 1,7 1,6 @@
[package]
name = "server"
name = "jeffaio-server"
version = "0.1.0"
authors = ["Jeff <dev@jeffa.io>"]
edition = "2018"

[dependencies]

M src/server/src/main.rs => src/server/src/main.rs +43 -7
@@ 1,12 1,48 @@
use std::{
    thread::sleep,
    time::Duration
};
mod request;

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

fn main() {
    loop {
        println!("Ahoy, matey!");
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    let buffer = [0; 1024];

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        handle_connection(buffer, stream);
    }
}

fn handle_connection(mut buffer: [u8; 1024], mut stream: TcpStream) {
    stream.read(&mut buffer).unwrap();

    let get = b"GET / HTTP/1.1\r\n";

    if buffer.starts_with(get) {
        let contents = fs::read_to_string("hello.html").unwrap();

        let response = format!(
            "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
            contents.len(),
            contents
        );

        stream.write(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    } else {
        let status_line = "HTTP/1.1 404 NOT FOUND";
        let contents = fs::read_to_string("404.html").unwrap();

        let response = format!(
            "{}\r\nContent-Length: {}\r\n\r\n{}",
            status_line,
            contents.len(),
            contents
        );

        sleep(Duration::from_secs(10));
        stream.write(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    }
}

A src/server/src/request.rs => src/server/src/request.rs +78 -0
@@ 0,0 1,78 @@
const GET: &'static str = "GET";
const POST: &'static str = "POST";

const HTTP_1_0: &'static str = "HTTP/1.0";
const HTTP_1_1: &'static str = "HTTP/1.1";

struct Request {
    method: &'static str,
    target: String,
    version: &'static str,
}

impl Request {
    pub fn new(raw: &str) -> Result<Self, String> {
        let mut lines = raw.split("\n");

        let start_line = {
            if let Some(line) = lines.next() {
                line
            } else {
                return Err("Could not read start line of HTTP request.".to_string());
            }
        };

        let mut start_line_parts = start_line.split(" ");

        let method = {
            let method_str = {
                if let Some(method_str) = start_line_parts.next() {
                    method_str
                } else {
                    return Err("Could not read method of HTTP request.".to_string());
                }
            };

            match method_str {
                GET => GET,
                POST => POST,
                _ => return Err(format!("HTTP method \"{}\" is not recognized.", method_str)),
            }
        };

        let target = {
            if let Some(method_str) = start_line_parts.next() {
                method_str.to_string()
            } else {
                return Err("Could not read target of HTTP request.".to_string());
            }
        };

        let version = {
            let version_str = {
                if let Some(version_str) = start_line_parts.next() {
                    version_str
                } else {
                    return Err("Could not read version of HTTP request.".to_string());
                }
            };

            match version_str {
                HTTP_1_0 => HTTP_1_0,
                HTTP_1_1 => HTTP_1_1,
                _ => {
                    return Err(format!(
                        "HTTP version \"{}\" is not recognized.",
                        version_str
                    ))
                }
            }
        };

        Ok(Request {
            method,
            target,
            version,
        })
    }
}