Created
August 17, 2018 18:37
-
-
Save v-stickykeys/1c96b27ab618d3d593fda393f509468b to your computer and use it in GitHub Desktop.
Single threaded Rust server from the Rust Programming Language 2018 book
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io::prelude::*; // Traits that let us read and write to the stream | |
use std::net::TcpStream; | |
use std::net::TcpListener; | |
use std::fs; // Bring standard library File into scope | |
fn main() { | |
// bind returns a new TcpListener instances | |
// Connecting to a port to listen to is also called "binding to a port" | |
// bind returns a Result<T, E> | |
// unwrap will stop the program if errors occur | |
let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); | |
// Nonadministrators can only listen on ports higher than 1024 | |
// incoming returns an iterator that gives a sequence of TcpStream type streams | |
// A single stream represents an open connection between client and server | |
// A connection is the full request and response process where a client connects to the server, | |
// the server generates a response, and the server closes the connection. | |
// Here we are iterating over connection attempts, not actual connections. | |
for stream in listener.incoming() { | |
// TcpStream instance keeps track of what data it returns to us internally. This means that | |
// it might read mroe data than we asked for and save that data for the next time we ask. | |
let stream = stream.unwrap(); | |
handle_connection(stream); | |
} | |
} | |
fn handle_connection(mut stream: TcpStream) { | |
// Declare buffer on the stack to hold the data that is read in | |
let mut buffer = [0; 512]; // 512 bytes | |
// Read bytes from the TcpStream and put them into the buffer | |
stream.read(&mut buffer).unwrap(); | |
// Transform the variable into a byte string | |
let get = b"GET / HTTP/1.1\r\n"; | |
// Return values in a tuple | |
// Destructuring assigns values using a pattern in the let statement | |
let (status_line, filename) = if buffer.starts_with(get) { | |
("HTTP/1.1 200 Ok\r\n\r\n", "public/index.html") | |
} else { | |
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "public/404.html") | |
}; | |
let contents = fs::read_to_string(filename).unwrap(); | |
let response = format!("{}{}", status_line, contents); | |
// The write method on stream takes a &[u8] and sends those bytes directly down the | |
// connection | |
stream.write(response.as_bytes()).unwrap(); | |
// Flush waits and prevents the program from continuing until all the bytes are written to | |
// the connection. | |
// The TcpStream type contains an internal buffer to minimize calls tot he underlying OS. | |
stream.flush().unwrap(); | |
// Convert bytes in buffer to a string to print it | |
// Lossy means invalid UTF-8 sequences are replaced with the replacement character U+FFFD | |
// Replacement characters will be in the buffer for characters that aren't filled by request | |
// data | |
// println!("Request: {}", String::from_utf8_lossy(&buffer[..])); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment