Skip to content

Instantly share code, notes, and snippets.

@v-stickykeys
Created August 17, 2018 18:37
Show Gist options
  • Save v-stickykeys/1c96b27ab618d3d593fda393f509468b to your computer and use it in GitHub Desktop.
Save v-stickykeys/1c96b27ab618d3d593fda393f509468b to your computer and use it in GitHub Desktop.
Single threaded Rust server from the Rust Programming Language 2018 book
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