<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate time;
extern crate url;

pub use assets::match_assets;
pub use log::LogEntry;

use std::io;
use std::io::Cursor;
use std::io::Read;
use std::fs::File;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;

pub mod input;

mod assets;
mod log;
mod router;

/// An error that one of your routes can return.
///
/// This is just a convenience enum and you don't need to use it in your project
/// if you don't want to.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RouteError {
    /// Couldn't find a way to handle this request.
    NoRouteFound,

    /// The user input is wrong.
    WrongInput,

    /// The user must be logged in.
    LoginRequired,

    /// The user entered a wrong login or password.
    WrongLoginPassword,

    /// The user is logged in but shouldn't be there.
    NotAuthorized,
}

/// Starts a server and uses the given requests handler.
///
/// The request handler takes a `&Request` and must return a `Response` to send to the user.
///
/// # Common mistakes
///
/// The handler must capture its environment by value and not by reference (`'static`). If you
/// use closure, don't forget to put `move` in front of the closure.
///
/// The handler must also be thread-safe (`Send` and `Sync`).
/// For example this handler isn't thread-safe:
///
/// ```ignore
/// let mut requests_counter = 0;
///
/// rouille::start_server("localhost:80", move |request| {
///     requests_counter += 1;
///
///     // rest of the handler
/// })
/// ```
///
/// Multiple requests can be processed simultaneously, therefore you can't mutably access
/// variables from the outside.
///
/// Instead you must use a `Mutex`:
///
/// ```no_run
/// use std::sync::Mutex;
/// let requests_counter = Mutex::new(0);
///
/// rouille::start_server("localhost:80", move |request| {
///     *requests_counter.lock().unwrap() += 1;
///
///     // rest of the handler
/// # panic!()
/// })
/// ```
///
/// # Panic handling
///
/// If your request handler panicks, a 500 error will automatically be sent to the client.
///
pub fn start_server<A, F>(addr: A, handler: F) -> !
                          where A: ToSocketAddrs,
                                F: Send + Sync + 'static + Fn(&Request) -> Response
{
    // TODO: unused result?!?
    // TODO: does this block forever or not?
    hyper::server::Server::http(addr).unwrap().handle(Handler(handler));

    struct Handler<H>(H);
    impl<H> hyper::server::Handler for Handler<H>
            where H: Send + Sync + 'static + Fn(&Request) -> Response
    {
        fn handle<'a, 'k>(&'a self, mut hrequest: hyper::server::request::Request<'a, 'k>,
                          mut hresponse: hyper::server::response::Response<'a, hyper::net::Fresh>)
        {
            *hresponse.status_mut() = hyper::status::StatusCode::InternalServerError;

            // TODO: don't read the body in memory immediately
            let mut data = Vec::new();
            hrequest.read_to_end(&mut data);     // TODO: handle error

            // building the `Request` object
            let request = Request {
                url: format!("{}", hrequest.uri),   // TODO: handle this properly?
                method: hrequest.method.as_ref().to_owned(),
                headers: hrequest.headers.iter().map(|h| (h.name().to_owned(), h.value_string()))
                                                .collect(),
                https: false,
                data: data,
            };

            // calling the handler ; this most likely takes a lot of time
            let mut response = (self.0)(&request);

            // writing the status code
            *hresponse.status_mut() = hyper::status::StatusCode::from_u16(response.status_code);

            // writing headers
            for (key, value) in response.headers {
                // FIXME: multiple headers with the same key
                hresponse.headers_mut().set_raw(key, vec![value.into_bytes()]);
            }

            if let Some(len) = response.data.data_length {
                hresponse.headers_mut().set(hyper::header::ContentLength(len as u64));
            }

            // sending status code and headers
            let mut hresponse = match hresponse.start() {
                Err(_) => return,
                Ok(r) => r
            };

            let _ = io::copy(response.data.data.by_ref(), &mut hresponse);
            let _ = hresponse.end();
        }
    }

    unreachable!()      // TODO: ?!?
}

/// Represents a request made by the client.
pub struct Request {
    method: String,
    url: String,
    headers: Vec<(String, String)>,
    https: bool,
    data: Vec<u8>,
}

impl Request {
    /// Builds a fake HTTP request to be used during tests.
    pub fn fake_http<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
                           -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: false,
            data: data,
            headers: headers,
        }
    }

    /// Builds a fake HTTPS request to be used during tests.
    pub fn fake_https<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
                            -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: true,
            data: data,
            headers: headers,
        }
    }

    /// Returns `true` if the request uses HTTPS instead of HTTP.
    #[inline]
    pub fn secure(&self) -> bool {
        self.https
    }

    /// Returns the method of the request (`GET`, `POST`, etc.).
    #[inline]
    pub fn method(&self) -> &str {
        &self.method
    }

    /// Returns the URL requested by the client. It is not decoded and thus can contain strings
    /// such as `%20`.
    ///
    /// See also `url`.
    #[inline]
    pub fn raw_url(&self) -> &str {
        &self.url
    }

    /// Returns the URL requested by the client.
    ///
    /// Contrary to `raw_url`, special characters have been decoded.
    /// If there is any non-unicode character in the URL, it will be replaced with `U+FFFD`.
    pub fn url(&self) -> String {
        url::percent_encoding::lossy_utf8_percent_decode(self.url.as_bytes())
    }

    /// Returns the value of a header of the request.
    #[inline]
    pub fn header(&self, key: &str) -> Option<String> {
        self.headers.iter().find(|&&(ref k, _)| k == key).map(|&(_, ref v)| v.clone())
    }

    /// Returns the data of the request.
    pub fn data(&self) -> Vec<u8> {
        self.data.clone()
    }
}

/// Contains a prototype of a response.
/// The response is only sent when you call `Request::respond`.
pub struct Response {
    /// The status code to return to the user.
    pub status_code: u16,

    /// List of headers to be returned in the response.
    ///
    /// Note that important headers such as `Connection` or `Content-Length` will be ignored
    /// from this list.
    // TODO: document precisely which headers
    pub headers: Vec<(String, String)>,

    /// An opaque type that contains the body of the response.
    pub data: ResponseBody,
}

impl Response {
    /// UNSTABLE. Builds a default response to handle the given route error.
    ///
    /// Important: don't use this in a real website. This function is just a convenience when
    /// prototyping.
    ///
    /// For authentication-related errors, you are strongly encouraged to handle them yourself.
    #[inline]
    pub fn from_error(err: &RouteError) -> Response {
        match err {
            &RouteError::NoRouteFound => Response {
                status_code: 404, headers: vec![], data: ResponseBody::empty()
            },
            &RouteError::WrongInput => Response {
                status_code: 400, headers: vec![], data: ResponseBody::empty()
            },
            &RouteError::LoginRequired => Response {
                status_code: 401, headers: vec![], data: ResponseBody::empty()
            },     // TODO: www-auth header?
            &RouteError::WrongLoginPassword => Response {
                status_code: 401, headers: vec![], data: ResponseBody::empty()
            },     // TODO: www-auth header?
            &RouteError::NotAuthorized => Response {
                status_code: 403, headers: vec![], data: ResponseBody::empty()
            },
        }
    }

    /// Builds a `Response` that redirects the user to another URL.
    #[inline]
    pub fn redirect(target: &str) -> Response {
        Response {
            status_code: 303,
            headers: vec![("Location".to_owned(), target.to_owned())],
            data: ResponseBody::empty(),
        }
    }

    /// Builds a `Response` that outputs HTML.
    #[inline]
    pub fn html<D>(content: D) -> Response where D: Into<Vec<u8>> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/html; charset=utf8".to_owned())],
            data: ResponseBody::from_data(content),
        }
    }

    /// Builds a `Response` that outputs plain text.
    #[inline]
    pub fn text<S>(text: S) -> Response where S: Into<String> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/plain; charset=utf8".to_owned())],
            data: ResponseBody::from_string(text),
        }
    }

    /// Builds a `Response` that outputs JSON.
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();

        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
            data: ResponseBody::from_data(data),
        }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        Response {
            status_code: 401,
            headers: vec![("WWW-Authenticate".to_owned(), format!("Basic realm=\"{}\"", realm))],
            data: ResponseBody::empty(),
        }
    }
}

/// An opaque type that represents the body of a response.
pub struct ResponseBody {
    data: Box<Read + Send>,
    data_length: Option<usize>,
}

impl ResponseBody {
    /// Builds a `ResponseBody` that doesn't return any data.
    #[inline]
    pub fn empty() -> ResponseBody {
        ResponseBody {
            data: Box::new(io::empty()),
            data_length: Some(0),
        }
    }

    /// Builds a new `ResponseBody` that will read the data from a `Read`.
    ///
    /// Note that this is suboptimal compared to other constructors because the length
    /// isn't known in advance.
    #[inline]
    pub fn from_reader<R>(data: R) -> ResponseBody where R: Read + Send + 'static {
        ResponseBody {
            data: Box::new(data),
            data_length: None,
        }
    }

    /// Builds a new `ResponseBody` that returns the given data.
    #[inline]
    pub fn from_data<D>(data: D) -> ResponseBody where D: Into<Vec<u8>> {
        let data = data.into();
        let len = data.len();

        ResponseBody {
            data: Box::new(Cursor::new(data)),
            data_length: Some(len),
        }
    }

    /// Builds a new `ResponseBody` that returns the content of the given file.
    #[inline]
    pub fn from_file(file: File) -> ResponseBody {
        let len = file.metadata().map(|metadata| metadata.len() as usize).ok();

        ResponseBody {
            data: Box::new(file),
            data_length: len,
        }
    }

    /// Builds a new `ResponseBody` that returns an UTF-8 string.
    #[inline]
    pub fn from_string<S>(data: S) -> ResponseBody where S: Into<String> {
        ResponseBody::from_data(data.into().into_bytes())
    }
}
<commit_msg>Add Request::remote_addr, Request::fake_http_from, Request::fake_https_from<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate time;
extern crate url;

pub use assets::match_assets;
pub use log::LogEntry;

use std::io;
use std::io::Cursor;
use std::io::Read;
use std::fs::File;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;

pub mod input;

mod assets;
mod log;
mod router;

/// An error that one of your routes can return.
///
/// This is just a convenience enum and you don't need to use it in your project
/// if you don't want to.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RouteError {
    /// Couldn't find a way to handle this request.
    NoRouteFound,

    /// The user input is wrong.
    WrongInput,

    /// The user must be logged in.
    LoginRequired,

    /// The user entered a wrong login or password.
    WrongLoginPassword,

    /// The user is logged in but shouldn't be there.
    NotAuthorized,
}

/// Starts a server and uses the given requests handler.
///
/// The request handler takes a `&Request` and must return a `Response` to send to the user.
///
/// # Common mistakes
///
/// The handler must capture its environment by value and not by reference (`'static`). If you
/// use closure, don't forget to put `move` in front of the closure.
///
/// The handler must also be thread-safe (`Send` and `Sync`).
/// For example this handler isn't thread-safe:
///
/// ```ignore
/// let mut requests_counter = 0;
///
/// rouille::start_server("localhost:80", move |request| {
///     requests_counter += 1;
///
///     // rest of the handler
/// })
/// ```
///
/// Multiple requests can be processed simultaneously, therefore you can't mutably access
/// variables from the outside.
///
/// Instead you must use a `Mutex`:
///
/// ```no_run
/// use std::sync::Mutex;
/// let requests_counter = Mutex::new(0);
///
/// rouille::start_server("localhost:80", move |request| {
///     *requests_counter.lock().unwrap() += 1;
///
///     // rest of the handler
/// # panic!()
/// })
/// ```
///
/// # Panic handling
///
/// If your request handler panicks, a 500 error will automatically be sent to the client.
///
pub fn start_server<A, F>(addr: A, handler: F) -> !
                          where A: ToSocketAddrs,
                                F: Send + Sync + 'static + Fn(&Request) -> Response
{
    // TODO: unused result?!?
    // TODO: does this block forever or not?
    hyper::server::Server::http(addr).unwrap().handle(Handler(handler));

    struct Handler<H>(H);
    impl<H> hyper::server::Handler for Handler<H>
            where H: Send + Sync + 'static + Fn(&Request) -> Response
    {
        fn handle<'a, 'k>(&'a self, mut hrequest: hyper::server::request::Request<'a, 'k>,
                          mut hresponse: hyper::server::response::Response<'a, hyper::net::Fresh>)
        {
            *hresponse.status_mut() = hyper::status::StatusCode::InternalServerError;

            // TODO: don't read the body in memory immediately
            let mut data = Vec::new();
            hrequest.read_to_end(&mut data);     // TODO: handle error

            // building the `Request` object
            let request = Request {
                url: format!("{}", hrequest.uri),   // TODO: handle this properly?
                method: hrequest.method.as_ref().to_owned(),
                headers: hrequest.headers.iter().map(|h| (h.name().to_owned(), h.value_string()))
                                                .collect(),
                https: false,
                data: data,
                remote_addr: hrequest.remote_addr.clone(),
            };

            // calling the handler ; this most likely takes a lot of time
            let mut response = (self.0)(&request);

            // writing the status code
            *hresponse.status_mut() = hyper::status::StatusCode::from_u16(response.status_code);

            // writing headers
            for (key, value) in response.headers {
                // FIXME: multiple headers with the same key
                hresponse.headers_mut().set_raw(key, vec![value.into_bytes()]);
            }

            if let Some(len) = response.data.data_length {
                hresponse.headers_mut().set(hyper::header::ContentLength(len as u64));
            }

            // sending status code and headers
            let mut hresponse = match hresponse.start() {
                Err(_) => return,
                Ok(r) => r
            };

            let _ = io::copy(response.data.data.by_ref(), &mut hresponse);
            let _ = hresponse.end();
        }
    }

    unreachable!()      // TODO: ?!?
}

/// Represents a request made by the client.
pub struct Request {
    method: String,
    url: String,
    headers: Vec<(String, String)>,
    https: bool,
    data: Vec<u8>,
    remote_addr: SocketAddr,
}

impl Request {
    /// Builds a fake HTTP request to be used during tests.
    pub fn fake_http<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
                           -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: false,
            data: data,
            headers: headers,
            remote_addr: "127.0.0.1:12345".parse().unwrap(),
        }
    }

    /// Builds a fake HTTP request to be used during tests.
    pub fn fake_http_from<U, M>(from: SocketAddr, method: M, url: U,
                                headers: Vec<(String, String)>, data: Vec<u8>)
                                -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: false,
            data: data,
            headers: headers,
            remote_addr: from,
        }
    }

    /// Builds a fake HTTPS request to be used during tests.
    pub fn fake_https<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
                            -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: true,
            data: data,
            headers: headers,
            remote_addr: "127.0.0.1:12345".parse().unwrap(),
        }
    }

    /// Builds a fake HTTPS request to be used during tests.
    pub fn fake_https_from<U, M>(from: SocketAddr, method: M, url: U,
                                 headers: Vec<(String, String)>, data: Vec<u8>)
                                 -> Request where U: Into<String>, M: Into<String>
    {
        Request {
            url: url.into(),
            method: method.into(),
            https: true,
            data: data,
            headers: headers,
            remote_addr: from,
        }
    }

    /// Returns `true` if the request uses HTTPS instead of HTTP.
    #[inline]
    pub fn secure(&self) -> bool {
        self.https
    }

    /// Returns the method of the request (`GET`, `POST`, etc.).
    #[inline]
    pub fn method(&self) -> &str {
        &self.method
    }

    /// Returns the URL requested by the client. It is not decoded and thus can contain strings
    /// such as `%20`.
    ///
    /// See also `url`.
    #[inline]
    pub fn raw_url(&self) -> &str {
        &self.url
    }

    /// Returns the URL requested by the client.
    ///
    /// Contrary to `raw_url`, special characters have been decoded.
    /// If there is any non-unicode character in the URL, it will be replaced with `U+FFFD`.
    pub fn url(&self) -> String {
        url::percent_encoding::lossy_utf8_percent_decode(self.url.as_bytes())
    }

    /// Returns the value of a header of the request.
    #[inline]
    pub fn header(&self, key: &str) -> Option<String> {
        self.headers.iter().find(|&&(ref k, _)| k == key).map(|&(_, ref v)| v.clone())
    }

    /// Returns the data of the request.
    pub fn data(&self) -> Vec<u8> {
        self.data.clone()
    }

    /// Returns the address of the client.
    #[inline]
    pub fn remote_addr(&self) -> &SocketAddr {
        &self.remote_addr
    }
}

/// Contains a prototype of a response.
/// The response is only sent when you call `Request::respond`.
pub struct Response {
    /// The status code to return to the user.
    pub status_code: u16,

    /// List of headers to be returned in the response.
    ///
    /// Note that important headers such as `Connection` or `Content-Length` will be ignored
    /// from this list.
    // TODO: document precisely which headers
    pub headers: Vec<(String, String)>,

    /// An opaque type that contains the body of the response.
    pub data: ResponseBody,
}

impl Response {
    /// UNSTABLE. Builds a default response to handle the given route error.
    ///
    /// Important: don't use this in a real website. This function is just a convenience when
    /// prototyping.
    ///
    /// For authentication-related errors, you are strongly encouraged to handle them yourself.
    #[inline]
    pub fn from_error(err: &RouteError) -> Response {
        match err {
            &RouteError::NoRouteFound => Response {
                status_code: 404, headers: vec![], data: ResponseBody::empty()
            },
            &RouteError::WrongInput => Response {
                status_code: 400, headers: vec![], data: ResponseBody::empty()
            },
            &RouteError::LoginRequired => Response {
                status_code: 401, headers: vec![], data: ResponseBody::empty()
            },     // TODO: www-auth header?
            &RouteError::WrongLoginPassword => Response {
                status_code: 401, headers: vec![], data: ResponseBody::empty()
            },     // TODO: www-auth header?
            &RouteError::NotAuthorized => Response {
                status_code: 403, headers: vec![], data: ResponseBody::empty()
            },
        }
    }

    /// Builds a `Response` that redirects the user to another URL.
    #[inline]
    pub fn redirect(target: &str) -> Response {
        Response {
            status_code: 303,
            headers: vec![("Location".to_owned(), target.to_owned())],
            data: ResponseBody::empty(),
        }
    }

    /// Builds a `Response` that outputs HTML.
    #[inline]
    pub fn html<D>(content: D) -> Response where D: Into<Vec<u8>> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/html; charset=utf8".to_owned())],
            data: ResponseBody::from_data(content),
        }
    }

    /// Builds a `Response` that outputs plain text.
    #[inline]
    pub fn text<S>(text: S) -> Response where S: Into<String> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/plain; charset=utf8".to_owned())],
            data: ResponseBody::from_string(text),
        }
    }

    /// Builds a `Response` that outputs JSON.
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();

        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
            data: ResponseBody::from_data(data),
        }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        Response {
            status_code: 401,
            headers: vec![("WWW-Authenticate".to_owned(), format!("Basic realm=\"{}\"", realm))],
            data: ResponseBody::empty(),
        }
    }
}

/// An opaque type that represents the body of a response.
pub struct ResponseBody {
    data: Box<Read + Send>,
    data_length: Option<usize>,
}

impl ResponseBody {
    /// Builds a `ResponseBody` that doesn't return any data.
    #[inline]
    pub fn empty() -> ResponseBody {
        ResponseBody {
            data: Box::new(io::empty()),
            data_length: Some(0),
        }
    }

    /// Builds a new `ResponseBody` that will read the data from a `Read`.
    ///
    /// Note that this is suboptimal compared to other constructors because the length
    /// isn't known in advance.
    #[inline]
    pub fn from_reader<R>(data: R) -> ResponseBody where R: Read + Send + 'static {
        ResponseBody {
            data: Box::new(data),
            data_length: None,
        }
    }

    /// Builds a new `ResponseBody` that returns the given data.
    #[inline]
    pub fn from_data<D>(data: D) -> ResponseBody where D: Into<Vec<u8>> {
        let data = data.into();
        let len = data.len();

        ResponseBody {
            data: Box::new(Cursor::new(data)),
            data_length: Some(len),
        }
    }

    /// Builds a new `ResponseBody` that returns the content of the given file.
    #[inline]
    pub fn from_file(file: File) -> ResponseBody {
        let len = file.metadata().map(|metadata| metadata.len() as usize).ok();

        ResponseBody {
            data: Box::new(file),
            data_length: len,
        }
    }

    /// Builds a new `ResponseBody` that returns an UTF-8 string.
    #[inline]
    pub fn from_string<S>(data: S) -> ResponseBody where S: Into<String> {
        ResponseBody::from_data(data.into().into_bytes())
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate libc;

use std::fmt;
use std::ptr;
use std::str;

type HttpCallback = extern fn(*mut HttpParser) -> libc::c_int;
type HttpDataCallback = extern fn(*mut HttpParser, *const u32, libc::size_t) -> libc::c_int;

#[repr(C)]
#[derive(Clone, Copy)]
enum ParserType {
    HttpRequest,
    HttpResponse,
    HttpBoth
}

#[repr(C)]
struct HttpParser {
    // Private Interface
    _internal_state: libc::uint32_t,
    _nread: libc::uint32_t,
    _content_length: libc::uint64_t,

    // Read-Only
    http_major: libc::c_ushort,
    http_minor: libc::c_ushort,
    _extended_status: libc::uint32_t,

    // Public Interface
    data: *mut libc::c_void
}

impl HttpParser {
    fn new() -> HttpParser {
        HttpParser {
            _internal_state: 0,
            _nread: 0,
            _content_length: 0,
            _extended_status: 0,
            http_major: 0,
            http_minor: 0,
            data: 0 as *mut libc::c_void
        }
    }

    fn status_code(&self) -> u16 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return (flags & 0xFFFF) as u16;
        }
    }

    fn method_code(&self) -> u8 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 16) & 0xFF) as u8;
        }
    }

    fn http_errno(&self) -> u8 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 24) & 0x7F) as u8;
        }
    }

    fn upgrade(&self) -> bool {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 31) & 0x01) == 1;
        }
    }

    fn http_method_str(&self) -> &str {
        unsafe {
            let method_str = http_method_str(self.method_code());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }

    fn http_errno_name(&self) -> &str {
        unsafe {
            let method_str = http_errno_name(self.http_errno());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }

    fn http_errno_description(&self) -> &str {
        unsafe {
            let method_str = http_errno_description(self.http_errno());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }
}

impl fmt::Debug for HttpParser {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        return write!(fmt, "status_code: {}\n\
                            method: 0x{:X}, {}\n\
                            errno: 0x{:X}, {}, {}\n\
                            upgrade: {}\n\
                            http_version: {}.{}",
                      self.status_code(), self.method_code(), self.http_method_str(), self.http_errno(), self.http_errno_name(), self.http_errno_description(), self.upgrade(), self.http_major, self.http_minor);
    }
}

#[repr(C)]
struct HttpParserSettings {
    on_message_begin: HttpCallback,
    on_url: HttpDataCallback,
    on_status: HttpDataCallback,
    on_header_field: HttpDataCallback,
    on_header_value: HttpDataCallback,
    on_headers_complete: HttpCallback,
    on_body: HttpDataCallback,
    on_message_complete: HttpCallback,
    on_chunk_header: HttpCallback,
    on_chunk_complete: HttpCallback
}

#[inline]
unsafe fn unwrap_parser<'a>(http: *mut HttpParser) -> &'a mut Parser<'a> {
    return &mut *((*http).data as *mut Parser);
}

macro_rules! notify_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback(http: *mut HttpParser) -> libc::c_int {
            unsafe {
                let result = unwrap_parser(http).handler.$callback();
                if result.is_none() {
                    return 0;
                } else {
                    return result.unwrap() as libc::c_int;
                }
            };
        };
        $callback
    });
}

macro_rules! data_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback(http: *mut HttpParser, data: *const u32, size: libc::size_t) -> libc::c_int {
            unsafe {
                let mut dst = Vec::<u8>::with_capacity(size as usize);
                dst.set_len(size as usize);
                ptr::copy(data as *const u8, dst.as_mut_ptr(), size as usize);

                let data = String::from_utf8(dst).unwrap();

                let result = unwrap_parser(http).handler.$callback(&data);
                if result.is_none() {
                    return 0;
                } else {
                    return result.unwrap() as libc::c_int;
                }
            };
        };

        $callback
    });
}

static CALLBACK_WRAPPERS: HttpParserSettings = HttpParserSettings {
    on_url: data_fn_wrapper!(on_url),
    on_message_begin: notify_fn_wrapper!(on_message_begin),
    on_status: data_fn_wrapper!(on_status),
    on_header_field: data_fn_wrapper!(on_header_field),
    on_header_value: data_fn_wrapper!(on_header_value),
    on_headers_complete: notify_fn_wrapper!(on_headers_complete),
    on_body: data_fn_wrapper!(on_body),
    on_message_complete: notify_fn_wrapper!(on_message_complete),
    on_chunk_header: notify_fn_wrapper!(on_chunk_header),
    on_chunk_complete: notify_fn_wrapper!(on_chunk_complete)
};

extern "C" {
    fn http_parser_version() -> u32;
    fn http_parser_init(parser: *mut HttpParser, parser_type: ParserType);
    fn http_parser_settings_init(settings: *mut HttpParserSettings);
    fn http_parser_execute(parser: *mut HttpParser, settings: *const HttpParserSettings, data: *const u8, len: libc::size_t) -> libc::size_t;
    fn http_method_str(method_code: u8) -> *const libc::c_char;
    fn http_errno_name(http_errno: u8) -> *const libc::c_char;
    fn http_errno_description(http_errno: u8) -> *const libc::c_char;

    // Helper function to predictably use aligned bit-field struct
    fn http_get_struct_flags(parser: *const HttpParser) -> u32;
}

// High level Rust interface
pub trait ParserHandler {
    fn on_url(&self, &String) -> Option<u16> { None }
    fn on_status(&self, &String) -> Option<u16> { None }
    fn on_header_field(&self, &String) -> Option<u16> { None }
    fn on_header_value(&self, &String) -> Option<u16> { None }
    fn on_body(&self, &String) -> Option<u16> { None }
    fn on_message_begin(&self) -> Option<u16> { None }
    fn on_headers_complete(&self) -> Option<u16> { None }
    fn on_message_complete(&self) -> Option<u16> { None }
    fn on_chunk_header(&self) -> Option<u16> { None }
    fn on_chunk_complete(&self) -> Option<u16> { None }
}

pub struct Parser<'a> {
    handler: &'a ParserHandler,
    state: HttpParser,
    parser_type: ParserType
}

impl<'a> Parser<'a> {
    pub fn response(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpResponse
        }
    }

    pub fn request(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpRequest
        }
    }

    pub fn request_and_response(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpBoth
        }
    }

    pub fn http_version(&self) -> (u16, u16) { return (self.state.http_major, self.state.http_minor) }
    pub fn http_status_code(&self) -> u16 { return self.state.status_code(); }
    pub fn is_upgrade(&self) -> bool { return self.state.upgrade() }
    pub fn http_method(&self) -> &str { return self.state.http_method_str(); }
}

pub fn parse(parser: &mut Parser, data: &[u8]) -> usize {
    unsafe {
        http_parser_init(&mut parser.state as *mut _, parser.parser_type);

        parser.state.data = &mut (*parser) as *mut _ as *mut libc::c_void;

        return http_parser_execute(&mut parser.state as *mut _,
                                         &CALLBACK_WRAPPERS as *const _,
                                         data.as_ptr(),
                                         data.len() as u64) as usize;
    }
}

pub fn version() -> String {
    unsafe {
        let v = http_parser_version();

        let major = (v >> 16) & 255;
        let minor = (v >> 8) & 255;
        let patch = v & 255;

        return fmt::format(format_args!("{}.{}.{}", major, minor, patch));
    }
}

#[test]
fn test_version() {
    assert_eq!("2.5.0", version());
}

#[test]
fn test_request_parser() {
    struct TestRequestParser;
    impl ParserHandler for TestRequestParser {
        fn on_url(&self, url: &String) -> Option<u16> {
            assert_eq!("/say_hello", url);
            None
        }
        fn on_header_field(&self, hdr: &String) -> Option<u16> {
            assert!(hdr == "Host" || hdr == "Content-Length");
            None
        }
        fn on_header_value(&self, val: &String) -> Option<u16> {
            assert!(val == "localhost.localdomain" || val == "11");
            None
        }
        fn on_body(&self, body: &String) -> Option<u16> {
            assert_eq!(body, "Hello world");
            None
        }
    }

    let req = "POST /say_hello HTTP/1.1\r\nContent-Length: 11\r\nHost: localhost.localdomain\r\n\r\nHello world";

    let handler = TestRequestParser;
    let mut parser = Parser::request(&handler);
    let parsed = parse(&mut parser, req.as_bytes());

    assert!(parsed > 0);
    assert_eq!((1, 1), parser.http_version());
    assert_eq!("POST", parser.http_method());
}

#[test]
fn test_response_parser() {
    struct TestResponseParser;
    impl ParserHandler for TestResponseParser {
        fn on_status(&self, status: &String) -> Option<u16> {
            assert_eq!("OK", status);
            None
        }
        fn on_header_field(&self, hdr: &String) -> Option<u16> {
            assert_eq!("Host", hdr);
            None
        }
        fn on_header_value(&self, val: &String) -> Option<u16> {
            assert_eq!("localhost.localdomain", val);
            None
        }
    }

    let req = "HTTP/1.1 200 OK\r\nHost: localhost.localdomain\r\n\r\n";

    let handler = TestResponseParser;
    let mut parser = Parser::response(&handler);
    let parsed = parse(&mut parser, req.as_bytes());

    assert!(parsed > 0);
    assert_eq!((1, 1), parser.http_version());
    assert_eq!(200, parser.http_status_code());
}

#[test]
fn test_ws_upgrade() {
    struct DummyHandler;
    impl ParserHandler for DummyHandler {};

    let req = "GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n";

    let handler = DummyHandler;
    let mut parser = Parser::request(&handler);
    parse(&mut parser, req.as_bytes());

    assert_eq!(parser.is_upgrade(), true);
}
<commit_msg>Test status return from a callback<commit_after>#![allow(dead_code)]
extern crate libc;

use std::fmt;
use std::ptr;
use std::str;

type HttpCallback = extern fn(*mut HttpParser) -> libc::c_int;
type HttpDataCallback = extern fn(*mut HttpParser, *const u32, libc::size_t) -> libc::c_int;

#[repr(C)]
#[derive(Clone, Copy)]
enum ParserType {
    HttpRequest,
    HttpResponse,
    HttpBoth
}

#[repr(C)]
struct HttpParser {
    // Private Interface
    _internal_state: libc::uint32_t,
    _nread: libc::uint32_t,
    _content_length: libc::uint64_t,

    // Read-Only
    http_major: libc::c_ushort,
    http_minor: libc::c_ushort,
    _extended_status: libc::uint32_t,

    // Public Interface
    data: *mut libc::c_void
}

impl HttpParser {
    fn new() -> HttpParser {
        HttpParser {
            _internal_state: 0,
            _nread: 0,
            _content_length: 0,
            _extended_status: 0,
            http_major: 0,
            http_minor: 0,
            data: 0 as *mut libc::c_void
        }
    }

    fn status_code(&self) -> u16 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return (flags & 0xFFFF) as u16;
        }
    }

    fn method_code(&self) -> u8 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 16) & 0xFF) as u8;
        }
    }

    fn http_errno(&self) -> u8 {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 24) & 0x7F) as u8;
        }
    }

    fn upgrade(&self) -> bool {
        unsafe {
            let flags = http_get_struct_flags(self as *const _);
            return ((flags >> 31) & 0x01) == 1;
        }
    }

    fn http_method_str(&self) -> &str {
        unsafe {
            let method_str = http_method_str(self.method_code());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }

    fn http_errno_name(&self) -> &str {
        unsafe {
            let method_str = http_errno_name(self.http_errno());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }

    fn http_errno_description(&self) -> &str {
        unsafe {
            let method_str = http_errno_description(self.http_errno());
            let buf = std::ffi::CStr::from_ptr(method_str);
            return str::from_utf8(buf.to_bytes()).unwrap();
        }
    }
}

impl fmt::Debug for HttpParser {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        return write!(fmt, "status_code: {}\n\
                            method: 0x{:X}, {}\n\
                            errno: 0x{:X}, {}, {}\n\
                            upgrade: {}\n\
                            http_version: {}.{}",
                      self.status_code(), self.method_code(), self.http_method_str(), self.http_errno(), self.http_errno_name(), self.http_errno_description(), self.upgrade(), self.http_major, self.http_minor);
    }
}

#[repr(C)]
struct HttpParserSettings {
    on_message_begin: HttpCallback,
    on_url: HttpDataCallback,
    on_status: HttpDataCallback,
    on_header_field: HttpDataCallback,
    on_header_value: HttpDataCallback,
    on_headers_complete: HttpCallback,
    on_body: HttpDataCallback,
    on_message_complete: HttpCallback,
    on_chunk_header: HttpCallback,
    on_chunk_complete: HttpCallback
}

#[inline]
unsafe fn unwrap_parser<'a>(http: *mut HttpParser) -> &'a mut Parser<'a> {
    return &mut *((*http).data as *mut Parser);
}

macro_rules! notify_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback(http: *mut HttpParser) -> libc::c_int {
            unsafe {
                let result = unwrap_parser(http).handler.$callback();
                if result.is_none() {
                    return 0;
                } else {
                    return result.unwrap() as libc::c_int;
                }
            };
        };
        $callback
    });
}

macro_rules! data_fn_wrapper {
    ( $callback:ident ) => ({
        extern "C" fn $callback(http: *mut HttpParser, data: *const u32, size: libc::size_t) -> libc::c_int {
            unsafe {
                let mut dst = Vec::<u8>::with_capacity(size as usize);
                dst.set_len(size as usize);
                ptr::copy(data as *const u8, dst.as_mut_ptr(), size as usize);

                let data = String::from_utf8(dst).unwrap();

                let result = unwrap_parser(http).handler.$callback(&data);
                if result.is_none() {
                    return 0;
                } else {
                    return result.unwrap() as libc::c_int;
                }
            };
        };

        $callback
    });
}

static CALLBACK_WRAPPERS: HttpParserSettings = HttpParserSettings {
    on_url: data_fn_wrapper!(on_url),
    on_message_begin: notify_fn_wrapper!(on_message_begin),
    on_status: data_fn_wrapper!(on_status),
    on_header_field: data_fn_wrapper!(on_header_field),
    on_header_value: data_fn_wrapper!(on_header_value),
    on_headers_complete: notify_fn_wrapper!(on_headers_complete),
    on_body: data_fn_wrapper!(on_body),
    on_message_complete: notify_fn_wrapper!(on_message_complete),
    on_chunk_header: notify_fn_wrapper!(on_chunk_header),
    on_chunk_complete: notify_fn_wrapper!(on_chunk_complete)
};

extern "C" {
    fn http_parser_version() -> u32;
    fn http_parser_init(parser: *mut HttpParser, parser_type: ParserType);
    fn http_parser_settings_init(settings: *mut HttpParserSettings);
    fn http_parser_execute(parser: *mut HttpParser, settings: *const HttpParserSettings, data: *const u8, len: libc::size_t) -> libc::size_t;
    fn http_method_str(method_code: u8) -> *const libc::c_char;
    fn http_errno_name(http_errno: u8) -> *const libc::c_char;
    fn http_errno_description(http_errno: u8) -> *const libc::c_char;

    // Helper function to predictably use aligned bit-field struct
    fn http_get_struct_flags(parser: *const HttpParser) -> u32;
}

// High level Rust interface
pub trait ParserHandler {
    fn on_url(&self, &String) -> Option<u16> { None }
    fn on_status(&self, &String) -> Option<u16> { None }
    fn on_header_field(&self, &String) -> Option<u16> { None }
    fn on_header_value(&self, &String) -> Option<u16> { None }
    fn on_body(&self, &String) -> Option<u16> { None }
    fn on_message_begin(&self) -> Option<u16> { None }
    fn on_headers_complete(&self) -> Option<u16> { None }
    fn on_message_complete(&self) -> Option<u16> { None }
    fn on_chunk_header(&self) -> Option<u16> { None }
    fn on_chunk_complete(&self) -> Option<u16> { None }
}

pub struct Parser<'a> {
    handler: &'a ParserHandler,
    state: HttpParser,
    parser_type: ParserType
}

impl<'a> Parser<'a> {
    pub fn response(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpResponse
        }
    }

    pub fn request(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpRequest
        }
    }

    pub fn request_and_response(handler: &'a ParserHandler) -> Parser<'a> {
        Parser {
            handler: handler,
            state: HttpParser::new(),
            parser_type: ParserType::HttpBoth
        }
    }

    pub fn http_version(&self) -> (u16, u16) { return (self.state.http_major, self.state.http_minor) }
    pub fn http_status_code(&self) -> u16 { return self.state.status_code(); }
    pub fn is_upgrade(&self) -> bool { return self.state.upgrade() }
    pub fn http_method(&self) -> &str { return self.state.http_method_str(); }
}

pub fn parse(parser: &mut Parser, data: &[u8]) -> usize {
    unsafe {
        http_parser_init(&mut parser.state as *mut _, parser.parser_type);

        parser.state.data = &mut (*parser) as *mut _ as *mut libc::c_void;

        return http_parser_execute(&mut parser.state as *mut _,
                                         &CALLBACK_WRAPPERS as *const _,
                                         data.as_ptr(),
                                         data.len() as u64) as usize;
    }
}

pub fn version() -> String {
    unsafe {
        let v = http_parser_version();

        let major = (v >> 16) & 255;
        let minor = (v >> 8) & 255;
        let patch = v & 255;

        return fmt::format(format_args!("{}.{}.{}", major, minor, patch));
    }
}

#[cfg(test)]
mod tests {
    use super::{version, ParserHandler, Parser, parse};

    #[test]
    fn test_version() {
        assert_eq!("2.5.0", version());
    }

    #[test]
    fn test_request_parser() {
        struct TestRequestParser;
        impl ParserHandler for TestRequestParser {
            fn on_url(&self, url: &String) -> Option<u16> {
                assert_eq!("/say_hello", url);
                None

            }
            fn on_header_field(&self, hdr: &String) -> Option<u16> {
                assert!(hdr == "Host" || hdr == "Content-Length");
                None
            }
            fn on_header_value(&self, val: &String) -> Option<u16> {
                assert!(val == "localhost.localdomain" || val == "11");
                None
            }
            fn on_body(&self, body: &String) -> Option<u16> {
                assert_eq!(body, "Hello world");
                None
            }
        }

        let req = "POST /say_hello HTTP/1.1\r\nContent-Length: 11\r\nHost: localhost.localdomain\r\n\r\nHello world";

        let handler = TestRequestParser;
        let mut parser = Parser::request(&handler);
        let parsed = parse(&mut parser, req.as_bytes());

        assert!(parsed > 0);
        assert_eq!((1, 1), parser.http_version());
        assert_eq!("POST", parser.http_method());
    }

    #[test]
    fn test_response_parser() {
        struct TestResponseParser;
        impl ParserHandler for TestResponseParser {
            fn on_status(&self, status: &String) -> Option<u16> {
                assert_eq!("OK", status);
                None
            }
            fn on_header_field(&self, hdr: &String) -> Option<u16> {
                assert_eq!("Host", hdr);
                None
            }
            fn on_header_value(&self, val: &String) -> Option<u16> {
                assert_eq!("localhost.localdomain", val);
                None
            }
        }

        let req = "HTTP/1.1 200 OK\r\nHost: localhost.localdomain\r\n\r\n";

        let handler = TestResponseParser;
        let mut parser = Parser::response(&handler);
        let parsed = parse(&mut parser, req.as_bytes());

        assert!(parsed > 0);
        assert_eq!((1, 1), parser.http_version());
        assert_eq!(200, parser.http_status_code());
    }

    #[test]
    fn test_ws_upgrade() {
        struct DummyHandler;
        impl ParserHandler for DummyHandler {};

        let req = "GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n";

        let handler = DummyHandler;
        let mut parser = Parser::request(&handler);
        parse(&mut parser, req.as_bytes());

        assert_eq!(parser.is_upgrade(), true);
    }

    #[test]
    fn test_error_status() {
        struct DummyHandler;
        impl ParserHandler for DummyHandler {
            fn on_url(&self, _: &String) -> Option<u16> {
                Some(1)
            }
            fn on_header_field(&self, _: &String) -> Option<u16> {
                panic!("This callback shouldn't be executed!");
            }
        }

        let req = "GET / HTTP/1.1\r\nHeader: hello\r\n\r\n";

        let handler = DummyHandler;
        let mut parser = Parser::request(&handler);
        parse(&mut parser, req.as_bytes());

        assert!(true);
    }
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/mio/0.7.0")]
#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
// Disallow warnings when running tests.
#![cfg_attr(test, deny(warnings))]
// Disallow warnings in examples.
#![doc(test(attr(deny(warnings))))]

//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
//! notification, and other useful utilities for building high performance IO
//! apps.
//!
//! # Features
//!
//! * Non-blocking TCP, UDP
//! * I/O event queue backed by epoll, kqueue, and IOCP
//! * Zero allocations at runtime
//! * Platform specific extensions
//!
//! # Non-goals
//!
//! The following are specifically omitted from Mio and are left to the user or
//! higher-level libraries.
//!
//! * File operations
//! * Thread pools / multi-threaded event loop
//! * Timers
//!
//! # Platforms
//!
//! Currently supported platforms:
//!
//! * Android
//! * DragonFly BSD
//! * FreeBSD
//! * Linux
//! * NetBSD
//! * OpenBSD
//! * Solaris
//! * Windows
//! * iOS
//! * macOS
//!
//! Mio can handle interfacing with each of the event systems of the
//! aforementioned platforms. The details of their implementation are further
//! discussed in [`Poll`].
//!
//! # Usage
//!
//! Using Mio starts by creating a [`Poll`], which reads events from the OS and
//! puts them into [`Events`]. You can handle IO events from the OS with it.
//!
//! For more detail, see [`Poll`].
//!
//! [`Poll`]: struct.Poll.html
//! [`Events`]: struct.Events.html
//!
//! # Example
//!
//! ```
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use mio::*;
//! use mio::net::{TcpListener, TcpStream};
//!
//! // Setup some tokens to allow us to identify which event is
//! // for which socket.
//! const SERVER: Token = Token(0);
//! const CLIENT: Token = Token(1);
//!
//! let addr = "127.0.0.1:13265".parse()?;
//!
//! // Setup the server socket
//! let server = TcpListener::bind(addr)?;
//!
//! // Create a poll instance
//! let mut poll = Poll::new()?;
//!
//! // Start listening for incoming connections
//! poll.registry().register(&server, SERVER, Interests::READABLE)?;
//!
//! // Setup the client socket
//! let sock = TcpStream::connect(addr)?;
//!
//! // Register the socket
//! poll.registry().register(&sock, CLIENT, Interests::READABLE)?;
//!
//! // Create storage for events
//! let mut events = Events::with_capacity(1024);
//!
//! loop {
//!     poll.poll(&mut events, None)?;
//!
//!     for event in events.iter() {
//!         match event.token() {
//!             SERVER => {
//!                 // Accept and drop the socket immediately, this will close
//!                 // the socket and notify the client of the EOF.
//!                 let _ = server.accept();
//!             }
//!             CLIENT => {
//!                 // The server just shuts down the socket, let's just exit
//!                 // from our event loop.
//!                 return Ok(());
//!             }
//!             _ => unreachable!(),
//!         }
//!     }
//! }
//! # }
//! ```

mod interests;
mod poll;
mod sys;
mod token;
mod waker;

pub mod event;
pub mod net;

#[doc(no_inline)]
pub use event::Events;
pub use interests::Interests;
pub use poll::{Poll, Registry};
pub use token::Token;
pub use waker::Waker;

#[cfg(unix)]
pub mod unix {
    //! Unix only extensions.
    pub use crate::sys::SocketAddr;
    pub use crate::sys::SourceFd;
}
<commit_msg>Add getting started guide<commit_after>#![doc(html_root_url = "https://docs.rs/mio/0.7.0")]
#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
// Disallow warnings when running tests.
#![cfg_attr(test, deny(warnings))]
// Disallow warnings in examples.
#![doc(test(attr(deny(warnings))))]

//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
//! notification, and other useful utilities for building high performance IO
//! apps.
//!
//! # Features
//!
//! * Non-blocking TCP, UDP
//! * I/O event queue backed by epoll, kqueue, and IOCP
//! * Zero allocations at runtime
//! * Platform specific extensions
//!
//! # Non-goals
//!
//! The following are specifically omitted from Mio and are left to the user or
//! higher-level libraries.
//!
//! * File operations
//! * Thread pools / multi-threaded event loop
//! * Timers
//!
//! # Platforms
//!
//! Currently supported platforms:
//!
//! * Android
//! * DragonFly BSD
//! * FreeBSD
//! * Linux
//! * NetBSD
//! * OpenBSD
//! * Solaris
//! * Windows
//! * iOS
//! * macOS
//!
//! Mio can handle interfacing with each of the event systems of the
//! aforementioned platforms. The details of their implementation are further
//! discussed in [`Poll`].
//!
//! # Usage
//!
//! Using Mio starts by creating a [`Poll`], which reads events from the OS and
//! puts them into [`Events`]. You can handle IO events from the OS with it.
//!
//! For more detail, see [`Poll`].
//!
//! [`Poll`]: struct.Poll.html
//! [`Events`]: struct.Events.html
//!
//! # Example
//!
//! ```
//! # use std::error::Error;
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use mio::*;
//! use mio::net::{TcpListener, TcpStream};
//!
//! // Setup some tokens to allow us to identify which event is
//! // for which socket.
//! const SERVER: Token = Token(0);
//! const CLIENT: Token = Token(1);
//!
//! let addr = "127.0.0.1:13265".parse()?;
//!
//! // Setup the server socket
//! let server = TcpListener::bind(addr)?;
//!
//! // Create a poll instance
//! let mut poll = Poll::new()?;
//!
//! // Start listening for incoming connections
//! poll.registry().register(&server, SERVER, Interests::READABLE)?;
//!
//! // Setup the client socket
//! let sock = TcpStream::connect(addr)?;
//!
//! // Register the socket
//! poll.registry().register(&sock, CLIENT, Interests::READABLE)?;
//!
//! // Create storage for events
//! let mut events = Events::with_capacity(1024);
//!
//! loop {
//!     poll.poll(&mut events, None)?;
//!
//!     for event in events.iter() {
//!         match event.token() {
//!             SERVER => {
//!                 // Accept and drop the socket immediately, this will close
//!                 // the socket and notify the client of the EOF.
//!                 let _ = server.accept();
//!             }
//!             CLIENT => {
//!                 // The server just shuts down the socket, let's just exit
//!                 // from our event loop.
//!                 return Ok(());
//!             }
//!             _ => unreachable!(),
//!         }
//!     }
//! }
//! # }
//! ```

mod interests;
mod poll;
mod sys;
mod token;
mod waker;

pub mod event;
pub mod net;

#[doc(no_inline)]
pub use event::Events;
pub use interests::Interests;
pub use poll::{Poll, Registry};
pub use token::Token;
pub use waker::Waker;

#[cfg(unix)]
pub mod unix {
    //! Unix only extensions.
    pub use crate::sys::SocketAddr;
    pub use crate::sys::SourceFd;
}

pub mod guide {
    //! # Getting started guide.
    //!
    //! Using Mio starts by creating a [`Poll`] instance, which reads events from
    //! the OS and puts them into [`Events`].
    //!
    //! [`Poll`]: crate::Poll
    //! [`Events`]: crate::Events
    //!
    //! ```
    //! # use mio::{Poll, Events};
    //! # fn main() -> std::io::Result<()> {
    //! // `Poll` allows for polling of readiness events.
    //! let poll = Poll::new()?;
    //! // `Events` is collection of readiness `Event`s and can be filled by calling
    //! // `Poll::poll`.
    //! let events = Events::with_capacity(128);
    //! # drop((poll, events));
    //! # Ok(())
    //! # }
    //! ```
    //!
    //! Next an [event source] needs to be registered with [`Poll`] to receive
    //! events for it. We'll use a [`TcpListener`] for which we'll receive an event
    //! once a connection is ready to be accepted.
    //!
    //! [event source]: crate::event::Source
    //! [`TcpListener`]: crate::net::TcpListener
    //!
    //! ```
    //! # use mio::net::TcpListener;
    //! # use mio::{Poll, Token, Interests};
    //! # fn main() -> std::io::Result<()> {
    //! # let poll = Poll::new()?;
    //! # let address = "127.0.0.1:0".parse().unwrap();
    //! // Create a `TcpListener`, binding it to `address`.
    //! let listener = TcpListener::bind(address)?;
    //!
    //! // Next we register it with `Poll` to receive events for it. The `SERVER`
    //! // `Token` is used to determine that we received an event for the listener
    //! // later on.
    //! const SERVER: Token = Token(0);
    //! poll.registry().register(&listener, SERVER, Interests::READABLE)?;
    //! # Ok(())
    //! # }
    //! ```
    //!
    //! As the name “event source” suggests it a source of events which can poll
    //! using a `Poll` instance. Multiple event sources can be [registered] with
    //! `Poll`. After we've done this we can start polling these events. If we do
    //! this in a loop we've got ourselves an event loop.
    //!
    //! [registered]: crate::Registry::register
    //!
    //! ```
    //! # use std::io;
    //! # use std::time::Duration;
    //! # use mio::net::TcpListener;
    //! # use mio::{Poll, Token, Interests, Events};
    //! # fn main() -> io::Result<()> {
    //! # let mut poll = Poll::new()?;
    //! # let mut events = Events::with_capacity(128);
    //! # let address = "127.0.0.1:0".parse().unwrap();
    //! # let listener = TcpListener::bind(address)?;
    //! # const SERVER: Token = Token(0);
    //! # poll.registry().register(&listener, SERVER, Interests::READABLE)?;
    //! // Start our event loop.
    //! loop {
    //!     // Poll Mio for events, waiting at most 100 milliseconds.
    //!     poll.poll(&mut events, Some(Duration::from_millis(100)))?;
    //!
    //!     // Process each event.
    //!     for event in events.iter() {
    //!         // We can use the token we previously provided to `register` to
    //!         // determine for which type the event is.
    //!         match event.token() {
    //!             SERVER => loop {
    //!                 // One or more connections are ready, so we'll attempt to
    //!                 // accept them in a loop.
    //!                 match listener.accept() {
    //!                     Ok((connection, address)) => {
    //!                         println!("Got a connection from: {}", address);
    //! #                       drop(connection);
    //!                     },
    //!                     // An "would block error" is returned if the operation
    //!                     // is not ready, so we'll stop trying to accept
    //!                     // connections.
    //!                     Err(ref err) if would_block(err) => break,
    //!                     Err(err) => return Err(err),
    //!                 }
    //!             }
    //! #           _ => unreachable!(),
    //!         }
    //!     }
    //! #   return Ok(());
    //! }
    //!
    //! fn would_block(err: &io::Error) -> bool {
    //!     err.kind() == io::ErrorKind::WouldBlock
    //! }
    //! # }
    //! ```
}
<|endoftext|>


<commit_before>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```
#[cfg(windows)]
extern crate winapi;

#[cfg(not(windows))]
use std::process::{Command, Stdio};

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    let path_ref = path.as_ref();
    let mut last_err: io::Error = io::Error::from_raw_os_error(0);
    for program in &["xdg-open", "gnome-open", "kde-open", "wslview"] {
        match Command::new(program)
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path_ref)
            .spawn()
        {
            Ok(mut child) => return child.wait(),
            Err(err) => {
                last_err = err;
                continue;
            }
        }
    }
    Err(last_err)
}

#[cfg(target_os = "windows")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    const SW_SHOW: c_int = 5;

    let path = windows::convert_path(path.as_ref())?;
    let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
    let result = unsafe {
        ShellExecuteW(
            ptr::null_mut(),
            operation.as_ptr(),
            path.as_ptr(),
            ptr::null(),
            ptr::null(),
            SW_SHOW,
        )
    };
    if result as c_int > 32 {
        Ok(ExitStatus::from_raw(0))
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(target_os = "macos")]
pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
    Command::new("open")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .arg(path.as_ref())
        .spawn()?
        .wait()
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
}

#[cfg(target_os = "windows")]
pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    use std::os::windows::ffi::OsStrExt;
    use std::os::windows::process::ExitStatusExt;
    use std::ptr;
    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    const SW_SHOW: c_int = 5;

    let path = windows::convert_path(path.as_ref())?;
    let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
    let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
        .encode_wide()
        .collect();
    let result = unsafe {
        ShellExecuteW(
            ptr::null_mut(),
            operation.as_ptr(),
            app_name.as_ptr(),
            path.as_ptr(),
            ptr::null(),
            SW_SHOW,
        )
    };
    if result as c_int > 32 {
        Ok(ExitStatus::from_raw(0))
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(target_os = "macos")]
pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> io::Result<ExitStatus> {
    Command::new("open")
        .arg(path.as_ref())
        .arg("-a")
        .arg(app.into())
        .spawn()?
        .wait()
}

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::ffi::OsStrExt;

    pub fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
}
<commit_msg>Modularize Code<commit_after>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(target_os = "windows")]
pub use windows::{that, with};

#[cfg(target_os = "macos")]
pub use macos::{that, with};

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub use unix::{that, with};

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::{ffi::OsStrExt, process::ExitStatusExt};
    use std::process::ExitStatus;
    use std::ptr;

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    pub fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn with<T: AsRef<OsStr> + Sized>(
        path: T,
        app: impl Into<String>,
    ) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(target_os = "macos")]
mod macos {

    use std::{
        ffi::OsStr,
        io::Result,
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        Command::new("open")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path.as_ref())
            .spawn()?
            .wait()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .spawn()?
            .wait()
    }
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
mod unix {

    use std::{
        ffi::OsStr,
        io::{Error, Result},
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        let path_ref = path.as_ref();
        let mut last_err = Error::from_raw_os_error(0);
        for program in &["xdg-open", "gnome-open", "kde-open", "wslview"] {
            match Command::new(program)
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .arg(path_ref)
                .spawn()
            {
                Ok(mut child) => return child.wait(),
                Err(err) => {
                    last_err = err;
                    continue;
                }
            }
        }
        Err(last_err)
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> Self {
        Self {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut Self {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

pub fn params(req: &dyn RequestExt) -> &Params {
    req.extensions().find::<Params>().expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{Body, Handler, Method, Response, StatusCode};
    use conduit_test::{MockRequest, ResponseExt};

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = MockRequest::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<commit_msg>Drop a redundant public function<commit_after>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> Self {
        Self {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut Self {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        self.extensions().find::<Params>().expect("Missing params")
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{Body, Handler, Method, Response, StatusCode};
    use conduit_test::{MockRequest, ResponseExt};

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = MockRequest::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<|endoftext|>


<commit_before>#![crate_name = "static_file"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving handler.

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate time;

extern crate http;
extern crate iron;
#[phase(plugin, link)]
extern crate log;
extern crate mount;

pub use cache_handler::StaticWithCache;
pub use static_handler::Static;

mod cache_handler;
mod errors;
mod requested_path;
mod static_handler;
<commit_msg>(chore) Deprecation flag to generate warnings<commit_after>#![crate_name = "static_file"]
#![deprecated = "use https://github.com/iron/static instead"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving handler.

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;
extern crate time;

extern crate http;
extern crate iron;
#[phase(plugin, link)]
extern crate log;
extern crate mount;

pub use cache_handler::StaticWithCache;
pub use static_handler::Static;

mod cache_handler;
mod errors;
mod requested_path;
mod static_handler;
<|endoftext|>


<commit_before>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "doc", feature(external_doc))]
#![doc(html_logo_url = "https://clap.rs/images/media/clap.png")]
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-beta.2")]
#![cfg_attr(feature = "doc", doc(include = "../README.md"))]
//! https://github.com/clap-rs/clap
#![crate_type = "lib"]
#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts
)]
#![forbid(unsafe_code)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::{
    build::{App, AppSettings, Arg, ArgGroup, ArgSettings, ValueHint},
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

#[cfg(feature = "derive")]
pub use crate::derive::{ArgEnum, Clap, FromArgMatches, IntoApp, Subcommand};

#[cfg(feature = "yaml")]
#[doc(hidden)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

#[cfg(any(feature = "derive", feature = "cargo"))]
#[doc(hidden)]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

#[cfg(feature = "derive")]
mod derive;

#[cfg(feature = "regex")]
pub use crate::build::arg::RegexRef;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
<commit_msg>Fix clippy lint<commit_after>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "doc", feature(external_doc))]
#![doc(html_logo_url = "https://clap.rs/images/media/clap.png")]
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-beta.2")]
#![cfg_attr(feature = "doc", doc(include = "../README.md"))]
//! https://github.com/clap-rs/clap
#![crate_type = "lib"]
#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts
)]
#![forbid(unsafe_code)]
// TODO: https://github.com/rust-lang/rust-clippy/issues/7290
#![allow(clippy::single_component_path_imports)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::{
    build::{App, AppSettings, Arg, ArgGroup, ArgSettings, ValueHint},
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

#[cfg(feature = "derive")]
pub use crate::derive::{ArgEnum, Clap, FromArgMatches, IntoApp, Subcommand};

#[cfg(feature = "yaml")]
#[doc(hidden)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

#[cfg(any(feature = "derive", feature = "cargo"))]
#[doc(hidden)]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

#[cfg(feature = "derive")]
mod derive;

#[cfg(feature = "regex")]
pub use crate::build::arg::RegexRef;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
<|endoftext|>


<commit_before>//! A notion of the calendar date.

#![feature(macro_rules)]

extern crate time;

/// A representation of a day in the Gregorian calendar.
#[deriving(Default, PartialEq, Eq, Ord, Show)]
pub struct Date {
    /// The year.
    pub year: u32,
    /// The month.
    pub month: u8,
    /// The day.
    pub day: u8,
}

impl PartialOrd for Date {
    fn partial_cmp(&self, other: &Date) -> Option<Ordering> {
        macro_rules! cmp(
            ($one:expr, $two:expr) => (
                if $one > $two {
                    return Some(std::cmp::Greater);
                } else if $one < $two {
                    return Some(std::cmp::Less);
                }
            );
        )

        cmp!(self.year, other.year);
        cmp!(self.month, other.month);
        cmp!(self.day, other.day);

        Some(std::cmp::Equal)
    }
}

impl Date {
    /// Create a date by the specified year, month, and day.
    #[inline]
    pub fn new(year: u32, month: u8, day: u8) -> Date {
        Date { year: year, month: month, day: day }
    }

    /// Return the UTC date specified in seconds counting from the Unix epoch.
    pub fn at_utc(seconds: i64) -> Date {
        let time = time::at_utc(time::Timespec { sec: seconds, nsec: 0 });
        Date::new(time.tm_year as u32 + 1900, time.tm_mon as u8 + 1, time.tm_mday as u8)
    }

    /// Return the UTC date specified in seconds counting from January 1, 1904.
    #[inline]
    pub fn at_utc_1904(seconds: i64) -> Date {
        Date::at_utc(seconds - 2082844800)
    }
}

#[cfg(test)]
mod test {
    macro_rules! date(
        ($year:expr, $month:expr, $day:expr) => (::Date::new($year, $month, $day));
    )

    #[test]
    fn eq() {
        assert_eq!(date!(2014, 8, 19), date!(2014, 8, 19));
    }

    #[test]
    fn ord() {
        assert!(date!(2014, 8, 19) < date!(2014, 8, 20));
        assert!(date!(2014, 8, 19) > date!(2014, 8, 18));
        assert!(date!(2014, 8, 19) < date!(2014, 9, 19));
        assert!(date!(2014, 8, 19) > date!(2014, 7, 19));
        assert!(date!(2014, 8, 19) < date!(2015, 8, 19));
        assert!(date!(2014, 8, 19) > date!(2013, 8, 19));
    }

    #[test]
    fn at_utc_1904() {
        macro_rules! at(($seconds:expr) => (::Date::at_utc_1904($seconds));)

        assert_eq!(at!(0), date!(1904, 1, 1));
        assert_eq!(at!(2678399), date!(1904, 1, 31));
        assert_eq!(at!(2678400), date!(1904, 2, 1));
        assert_eq!(at!(5184000), date!(1904, 3, 1));
        assert_eq!(at!(3491078399), date!(2014, 8, 16));
        assert_eq!(at!(3491078400), date!(2014, 8, 17));
    }
}
<commit_msg>Added Copy to Date<commit_after>//! A notion of the calendar date.

#![feature(macro_rules)]

extern crate time;

/// A representation of a day in the Gregorian calendar.
#[deriving(Copy, Default, PartialEq, Eq, Ord, Show)]
pub struct Date {
    /// The year.
    pub year: u32,
    /// The month.
    pub month: u8,
    /// The day.
    pub day: u8,
}

impl PartialOrd for Date {
    fn partial_cmp(&self, other: &Date) -> Option<Ordering> {
        macro_rules! cmp(
            ($one:expr, $two:expr) => (
                if $one > $two {
                    return Some(std::cmp::Greater);
                } else if $one < $two {
                    return Some(std::cmp::Less);
                }
            );
        )

        cmp!(self.year, other.year);
        cmp!(self.month, other.month);
        cmp!(self.day, other.day);

        Some(std::cmp::Equal)
    }
}

impl Date {
    /// Create a date by the specified year, month, and day.
    #[inline]
    pub fn new(year: u32, month: u8, day: u8) -> Date {
        Date { year: year, month: month, day: day }
    }

    /// Return the UTC date specified in seconds counting from the Unix epoch.
    pub fn at_utc(seconds: i64) -> Date {
        let time = time::at_utc(time::Timespec { sec: seconds, nsec: 0 });
        Date::new(time.tm_year as u32 + 1900, time.tm_mon as u8 + 1, time.tm_mday as u8)
    }

    /// Return the UTC date specified in seconds counting from January 1, 1904.
    #[inline]
    pub fn at_utc_1904(seconds: i64) -> Date {
        Date::at_utc(seconds - 2082844800)
    }
}

#[cfg(test)]
mod test {
    macro_rules! date(
        ($year:expr, $month:expr, $day:expr) => (::Date::new($year, $month, $day));
    )

    #[test]
    fn eq() {
        assert_eq!(date!(2014, 8, 19), date!(2014, 8, 19));
    }

    #[test]
    fn ord() {
        assert!(date!(2014, 8, 19) < date!(2014, 8, 20));
        assert!(date!(2014, 8, 19) > date!(2014, 8, 18));
        assert!(date!(2014, 8, 19) < date!(2014, 9, 19));
        assert!(date!(2014, 8, 19) > date!(2014, 7, 19));
        assert!(date!(2014, 8, 19) < date!(2015, 8, 19));
        assert!(date!(2014, 8, 19) > date!(2013, 8, 19));
    }

    #[test]
    fn at_utc_1904() {
        macro_rules! at(($seconds:expr) => (::Date::at_utc_1904($seconds));)

        assert_eq!(at!(0), date!(1904, 1, 1));
        assert_eq!(at!(2678399), date!(1904, 1, 31));
        assert_eq!(at!(2678400), date!(1904, 2, 1));
        assert_eq!(at!(5184000), date!(1904, 3, 1));
        assert_eq!(at!(3491078399), date!(2014, 8, 16));
        assert_eq!(at!(3491078400), date!(2014, 8, 17));
    }
}
<|endoftext|>