<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

//! # Canteen
//!
//! ## Description
//!
//! Canteen is a simple clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework. There is code for an example implementation in the repository located
//! here: [canteen-impl](https://gitlab.com/jeffdn/canteen-impl).
//!
//! ## Usage
//!
//! It's by no means complete, but I'm working on it, and it's now available on
//! [crates.io](https://crates.io/)! To install and check it out, add the following to
//! your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! canteen = "0.2"
//! ```
//!
//! ## Example
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<path:name>` will greedily take all path data contained
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//! - `<int:name>` will return an integer from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points
//! - `<str:name>` will match anything inside a path segment, except a forward slash
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_code(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;

pub mod utils;
pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::with_capacity(2048),
            o_buf:  Vec::with_capacity(2048),
        }
    }

    fn receive(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    // write the client's output buffer to the socket.
    //
    // the following return values mean:
    //  - Ok(true):  we can close the connection
    //  - Ok(false): keep listening for writeable event and continue next time
    //  - Err(e):    something dun fucked up
    fn send(&mut self) -> Result<bool> {
        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(e)  => {
                    panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
                }
            }
        }

        Ok(true)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: utils::err_404,
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, route::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&mut self, req: &mut Request) -> Vec<u8> {
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).receive() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        // kill the connection
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<commit_msg>update and clean up documentation in lib.rs<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

//! # Canteen
//!
//! ## Description
//!
//! A pure Rust clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework.
//!
//! ## Example
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<str:name>` will match anything inside a path segment, returns a `String`
//! - `<int:name>` will return a signed integer (`i32`) from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<uint:name>` will return an unsigned integer (`u32`)
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points and returns an `f32`
//! - `<path:name>` will greedily take all path data contained, returns a `String`
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_code(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;

pub mod utils;
pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::with_capacity(2048),
            o_buf:  Vec::with_capacity(2048),
        }
    }

    fn receive(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    // write the client's output buffer to the socket.
    //
    // the following return values mean:
    //  - Ok(true):  we can close the connection
    //  - Ok(false): keep listening for writeable event and continue next time
    //  - Err(e):    something dun fucked up
    fn send(&mut self) -> Result<bool> {
        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(e)  => {
                    panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
                }
            }
        }

        Ok(true)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: utils::err_404,
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, route::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&mut self, req: &mut Request) -> Vec<u8> {
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).receive() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        // kill the connection
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<|endoftext|>


<commit_before>//! # Multihash
//!
//! Implementation of [multihash](https://github.com/multiformats/multihash) in Rust.
//!
//! A `Multihash` is a structure that contains a hashing algorithm, plus some hashed data.
//! A `MultihashRef` is the same as a `Multihash`, except that it doesn't own its data.
//!

mod errors;
mod hashes;
mod storage;

use std::convert::TryFrom;
use std::fmt::Debug;
use std::hash;

use blake2b_simd::{blake2b, Params as Blake2bVariable};
use blake2s_simd::{blake2s, Params as Blake2sVariable};
use sha2::Digest;
use tiny_keccak::Keccak;
use unsigned_varint::{decode, encode};

pub use errors::{DecodeError, DecodeOwnedError, EncodeError};
pub use hashes::Hash;
use std::fmt;
use storage::Storage;

// Helper macro for encoding input into output using sha1, sha2, tiny_keccak, or blake2
macro_rules! encode {
    (sha1, Sha1, $input:expr, $output:expr) => {{
        let mut hasher = sha1::Sha1::new();
        hasher.update($input);
        $output.copy_from_slice(&hasher.digest().bytes());
    }};
    (sha2, $algorithm:ident, $input:expr, $output:expr) => {{
        let mut hasher = sha2::$algorithm::default();
        hasher.input($input);
        $output.copy_from_slice(hasher.result().as_ref());
    }};
    (tiny, $constructor:ident, $input:expr, $output:expr) => {{
        let mut kec = Keccak::$constructor();
        kec.update($input);
        kec.finalize($output);
    }};
    (blake2, $algorithm:ident, $input:expr, $output:expr) => {{
        let hash = $algorithm($input);
        $output.copy_from_slice(hash.as_ref());
    }};
    (blake2_256, $constructor:ident, $input:expr, $output:expr) => {{
        let hash = $constructor::new()
            .hash_length(32)
            .to_state()
            .update($input)
            .finalize();
        $output.copy_from_slice(hash.as_ref());
    }};
    (blake2_128, $constructor:ident, $input:expr, $output:expr) => {{
        let hash = $constructor::new()
            .hash_length(16)
            .to_state()
            .update($input)
            .finalize();
        $output.copy_from_slice(hash.as_ref());
    }};
}

// And another one to keep the matching DRY
macro_rules! match_encoder {
    ($hash:ident for ($input:expr, $output:expr) {
        $( $hashtype:ident => $lib:ident :: $method:ident, )*
    }) => ({
        match $hash {
            $(
                Hash::$hashtype => encode!($lib, $method, $input, $output),
            )*

            _ => return Err(EncodeError::UnsupportedType)
        }
    })
}

/// Encodes data into a multihash.
///
/// # Errors
///
/// Will return an error if the specified hash type is not supported. See the docs for `Hash`
/// to see what is supported.
///
/// # Examples
///
/// ```
/// use multihash::{encode, Hash};
///
/// assert_eq!(
///     encode(Hash::SHA2256, b"hello world").unwrap().to_vec(),
///     vec![18, 32, 185, 77, 39, 185, 147, 77, 62, 8, 165, 46, 82, 215, 218, 125, 171, 250, 196,
///     132, 239, 227, 122, 83, 128, 238, 144, 136, 247, 172, 226, 239, 205, 233]
/// );
/// ```
///
pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
    // Custom length encoding for the identity multihash
    if let Hash::Identity = hash {
        if u64::from(std::u32::MAX) < as_u64(input.len()) {
            return Err(EncodeError::UnsupportedInputLength);
        }
        let mut buf = encode::u16_buffer();
        let code = encode::u16(hash.code(), &mut buf);
        let mut len_buf = encode::u32_buffer();
        let size = encode::u32(input.len() as u32, &mut len_buf);
        Ok(Multihash {
            storage: Storage::from_slices(&[&code, &size, &input]),
        })
    } else {
        let (offset, mut output) = encode_hash(hash);
        match_encoder!(hash for (input, &mut output[offset ..]) {
            SHA1 => sha1::Sha1,
            SHA2256 => sha2::Sha256,
            SHA2512 => sha2::Sha512,
            SHA3224 => tiny::new_sha3_224,
            SHA3256 => tiny::new_sha3_256,
            SHA3384 => tiny::new_sha3_384,
            SHA3512 => tiny::new_sha3_512,
            Keccak224 => tiny::new_keccak224,
            Keccak256 => tiny::new_keccak256,
            Keccak384 => tiny::new_keccak384,
            Keccak512 => tiny::new_keccak512,
            Blake2b512 => blake2::blake2b,
            Blake2b256 => blake2_256::Blake2bVariable,
            Blake2s256 => blake2::blake2s,
            Blake2s128 => blake2_128::Blake2sVariable,
        });

        Ok(Multihash {
            storage: Storage::from_slice(&output),
        })
    }
}

// Encode the given [`Hash`] value and ensure the returned [`Vec<u8>`]
// has enough capacity to hold the actual digest.
fn encode_hash(hash: Hash) -> (usize, Vec<u8>) {
    let mut buf = encode::u16_buffer();
    let code = encode::u16(hash.code(), &mut buf);

    let len = code.len() + 1 + usize::from(hash.size());

    let mut output = Vec::with_capacity(len);
    output.extend_from_slice(code);
    output.push(hash.size());
    output.resize(len, 0);

    (code.len() + 1, output)
}

/// Represents a valid multihash.
#[derive(Clone)]
pub struct Multihash {
    storage: Storage,
}

impl Debug for Multihash {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
    }
}

impl PartialEq for Multihash {
    fn eq(&self, other: &Self) -> bool {
        self.storage.bytes() == other.storage.bytes()
    }
}

impl Eq for Multihash {}

impl hash::Hash for Multihash {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.storage.bytes().hash(state);
    }
}

impl Multihash {
    /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
    pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
        if let Err(err) = MultihashRef::from_slice(&bytes) {
            return Err(DecodeOwnedError {
                error: err,
                data: bytes,
            });
        }
        Ok(Multihash {
            storage: Storage::from_slice(&bytes),
        })
    }

    /// Returns the bytes representation of the multihash.
    pub fn into_bytes(self) -> Vec<u8> {
        self.to_vec()
    }

    /// Returns the bytes representation of the multihash.
    pub fn to_vec(&self) -> Vec<u8> {
        Vec::from(self.as_bytes())
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &[u8] {
        self.storage.bytes()
    }

    /// Builds a `MultihashRef` corresponding to this `Multihash`.
    pub fn as_ref(&self) -> MultihashRef {
        MultihashRef {
            bytes: self.as_bytes(),
        }
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Hash {
        self.as_ref().algorithm()
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &[u8] {
        self.as_ref().digest()
    }
}

impl AsRef<[u8]> for Multihash {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
    fn eq(&self, other: &MultihashRef<'a>) -> bool {
        &*self.as_bytes() == other.as_bytes()
    }
}

impl TryFrom<Vec<u8>> for Multihash {
    type Error = DecodeOwnedError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Multihash::from_bytes(value)
    }
}

/// Represents a valid multihash.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MultihashRef<'a> {
    bytes: &'a [u8],
}

impl<'a> MultihashRef<'a> {
    /// Creates a `MultihashRef` from the given `input`.
    pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
        if input.is_empty() {
            return Err(DecodeError::BadInputLength);
        }

        // Ensure `Hash::code` returns a `u16` so that our `decode::u16` here is correct.
        std::convert::identity::<fn(Hash) -> u16>(Hash::code);
        let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?;

        let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?;

        // handle the identity case
        if alg == Hash::Identity {
            let (hash_len, bytes) = decode::u32(&bytes).map_err(|_| DecodeError::BadInputLength)?;
            if as_u64(bytes.len()) != u64::from(hash_len) {
                return Err(DecodeError::BadInputLength);
            }
            return Ok(MultihashRef { bytes: input });
        }

        let hash_len = usize::from(alg.size());

        // Length of input after hash code should be exactly hash_len + 1
        if bytes.len() != hash_len + 1 {
            return Err(DecodeError::BadInputLength);
        }

        if usize::from(bytes[0]) != hash_len {
            return Err(DecodeError::BadInputLength);
        }

        Ok(MultihashRef { bytes: input })
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Hash {
        let code = decode::u16(&self.bytes)
            .expect("multihash is known to be valid algorithm")
            .0;
        Hash::from_code(code).expect("multihash is known to be valid")
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &'a [u8] {
        let bytes = decode::u16(&self.bytes)
            .expect("multihash is known to be valid digest")
            .1;
        &bytes[1..]
    }

    /// Builds a `Multihash` that owns the data.
    ///
    /// This operation allocates.
    pub fn to_owned(&self) -> Multihash {
        Multihash {
            storage: Storage::from_slice(self.bytes),
        }
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &'a [u8] {
        &self.bytes
    }
}

impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
    fn eq(&self, other: &Multihash) -> bool {
        self.as_bytes() == &*other.as_bytes()
    }
}

#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
fn as_u64(a: usize) -> u64 {
    a as u64
}
<commit_msg>feat : add ordering for Multihash and MultihashRef (#50)<commit_after>//! # Multihash
//!
//! Implementation of [multihash](https://github.com/multiformats/multihash) in Rust.
//!
//! A `Multihash` is a structure that contains a hashing algorithm, plus some hashed data.
//! A `MultihashRef` is the same as a `Multihash`, except that it doesn't own its data.
//!

mod errors;
mod hashes;
mod storage;

use std::convert::TryFrom;
use std::fmt::Debug;
use std::hash;

use blake2b_simd::{blake2b, Params as Blake2bVariable};
use blake2s_simd::{blake2s, Params as Blake2sVariable};
use sha2::Digest;
use tiny_keccak::Keccak;
use unsigned_varint::{decode, encode};

pub use errors::{DecodeError, DecodeOwnedError, EncodeError};
pub use hashes::Hash;
use std::{cmp, fmt};
use storage::Storage;

// Helper macro for encoding input into output using sha1, sha2, tiny_keccak, or blake2
macro_rules! encode {
    (sha1, Sha1, $input:expr, $output:expr) => {{
        let mut hasher = sha1::Sha1::new();
        hasher.update($input);
        $output.copy_from_slice(&hasher.digest().bytes());
    }};
    (sha2, $algorithm:ident, $input:expr, $output:expr) => {{
        let mut hasher = sha2::$algorithm::default();
        hasher.input($input);
        $output.copy_from_slice(hasher.result().as_ref());
    }};
    (tiny, $constructor:ident, $input:expr, $output:expr) => {{
        let mut kec = Keccak::$constructor();
        kec.update($input);
        kec.finalize($output);
    }};
    (blake2, $algorithm:ident, $input:expr, $output:expr) => {{
        let hash = $algorithm($input);
        $output.copy_from_slice(hash.as_ref());
    }};
    (blake2_256, $constructor:ident, $input:expr, $output:expr) => {{
        let hash = $constructor::new()
            .hash_length(32)
            .to_state()
            .update($input)
            .finalize();
        $output.copy_from_slice(hash.as_ref());
    }};
    (blake2_128, $constructor:ident, $input:expr, $output:expr) => {{
        let hash = $constructor::new()
            .hash_length(16)
            .to_state()
            .update($input)
            .finalize();
        $output.copy_from_slice(hash.as_ref());
    }};
}

// And another one to keep the matching DRY
macro_rules! match_encoder {
    ($hash:ident for ($input:expr, $output:expr) {
        $( $hashtype:ident => $lib:ident :: $method:ident, )*
    }) => ({
        match $hash {
            $(
                Hash::$hashtype => encode!($lib, $method, $input, $output),
            )*

            _ => return Err(EncodeError::UnsupportedType)
        }
    })
}

/// Encodes data into a multihash.
///
/// # Errors
///
/// Will return an error if the specified hash type is not supported. See the docs for `Hash`
/// to see what is supported.
///
/// # Examples
///
/// ```
/// use multihash::{encode, Hash};
///
/// assert_eq!(
///     encode(Hash::SHA2256, b"hello world").unwrap().to_vec(),
///     vec![18, 32, 185, 77, 39, 185, 147, 77, 62, 8, 165, 46, 82, 215, 218, 125, 171, 250, 196,
///     132, 239, 227, 122, 83, 128, 238, 144, 136, 247, 172, 226, 239, 205, 233]
/// );
/// ```
///
pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
    // Custom length encoding for the identity multihash
    if let Hash::Identity = hash {
        if u64::from(std::u32::MAX) < as_u64(input.len()) {
            return Err(EncodeError::UnsupportedInputLength);
        }
        let mut buf = encode::u16_buffer();
        let code = encode::u16(hash.code(), &mut buf);
        let mut len_buf = encode::u32_buffer();
        let size = encode::u32(input.len() as u32, &mut len_buf);
        Ok(Multihash {
            storage: Storage::from_slices(&[&code, &size, &input]),
        })
    } else {
        let (offset, mut output) = encode_hash(hash);
        match_encoder!(hash for (input, &mut output[offset ..]) {
            SHA1 => sha1::Sha1,
            SHA2256 => sha2::Sha256,
            SHA2512 => sha2::Sha512,
            SHA3224 => tiny::new_sha3_224,
            SHA3256 => tiny::new_sha3_256,
            SHA3384 => tiny::new_sha3_384,
            SHA3512 => tiny::new_sha3_512,
            Keccak224 => tiny::new_keccak224,
            Keccak256 => tiny::new_keccak256,
            Keccak384 => tiny::new_keccak384,
            Keccak512 => tiny::new_keccak512,
            Blake2b512 => blake2::blake2b,
            Blake2b256 => blake2_256::Blake2bVariable,
            Blake2s256 => blake2::blake2s,
            Blake2s128 => blake2_128::Blake2sVariable,
        });

        Ok(Multihash {
            storage: Storage::from_slice(&output),
        })
    }
}

// Encode the given [`Hash`] value and ensure the returned [`Vec<u8>`]
// has enough capacity to hold the actual digest.
fn encode_hash(hash: Hash) -> (usize, Vec<u8>) {
    let mut buf = encode::u16_buffer();
    let code = encode::u16(hash.code(), &mut buf);

    let len = code.len() + 1 + usize::from(hash.size());

    let mut output = Vec::with_capacity(len);
    output.extend_from_slice(code);
    output.push(hash.size());
    output.resize(len, 0);

    (code.len() + 1, output)
}

/// Represents a valid multihash.
#[derive(Clone)]
pub struct Multihash {
    storage: Storage,
}

impl Debug for Multihash {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
    }
}

impl PartialEq for Multihash {
    fn eq(&self, other: &Self) -> bool {
        self.storage.bytes() == other.storage.bytes()
    }
}

impl Eq for Multihash {}

impl hash::Hash for Multihash {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.storage.bytes().hash(state);
    }
}

impl Multihash {
    /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
    pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
        if let Err(err) = MultihashRef::from_slice(&bytes) {
            return Err(DecodeOwnedError {
                error: err,
                data: bytes,
            });
        }
        Ok(Multihash {
            storage: Storage::from_slice(&bytes),
        })
    }

    /// Returns the bytes representation of the multihash.
    pub fn into_bytes(self) -> Vec<u8> {
        self.to_vec()
    }

    /// Returns the bytes representation of the multihash.
    pub fn to_vec(&self) -> Vec<u8> {
        Vec::from(self.as_bytes())
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &[u8] {
        self.storage.bytes()
    }

    /// Builds a `MultihashRef` corresponding to this `Multihash`.
    pub fn as_ref(&self) -> MultihashRef {
        MultihashRef {
            bytes: self.as_bytes(),
        }
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Hash {
        self.as_ref().algorithm()
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &[u8] {
        self.as_ref().digest()
    }
}

impl AsRef<[u8]> for Multihash {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
    fn eq(&self, other: &MultihashRef<'a>) -> bool {
        &*self.as_bytes() == other.as_bytes()
    }
}

impl TryFrom<Vec<u8>> for Multihash {
    type Error = DecodeOwnedError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Multihash::from_bytes(value)
    }
}

impl PartialOrd for Multihash {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Multihash {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.as_ref().cmp(&other.as_ref())
    }
}

/// Represents a valid multihash.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultihashRef<'a> {
    bytes: &'a [u8],
}

impl<'a> MultihashRef<'a> {
    /// Creates a `MultihashRef` from the given `input`.
    pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
        if input.is_empty() {
            return Err(DecodeError::BadInputLength);
        }

        // Ensure `Hash::code` returns a `u16` so that our `decode::u16` here is correct.
        std::convert::identity::<fn(Hash) -> u16>(Hash::code);
        let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?;

        let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?;

        // handle the identity case
        if alg == Hash::Identity {
            let (hash_len, bytes) = decode::u32(&bytes).map_err(|_| DecodeError::BadInputLength)?;
            if as_u64(bytes.len()) != u64::from(hash_len) {
                return Err(DecodeError::BadInputLength);
            }
            return Ok(MultihashRef { bytes: input });
        }

        let hash_len = usize::from(alg.size());

        // Length of input after hash code should be exactly hash_len + 1
        if bytes.len() != hash_len + 1 {
            return Err(DecodeError::BadInputLength);
        }

        if usize::from(bytes[0]) != hash_len {
            return Err(DecodeError::BadInputLength);
        }

        Ok(MultihashRef { bytes: input })
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Hash {
        let code = decode::u16(&self.bytes)
            .expect("multihash is known to be valid algorithm")
            .0;
        Hash::from_code(code).expect("multihash is known to be valid")
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &'a [u8] {
        let bytes = decode::u16(&self.bytes)
            .expect("multihash is known to be valid digest")
            .1;
        &bytes[1..]
    }

    /// Builds a `Multihash` that owns the data.
    ///
    /// This operation allocates.
    pub fn to_owned(&self) -> Multihash {
        Multihash {
            storage: Storage::from_slice(self.bytes),
        }
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &'a [u8] {
        &self.bytes
    }
}

impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
    fn eq(&self, other: &Multihash) -> bool {
        self.as_bytes() == &*other.as_bytes()
    }
}

#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
fn as_u64(a: usize) -> u64 {
    a as u64
}
<|endoftext|>


<commit_before>//! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs)
//!
//! Compile-time assertions to ensure that invariants are met.
//!
//! _All_ assertions within this crate are performed at [compile-time]. This
//! allows for finding errors quickly and early when it comes to ensuring
//! certain features or aspects of a codebase. These macros are especially
//! important when exposing a public API that requires types to be the same size
//! or implement certain traits.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.3.3"
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Examples
//!
//! Very thorough examples are provided in the docs for
//! [each individual macro](#macros). Failure case examples are also documented.
//!
//! # Limitations
//!
//! Due to implementation details, some macros can only be used normally from
//! within the context of a function. To use these macros in other contexts, a
//! unique label must be provided.
//!
//! ```compile_fail
//! # #[macro_use] extern crate static_assertions;
//! # fn main() {}
//! // error: expected item after attributes
//! const_assert!(true == true);
//! ```
//!
//! This can be fixed via:
//!
#![cfg_attr(feature = "nightly", doc = "```ignore")]
#![cfg_attr(not(feature = "nightly"), doc = "```")]
//! # #[macro_use] extern crate static_assertions;
//! # fn main() {}
//! const_assert!(label; true == true);
//! ```
//!
//! This can be followed at [issue #1][issue1].
//!
//! ## Labeling Limitation Fix
//!
//!  The labeling workaround is **not
//! necessary** (and is <span style="color:red">r<strong>emoved</strong></span>)
//! when compiling on nightly Rust with the `nightly` feature flag enabled. This
//! can be done by having the following in your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies.static_assertions]
//! version  = "0.3.3"
//! features = ["nightly"]
//! ```
//!
//! To compile with nightly Rust, run the following in your
//! [shell](https://en.wikipedia.org/wiki/Shell_(computing)) or
//! [command prompt](https://en.wikipedia.org/wiki/Command_Prompt) of choice:
//!
//! ```sh
//! rustup install nightly
//! cargo +nightly build
//! ```
//!
//! Notice that this also requires enabling the
//! [`underscore_const_names`](https://github.com/rust-lang/rust/issues/54912)
//! nightly Rust feature:
//!
#![cfg_attr(feature = "nightly", doc = "```")]
#![cfg_attr(not(feature = "nightly"), doc = "```ignore")]
//! #![feature(underscore_const_names)]
//! # #[macro_use] extern crate static_assertions;
//!
//! const_assert!(true != false);
//!
//! fn main() {
//!     const_assert!(false != true);
//! }
//! ```
//!
//! # Changes
//!
//! See [`CHANGELOG.md`](https://github.com/nvzqz/static-assertions-rs/blob/master/CHANGELOG.md)
//! for a complete list of what has changed from one version to another.
//!
//! # Donate
//!
//! This project is made freely available (as in free beer), but unfortunately
//! not all beer is free! So, if you would like to buy me a beer (or coffee or
//! *more*), then consider supporting my work that's benefited your project
//! and thousands of others.
//!
//!
//!
//!
//!
//!
//!
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [compile-time]: https://en.wikipedia.org/wiki/Compile_time
//! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html

#![doc(html_root_url = "https://docs.rs/static_assertions/0.3.3")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png")]

#![no_std]

#![deny(unused_macros)]

#[doc(hidden)]
pub extern crate core as _core;

mod assert_cfg;
mod assert_eq_size;
mod assert_eq_type;
mod assert_fields;
mod assert_impl;
mod assert_ne_type;
mod assert_obj_safe;
mod const_assert;
<commit_msg>Fix `compile_fail` example in crate root<commit_after>//! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs)
//!
//! Compile-time assertions to ensure that invariants are met.
//!
//! _All_ assertions within this crate are performed at [compile-time]. This
//! allows for finding errors quickly and early when it comes to ensuring
//! certain features or aspects of a codebase. These macros are especially
//! important when exposing a public API that requires types to be the same size
//! or implement certain traits.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.3.3"
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Examples
//!
//! Very thorough examples are provided in the docs for
//! [each individual macro](#macros). Failure case examples are also documented.
//!
//! # Limitations
//!
//! Due to implementation details, some macros can only be used normally from
//! within the context of a function. To use these macros in other contexts, a
//! unique label must be provided.
//!
#![cfg_attr(feature = "nightly", doc = "```ignore")]
#![cfg_attr(not(feature = "nightly"), doc = "```compile_fail")]
//! # #[macro_use] extern crate static_assertions;
//! # fn main() {}
//! // error: expected item after attributes
//! const_assert!(true == true);
//! ```
//!
//! This can be fixed via:
//!
#![cfg_attr(feature = "nightly", doc = "```ignore")]
#![cfg_attr(not(feature = "nightly"), doc = "```")]
//! # #[macro_use] extern crate static_assertions;
//! # fn main() {}
//! const_assert!(label; true == true);
//! ```
//!
//! This can be followed at [issue #1][issue1].
//!
//! ## Labeling Limitation Fix
//!
//!  The labeling workaround is **not
//! necessary** (and is removed)
//! when compiling on nightly Rust with the `nightly` feature flag enabled. This
//! can be done by having the following in your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies.static_assertions]
//! version  = "0.3.3"
//! features = ["nightly"]
//! ```
//!
//! To compile with nightly Rust, run the following in your
//! [shell](https://en.wikipedia.org/wiki/Shell_(computing)) or
//! [command prompt](https://en.wikipedia.org/wiki/Command_Prompt) of choice:
//!
//! ```sh
//! rustup install nightly
//! cargo +nightly build
//! ```
//!
//! Notice that this also requires enabling the
//! [`underscore_const_names`](https://github.com/rust-lang/rust/issues/54912)
//! nightly Rust feature:
//!
#![cfg_attr(feature = "nightly", doc = "```")]
#![cfg_attr(not(feature = "nightly"), doc = "```ignore")]
//! #![feature(underscore_const_names)]
//! # #[macro_use] extern crate static_assertions;
//!
//! const_assert!(true != false);
//!
//! fn main() {
//!     const_assert!(false != true);
//! }
//! ```
//!
//! # Changes
//!
//! See [`CHANGELOG.md`](https://github.com/nvzqz/static-assertions-rs/blob/master/CHANGELOG.md)
//! for a complete list of what has changed from one version to another.
//!
//! # Donate
//!
//! This project is made freely available (as in free beer), but unfortunately
//! not all beer is free! So, if you would like to buy me a beer (or coffee or
//! *more*), then consider supporting my work that's benefited your project
//! and thousands of others.
//!
//!
//!
//!
//!
//!
//!
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [compile-time]: https://en.wikipedia.org/wiki/Compile_time
//! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html

#![doc(html_root_url = "https://docs.rs/static_assertions/0.3.3")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png")]

#![no_std]

#![deny(unused_macros)]

#[doc(hidden)]
pub extern crate core as _core;

mod assert_cfg;
mod assert_eq_size;
mod assert_eq_type;
mod assert_fields;
mod assert_impl;
mod assert_ne_type;
mod assert_obj_safe;
mod const_assert;
<|endoftext|>


<commit_before>/*!
# Simple usage

The first step is to create a `Server` object. To do so, simply call `Server::new()`.
The `new()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```rust
let server = httpd::Server::new().unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

Calling `server.recv()` will block until the next request is available.
This is usually what you should do if you write a website in Rust.

This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```rust
loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // user-defined function to handle the request
    handle_request(request)
}
```

If you don't want to block, you can call `server.try_recv()` instead.

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.get_method()` and `request.get_url()` which return
the requested method (GET, POST, etc.) and url.

To handle a request, you need to create a `Response` object. There are multiple
functions that allow you to create this object.
Here is an example of creating a Response from a file:

```rust
let response = httpd::Response::from_file(Path::new("image.png"));
```

All that remains to do is call `request.respond()`:

```rust
request.respond(response)
```
*/

#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate time;
extern crate url;

use std::io::{Acceptor, IoError, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::sync;
use std::sync::Mutex;
use std::comm::Select;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use response::Response;

mod client;
mod common;
mod response;
mod sequential;
mod util;

/// The main class of this library.
///
/// Usually your code will look like this:
///
/// ```
/// let server = httpd::Server::new();
///
/// let pool = std::sync::TaskPool<()>::new(
///     std::cmp::min(1, std::os::num_cpus() - 1), || {}
/// );
///
/// loop {
///     let rq = match server.recv() {
///         Ok(rq) => rq,
///         Err(_) => break
///     };
///
///     pool.execute(proc(_) {
///         handle_request(rq)
///     });
/// }
/// ```
#[unstable]
pub struct Server {
    tasks_pool: Mutex<util::TaskPool>,
    connections_receiver: Receiver<IoResult<(ClientConnection, Sender<()>)>>,
    connections_close: Sender<()>,
    requests_receiver: sync::Mutex<Vec<(Receiver<Request>, Sender<()>)>>,
    listening_addr: ip::SocketAddr,
}

#[unstable]
pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can spawn several threads to
///  handle multiple requests at once.
///
/// It is possible that multiple requests objects are linked to the same client, but
///  don't worry: the library automatically handles synchronization of the answers.
#[unstable]
pub struct Request {
    data_reader: Box<Reader + Send>,
    response_writer: Box<Writer + Send>,
    remote_addr: ip::SocketAddr,
    method: Method,
    path: url::Path,
    http_version: HTTPVersion,
    headers: Vec<Header>,
    body_length: uint,
}

enum ServerRecvEvent {
    NewRequest(Request),
    NewClient((ClientConnection, Sender<()>)),
    ReceiverErrord(uint),
    ServerSocketCrashed(IoError),
}

impl Server {
    /// Builds a new server on port 80 that listens to all inputs.
    #[unstable]
    pub fn new() -> IoResult<Server> {
        Server::new_with_port(80)
    }

    /// Builds a new server on a given port and that listens to all inputs.
    #[unstable]
    pub fn new_with_port(port: ip::Port) -> IoResult<Server> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: port})
    }

    /// Builds a new server on a rand port and that listens to all inputs.
    /// Returns the server and the port it was created on.
    /// This function is guaranteed not to fail because of a port already in use,
    ///  and is useful for testing purposes.
    #[unstable]
    pub fn new_with_random_port() -> IoResult<(Server, ip::Port)> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: 0})
            .map(|s| { let port = s.get_server_addr().port; (s, port) })
    }

    /// Builds a new server that listens on the specified address.
    #[unstable]
    pub fn new_with_addr(addr: &ip::SocketAddr) -> IoResult<Server> {
        // building the TcpAcceptor
        let mut listener = try!(tcp::TcpListener::bind(
            format!("{}", addr.ip).as_slice(), addr.port));
        let local_addr = try!(listener.socket_name());
        let server = try!(listener.listen());
        let (server, tx_close) = util::ClosableTcpAcceptor::new(server);

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;
                    let (read_closable, tx_close) = ClosableTcpStream::new(sock.clone(), true, false);
                    let (write_closable, _) = ClosableTcpStream::new(sock.clone(), false, true);
                    (ClientConnection::new(write_closable, read_closable), tx_close)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        // result
        Ok(Server {
            tasks_pool: Mutex::new(util::TaskPool::new()),
            connections_receiver: rx_incoming,
            connections_close: tx_close,
            requests_receiver: sync::Mutex::new(Vec::new()),
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[unstable]
    pub fn incoming_requests<'a>(&'a self) -> IncomingRequests<'a> {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[experimental]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.recv_impl() {
                NewClient(client) => self.add_client(client),
                NewRequest(rq) => return Ok(rq),
                ReceiverErrord(id) => { self.requests_receiver.lock().remove(id); },
                ServerSocketCrashed(err) => return Err(err)
            }
        }
    }

    /// Returns either a new client or a request, plus a list of connections that are
    ///   no longer valid
    fn recv_impl(&self) -> ServerRecvEvent {
        let mut locked_receivers = self.requests_receiver.lock();

        let select = Select::new();

        // add the handle for a new connection to the select
        let mut connections_handle = select.handle(&self.connections_receiver);
        unsafe { connections_handle.add() };

        // add all the existing connections
        let mut rq_handles = Vec::new();
        for rc in locked_receivers.iter() {
            rq_handles.push(select.handle(rc.ref0()));
        }
        for h in rq_handles.mut_iter() { unsafe { h.add() } }

        // getting the result
        loop {
            // yielding ; this function call is very important for good perfs
            { use std::task; task::deschedule(); }

            // waiting
            let handle_id = select.wait();

            // checking for connections_handle
            if handle_id == connections_handle.id() {
                match connections_handle.recv_opt() {
                    Ok(Ok(connec)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return NewClient(connec);
                    },
                    Ok(Err(err)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return ServerSocketCrashed(err)
                    },
                    _ => ()
                }
            }

            // checking the clients
            let mut result = None;
            for (id, h) in rq_handles.mut_iter().enumerate() {
                if handle_id == h.id() {
                    match h.recv_opt() {
                        Ok(rq) => result = Some(NewRequest(rq)),
                        Err(_) => result = Some(ReceiverErrord(id))
                    }
                    break
                }
            };

            match result {
                None => continue,
                Some(r) => {
                    for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                    unsafe { connections_handle.remove() };
                    return r;
                }
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        self.process_new_clients();

        {
            let mut locked_receivers = self.requests_receiver.lock();
            for rx in locked_receivers.iter() {
                let attempt = rx.ref0().try_recv();
                if attempt.is_ok() {       // TODO: remove the channel if it is closed
                    return Ok(Some(attempt.unwrap()));
                }
            }
        }

        Ok(None)
    }

    /// Does not block.
    fn process_new_clients(&self) {
        let mut new_clients = Vec::new();

        // we add all the elements available on connections_receiver to new_clients
        loop {
            match self.connections_receiver.try_recv() {
                Ok(client) => new_clients.push(client),
                Err(_) => break
            }
        }

        // for each new client, spawning a task that will
        // continuously try to read a Request
        for client in new_clients.move_iter().filter_map(|c| c.ok()) {
            self.add_client(client)
        }
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: (ClientConnection, Sender<()>)) {
        let (client, tx_close) = client;

        let (tx, rx) = channel();

        {
            let mut locked_tasks_pool = self.tasks_pool.lock();
            locked_tasks_pool.spawn(proc() {
                let mut client = client;
                // TODO: when the channel is being closed, immediatly notify the task
                client.advance(|rq| tx.send_opt(rq).is_ok());
            });
        }

        self.requests_receiver.lock().push((rx, tx_close));
    }
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the length of the body in bytes.
    #[unstable]
    pub fn get_body_length(&self) -> uint {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(self) -> Box<Writer + Send> {
        self.response_writer
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }

        // TODO: pass a NullWriter if method is HEAD

        match response.raw_print(passthrough(self.response_writer),
                                self.http_version, self.headers.as_slice())
        {
            Ok(_) => (),
            Err(err) => println!("error while sending answer: {}", err)     // TODO: handle better?
        }
    }
}

impl<'a> Iterator<Request> for IncomingRequests<'a> {
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut std::fmt::Formatter)
        -> Result<(), std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.connections_close.send_opt(()).ok();
    }
}
<commit_msg>Remove reliquate<commit_after>/*!
# Simple usage

The first step is to create a `Server` object. To do so, simply call `Server::new()`.
The `new()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```rust
let server = httpd::Server::new().unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

Calling `server.recv()` will block until the next request is available.
This is usually what you should do if you write a website in Rust.

This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```rust
loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // user-defined function to handle the request
    handle_request(request)
}
```

If you don't want to block, you can call `server.try_recv()` instead.

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.get_method()` and `request.get_url()` which return
the requested method (GET, POST, etc.) and url.

To handle a request, you need to create a `Response` object. There are multiple
functions that allow you to create this object.
Here is an example of creating a Response from a file:

```rust
let response = httpd::Response::from_file(Path::new("image.png"));
```

All that remains to do is call `request.respond()`:

```rust
request.respond(response)
```
*/

#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate time;
extern crate url;

use std::io::{Acceptor, IoError, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::sync;
use std::sync::Mutex;
use std::comm::Select;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use response::Response;

mod client;
mod common;
mod response;
mod sequential;
mod util;

/// The main class of this library.
///
/// Usually your code will look like this:
///
/// ```
/// let server = httpd::Server::new();
///
/// let pool = std::sync::TaskPool<()>::new(
///     std::cmp::min(1, std::os::num_cpus() - 1), || {}
/// );
///
/// loop {
///     let rq = match server.recv() {
///         Ok(rq) => rq,
///         Err(_) => break
///     };
///
///     pool.execute(proc(_) {
///         handle_request(rq)
///     });
/// }
/// ```
#[unstable]
pub struct Server {
    tasks_pool: Mutex<util::TaskPool>,
    connections_receiver: Receiver<IoResult<(ClientConnection, Sender<()>)>>,
    connections_close: Sender<()>,
    requests_receiver: sync::Mutex<Vec<(Receiver<Request>, Sender<()>)>>,
    listening_addr: ip::SocketAddr,
}

#[unstable]
pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can spawn several threads to
///  handle multiple requests at once.
///
/// It is possible that multiple requests objects are linked to the same client, but
///  don't worry: the library automatically handles synchronization of the answers.
#[unstable]
pub struct Request {
    data_reader: Box<Reader + Send>,
    response_writer: Box<Writer + Send>,
    remote_addr: ip::SocketAddr,
    method: Method,
    path: url::Path,
    http_version: HTTPVersion,
    headers: Vec<Header>,
    body_length: uint,
}

enum ServerRecvEvent {
    NewRequest(Request),
    NewClient((ClientConnection, Sender<()>)),
    ReceiverErrord(uint),
    ServerSocketCrashed(IoError),
}

impl Server {
    /// Builds a new server on port 80 that listens to all inputs.
    #[unstable]
    pub fn new() -> IoResult<Server> {
        Server::new_with_port(80)
    }

    /// Builds a new server on a given port and that listens to all inputs.
    #[unstable]
    pub fn new_with_port(port: ip::Port) -> IoResult<Server> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: port})
    }

    /// Builds a new server on a rand port and that listens to all inputs.
    /// Returns the server and the port it was created on.
    /// This function is guaranteed not to fail because of a port already in use,
    ///  and is useful for testing purposes.
    #[unstable]
    pub fn new_with_random_port() -> IoResult<(Server, ip::Port)> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: 0})
            .map(|s| { let port = s.get_server_addr().port; (s, port) })
    }

    /// Builds a new server that listens on the specified address.
    #[unstable]
    pub fn new_with_addr(addr: &ip::SocketAddr) -> IoResult<Server> {
        // building the TcpAcceptor
        let mut listener = try!(tcp::TcpListener::bind(
            format!("{}", addr.ip).as_slice(), addr.port));
        let local_addr = try!(listener.socket_name());
        let server = try!(listener.listen());
        let (server, tx_close) = util::ClosableTcpAcceptor::new(server);

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;
                    let (read_closable, tx_close) = ClosableTcpStream::new(sock.clone(), true, false);
                    let (write_closable, _) = ClosableTcpStream::new(sock.clone(), false, true);
                    (ClientConnection::new(write_closable, read_closable), tx_close)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        // result
        Ok(Server {
            tasks_pool: Mutex::new(util::TaskPool::new()),
            connections_receiver: rx_incoming,
            connections_close: tx_close,
            requests_receiver: sync::Mutex::new(Vec::new()),
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[unstable]
    pub fn incoming_requests<'a>(&'a self) -> IncomingRequests<'a> {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[experimental]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.recv_impl() {
                NewClient(client) => self.add_client(client),
                NewRequest(rq) => return Ok(rq),
                ReceiverErrord(id) => { self.requests_receiver.lock().remove(id); },
                ServerSocketCrashed(err) => return Err(err)
            }
        }
    }

    /// Returns either a new client or a request, plus a list of connections that are
    ///   no longer valid
    fn recv_impl(&self) -> ServerRecvEvent {
        let mut locked_receivers = self.requests_receiver.lock();

        let select = Select::new();

        // add the handle for a new connection to the select
        let mut connections_handle = select.handle(&self.connections_receiver);
        unsafe { connections_handle.add() };

        // add all the existing connections
        let mut rq_handles = Vec::new();
        for rc in locked_receivers.iter() {
            rq_handles.push(select.handle(rc.ref0()));
        }
        for h in rq_handles.mut_iter() { unsafe { h.add() } }

        // getting the result
        loop {
            // waiting
            let handle_id = select.wait();

            // checking for connections_handle
            if handle_id == connections_handle.id() {
                match connections_handle.recv_opt() {
                    Ok(Ok(connec)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return NewClient(connec);
                    },
                    Ok(Err(err)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return ServerSocketCrashed(err)
                    },
                    _ => ()
                }
            }

            // checking the clients
            let mut result = None;
            for (id, h) in rq_handles.mut_iter().enumerate() {
                if handle_id == h.id() {
                    match h.recv_opt() {
                        Ok(rq) => result = Some(NewRequest(rq)),
                        Err(_) => result = Some(ReceiverErrord(id))
                    }
                    break
                }
            };

            match result {
                None => continue,
                Some(r) => {
                    for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                    unsafe { connections_handle.remove() };
                    return r;
                }
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        self.process_new_clients();

        {
            let mut locked_receivers = self.requests_receiver.lock();
            for rx in locked_receivers.iter() {
                let attempt = rx.ref0().try_recv();
                if attempt.is_ok() {       // TODO: remove the channel if it is closed
                    return Ok(Some(attempt.unwrap()));
                }
            }
        }

        Ok(None)
    }

    /// Does not block.
    fn process_new_clients(&self) {
        let mut new_clients = Vec::new();

        // we add all the elements available on connections_receiver to new_clients
        loop {
            match self.connections_receiver.try_recv() {
                Ok(client) => new_clients.push(client),
                Err(_) => break
            }
        }

        // for each new client, spawning a task that will
        // continuously try to read a Request
        for client in new_clients.move_iter().filter_map(|c| c.ok()) {
            self.add_client(client)
        }
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: (ClientConnection, Sender<()>)) {
        let (client, tx_close) = client;

        let (tx, rx) = channel();

        {
            let mut locked_tasks_pool = self.tasks_pool.lock();
            locked_tasks_pool.spawn(proc() {
                let mut client = client;
                // TODO: when the channel is being closed, immediatly notify the task
                client.advance(|rq| tx.send_opt(rq).is_ok());
            });
        }

        self.requests_receiver.lock().push((rx, tx_close));
    }
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the length of the body in bytes.
    #[unstable]
    pub fn get_body_length(&self) -> uint {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(self) -> Box<Writer + Send> {
        self.response_writer
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }

        // TODO: pass a NullWriter if method is HEAD

        match response.raw_print(passthrough(self.response_writer),
                                self.http_version, self.headers.as_slice())
        {
            Ok(_) => (),
            Err(err) => println!("error while sending answer: {}", err)     // TODO: handle better?
        }
    }
}

impl<'a> Iterator<Request> for IncomingRequests<'a> {
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut std::fmt::Formatter)
        -> Result<(), std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.connections_close.send_opt(()).ok();
    }
}
<|endoftext|>