<commit_before>//
// zhtta.rs
//
// Starting code for PS3
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.5

// To see debug! outputs set the RUST_LOG environment variable, e.g.: export RUST_LOG="zhtta=debug"

#[feature(globs)];
extern mod extra;

use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{os, str, libc, from_str};
use std::path::Path;
use std::hashmap::HashMap;

use extra::getopts;
use extra::arc::MutexArc;

static SERVER_NAME : &'static str = "Zhtta Version 0.5";

static IP : &'static str = "127.0.0.1";
static PORT : uint = 4414;
static WWW_DIR : &'static str = "./www";

static HTTP_OK : &'static str = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
static HTTP_BAD : &'static str = "HTTP/1.1 404 Not Found\r\n\r\n";

static COUNTER_STYLE : &'static str = "<doctype !html><title>Hello, Rust!</title>

             ";

static mut visitor_count : uint = 0;

struct HTTP_Request {
    // Use peer_name as the key to access TcpStream in hashmap.

    // (Due to a bug in extra::arc in Rust 0.9, it is very inconvenient to use TcpStream without the "Freeze" bound.
    //  See issue: https://github.com/mozilla/rust/issues/12139)
    peer_name: ~str,
    path: ~Path,
}

struct WebServer {
    ip: ~str,
    port: uint,
    www_dir_path: ~Path,

    request_queue_arc: MutexArc<~[HTTP_Request]>,
    stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>,

    notify_port: Port<()>,
    shared_notify_chan: SharedChan<()>,
}

impl WebServer {
    fn new(ip: &str, port: uint, www_dir: &str) -> WebServer {
        let (notify_port, shared_notify_chan) = SharedChan::new();
        let www_dir_path = ~Path::new(www_dir);
        os::change_dir(www_dir_path.clone());

        WebServer {
            ip: ip.to_owned(),
            port: port,
            www_dir_path: www_dir_path,

            request_queue_arc: MutexArc::new(~[]),
            stream_map_arc: MutexArc::new(HashMap::new()),

            notify_port: notify_port,
            shared_notify_chan: shared_notify_chan,
        }
    }

    fn run(&mut self) {
        self.listen();
        self.dequeue_static_file_request();
    }

    fn listen(&mut self) {
        let addr = from_str::<SocketAddr>(format!("{:s}:{:u}", self.ip, self.port)).expect("Address error.");
        let www_dir_path_str = self.www_dir_path.as_str().expect("invalid www path?").to_owned();

        let request_queue_arc = self.request_queue_arc.clone();
        let shared_notify_chan = self.shared_notify_chan.clone();
        let stream_map_arc = self.stream_map_arc.clone();

        spawn(proc() {
            let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
            println!("{:s} listening on {:s} (serving from: {:s}).",
                     SERVER_NAME, addr.to_str(), www_dir_path_str);

            for stream in acceptor.incoming() {
                let (queue_port, queue_chan) = Chan::new();
                queue_chan.send(request_queue_arc.clone());

                let notify_chan = shared_notify_chan.clone();
                let stream_map_arc = stream_map_arc.clone();

                // Spawn a task to handle the connection.
                spawn(proc() {
                    unsafe { visitor_count += 1; } // TODO: Fix unsafe counter
                    let request_queue_arc = queue_port.recv();

                    let mut stream = stream;

                    let peer_name = WebServer::get_peer_name(&mut stream);

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);
                    debug!("Request:\n{:s}", request_str);

                    let req_group : ~[&str]= request_str.splitn(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path_str = "." + req_group[1].to_owned();

                        let mut path_obj = ~os::getcwd();
                        path_obj.push(path_str.clone());

                        let ext_str = match path_obj.extension_str() {
                            Some(e) => e,
                            None => "",
                        };

                        debug!("Requested path: [{:s}]", path_obj.as_str().expect("error"));
                        debug!("Requested path: [{:s}]", path_str);

                        if path_str == ~"./" {
                            debug!("===== Counter Page request =====");
                            WebServer::respond_with_counter_page(stream);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if !path_obj.exists() || path_obj.is_dir() {
                            debug!("===== Error page request =====");
                            WebServer::respond_with_error_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if ext_str == "shtml" { // Dynamic web pages.
                            debug!("===== Dynamic Page request =====");
                            WebServer::respond_with_dynamic_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else {
                            debug!("===== Static Page request =====");
                            WebServer::enqueue_static_file_request(stream, path_obj, stream_map_arc, request_queue_arc, notify_chan);
                        }
                    }
                });
            }
        });
    }

    fn respond_with_error_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let msg: ~str = format!("Cannot open: {:s}", path.as_str().expect("invalid path").to_owned());

        stream.write(HTTP_BAD.as_bytes());
        stream.write(msg.as_bytes());
    }

    // TODO: Safe visitor counter.
    fn respond_with_counter_page(stream: Option<std::io::net::tcp::TcpStream>) {
        let mut stream = stream;
        let response: ~str =
            format!("{:s}{:s}
Greetings, Krusty!

Visitor count: {:u}
\r\n",
                    HTTP_OK, COUNTER_STYLE,
                    unsafe { visitor_count } );
        debug!("Responding to counter request");
        stream.write(response.as_bytes());
    }

    // TODO: Streaming file.
    // TODO: Application-layer file caching.
    fn respond_with_static_file(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let mut file_reader = File::open(path).expect("Invalid file!");
        stream.write(HTTP_OK.as_bytes());
        stream.write(file_reader.read_to_end());
    }

    // TODO: Server-side gashing.
    fn respond_with_dynamic_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        // for now, just serve as static file
        WebServer::respond_with_static_file(stream, path);
    }

    // TODO: Smarter Scheduling.
    fn enqueue_static_file_request(stream: Option<std::io::net::tcp::TcpStream>, path_obj: &Path, stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>, req_queue_arc: MutexArc<~[HTTP_Request]>, notify_chan: SharedChan<()>) {
        // Save stream in hashmap for later response.
        let mut stream = stream;
        let peer_name = WebServer::get_peer_name(&mut stream);
        let (stream_port, stream_chan) = Chan::new();
        stream_chan.send(stream);
        unsafe {
            // Use an unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            stream_map_arc.unsafe_access(|local_stream_map| {
                let stream = stream_port.recv();
                local_stream_map.swap(peer_name.clone(), stream);
            });
        }

        // Enqueue the HTTP request.
        let req = HTTP_Request { peer_name: peer_name.clone(), path: ~path_obj.clone() };
        let (req_port, req_chan) = Chan::new();
        req_chan.send(req);

        debug!("Waiting for queue mutex lock.");
        req_queue_arc.access(|local_req_queue| {
            debug!("Got queue mutex lock.");
            let req: HTTP_Request = req_port.recv();
            local_req_queue.push(req);
            debug!("A new request enqueued, now the length of queue is {:u}.", local_req_queue.len());
        });

        notify_chan.send(()); // Send incoming notification to responder task.

    }

    // TODO: Smarter Scheduling.
    fn dequeue_static_file_request(&mut self) {
        let req_queue_get = self.request_queue_arc.clone();
        let stream_map_get = self.stream_map_arc.clone();

        // Port<> cannot be sent to another task. So we have to make this task as the main task that can access self.notify_port.

        let (request_port, request_chan) = Chan::new();
        loop {
            self.notify_port.recv();    // waiting for new request enqueued.

            req_queue_get.access( |req_queue| {
                match req_queue.shift_opt() { // FIFO queue.
                    None => { /* do nothing */ }
                    Some(req) => {
                        request_chan.send(req);
                        debug!("A new request dequeued, now the length of queue is {:u}.", req_queue.len());
                    }
                }
            });

            let request = request_port.recv();

            // Get stream from hashmap.
            // Use unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            let (stream_port, stream_chan) = Chan::new();
            unsafe {
                stream_map_get.unsafe_access(|local_stream_map| {
                    let stream = local_stream_map.pop(&request.peer_name).expect("no option tcpstream");
                    stream_chan.send(stream);
                });
            }

            // TODO: Spawning more tasks to respond the dequeued requests concurrently. You may need a semophore to control the concurrency.
            let stream = stream_port.recv();
            WebServer::respond_with_static_file(stream, request.path);
            // Close stream automatically.
            debug!("=====Terminated connection from [{:s}].=====", request.peer_name);
        }
    }

    fn get_peer_name(stream: &mut Option<std::io::net::tcp::TcpStream>) -> ~str {
        match *stream {
            Some(ref mut s) => {
                         match s.peer_name() {
                            Some(pn) => {pn.to_str()},
                            None => (~"")
                         }
                       },
            None => (~"")
        }
    }
}

fn get_args() -> (~str, uint, ~str) {
    fn print_usage(program: &str) {
        println!("Usage: {:s} [options]", program);
        println!("--ip     \tIP address, \"{:s}\" by default.", IP);
        println!("--port   \tport number, \"{:u}\" by default.", PORT);
        println!("--www    \tworking directory, \"{:s}\" by default", WWW_DIR);
        println("-h --help \tUsage");
    }

    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        getopts::optopt("ip"),
        getopts::optopt("port"),
        getopts::optopt("www"),
        getopts::optflag("h"),
        getopts::optflag("help")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage(program);
        unsafe { libc::exit(1); }
    }

    let ip_str = if matches.opt_present("ip") {
                    matches.opt_str("ip").expect("invalid ip address?").to_owned()
                 } else {
                    IP.to_owned()
                 };

    let port:uint = if matches.opt_present("port") {
                        from_str::from_str(matches.opt_str("port").expect("invalid port number?")).expect("not uint?")
                    } else {
                        PORT
                    };

    let www_dir_str = if matches.opt_present("www") {
                        matches.opt_str("www").expect("invalid www argument?")
                      } else { WWW_DIR.to_owned() };

    (ip_str, port, www_dir_str)
}

fn main() {
    let (ip_str, port, www_dir_str) = get_args();
    let mut zhtta = WebServer::new(ip_str, port, www_dir_str);
    zhtta.run();
}
<commit_msg>Fixed tabbing<commit_after>//
// zhtta.rs
//
// Starting code for PS3
// Running on Rust 0.9
//
// Note that this code has serious security risks!	You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.5

// To see debug! outputs set the RUST_LOG environment variable, e.g.: export RUST_LOG="zhtta=debug"

#[feature(globs)];
extern mod extra;

use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{os, str, libc, from_str};
use std::path::Path;
use std::hashmap::HashMap;

use extra::getopts;
use extra::arc::MutexArc;

static SERVER_NAME : &'static str = "Zhtta Version 0.5";

static IP : &'static str = "127.0.0.1";
static PORT : uint = 4414;
static WWW_DIR : &'static str = "./www";

static HTTP_OK : &'static str = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
static HTTP_BAD : &'static str = "HTTP/1.1 404 Not Found\r\n\r\n";

static COUNTER_STYLE : &'static str = "<doctype !html><title>Hello, Rust!</title>

			 ";

static mut visitor_count : uint = 0;

struct HTTP_Request {
	// Use peer_name as the key to access TcpStream in hashmap.

	// (Due to a bug in extra::arc in Rust 0.9, it is very inconvenient to use TcpStream without the "Freeze" bound.
	//	See issue: https://github.com/mozilla/rust/issues/12139)
	peer_name: ~str,
	path: ~Path,
}

struct WebServer {
	ip: ~str,
	port: uint,
	www_dir_path: ~Path,

	request_queue_arc: MutexArc<~[HTTP_Request]>,
	stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>,

	notify_port: Port<()>,
	shared_notify_chan: SharedChan<()>,
}

impl WebServer {
	fn new(ip: &str, port: uint, www_dir: &str) -> WebServer {
		let (notify_port, shared_notify_chan) = SharedChan::new();
		let www_dir_path = ~Path::new(www_dir);
		os::change_dir(www_dir_path.clone());

		WebServer {
			ip: ip.to_owned(),
			port: port,
			www_dir_path: www_dir_path,

			request_queue_arc: MutexArc::new(~[]),
			stream_map_arc: MutexArc::new(HashMap::new()),

			notify_port: notify_port,
			shared_notify_chan: shared_notify_chan,
		}
	}

	fn run(&mut self) {
		self.listen();
		self.dequeue_static_file_request();
	}

	fn listen(&mut self) {
		let addr = from_str::<SocketAddr>(format!("{:s}:{:u}", self.ip, self.port)).expect("Address error.");
		let www_dir_path_str = self.www_dir_path.as_str().expect("invalid www path?").to_owned();

		let request_queue_arc = self.request_queue_arc.clone();
		let shared_notify_chan = self.shared_notify_chan.clone();
		let stream_map_arc = self.stream_map_arc.clone();

		spawn(proc() {
			let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
			println!("{:s} listening on {:s} (serving from: {:s}).",
					 SERVER_NAME, addr.to_str(), www_dir_path_str);

			for stream in acceptor.incoming() {
				let (queue_port, queue_chan) = Chan::new();
				queue_chan.send(request_queue_arc.clone());

				let notify_chan = shared_notify_chan.clone();
				let stream_map_arc = stream_map_arc.clone();

				// Spawn a task to handle the connection.
				spawn(proc() {
					unsafe { visitor_count += 1; } // TODO: Fix unsafe counter
					let request_queue_arc = queue_port.recv();

					let mut stream = stream;

					let peer_name = WebServer::get_peer_name(&mut stream);

					let mut buf = [0, ..500];
					stream.read(buf);
					let request_str = str::from_utf8(buf);
					debug!("Request:\n{:s}", request_str);

					let req_group : ~[&str]= request_str.splitn(' ', 3).collect();
					if req_group.len() > 2 {
						let path_str = "." + req_group[1].to_owned();

						let mut path_obj = ~os::getcwd();
						path_obj.push(path_str.clone());

						let ext_str = match path_obj.extension_str() {
							Some(e) => e,
							None => "",
						};

						debug!("Requested path: [{:s}]", path_obj.as_str().expect("error"));
						debug!("Requested path: [{:s}]", path_str);

						if path_str == ~"./" {
							debug!("===== Counter Page request =====");
							WebServer::respond_with_counter_page(stream);
							debug!("=====Terminated connection from [{:s}].=====", peer_name);
						} else if !path_obj.exists() || path_obj.is_dir() {
							debug!("===== Error page request =====");
							WebServer::respond_with_error_page(stream, path_obj);
							debug!("=====Terminated connection from [{:s}].=====", peer_name);
						} else if ext_str == "shtml" { // Dynamic web pages.
							debug!("===== Dynamic Page request =====");
							WebServer::respond_with_dynamic_page(stream, path_obj);
							debug!("=====Terminated connection from [{:s}].=====", peer_name);
						} else {
							debug!("===== Static Page request =====");
							WebServer::enqueue_static_file_request(stream, path_obj, stream_map_arc, request_queue_arc, notify_chan);
						}
					}
				});
			}
		});
	}

	fn respond_with_error_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
		let mut stream = stream;
		let msg: ~str = format!("Cannot open: {:s}", path.as_str().expect("invalid path").to_owned());

		stream.write(HTTP_BAD.as_bytes());
		stream.write(msg.as_bytes());
	}

	// TODO: Safe visitor counter.
	fn respond_with_counter_page(stream: Option<std::io::net::tcp::TcpStream>) {
		let mut stream = stream;
		let response: ~str =
			format!("{:s}{:s}
Greetings, Krusty!

Visitor count: {:u}
\r\n",
					HTTP_OK, COUNTER_STYLE,
					unsafe { visitor_count } );
		debug!("Responding to counter request");
		stream.write(response.as_bytes());
	}

	// TODO: Streaming file.
	// TODO: Application-layer file caching.
	fn respond_with_static_file(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
		let mut stream = stream;
		let mut file_reader = File::open(path).expect("Invalid file!");
		stream.write(HTTP_OK.as_bytes());
		stream.write(file_reader.read_to_end());
	}

	// TODO: Server-side gashing.
	fn respond_with_dynamic_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
		// for now, just serve as static file
		WebServer::respond_with_static_file(stream, path);
	}

	// TODO: Smarter Scheduling.
	fn enqueue_static_file_request(stream: Option<std::io::net::tcp::TcpStream>, path_obj: &Path, stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>, req_queue_arc: MutexArc<~[HTTP_Request]>, notify_chan: SharedChan<()>) {
		// Save stream in hashmap for later response.
		let mut stream = stream;
		let peer_name = WebServer::get_peer_name(&mut stream);
		let (stream_port, stream_chan) = Chan::new();
		stream_chan.send(stream);
		unsafe {
			// Use an unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
			stream_map_arc.unsafe_access(|local_stream_map| {
				let stream = stream_port.recv();
				local_stream_map.swap(peer_name.clone(), stream);
			});
		}

		// Enqueue the HTTP request.
		let req = HTTP_Request { peer_name: peer_name.clone(), path: ~path_obj.clone() };
		let (req_port, req_chan) = Chan::new();
		req_chan.send(req);

		debug!("Waiting for queue mutex lock.");
		req_queue_arc.access(|local_req_queue| {
			debug!("Got queue mutex lock.");
			let req: HTTP_Request = req_port.recv();
			local_req_queue.push(req);
			debug!("A new request enqueued, now the length of queue is {:u}.", local_req_queue.len());
		});

		notify_chan.send(()); // Send incoming notification to responder task.

	}

	// TODO: Smarter Scheduling.
	fn dequeue_static_file_request(&mut self) {
		let req_queue_get = self.request_queue_arc.clone();
		let stream_map_get = self.stream_map_arc.clone();

		// Port<> cannot be sent to another task. So we have to make this task as the main task that can access self.notify_port.

		let (request_port, request_chan) = Chan::new();
		loop {
			self.notify_port.recv();	// waiting for new request enqueued.

			req_queue_get.access( |req_queue| {
				match req_queue.shift_opt() { // FIFO queue.
					None => { /* do nothing */ }
					Some(req) => {
						request_chan.send(req);
						debug!("A new request dequeued, now the length of queue is {:u}.", req_queue.len());
					}
				}
			});

			let request = request_port.recv();

			// Get stream from hashmap.
			// Use unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
			let (stream_port, stream_chan) = Chan::new();
			unsafe {
				stream_map_get.unsafe_access(|local_stream_map| {
					let stream = local_stream_map.pop(&request.peer_name).expect("no option tcpstream");
					stream_chan.send(stream);
				});
			}

			// TODO: Spawning more tasks to respond the dequeued requests concurrently. You may need a semophore to control the concurrency.
			let stream = stream_port.recv();
			WebServer::respond_with_static_file(stream, request.path);
			// Close stream automatically.
			debug!("=====Terminated connection from [{:s}].=====", request.peer_name);
		}
	}

	fn get_peer_name(stream: &mut Option<std::io::net::tcp::TcpStream>) -> ~str {
		match *stream {
			Some(ref mut s) => {
						 match s.peer_name() {
							Some(pn) => {pn.to_str()},
							None => (~"")
						 }
					   },
			None => (~"")
		}
	}
}

fn get_args() -> (~str, uint, ~str) {
	fn print_usage(program: &str) {
		println!("Usage: {:s} [options]", program);
		println!("--ip	   \tIP address, \"{:s}\" by default.", IP);
		println!("--port   \tport number, \"{:u}\" by default.", PORT);
		println!("--www    \tworking directory, \"{:s}\" by default", WWW_DIR);
		println("-h --help \tUsage");
	}

	/* Begin processing program arguments and initiate the parameters. */
	let args = os::args();
	let program = args[0].clone();

	let opts = ~[
		getopts::optopt("ip"),
		getopts::optopt("port"),
		getopts::optopt("www"),
		getopts::optflag("h"),
		getopts::optflag("help")
	];

	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { fail!(f.to_err_msg()) }
	};

	if matches.opt_present("h") || matches.opt_present("help") {
		print_usage(program);
		unsafe { libc::exit(1); }
	}

	let ip_str = if matches.opt_present("ip") {
					matches.opt_str("ip").expect("invalid ip address?").to_owned()
				 } else {
					IP.to_owned()
				 };

	let port:uint = if matches.opt_present("port") {
						from_str::from_str(matches.opt_str("port").expect("invalid port number?")).expect("not uint?")
					} else {
						PORT
					};

	let www_dir_str = if matches.opt_present("www") {
						matches.opt_str("www").expect("invalid www argument?")
					  } else { WWW_DIR.to_owned() };

	(ip_str, port, www_dir_str)
}

fn main() {
	let (ip_str, port, www_dir_str) = get_args();
	let mut zhtta = WebServer::new(ip_str, port, www_dir_str);
	zhtta.run();
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, vec, hashmap, task};
use extra::arc;
use extra::priority_queue::PriorityQueue;
use std::comm::*;
use std::cast;
use extra::comm;
use extra::comm::DuplexStream;
use std::hashmap::HashSet;
use std::path::Path;
use extra::ringbuf::RingBuf;
use extra::sort;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";
static mut visitor_count: uint = 0;

#[deriving(Clone)]
struct access_t {
    filepath: ~std::path::PosixPath,
    size: i64,
    num_access: uint
}

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    priority: uint
}

impl std::cmp::Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {
        return self.priority > other.priority;
    }
}

fn main() {
    let req_heap: PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_heap = arc::RWArc::new(req_heap);
    let add_vec = shared_req_heap.clone();
    let take_vec = shared_req_heap.clone();

    let cache: hashmap::HashMap<~str, ~str> = hashmap::HashMap::new();
    let shared_cache = arc::RWArc::new(cache);
    let add_cache = shared_cache.clone();
    let check_cache = shared_cache.clone();

    let accesses: ~[access_t] = ~[];
    let shared_accesses = arc::RWArc::new(accesses);
    let exist_accesses = shared_accesses.clone();
    let new_accesses = shared_accesses.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                println(fmt!("begin serving file [%?]", tf.filepath.to_str()));
                // A web server should always reply a HTTP header for any legal HTTP request.
                tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                match do check_cache.read |cc| { (*cc).find_copy(&tf.filepath.to_str()) } {
                    None        =>  { if tf.filepath.get_mode().unwrap() % 2 == 1 {
                                            execFile(tf);
                                            // No cache for dynamically-generated files.
                                            loop;
                                      }

                                      let data = writeFile(tf);
                                      do new_accesses.write |na| {
                                            if (*na).len() > 20 {
                                                (*na).pop_opt();
                                            }

                                            let file_info = access_t{filepath: tf.filepath, size: tf.filepath.stat().unwrap().st_size, num_access: 1};
                                            (*na).push(file_info);
                                            do add_cache.write |ac| {
                                                let sort_access = sort::merge_sort(*na, |it1: &access_t, it2: &access_t| {
                                                                                (it1.size*it1.num_access as i64) <= (it2.size*it2.num_access as i64)
                                                                                });
                                                for item in sort_access.iter() {
                                                    if file_info.size > (item.size*item.num_access as i64) {
                                                        match (*ac).pop(&item.filepath.to_str()) {
                                                            Some(thing)    =>  { (*ac).swap(file_info.filepath.to_str(), data); break;}
                                                            None           =>  { }
                                                        }
                                                    }
                                                }
                                            }
                                      }
                                  }

                    Some(ct)    =>  { tf.stream.write(ct.as_bytes());
                                      do exist_accesses.write |ea| {
                                            for i in range(0, (*ea).len()) {
                                                let mut item = (*ea)[i];
                                                if item.filepath == tf.filepath {
                                                    item.num_access += 1;
                                                    item = item.clone();
                                                    (*ea).remove(i);
                                                    (*ea).push(item);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                }
                println(fmt!("finish file [%?]", tf.filepath.to_str()));
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf: sched_msg = (*vec).pop();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    // IP addresses to give higher priority
    let mut ip_vals: HashSet<u32> = HashSet::with_capacity(9000);
    ip_vals.insert((192 as u32 << 24) + (168 as u32 << 16));
    ip_vals.insert((127 as u32 << 24) + (143 as u32 << 16));
    ip_vals.insert((137 as u32 << 24) + (54 as u32 << 16));
    ip_vals.insert(0);
    let shared_ip_map = arc::RWArc::new(ip_vals);

    let shared_count = arc::RWArc::new(0);

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        let incr_count = shared_count.clone();

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let shared_ip_map = shared_ip_map.clone();
        let child_add_vec = add_vec.clone();

        do spawn {
            do incr_count.write |count| {
                *count += 1;
            }

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));
                // More better path security!
                let unclean_path = os::getcwd().push(Path(path).to_str()).to_str();
                let mut file_path = ~os::getcwd();
                // paths are always normalized so a/b/../c becomes a/c
                if unclean_path.starts_with(file_path.to_str()) {
                    file_path = ~file_path.push(path);
                }
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", incr_count.read(|c| { *c }));

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling

                    let mut priority = file_path.stat().unwrap().st_size as uint;
                    unsafe {
                        match stream {
                            Some(ref s) => {
                                    let stream = cast::transmute_mut(s);
                                    let pn = stream.peer_name().unwrap();
                                    println(fmt!("Peer is: %?", pn));
                                    match pn.ip {
                                        Ipv4Addr(a, b, c, d) => {
                                                                // Since we are sharing the ip_map it must be read
                                                                do shared_ip_map.read |map| {
                                                                    if check_ip(a,b,c,d, map) {
                                                                        priority = 1;
                                                                        println("local request!");
                                                                    }
                                                                }
                                                            },
                                        _                    =>  fail!()
                                    }
                            },
                            _    => fail!()
                        };
                    }
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), priority: priority};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

// Looks up an ip prefix in the hashset by trying each octet
fn check_ip(a: u8, b: u8, c: u8, d: u8, map: &HashSet<u32>) -> bool {
    let mut mut_ip = a as u32 << 24;
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (b as u32 << 16);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (c as u32 << 8);
    if map.contains(&mut_ip) {
        return true;
    }
    mut_ip += (d as u32);
    if map.contains(&mut_ip) {
        return true;
    }
    false
}

pub fn execFile(file_data: sched_msg) -> ~str {
    let index = 0;
    let closes: ~[(uint, uint)] = file_data.matches_index_iter("\" -->").collect();
    let (port, chan) = DuplexStream();
    do task::spawn_supervised {
        do_gash(&chan)
    }

    let mut i = 0;
    let mut prev = 0;
    let mut result = ~"";
    for (begin, end) in  file_data.matches_index_iter("").collect();
    let (port, chan) = DuplexStream();
    do task::spawn_supervised {
        do_gash(&chan)
    }

    let mut i = 0;
    let mut prev = 0;
    let mut result = ~"";
    for (begin, end) in  file_data.matches_index_iter("


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Daniel Nizri, Renee Seaman, and Alex Fabian
// Version 0.4

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, libc, hashmap};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    file_size: uint
}

struct cached_file {
    content: ~str,
    modified: ~str
}

fn get_file_contents(map: &mut hashmap::HashMap<~str, cached_file>, filepath: ~std::path::PosixPath) -> ~str {
    if map.contains_key(&filepath.to_str()) {
        match map.find(&filepath.to_str()) {
            Some(cached_file) => {
                let last_modified = get_gash_output(fmt!("stat -c %s %s", "%y", filepath.to_str()));
                if last_modified != cached_file.modified {
                    println(fmt!("file in cache was modified, re-reading %s", filepath.to_str()));
                    match io::read_whole_file_str(filepath) {
                        Ok(file_contents) => {
                            let path = filepath.to_str();
                            if path.slice(path.len() - 4, path.len()) != "html" {
                                return file_contents.replace("\n", "
");
                            }
                            else {
                                return file_contents;
                            }
                        }
                        Err(err)          => { return err; }
                    }
                } else {
                    println(fmt!("retrieving cached file: %s", filepath.to_str()));
                    return cached_file.content.clone();
                }
            },
            None    => { return ~""; }
        }
    }
    else {
        println(fmt!("reading file: %s", filepath.to_str()));
        match io::read_whole_file_str(filepath) {
            Ok(file_contents) => {
                let path = filepath.to_str();
                if path.slice(path.len() - 4, path.len()) != "html" {
                    return file_contents.replace("\n", "
");
                }
                else {
                    return file_contents;
                }
            }
            Err(err)          => { return err; }
        }
    }
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();
    let visitor_count : uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // FIFO - dequeue file requests, and send responses.
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            let mut cache_map: hashmap::HashMap<~str, cached_file> = hashmap::HashMap::new();

            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                let file_contents = get_file_contents(&mut cache_map, tf.filepath.clone());
                let last_modified = get_gash_output(fmt!("stat -c %s %s", "%y", tf.filepath.to_str()));
                let cached_file: cached_file = cached_file{content: file_contents.clone(), modified: last_modified};
                cache_map.insert(tf.filepath.to_str(), cached_file);

                println(fmt!("begin serving file [%?]", tf.filepath));
                // A web server should always reply a HTTP header for any legal HTTP request.
                tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());

                let mut file_data_vec = ~[file_contents.clone()];

                while(file_data_vec[0].contains("");
                            match end_pos_ssi {
                                Some(end_ssi) => {
                                    let start_pos_cmd = start_ssi + 15;
                                    let end_pos_cmd = end_ssi;
                                    let cmd = file_data_clone.slice(start_pos_cmd, end_pos_cmd);
                                    let output = get_gash_output(cmd.to_owned());
                                    file_data_vec[0] = file_data_clone.slice(0, start_ssi).clone().to_owned().append(output).append(file_data_clone.slice(end_ssi + 5, file_data_clone.len()));
                                }
                                None      => { println("Error --- Found ''") }
                            }
                        }
                        None      => { println("Error --- Expected to find '");
                            match end_pos_ssi {
                                Some(end_ssi) => {
                                    let start_pos_cmd = start_ssi + 15;
                                    let end_pos_cmd = end_ssi;
                                    let cmd = file_data_clone.slice(start_pos_cmd, end_pos_cmd);
                                    let output = get_gash_output(cmd.to_owned());
                                    file_data_vec[0] = file_data_clone.slice(0, start_ssi).clone().to_owned().append(output).append(file_data_clone.slice(end_ssi + 5, file_data_clone.len()));
                                }
                                None      => { println("Error --- Found ''") }
                            }
                        }
                        None      => { println("Error --- Expected to find '


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate httparse;
extern crate mio;
extern crate slab;
extern crate time;

use std::ascii::AsciiExt;
use std::env;
use std::io::{self, Read, Write};
use std::mem;
use std::net::SocketAddr;
use std::slice;
use std::str;

use mio::tcp::{TcpStream, TcpListener};
use mio::{Poll, Token, EventSet, PollOpt, Events};
use slab::Slab;

const LISTENER: mio::Token = mio::Token(0);

struct Server<'a> {
    count: u64,
    listener: &'a TcpListener,
    connections: Slab<Connection, mio::Token>,
}

impl<'a> Server<'a> {
    fn new(listener: &'a TcpListener) -> Server<'a> {
        Server {
            count: 0,
            listener: listener,
            connections: Slab::new_starting_at(mio::Token(1), 1024),
        }
    }

    fn ready(&mut self,
             poll: &Poll,
             token: Token,
             events: EventSet) {
        debug!("{:?} {:?}", token, events);
        if token == LISTENER {
            while let Ok(Some(socket)) = self.listener.accept() {
                debug!("accepted");
                self.count += 1;
                // socket.0.set_nodelay(true).unwrap();
                let token = self.connections
                    .insert_with(move |_| Connection::new(socket.0))
                    .unwrap();
                poll.register(&self.connections[token].socket,
                              token,
                              EventSet::readable() | EventSet::writable(),
                              PollOpt::edge()).unwrap();
                self.try_connection(poll, token, EventSet::all());
            }
        } else {
            self.try_connection(poll, token, events);
        }
    }

    fn try_connection(&mut self, poll: &Poll, token: Token, events: EventSet) {
        let res = self.connections[token].ready(events);

        if res.is_err() || self.connections[token].closed {
            if let Err(ref e) = res {
                info!("error: {:?}\non: {:?} {:?}", e,
                       token, self.connections[token].socket);
            }
            debug!("removing");
            self.connections.remove(token);
        }
    }
}

struct Connection {
    socket: TcpStream,
    input: Vec<u8>,
    output: Output,
    keepalive: bool,
    closed: bool,
    read_closed: bool,
    events: EventSet,
}

struct Output {
    buf: Vec<u8>,
}

impl Connection {
    fn new(socket: TcpStream) -> Connection {
        Connection {
            socket: socket,
            input: Vec::with_capacity(2048),
            output: Output {
                buf: Vec::with_capacity(2048),
            },
            keepalive: false,
            read_closed: false,
            closed: false,
            events: EventSet::none(),
        }
    }

    fn ready(&mut self, events: EventSet) -> io::Result<()> {
        self.events = self.events | events;
        while self.events.is_readable() && !self.read_closed {
            let before = self.input.len();
            let eof = try!(read(&mut self.socket,
                                &mut self.input,
                                &mut self.events));
            if eof {
                debug!("eof");
            }
            self.read_closed = eof;
            if self.input.len() == before {
                break
            }

            while self.input.len() > 0 {
                let (req, amt) = match try!(parse(&self.input)) {
                    Some(pair) => pair,
                    None => {
                        debug!("need more data for a request");
                        return Ok(())
                    }
                };
                let request = Request {
                    inner: req,
                    amt: amt,
                    data: mem::replace(&mut self.input, Vec::new()),
                };
                debug!("got a request");
                self.keepalive = request.version() >= 1;
                self.keepalive = self.keepalive || request.headers().any(|s| {
                    s.0.eq_ignore_ascii_case("connection") &&
                        s.1.eq_ignore_ascii_case(b"keep-alive")
                });

                let response = process(&request);
                response.to_bytes(&mut self.output.buf);

                self.input = request.into_input_buf();
                if !self.keepalive {
                    debug!("disabling keepalive");
                    self.read_closed = true;
                }
            }
        }

        if self.events.is_writable() && self.output.buf.len() > 0 {
            let done = try!(write(&mut self.socket,
                                  &mut self.output,
                                  &mut self.events));
            if done {
                debug!("wrote response");
                if !self.keepalive || self.read_closed {
                    self.closed = true;
                }
            }
        }

        if self.read_closed && self.output.buf.len() == 0 {
            self.closed = true;
        }
        Ok(())
    }
}

fn process(r: &Request) -> Response {
    assert!(r.path() == "/plaintext");
    let mut r = Response::new();
    r.header("Content-Type", "text/plain; charset=UTF-8")
     .body("Hello, World!");
    return r
}

type Slice = (usize, usize);

#[allow(dead_code)]
pub struct Request {
    inner: RawRequest,
    data: Vec<u8>,
    amt: usize,
}

struct RawRequest {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
}

pub struct Headers<'a> {
    iter: slice::Iter<'a, (Slice, Slice)>,
    req: &'a Request,
}

impl Request {
    pub fn method(&self) -> &str {
        str::from_utf8(self.get(&self.inner.method)).unwrap()
    }

    pub fn path(&self) -> &str {
        str::from_utf8(self.get(&self.inner.path)).unwrap()
    }

    pub fn version(&self) -> u8 {
        self.inner.version
    }

    pub fn headers(&self) -> Headers {
        Headers {
            iter: self.inner.headers.iter(),
            req: self,
        }
    }

    pub fn into_input_buf(mut self) -> Vec<u8> {
        self.data.drain(..self.amt);
        self.data
    }

    fn get(&self, s: &Slice) -> &[u8] {
        &self.data[s.0..s.1]
    }
}

impl<'a> Iterator for Headers<'a> {
    type Item = (&'a str, &'a [u8]);

    fn next(&mut self) -> Option<(&'a str, &'a [u8])> {
        self.iter.next().map(|&(ref k, ref v)| {
            (str::from_utf8(self.req.get(k)).unwrap(), self.req.get(v))
        })
    }
}

fn parse(buf: &[u8]) -> io::Result<Option<(RawRequest, usize)>> {
    let mut headers = [httparse::EMPTY_HEADER; 16];
    let mut r = httparse::Request::new(&mut headers);
    let status = try!(r.parse(&buf).map_err(|_| {
        io::Error::new(io::ErrorKind::Other, "failed to parse")
    }));
    return match status {
        httparse::Status::Complete(amt) => {
            debug!("ok {:?}", String::from_utf8_lossy(&buf[..amt]));
            Ok(Some((RawRequest {
                method: slice(buf, r.method.unwrap().as_bytes()),
                path: slice(buf, r.path.unwrap().as_bytes()),
                version: r.version.unwrap(),
                headers: r.headers.iter().map(|h| {
                    (slice(buf, h.name.as_bytes()), slice(buf, &h.value))
                }).collect(),
            }, amt)))
        }
        httparse::Status::Partial => Ok(None),
    };

    fn slice(buf: &[u8], inner: &[u8]) -> Slice {
        let start = inner.as_ptr() as usize - buf.as_ptr() as usize;
        assert!(start < buf.len());
        (start, start + inner.len())
    }
}

pub struct Response {
    headers: Vec<(String, String)>,
    response: String,
}

impl Response {
    pub fn new() -> Response {
        Response {
            headers: Vec::new(),
            response: String::new(),
        }
    }

    pub fn header(&mut self, name: &str, val: &str) -> &mut Response {
        self.headers.push((name.to_string(), val.to_string()));
        self
    }

    pub fn body(&mut self, s: &str) -> &mut Response {
        self.response = s.to_string();
        self
    }

    fn to_bytes(&self, into: &mut Vec<u8>) {
        write!(into, "\
            HTTP/1.1 200 OK\r\n\
            Server: Example\r\n\
            Date: {}\r\n\
            Content-Length: {}\r\n\
        ", time::now().rfc822(), self.response.len()).unwrap();
        for &(ref k, ref v) in &self.headers {
            extend(into, k.as_bytes());
            extend(into, b": ");
            extend(into, v.as_bytes());
            extend(into, b"\r\n");
        }
        extend(into, b"\r\n");
        extend(into, self.response.as_bytes());
    }
}

// TODO: why does extend_from_slice not optimize?
fn extend(dst: &mut Vec<u8>, data: &[u8]) {
    use std::ptr;
    dst.reserve(data.len());
    let prev = dst.len();
    unsafe {
        ptr::copy_nonoverlapping(data.as_ptr(),
                                 dst.as_mut_ptr().offset(prev as isize),
                                 data.len());
        dst.set_len(prev + data.len());
    }
}

fn read(socket: &mut TcpStream,
        input: &mut Vec<u8>,
        events: &mut EventSet) -> io::Result<bool> {
    match socket.read(unsafe { slice_to_end(input) }) {
        Ok(0) => return Ok(true),
        Ok(n) => {
            let len = input.len();
            unsafe { input.set_len(len + n); }
            return Ok(false)
        }
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
            *events = *events & !EventSet::readable();
            return Ok(false)
        }
        Err(e) => return Err(e),
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        use std::slice;
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}

fn write(socket: &mut TcpStream,
         output: &mut Output,
         events: &mut EventSet) -> io::Result<bool> {
    assert!(output.buf.len() > 0);
    loop {
        match socket.write(&output.buf) {
            Ok(0) => {
                return Err(io::Error::new(io::ErrorKind::Other, "early eof2"))
            }
            Ok(n) => {
                output.buf.drain(..n);
                if output.buf.len() == 0 {
                    return Ok(true)
                }
            }
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                *events = *events & !EventSet::writable();
                return Ok(false)
            }
            Err(e) => return Err(e),
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let poll = mio::Poll::new().unwrap();

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();
    let listener = TcpListener::bind(&addr).unwrap();
    poll.register(&listener,
                  LISTENER,
                  EventSet::readable(),
                  PollOpt::level()).unwrap();

    let mut events = Events::new();
    let mut server = Server::new(&listener);
    loop {
        poll.poll(&mut events, None).unwrap();

        for i in 0..events.len() {
            let event = events.get(i).unwrap();
            server.ready(&poll, event.token(), event.kind());
        }
    }
}
<commit_msg>Add a faster write!() adaptor<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate httparse;
extern crate mio;
extern crate slab;
extern crate time;

use std::ascii::AsciiExt;
use std::env;
use std::io::{self, Read, Write};
use std::fmt;
use std::mem;
use std::net::SocketAddr;
use std::slice;
use std::str;

use mio::tcp::{TcpStream, TcpListener};
use mio::{Poll, Token, EventSet, PollOpt, Events};
use slab::Slab;

const LISTENER: mio::Token = mio::Token(0);

struct Server<'a> {
    count: u64,
    listener: &'a TcpListener,
    connections: Slab<Connection, mio::Token>,
}

impl<'a> Server<'a> {
    fn new(listener: &'a TcpListener) -> Server<'a> {
        Server {
            count: 0,
            listener: listener,
            connections: Slab::new_starting_at(mio::Token(1), 1024),
        }
    }

    fn ready(&mut self,
             poll: &Poll,
             token: Token,
             events: EventSet) {
        debug!("{:?} {:?}", token, events);
        if token == LISTENER {
            while let Ok(Some(socket)) = self.listener.accept() {
                debug!("accepted");
                self.count += 1;
                // socket.0.set_nodelay(true).unwrap();
                let token = self.connections
                    .insert_with(move |_| Connection::new(socket.0))
                    .unwrap();
                poll.register(&self.connections[token].socket,
                              token,
                              EventSet::readable() | EventSet::writable(),
                              PollOpt::edge()).unwrap();
                self.try_connection(token, EventSet::all());
            }
        } else {
            self.try_connection(token, events);
        }
    }

    fn try_connection(&mut self, token: Token, events: EventSet) {
        let res = self.connections[token].ready(events);

        if res.is_err() || self.connections[token].closed {
            if let Err(ref e) = res {
                info!("error: {:?}\non: {:?} {:?}", e,
                       token, self.connections[token].socket);
            }
            debug!("removing");
            self.connections.remove(token);
        }
    }
}

struct Connection {
    socket: TcpStream,
    input: Vec<u8>,
    output: Output,
    keepalive: bool,
    closed: bool,
    read_closed: bool,
    events: EventSet,
}

struct Output {
    buf: Vec<u8>,
}

impl Connection {
    fn new(socket: TcpStream) -> Connection {
        Connection {
            socket: socket,
            input: Vec::with_capacity(2048),
            output: Output {
                buf: Vec::with_capacity(2048),
            },
            keepalive: false,
            read_closed: false,
            closed: false,
            events: EventSet::none(),
        }
    }

    fn ready(&mut self, events: EventSet) -> io::Result<()> {
        self.events = self.events | events;
        while self.events.is_readable() && !self.read_closed {
            let before = self.input.len();
            let eof = try!(read(&mut self.socket,
                                &mut self.input,
                                &mut self.events));
            if eof {
                debug!("eof");
            }
            self.read_closed = eof;
            if self.input.len() == before {
                break
            }

            while self.input.len() > 0 {
                let (req, amt) = match try!(parse(&self.input)) {
                    Some(pair) => pair,
                    None => {
                        debug!("need more data for a request");
                        return Ok(())
                    }
                };
                let request = Request {
                    inner: req,
                    amt: amt,
                    data: mem::replace(&mut self.input, Vec::new()),
                };
                debug!("got a request");
                self.keepalive = request.version() >= 1;
                self.keepalive = self.keepalive || request.headers().any(|s| {
                    s.0.eq_ignore_ascii_case("connection") &&
                        s.1.eq_ignore_ascii_case(b"keep-alive")
                });

                let response = process(&request);
                response.to_bytes(&mut self.output.buf);

                self.input = request.into_input_buf();
                if !self.keepalive {
                    debug!("disabling keepalive");
                    self.read_closed = true;
                }
            }
        }

        if self.events.is_writable() && self.output.buf.len() > 0 {
            let done = try!(write(&mut self.socket,
                                  &mut self.output,
                                  &mut self.events));
            if done {
                debug!("wrote response");
                if !self.keepalive || self.read_closed {
                    self.closed = true;
                }
            }
        }

        if self.read_closed && self.output.buf.len() == 0 {
            self.closed = true;
        }
        Ok(())
    }
}

fn process(r: &Request) -> Response {
    assert!(r.path() == "/plaintext");
    let mut r = Response::new();
    r.header("Content-Type", "text/plain; charset=UTF-8")
     .body("Hello, World!");
    return r
}

type Slice = (usize, usize);

#[allow(dead_code)]
pub struct Request {
    inner: RawRequest,
    data: Vec<u8>,
    amt: usize,
}

struct RawRequest {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
}

pub struct Headers<'a> {
    iter: slice::Iter<'a, (Slice, Slice)>,
    req: &'a Request,
}

impl Request {
    pub fn method(&self) -> &str {
        str::from_utf8(self.get(&self.inner.method)).unwrap()
    }

    pub fn path(&self) -> &str {
        str::from_utf8(self.get(&self.inner.path)).unwrap()
    }

    pub fn version(&self) -> u8 {
        self.inner.version
    }

    pub fn headers(&self) -> Headers {
        Headers {
            iter: self.inner.headers.iter(),
            req: self,
        }
    }

    pub fn into_input_buf(mut self) -> Vec<u8> {
        self.data.drain(..self.amt);
        self.data
    }

    fn get(&self, s: &Slice) -> &[u8] {
        &self.data[s.0..s.1]
    }
}

impl<'a> Iterator for Headers<'a> {
    type Item = (&'a str, &'a [u8]);

    fn next(&mut self) -> Option<(&'a str, &'a [u8])> {
        self.iter.next().map(|&(ref k, ref v)| {
            (str::from_utf8(self.req.get(k)).unwrap(), self.req.get(v))
        })
    }
}

fn parse(buf: &[u8]) -> io::Result<Option<(RawRequest, usize)>> {
    let mut headers = [httparse::EMPTY_HEADER; 16];
    let mut r = httparse::Request::new(&mut headers);
    let status = try!(r.parse(&buf).map_err(|_| {
        io::Error::new(io::ErrorKind::Other, "failed to parse")
    }));
    return match status {
        httparse::Status::Complete(amt) => {
            debug!("ok {:?}", String::from_utf8_lossy(&buf[..amt]));
            Ok(Some((RawRequest {
                method: slice(buf, r.method.unwrap().as_bytes()),
                path: slice(buf, r.path.unwrap().as_bytes()),
                version: r.version.unwrap(),
                headers: r.headers.iter().map(|h| {
                    (slice(buf, h.name.as_bytes()), slice(buf, &h.value))
                }).collect(),
            }, amt)))
        }
        httparse::Status::Partial => Ok(None),
    };

    fn slice(buf: &[u8], inner: &[u8]) -> Slice {
        let start = inner.as_ptr() as usize - buf.as_ptr() as usize;
        assert!(start < buf.len());
        (start, start + inner.len())
    }
}

pub struct Response {
    headers: Vec<(String, String)>,
    response: String,
}

impl Response {
    pub fn new() -> Response {
        Response {
            headers: Vec::new(),
            response: String::new(),
        }
    }

    pub fn header(&mut self, name: &str, val: &str) -> &mut Response {
        self.headers.push((name.to_string(), val.to_string()));
        self
    }

    pub fn body(&mut self, s: &str) -> &mut Response {
        self.response = s.to_string();
        self
    }

    fn to_bytes(&self, into: &mut Vec<u8>) {
        use std::fmt::Write;

        write!(FastWrite(into), "\
            HTTP/1.1 200 OK\r\n\
            Server: Example\r\n\
            Date: {}\r\n\
            Content-Length: {}\r\n\
        ", time::now().rfc822(), self.response.len()).unwrap();
        for &(ref k, ref v) in &self.headers {
            extend(into, k.as_bytes());
            extend(into, b": ");
            extend(into, v.as_bytes());
            extend(into, b"\r\n");
        }
        extend(into, b"\r\n");
        extend(into, self.response.as_bytes());
    }
}

// TODO: impl fmt::Write for Vec<u8>
//
// Right now `write!` on `Vec<u8>` goes through io::Write and is not super
// speedy, so inline a less-crufty implementation here which doesn't go through
// io::Error.
struct FastWrite<'a>(&'a mut Vec<u8>);

impl<'a> fmt::Write for FastWrite<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        extend(self.0, s.as_bytes());
        Ok(())
    }
}

// TODO: why does extend_from_slice not optimize?
fn extend(dst: &mut Vec<u8>, data: &[u8]) {
    use std::ptr;
    dst.reserve(data.len());
    let prev = dst.len();
    unsafe {
        ptr::copy_nonoverlapping(data.as_ptr(),
                                 dst.as_mut_ptr().offset(prev as isize),
                                 data.len());
        dst.set_len(prev + data.len());
    }
}

fn read(socket: &mut TcpStream,
        input: &mut Vec<u8>,
        events: &mut EventSet) -> io::Result<bool> {
    match socket.read(unsafe { slice_to_end(input) }) {
        Ok(0) => return Ok(true),
        Ok(n) => {
            let len = input.len();
            unsafe { input.set_len(len + n); }
            return Ok(false)
        }
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
            *events = *events & !EventSet::readable();
            return Ok(false)
        }
        Err(e) => return Err(e),
    }

    unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
        use std::slice;
        if v.capacity() == 0 {
            v.reserve(16);
        }
        if v.capacity() == v.len() {
            v.reserve(1);
        }
        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize),
                                  v.capacity() - v.len())
    }
}

fn write(socket: &mut TcpStream,
         output: &mut Output,
         events: &mut EventSet) -> io::Result<bool> {
    assert!(output.buf.len() > 0);
    loop {
        match socket.write(&output.buf) {
            Ok(0) => {
                return Err(io::Error::new(io::ErrorKind::Other, "early eof2"))
            }
            Ok(n) => {
                output.buf.drain(..n);
                if output.buf.len() == 0 {
                    return Ok(true)
                }
            }
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                *events = *events & !EventSet::writable();
                return Ok(false)
            }
            Err(e) => return Err(e),
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let poll = mio::Poll::new().unwrap();

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();
    let listener = TcpListener::bind(&addr).unwrap();
    poll.register(&listener,
                  LISTENER,
                  EventSet::readable(),
                  PollOpt::level()).unwrap();

    let mut events = Events::new();
    let mut server = Server::new(&listener);
    loop {
        poll.poll(&mut events, None).unwrap();

        for i in 0..events.len() {
            let event = events.get(i).unwrap();
            server.ready(&poll, event.token(), event.kind());
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]

use std::arch::x86_64::*;
use std::io::Write;
use std::intrinsics;

fn main() {
    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
    let stderr = ::std::io::stderr();
    let mut stderr = stderr.lock();

    writeln!(stderr, "some {} text", "<unknown>").unwrap();

    let _ = std::process::Command::new("true").env("c", "d").spawn();

    println!("cargo:rustc-link-lib=z");

    static ONCE: std::sync::Once = std::sync::ONCE_INIT;
    ONCE.call_once(|| {});

    LoopState::Continue(()) == LoopState::Break(());

    // Make sure ByValPair values with differently sized components are correctly passed
    map(None::<(u8, Box<Instruction>)>);

    println!("{}", 2.3f32.exp());
    println!("{}", 2.3f32.exp2());
    println!("{}", 2.3f32.abs());
    println!("{}", 2.3f32.sqrt());
    println!("{}", 2.3f32.floor());
    println!("{}", 2.3f32.ceil());
    println!("{}", 2.3f32.min(1.0));
    println!("{}", 2.3f32.max(1.0));
    println!("{}", 2.3f32.powi(2));

    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);

    0i128.checked_div(2i128);
    0u128.checked_div(2u128);
    assert_eq!(1u128 + 2, 3);

    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
    assert_eq!(353985398u128 * 932490u128, 330087843781020u128);

    unsafe {
        test_simd();
    }
}

#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
    let x = _mm_setzero_si128();
    let y = _mm_set1_epi16(7);
    let or = _mm_or_si128(x, y);
    let cmp_eq = _mm_cmpeq_epi8(y, y);
    let cmp_lt = _mm_cmplt_epi8(y, y);

    assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);

    test_mm_slli_si128();
    test_mm_movemask_epi8();
    test_mm256_movemask_epi8();
    test_mm_add_epi8();
    test_mm_add_pd();
    test_mm_cvtepi8_epi16();

    let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
    assert_eq!(mask1, 1);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_slli_si128() {
    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 1);
    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    assert_eq_m128i(r, e);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 15);
    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
    assert_eq_m128i(r, e);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 16);
    assert_eq_m128i(r, _mm_set1_epi8(0));

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, -1);
    assert_eq_m128i(_mm_set1_epi8(0), r);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, -0x80000000);
    assert_eq_m128i(r, _mm_set1_epi8(0));
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_movemask_epi8() {
    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
        0b0101, 0b1111_0000u8 as i8, 0, 0,
        0, 0, 0b1111_0000u8 as i8, 0b0101,
        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
    );
    let r = _mm_movemask_epi8(a);
    assert_eq!(r, 0b10100100_00100101);
}

#[target_feature(enable = "avx2")]
unsafe fn test_mm256_movemask_epi8() {
    let a = _mm256_set1_epi8(-1);
    let r = _mm256_movemask_epi8(a);
    let e = -1;
    assert_eq!(r, e);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_epi8() {
    let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    #[rustfmt::skip]
    let b = _mm_setr_epi8(
        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
    );
    let r = _mm_add_epi8(a, b);
    #[rustfmt::skip]
    let e = _mm_setr_epi8(
        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
    );
    assert_eq_m128i(r, e);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_pd() {
    let a = _mm_setr_pd(1.0, 2.0);
    let b = _mm_setr_pd(5.0, 10.0);
    let r = _mm_add_pd(a, b);
    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
}

fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
    unsafe {
        assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(x));
    }
}

#[target_feature(enable = "sse2")]
pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
        panic!("{:?} != {:?}", a, b);
    }
}

#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_cvtepi8_epi16() {
    let a = _mm_set1_epi8(10);
    let r = _mm_cvtepi8_epi16(a);
    let e = _mm_set1_epi16(10);
    assert_eq_m128i(r, e);
    let a = _mm_set1_epi8(-10);
    let r = _mm_cvtepi8_epi16(a);
    let e = _mm_set1_epi16(-10);
    assert_eq_m128i(r, e);
}

#[derive(PartialEq)]
enum LoopState {
    Continue(()),
    Break(())
}

pub enum Instruction {
    Increment,
    Loop,
}

fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
    match a {
        None => None,
        Some((_, instr)) => Some(instr),
    }
}
<commit_msg>Test mutex locking<commit_after>#![feature(core_intrinsics)]

use std::arch::x86_64::*;
use std::io::Write;
use std::intrinsics;

fn main() {
    let mutex = std::sync::Mutex::new(());
    mutex.lock().unwrap();

    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
    let stderr = ::std::io::stderr();
    let mut stderr = stderr.lock();

    writeln!(stderr, "some {} text", "<unknown>").unwrap();

    let _ = std::process::Command::new("true").env("c", "d").spawn();

    println!("cargo:rustc-link-lib=z");

    static ONCE: std::sync::Once = std::sync::ONCE_INIT;
    ONCE.call_once(|| {});

    LoopState::Continue(()) == LoopState::Break(());

    // Make sure ByValPair values with differently sized components are correctly passed
    map(None::<(u8, Box<Instruction>)>);

    println!("{}", 2.3f32.exp());
    println!("{}", 2.3f32.exp2());
    println!("{}", 2.3f32.abs());
    println!("{}", 2.3f32.sqrt());
    println!("{}", 2.3f32.floor());
    println!("{}", 2.3f32.ceil());
    println!("{}", 2.3f32.min(1.0));
    println!("{}", 2.3f32.max(1.0));
    println!("{}", 2.3f32.powi(2));

    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);

    0i128.checked_div(2i128);
    0u128.checked_div(2u128);
    assert_eq!(1u128 + 2, 3);

    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
    assert_eq!(353985398u128 * 932490u128, 330087843781020u128);

    unsafe {
        test_simd();
    }
}

#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
    let x = _mm_setzero_si128();
    let y = _mm_set1_epi16(7);
    let or = _mm_or_si128(x, y);
    let cmp_eq = _mm_cmpeq_epi8(y, y);
    let cmp_lt = _mm_cmplt_epi8(y, y);

    assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);

    test_mm_slli_si128();
    test_mm_movemask_epi8();
    test_mm256_movemask_epi8();
    test_mm_add_epi8();
    test_mm_add_pd();
    test_mm_cvtepi8_epi16();

    let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
    assert_eq!(mask1, 1);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_slli_si128() {
    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 1);
    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    assert_eq_m128i(r, e);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 15);
    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
    assert_eq_m128i(r, e);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, 16);
    assert_eq_m128i(r, _mm_set1_epi8(0));

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, -1);
    assert_eq_m128i(_mm_set1_epi8(0), r);

    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    );
    let r = _mm_slli_si128(a, -0x80000000);
    assert_eq_m128i(r, _mm_set1_epi8(0));
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_movemask_epi8() {
    #[rustfmt::skip]
    let a = _mm_setr_epi8(
        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
        0b0101, 0b1111_0000u8 as i8, 0, 0,
        0, 0, 0b1111_0000u8 as i8, 0b0101,
        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
    );
    let r = _mm_movemask_epi8(a);
    assert_eq!(r, 0b10100100_00100101);
}

#[target_feature(enable = "avx2")]
unsafe fn test_mm256_movemask_epi8() {
    let a = _mm256_set1_epi8(-1);
    let r = _mm256_movemask_epi8(a);
    let e = -1;
    assert_eq!(r, e);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_epi8() {
    let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    #[rustfmt::skip]
    let b = _mm_setr_epi8(
        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
    );
    let r = _mm_add_epi8(a, b);
    #[rustfmt::skip]
    let e = _mm_setr_epi8(
        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
    );
    assert_eq_m128i(r, e);
}

#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_pd() {
    let a = _mm_setr_pd(1.0, 2.0);
    let b = _mm_setr_pd(5.0, 10.0);
    let r = _mm_add_pd(a, b);
    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
}

fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
    unsafe {
        assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(x));
    }
}

#[target_feature(enable = "sse2")]
pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
        panic!("{:?} != {:?}", a, b);
    }
}

#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_cvtepi8_epi16() {
    let a = _mm_set1_epi8(10);
    let r = _mm_cvtepi8_epi16(a);
    let e = _mm_set1_epi16(10);
    assert_eq_m128i(r, e);
    let a = _mm_set1_epi8(-10);
    let r = _mm_cvtepi8_epi16(a);
    let e = _mm_set1_epi16(-10);
    assert_eq_m128i(r, e);
}

#[derive(PartialEq)]
enum LoopState {
    Continue(()),
    Break(())
}

pub enum Instruction {
    Increment,
    Loop,
}

fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
    match a {
        None => None,
        Some((_, instr)) => Some(instr),
    }
}
<|endoftext|>


<commit_before>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let path = format!(
            "{}-{}/{}",
            krate_name, version.num, manifest.package.readme?
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        text_to_html(
            &contents,
            manifest
                .package
                .readme_file
                .as_ref()
                .map_or("README.md", |e| &**e),
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
        readme_file: Option<String>,
        repository: Option<String>,
    }

    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<commit_msg>Auto merge of #3967 - nipunn1313:rerender_readme, r=Turbo87<commit_after>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}-{}/{}", krate_name, version.num, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<|endoftext|>


<commit_before>use super::*;
use core::clock::*;
use backend::world;
use core::geometry::*;
use cgmath::Vector;

pub struct GameSystem {
	hourglass: Hourglass<SystemStopwatch>,
	to_spawn: usize,
	spawned: usize,
}

impl Updateable for GameSystem {
	fn update(&mut self, _: &world::WorldState, _: f32) {
		if self.hourglass.is_expired() {
			self.hourglass.flip();
			self.to_spawn += 1;
		}
	}
}

impl System for GameSystem {
	fn from_world(&mut self, _: &world::World) {
		self.spawned = self.to_spawn;
	}
	fn to_world(&self, world: &mut world::World) {
		for i in self.spawned..self.to_spawn {
			let r = 0.2 * i as f32;
			world.new_resource(Position::zero(),
			                   Some(Motion {
				                   velocity: Velocity::new(r.cos(), r.sin()) * 5.,
				                   spin: 0.16,
			                   }));
		}
	}
}

impl Default for GameSystem {
	fn default() -> Self {
		GameSystem {
			hourglass: Hourglass::new(0.5),
			to_spawn: 0,
			spawned: 0,
		}
	}
}

impl GameSystem {}
<commit_msg>Velocity tweaks<commit_after>use super::*;
use core::clock::*;
use backend::world;
use core::geometry::*;
use cgmath::Vector;

pub struct GameSystem {
	hourglass: Hourglass<SystemStopwatch>,
	to_spawn: usize,
	spawned: usize,
}

impl Updateable for GameSystem {
	fn update(&mut self, _: &world::WorldState, _: f32) {
		if self.hourglass.is_expired() {
			self.hourglass.flip();
			self.to_spawn += 1;
		}
	}
}

impl System for GameSystem {
	fn from_world(&mut self, _: &world::World) {
		self.spawned = self.to_spawn;
	}
	fn to_world(&self, world: &mut world::World) {
		for i in self.spawned..self.to_spawn {
			let r = 0.2 * i as f32;
			world.new_resource(Position::zero(),
			                   Some(Motion {
				                   velocity: Velocity::new(r.cos(), r.sin()) * 10.,
				                   spin: 3.14,
			                   }));
		}
	}
}

impl Default for GameSystem {
	fn default() -> Self {
		GameSystem {
			hourglass: Hourglass::new(0.5),
			to_spawn: 0,
			spawned: 0,
		}
	}
}

impl GameSystem {}
<|endoftext|>