<commit_before>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::Error;
use tftp_specific::PacketType;
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    let (amt, src) = try!(socket.recv_from(&mut buf));
                    if buf[1] == 4 {
                        println!("ACK received");
                        last_blk_id += 1;
                        let (buf, num_bytes_read) = fs.next().unwrap();
                        let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                        try!(socket.send_to(v.as_slice(), src));
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                //send ACK
                let mut block_num = 0u16;
                let low = block_num & 0x00FF;
                let high = (block_num & 0xFF00) >> 8;

                println!("Sending ACK");
                socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.push(0);//zero terminator
        v.extend(mode.as_bytes());
        v.push(0);//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<commit_msg>Send ACK for every block received and add a buf clear() function<commit_after>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::Error;
use tftp_specific::PacketType;
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    let (amt, src) = try!(socket.recv_from(&mut buf));
                    if buf[1] == 4 {
                        println!("ACK received");
                        last_blk_id += 1;
                        let (buf, num_bytes_read) = fs.next().unwrap();
                        let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                        try!(socket.send_to(v.as_slice(), src));
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let mut v = vec![];
                v.copy_from_slice(&buf[2..i]);
                let filename = str::from_utf8(v.as_slice());
                println!("file requested: {}", filename.unwrap());
                let mut writer = FileStreamWriter::new(String::from(filename.unwrap())).unwrap();
                //send ACK
                let mut block_num = 0u16;
                loop{
                    let low = block_num & 0x00FF;
                    let high = (block_num & 0xFF00) >> 8;

                    println!("Sending ACK");
                    socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    Self::clear_buf(&mut buf);
                    let (amt, src) = try!(socket.recv_from(&mut buf));

                    writer.append(&mut buf);
                    if amt - 4 < 512{
                        //TODO do we close writer here?
                        break;
                    }
                    block_num += 1;

                }

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn clear_buf(buf : &mut[u8]){
        assert!(buf.len() == 516);
        for i in 0..516{
            buf[i] = 0;
        }
    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.push(0);//zero terminator
        v.extend(mode.as_bytes());
        v.push(0);//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<|endoftext|>


<commit_before>//! Fairing implementation

#[allow(unused_imports)]
use ::log::{error, info};
use rocket::http::{self, uri::Origin, Status};
use rocket::{self, error_, info_, outcome::Outcome, Request};

use crate::{
    actual_request_response, origin, preflight_response, request_headers, validate, Cors, Error,
};

/// Request Local State to store CORS validation results
enum CorsValidation {
    Success,
    Failure,
}

/// Create a `Handler` for Fairing error handling
#[derive(Clone)]
struct FairingErrorRoute {}

#[rocket::async_trait]
impl rocket::route::Handler for FairingErrorRoute {
    async fn handle<'r>(
        &self,
        request: &'r Request<'_>,
        _: rocket::Data<'r>,
    ) -> rocket::route::Outcome<'r> {
        let status = request
            .param::<u16>(0)
            .unwrap_or(Ok(0))
            .unwrap_or_else(|e| {
                error_!("Fairing Error Handling Route error: {:?}", e);
                500
            });
        let status = Status::from_code(status).unwrap_or(Status::InternalServerError);
        Outcome::Failure(status)
    }
}

/// Create a new `Route` for Fairing handling
fn fairing_route(rank: isize) -> rocket::Route {
    rocket::Route::ranked(rank, http::Method::Get, "/<status>", FairingErrorRoute {})
}

/// Modifies a `Request` to route to Fairing error handler
fn route_to_fairing_error_handler(options: &Cors, status: u16, request: &mut Request<'_>) {
    let origin = Origin::parse_owned(format!("{}/{}", options.fairing_route_base, status)).unwrap();

    request.set_method(http::Method::Get);
    request.set_uri(origin);
}

fn on_response_wrapper(
    options: &Cors,
    request: &Request<'_>,
    response: &mut rocket::Response<'_>,
) -> Result<(), Error> {
    let origin = match origin(request)? {
        None => {
            // Not a CORS request
            return Ok(());
        }
        Some(origin) => origin,
    };

    let result = request.local_cache(|| unreachable!("This should not be executed so late"));

    if let CorsValidation::Failure = *result {
        // Nothing else for us to do
        return Ok(());
    }

    let origin = origin.to_string();
    let cors_response = if request.method() == http::Method::Options {
        let headers = request_headers(request)?;
        preflight_response(options, &origin, headers.as_ref())
    } else {
        actual_request_response(options, &origin)
    };

    cors_response.merge(response);

    // If this was an OPTIONS request and no route can be found, we should turn this
    // into a HTTP 204 with no content body.
    // This allows the user to not have to specify an OPTIONS route for everything.
    //
    // TODO: Is there anyway we can make this smarter? Only modify status codes for
    // requests where an actual route exist?
    if request.method() == http::Method::Options && request.route().is_none() {
        info_!(
            "CORS Fairing: Turned missing route {} into an OPTIONS pre-flight request",
            request
        );
        response.set_status(Status::NoContent);
        let _ = response.body();
    }
    Ok(())
}

#[rocket::async_trait]
impl rocket::fairing::Fairing for Cors {
    fn info(&self) -> rocket::fairing::Info {
        rocket::fairing::Info {
            name: "CORS",
            kind: rocket::fairing::Kind::Ignite
                | rocket::fairing::Kind::Request
                | rocket::fairing::Kind::Response,
        }
    }

    async fn on_ignite(&self, rocket: rocket::Rocket<rocket::Build>) -> rocket::fairing::Result {
        Ok(rocket.mount(
            &self.fairing_route_base,
            vec![fairing_route(self.fairing_route_rank)],
        ))
    }

    async fn on_request(&self, request: &mut Request<'_>, _: &mut rocket::Data<'_>) {
        let result = match validate(self, request) {
            Ok(_) => CorsValidation::Success,
            Err(err) => {
                error_!("CORS Error: {}", err);
                let status = err.status();
                route_to_fairing_error_handler(self, status.code, request);
                CorsValidation::Failure
            }
        };

        let _ = request.local_cache(|| result);
    }

    async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut rocket::Response<'r>) {
        if let Err(err) = on_response_wrapper(self, request, response) {
            error_!("Fairings on_response error: {}\nMost likely a bug", err);
            response.set_status(Status::InternalServerError);
            let _ = response.body();
        }
    }
}

#[cfg(test)]
mod tests {
    use rocket::http::{Method, Status};
    use rocket::local::blocking::Client;
    use rocket::Rocket;

    use crate::{AllowedHeaders, AllowedOrigins, Cors, CorsOptions};

    const CORS_ROOT: &str = "/my_cors";

    fn make_cors_options() -> Cors {
        let allowed_origins = AllowedOrigins::some_exact(&["https://www.acme.com"]);

        CorsOptions {
            allowed_origins,
            allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
            allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
            allow_credentials: true,
            fairing_route_base: CORS_ROOT.to_string(),

            ..Default::default()
        }
        .to_cors()
        .expect("Not to fail")
    }

    fn rocket(fairing: Cors) -> Rocket<rocket::Build> {
        Rocket::build().attach(fairing)
    }

    #[test]
    #[allow(non_snake_case)]
    fn FairingErrorRoute_returns_passed_in_status() {
        let client = Client::tracked(rocket(make_cors_options())).expect("to not fail");
        let request = client.get(format!("{}/403", CORS_ROOT));
        let response = request.dispatch();
        assert_eq!(Status::Forbidden, response.status());
    }

    #[test]
    #[allow(non_snake_case)]
    fn FairingErrorRoute_returns_500_for_unknown_status() {
        let client = Client::tracked(rocket(make_cors_options())).expect("to not fail");
        let request = client.get(format!("{}/999", CORS_ROOT));
        let response = request.dispatch();
        assert_eq!(Status::InternalServerError, response.status());
    }

    #[rocket::async_test]
    async fn error_route_is_mounted_on_ignite() {
        let rocket = rocket(make_cors_options())
            .ignite()
            .await
            .expect("to ignite");

        let expected_uri = format!("{}/<status>", CORS_ROOT);
        let error_route = rocket
            .routes()
            .find(|r| r.method == Method::Get && r.uri.to_string() == expected_uri);
        assert!(error_route.is_some());
    }

    // Rest of the things can only be tested in integration tests
}
<commit_msg>Drop body from response to preflight request (#100)<commit_after>//! Fairing implementation

#[allow(unused_imports)]
use ::log::{error, info};
use rocket::http::{self, uri::Origin, Status};
use rocket::{self, error_, info_, outcome::Outcome, Request};

use crate::{
    actual_request_response, origin, preflight_response, request_headers, validate, Cors, Error,
};

/// Request Local State to store CORS validation results
enum CorsValidation {
    Success,
    Failure,
}

/// Create a `Handler` for Fairing error handling
#[derive(Clone)]
struct FairingErrorRoute {}

#[rocket::async_trait]
impl rocket::route::Handler for FairingErrorRoute {
    async fn handle<'r>(
        &self,
        request: &'r Request<'_>,
        _: rocket::Data<'r>,
    ) -> rocket::route::Outcome<'r> {
        let status = request
            .param::<u16>(0)
            .unwrap_or(Ok(0))
            .unwrap_or_else(|e| {
                error_!("Fairing Error Handling Route error: {:?}", e);
                500
            });
        let status = Status::from_code(status).unwrap_or(Status::InternalServerError);
        Outcome::Failure(status)
    }
}

/// Create a new `Route` for Fairing handling
fn fairing_route(rank: isize) -> rocket::Route {
    rocket::Route::ranked(rank, http::Method::Get, "/<status>", FairingErrorRoute {})
}

/// Modifies a `Request` to route to Fairing error handler
fn route_to_fairing_error_handler(options: &Cors, status: u16, request: &mut Request<'_>) {
    let origin = Origin::parse_owned(format!("{}/{}", options.fairing_route_base, status)).unwrap();

    request.set_method(http::Method::Get);
    request.set_uri(origin);
}

fn on_response_wrapper(
    options: &Cors,
    request: &Request<'_>,
    response: &mut rocket::Response<'_>,
) -> Result<(), Error> {
    let origin = match origin(request)? {
        None => {
            // Not a CORS request
            return Ok(());
        }
        Some(origin) => origin,
    };

    let result = request.local_cache(|| unreachable!("This should not be executed so late"));

    if let CorsValidation::Failure = *result {
        // Nothing else for us to do
        return Ok(());
    }

    let origin = origin.to_string();
    let cors_response = if request.method() == http::Method::Options {
        let headers = request_headers(request)?;
        preflight_response(options, &origin, headers.as_ref())
    } else {
        actual_request_response(options, &origin)
    };

    cors_response.merge(response);

    // If this was an OPTIONS request and no route can be found, we should turn this
    // into a HTTP 204 with no content body.
    // This allows the user to not have to specify an OPTIONS route for everything.
    //
    // TODO: Is there anyway we can make this smarter? Only modify status codes for
    // requests where an actual route exist?
    if request.method() == http::Method::Options && request.route().is_none() {
        info_!(
            "CORS Fairing: Turned missing route {} into an OPTIONS pre-flight request",
            request
        );
        response.set_status(Status::NoContent);
        let _ = response.body_mut().take();
    }
    Ok(())
}

#[rocket::async_trait]
impl rocket::fairing::Fairing for Cors {
    fn info(&self) -> rocket::fairing::Info {
        rocket::fairing::Info {
            name: "CORS",
            kind: rocket::fairing::Kind::Ignite
                | rocket::fairing::Kind::Request
                | rocket::fairing::Kind::Response,
        }
    }

    async fn on_ignite(&self, rocket: rocket::Rocket<rocket::Build>) -> rocket::fairing::Result {
        Ok(rocket.mount(
            &self.fairing_route_base,
            vec![fairing_route(self.fairing_route_rank)],
        ))
    }

    async fn on_request(&self, request: &mut Request<'_>, _: &mut rocket::Data<'_>) {
        let result = match validate(self, request) {
            Ok(_) => CorsValidation::Success,
            Err(err) => {
                error_!("CORS Error: {}", err);
                let status = err.status();
                route_to_fairing_error_handler(self, status.code, request);
                CorsValidation::Failure
            }
        };

        let _ = request.local_cache(|| result);
    }

    async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut rocket::Response<'r>) {
        if let Err(err) = on_response_wrapper(self, request, response) {
            error_!("Fairings on_response error: {}\nMost likely a bug", err);
            response.set_status(Status::InternalServerError);
            let _ = response.body();
        }
    }
}

#[cfg(test)]
mod tests {
    use rocket::http::{Method, Status};
    use rocket::local::blocking::Client;
    use rocket::Rocket;

    use crate::{AllowedHeaders, AllowedOrigins, Cors, CorsOptions};

    const CORS_ROOT: &str = "/my_cors";

    fn make_cors_options() -> Cors {
        let allowed_origins = AllowedOrigins::some_exact(&["https://www.acme.com"]);

        CorsOptions {
            allowed_origins,
            allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
            allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
            allow_credentials: true,
            fairing_route_base: CORS_ROOT.to_string(),

            ..Default::default()
        }
        .to_cors()
        .expect("Not to fail")
    }

    fn rocket(fairing: Cors) -> Rocket<rocket::Build> {
        Rocket::build().attach(fairing)
    }

    #[test]
    #[allow(non_snake_case)]
    fn FairingErrorRoute_returns_passed_in_status() {
        let client = Client::tracked(rocket(make_cors_options())).expect("to not fail");
        let request = client.get(format!("{}/403", CORS_ROOT));
        let response = request.dispatch();
        assert_eq!(Status::Forbidden, response.status());
    }

    #[test]
    #[allow(non_snake_case)]
    fn FairingErrorRoute_returns_500_for_unknown_status() {
        let client = Client::tracked(rocket(make_cors_options())).expect("to not fail");
        let request = client.get(format!("{}/999", CORS_ROOT));
        let response = request.dispatch();
        assert_eq!(Status::InternalServerError, response.status());
    }

    #[rocket::async_test]
    async fn error_route_is_mounted_on_ignite() {
        let rocket = rocket(make_cors_options())
            .ignite()
            .await
            .expect("to ignite");

        let expected_uri = format!("{}/<status>", CORS_ROOT);
        let error_route = rocket
            .routes()
            .find(|r| r.method == Method::Get && r.uri.to_string() == expected_uri);
        assert!(error_route.is_some());
    }

    // Rest of the things can only be tested in integration tests
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLUListElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLUListElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLUListElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLUListElement {
    pub htmlelement: HTMLElement
}

impl HTMLUListElementDerived for EventTarget {
    fn is_htmlulistelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLUListElementTypeId))
    }
}

impl HTMLUListElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLUListElement {
        HTMLUListElement {
            htmlelement: HTMLElement::new_inherited(HTMLUListElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLUListElement> {
        let element = HTMLUListElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLUListElementBinding::Wrap)
    }
}

pub trait HTMLUListElementMethods {
    fn Compact(&self) -> bool;
    fn SetCompact(&mut self, _compact: bool) -> ErrorResult;
    fn Type(&self) -> DOMString;
    fn SetType(&mut self, _type: DOMString) -> ErrorResult;
}

impl<'a> HTMLUListElementMethods for JSRef<'a, HTMLUListElement> {
    fn Compact(&self) -> bool {
        false
    }

    fn SetCompact(&mut self, _compact: bool) -> ErrorResult {
        Ok(())
    }

    fn Type(&self) -> DOMString {
        "".to_owned()
    }

    fn SetType(&mut self, _type: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLUListElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLUListElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLUListElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLUListElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLUListElement {
    pub htmlelement: HTMLElement
}

impl HTMLUListElementDerived for EventTarget {
    fn is_htmlulistelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLUListElementTypeId))
    }
}

impl HTMLUListElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLUListElement {
        HTMLUListElement {
            htmlelement: HTMLElement::new_inherited(HTMLUListElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLUListElement> {
        let element = HTMLUListElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLUListElementBinding::Wrap)
    }
}

pub trait HTMLUListElementMethods {
    fn Compact(&self) -> bool;
    fn SetCompact(&self, _compact: bool) -> ErrorResult;
    fn Type(&self) -> DOMString;
    fn SetType(&self, _type: DOMString) -> ErrorResult;
}

impl<'a> HTMLUListElementMethods for JSRef<'a, HTMLUListElement> {
    fn Compact(&self) -> bool {
        false
    }

    fn SetCompact(&self, _compact: bool) -> ErrorResult {
        Ok(())
    }

    fn Type(&self) -> DOMString {
        "".to_owned()
    }

    fn SetType(&self, _type: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uptime"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 * (c) Jian Zeng <anonymousknight86@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;
extern crate time;

#[macro_use]
extern crate uucore;
// import crate time from utmpx
use uucore::libc::time_t;
pub use uucore::libc;

use getopts::Options;

static NAME: &str = "uptime";
static VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg(unix)]
use libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> libc::uint32_t;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("v", "version", "output version information and exit");
    opts.optflag("h", "help", "display this help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }
    if matches.opt_present("help") || !matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!();
        println!("Usage:");
        println!("  {0} [OPTION]", NAME);
        println!();
        println!(
            "{}",
            opts.usage(
                "Print the current time, the length of time the system has been up,\n\
                 the number of users on the system, and the average number of jobs\n\
                 in the run queue over the last 1, 5 and 15 minutes."
            )
        );
        return 0;
    }

    print_time();
    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        show_error!("could not retrieve system uptime");

        1
    } else {
        let upsecs = uptime / 100;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        0
    }
}

#[cfg(unix)]
fn print_loadavg() {
    use libc::c_double;
    use std::mem::transmute;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { transmute(getloadavg(avg.as_mut_ptr(), 3)) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let t = line.login_time().to_timespec();
                if t.sec > 0 {
                    boot_time = Some(t.sec as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    if nusers == 1 {
        print!("1 user,  ");
    } else if nusers > 1 {
        print!("{} users,  ", nusers);
    }
}

fn print_time() {
    let local_time = time::now();

    print!(
        " {:02}:{:02}:{:02} ",
        local_time.tm_hour, local_time.tm_min, local_time.tm_sec
    );
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime = String::new();

    if let Some(n) = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
        .and_then(|_| proc_uptime.split_whitespace().next())
        .and_then(|s| s.replace(".", "").parse().ok())
    {
        n
    } else {
        match boot_time {
            Some(t) => {
                let now = time::get_time().sec;
                let boottime = t as i64;
                ((now - boottime) * 100)
            }
            _ => -1,
        }
    }
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    if updays == 1 {
        print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins);
    } else if updays > 1 {
        print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins);
    } else {
        print!("up  {:2}:{:02}, ", uphours, upmins);
    }
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (unneeded transmute)<commit_after>#![crate_name = "uu_uptime"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 * (c) Jian Zeng <anonymousknight86@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;
extern crate time;

#[macro_use]
extern crate uucore;
// import crate time from utmpx
use uucore::libc::time_t;
pub use uucore::libc;

use getopts::Options;

static NAME: &str = "uptime";
static VERSION: &str = env!("CARGO_PKG_VERSION");

#[cfg(unix)]
use libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> libc::uint32_t;
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("v", "version", "output version information and exit");
    opts.optflag("h", "help", "display this help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f),
    };
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }
    if matches.opt_present("help") || !matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!();
        println!("Usage:");
        println!("  {0} [OPTION]", NAME);
        println!();
        println!(
            "{}",
            opts.usage(
                "Print the current time, the length of time the system has been up,\n\
                 the number of users on the system, and the average number of jobs\n\
                 in the run queue over the last 1, 5 and 15 minutes."
            )
        );
        return 0;
    }

    print_time();
    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        show_error!("could not retrieve system uptime");

        1
    } else {
        let upsecs = uptime / 100;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        0
    }
}

#[cfg(unix)]
fn print_loadavg() {
    use libc::c_double;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let t = line.login_time().to_timespec();
                if t.sec > 0 {
                    boot_time = Some(t.sec as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    if nusers == 1 {
        print!("1 user,  ");
    } else if nusers > 1 {
        print!("{} users,  ", nusers);
    }
}

fn print_time() {
    let local_time = time::now();

    print!(
        " {:02}:{:02}:{:02} ",
        local_time.tm_hour, local_time.tm_min, local_time.tm_sec
    );
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime = String::new();

    if let Some(n) = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
        .and_then(|_| proc_uptime.split_whitespace().next())
        .and_then(|s| s.replace(".", "").parse().ok())
    {
        n
    } else {
        match boot_time {
            Some(t) => {
                let now = time::get_time().sec;
                let boottime = t as i64;
                ((now - boottime) * 100)
            }
            _ => -1,
        }
    }
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    if updays == 1 {
        print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins);
    } else if updays > 1 {
        print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins);
    } else {
        print!("up  {:2}:{:02}, ", uphours, upmins);
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_int, size_t, c_void};
use std::mem;
use std::marker::PhantomData;

#[repr(C)]
pub struct nl_msg;
#[repr(C)]
pub struct nlmsghdr;

#[link(name="nl-3")]
extern "C" {
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;
    fn nlmsg_inherit(nlh: *const nlmsghdr) -> *const nl_msg;
    fn nlmsg_hdr(msg: *const nl_msg) -> *const nlmsghdr;
    fn nlmsg_ok(msg: *const nl_msg) -> u32;
    fn nlmsg_data(msg: *const nlmsghdr) -> *const c_void;
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: *const nlmsghdr,
}

pub struct NetlinkData <T> {
    ptr: Option<*const c_void>,
    phantom: PhantomData<T>
}

impl <T> NetlinkData <T> {

    pub fn new() -> NetlinkData<T> {
        NetlinkData {
            ptr: None,
            phantom: PhantomData
        }
    }

    pub fn get(&self) -> Option<&T> {
        match self.ptr {
        None => None,
        Some(vptr) => {
            Some( unsafe { mem::transmute(vptr) } )
            }
        }
    }

    pub fn set(&mut self, data: &T) {
        match self.ptr {

        None => {
            let p: *const c_void =  unsafe{ mem::transmute(data) };
            self.ptr = Some( p );
            },

         _   => return

        }
    }

    pub fn from_vptr(&mut self, data: *const c_void) {
        match self.ptr {
            None    => self.ptr = Some(data),
            _       =>  return
        }
    }

    pub fn to_vptr(&self) -> Option<*const c_void> {
        self.ptr
    }
}

pub fn contain(ptr: *const nl_msg) -> Option<NetlinkMessage> {
    match ptr as isize {
        0x0 => None,
        _   => Some (
            NetlinkMessage {
                ptr: ptr,
                hdr: unsafe { nlmsg_hdr(ptr) }
            })
    }
}

pub fn alloc() -> Option<NetlinkMessage> {
    let mptr = unsafe { nlmsg_alloc() };
    contain(mptr)
}

pub fn free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {

        let hdr = unsafe { nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int) };

        match hdr as i32 {
            0x0 => false,
            _ => {
                true
            }
        }
}

pub fn data_len(msg: &NetlinkMessage) -> i32 {

            unsafe { nlmsg_datalen(msg.hdr) }
}

pub fn inherit(msg: &NetlinkMessage) -> NetlinkMessage {

    let mptr = unsafe { nlmsg_inherit(msg.hdr) };

    NetlinkMessage {
        ptr: mptr,
        hdr: unsafe { nlmsg_hdr(mptr) }
    }

}

pub fn data<T>(msg: &NetlinkMessage, container: &mut NetlinkData<T>) {

    unsafe {
        let vptr = nlmsg_data(msg.hdr);
        container.from_vptr(vptr);
    }

}

pub mod expose {
    pub fn nl_msg_ptr(msg: &::message::NetlinkMessage) -> *const ::message::nl_msg {
        msg.ptr
    }

    pub fn nlmsghdr_ptr(msg: &::message::NetlinkMessage) -> *const ::message::nlmsghdr {
        msg.hdr
    }
}
<commit_msg>NetlinkData container has more inst methods<commit_after>extern crate libc;

use libc::{c_int, size_t, c_void};
use std::mem;
use std::marker::PhantomData;

#[repr(C)]
pub struct nl_msg;
#[repr(C)]
pub struct nlmsghdr;

#[link(name="nl-3")]
extern "C" {
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;
    fn nlmsg_inherit(nlh: *const nlmsghdr) -> *const nl_msg;
    fn nlmsg_hdr(msg: *const nl_msg) -> *const nlmsghdr;
    fn nlmsg_ok(msg: *const nl_msg) -> u32;
    fn nlmsg_data(msg: *const nlmsghdr) -> *const c_void;
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: *const nlmsghdr,
}

pub struct NetlinkData <T> {
    ptr: Option<*const c_void>,
    phantom: PhantomData<T>
}

impl <T> NetlinkData <T> {

    pub fn new() -> NetlinkData<T> {
        NetlinkData {
            ptr: None,
            phantom: PhantomData
        }
    }

    pub fn with_data<D>(data: &D) -> NetlinkData<D> {
        NetlinkData {
            ptr: Some(unsafe{ mem::transmute(data) }),
            phantom: PhantomData
        }
    }

    pub fn with_vptr(data: *const c_void) -> NetlinkData<T> {
        NetlinkData {
            ptr: Some(data),
            phantom: PhantomData
        }
    }

    pub fn get(&self) -> Option<&T> {
        match self.ptr {
        None => None,
        Some(vptr) => {
            Some( unsafe { mem::transmute(vptr) } )
            }
        }
    }

    pub fn set(&mut self, data: &T) {
        match self.ptr {

        None => {
            let p: *const c_void =  unsafe{ mem::transmute(data) };
            self.ptr = Some( p );
            },

         _   => return

        }
    }

    pub fn from_vptr(&mut self, data: *const c_void) {
        match self.ptr {
            None    => self.ptr = Some(data),
            _       =>  return
        }
    }

    pub fn to_vptr(&self) -> Option<*const c_void> {
        self.ptr
    }
}

pub fn contain(ptr: *const nl_msg) -> Option<NetlinkMessage> {
    match ptr as isize {
        0x0 => None,
        _   => Some (
            NetlinkMessage {
                ptr: ptr,
                hdr: unsafe { nlmsg_hdr(ptr) }
            })
    }
}

pub fn alloc() -> Option<NetlinkMessage> {
    let mptr = unsafe { nlmsg_alloc() };
    contain(mptr)
}

pub fn free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {

        let hdr = unsafe { nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int) };

        match hdr as i32 {
            0x0 => false,
            _ => {
                true
            }
        }
}

pub fn data_len(msg: &NetlinkMessage) -> i32 {

            unsafe { nlmsg_datalen(msg.hdr) }
}

pub fn inherit(msg: &NetlinkMessage) -> NetlinkMessage {

    let mptr = unsafe { nlmsg_inherit(msg.hdr) };

    NetlinkMessage {
        ptr: mptr,
        hdr: unsafe { nlmsg_hdr(mptr) }
    }

}

pub fn data<T>(msg: &NetlinkMessage, container: &mut NetlinkData<T>) {

    unsafe {
        let vptr = nlmsg_data(msg.hdr);
        container.from_vptr(vptr);
    }

}

pub mod expose {
    pub fn nl_msg_ptr(msg: &::message::NetlinkMessage) -> *const ::message::nl_msg {
        msg.ptr
    }

    pub fn nlmsghdr_ptr(msg: &::message::NetlinkMessage) -> *const ::message::nlmsghdr {
        msg.hdr
    }
}
<|endoftext|>


<commit_before>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc::{c_char, c_uint};
use std::ffi::{CString, NulError};
use std::io;

/// Error that can occur during interface name resolution.
#[derive(Debug)]
pub enum NameToIndexError {
    /// Failed to allocate a C-style string to for the syscall
    NulError,
    IOError(io::Error),
}

impl From<NulError> for NameToIndexError {
    fn from(_: NulError) -> NameToIndexError {
        NameToIndexError::NulError
    }
}

impl From<io::Error> for NameToIndexError {
    fn from(e: io::Error) -> NameToIndexError {
        NameToIndexError::IOError(e)
    }
}

extern {
    fn if_nametoindex(ifname: *const c_char) -> c_uint;
}

/// Resolve an interface into a interface number.
pub fn name_to_index(name: &str) -> Result<c_uint, NameToIndexError> {
    let name = try!(CString::new(name));

    let if_index;
    unsafe {
        if_index = if_nametoindex(name.as_ptr());
    }

    if if_index == 0 {
        return Err(NameToIndexError::from(io::Error::last_os_error()));
    }

    Ok(if_index)
}
<commit_msg>Do not use extern, but if_nametoindex from libc instead.<commit_after>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc::{c_uint, if_nametoindex};
use std::ffi::{CString, NulError};
use std::io;

/// Error that can occur during interface name resolution.
#[derive(Debug)]
pub enum NameToIndexError {
    /// Failed to allocate a C-style string to for the syscall
    NulError,
    IOError(io::Error),
}

impl From<NulError> for NameToIndexError {
    fn from(_: NulError) -> NameToIndexError {
        NameToIndexError::NulError
    }
}

impl From<io::Error> for NameToIndexError {
    fn from(e: io::Error) -> NameToIndexError {
        NameToIndexError::IOError(e)
    }
}

/// Resolve an interface into a interface number.
pub fn name_to_index(name: &str) -> Result<c_uint, NameToIndexError> {
    let name = try!(CString::new(name));

    let if_index;
    unsafe {
        if_index = if_nametoindex(name.as_ptr());
    }

    if if_index == 0 {
        return Err(NameToIndexError::from(io::Error::last_os_error()));
    }

    Ok(if_index)
}
<|endoftext|>


<commit_before>
include!(concat!(env!("OUT_DIR"), "/exceptional-grammar.rs"));

#[cfg(test)]
pub mod test_helpers {
    use super::*;
    use ast::*;
    use num::rational::{Ratio};
    use num::{BigInt};

    pub fn l_string(name: &str) -> Literal {
        Literal::CharString(
           name.to_owned()
        )
    }

    pub fn l_number(num: i64, denom: i64) -> Literal {
        Literal::Number(build_ratio(num, denom))
    }

    pub fn l_bool(b: bool) -> Literal {
        match b {
            true => Literal::Boolean(true),
            false => Literal::Boolean(false)
        }
    }

    pub fn l_function(args: Vec<String>, statements: Vec<Statement>) -> Literal {
        Literal::Fn(Box::new(args), Box::new(statements))
    }

    pub fn l_map(pairs: Vec<(Expression, Expression)>) -> Literal {
        Literal::Map(pairs)
    }

    pub fn s_assign(name: &str, literal: Literal) -> Statement {
        Statement::Assign(
            true,
            name.to_owned(),
            Box::new(
                e_literal(
                    literal
                )
            )
        )
    }

    pub fn s_call(name: &str, args: Vec<Expression>) -> Statement {
        Statement::Call(name.to_owned(), args)
    }

    pub fn e_literal(literal: Literal) -> Expression {
        Expression::Literal(literal)
    }

    pub fn e_identifier(name: &str) -> Expression {
        Expression::Identifier(name.to_owned())
    }

    pub fn e_binop(op: &str, left: Expression, right: Expression) -> Expression {
        Expression::BinOp(op.to_owned(), Box::new(left), Box::new(right))
    }

    pub fn build_ratio(num: i64, denom: i64) -> Ratio<BigInt> {
        Ratio::new(
            BigInt::from(num),
            BigInt::from(denom)
        )
    }

    pub fn parse_expression(input: &str) -> Expression {
        expression(input).unwrap()
    }

    pub fn parse_statements(input: &str) -> Vec<Statement> {
        statements(input).unwrap()
    }

    pub fn parse_literal(input: &str) -> Literal {
        literal(input).unwrap()
    }
}

#[cfg(test)]
mod test_literals {
    use super::test_helpers::*;

    #[test]
    fn parses_number() {
        assert_eq!(
            parse_literal(&"1234"),
            l_number(1234, 1)
        );

        assert_eq!(
            parse_literal(&"0011"),
            l_number(11, 1)
        );
    }

    #[test]
    fn parses_strings() {
        assert_eq!(
            parse_literal(&"\"\""),
            l_string(&"")
        );

        assert_eq!(
            parse_literal(&"\"string with more words\""),
            l_string(&"string with more words")
        );
    }

    #[test]
    fn parses_booleans() {
        assert_eq!(
            parse_literal(&"true"),
            l_bool(true)
        );

        assert_eq!(
            parse_literal(&"false"),
            l_bool(false)
        );
    }

    #[test]
    fn parses_maps() {
        assert_eq!(
            parse_literal(&"{ a => b }"),
            l_map(vec![(e_identifier(&"a"), e_identifier(&"b"))])
        )
    }
}

#[cfg(test)]
mod test_expressions {
    use super::test_helpers::*;

    #[test]
    fn parses_simple_literal_expressions() {
        assert_eq!(
            parse_expression(&"1"),
            e_literal(l_number(1, 1))
        );

        assert_eq!(
            parse_expression(&"\"\""),
            e_literal(l_string(&""))
        )
    }

    #[test]
    fn parses_math() {
        assert_eq!(
            parse_expression(&"1 + 2 * 3 / 5 - d"),
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_binop(
                    "-",
                    e_binop(
                        "*",
                        e_literal(l_number(2, 1)),
                        e_binop("/", e_literal(l_number(3, 1)), e_literal(l_number(5, 1)))
                    ),
                    e_identifier(&"d")
                )
            )
        );
    }

    #[test]
    fn parses_identifiers() {
        assert_eq!(
            parse_expression(&"toto"),
            e_identifier(&"toto")
        )
    }

    #[test]
    fn parses_simple_functions() {
        assert_eq!(
            parse_expression(&"def() do end"),
            e_literal(
                l_function(vec![], vec![])
            )
        )
    }

    #[test]
    fn parses_functions_with_args() {
        assert_eq!(
            parse_expression(&"def(a, b) do end"),
            e_literal(
                l_function(vec!["a".to_owned(), "b".to_owned()], vec![])
            )
        )
    }

    #[test]
    fn prases_functions_with_bodies() {
        assert_eq!(
            parse_expression(&"def(a, b) do\nlet c = 1\nend"),
            e_literal(
                l_function(
                    vec!["a".to_owned(), "b".to_owned()],
                    vec![s_assign(&"c", l_number(1, 1))]
                )
            )
        )
    }
}

#[cfg(test)]
mod test_statements {
    use super::test_helpers::*;

    #[test]
    fn parses_assigns() {
        assert_eq!(
            parse_statements(&"let a = 1"),
            [s_assign(&"a", l_number(1, 1))]
        )
    }

    #[test]
    fn parses_calls() {
        assert_eq!(
            parse_statements("a()"),
            [s_call(&"a", vec![])]
        )
    }

    #[test]
    fn parses_calls_with_simple_args() {
        assert_eq!(
            parse_statements("a(1, b)"),
            [s_call(&"a", vec![e_literal(l_number(1, 1)), e_identifier(&"b")])]
        )
    }

    #[test]
    fn parses_calls_with_expressive_args() {
        let args = vec![
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_literal(l_number(2, 1)),
            ),
            e_literal(l_function(vec!["x".to_owned()], vec![]))
        ];
        assert_eq!(
            parse_statements("a(1 + 2, def(x) do end)"),
            [s_call(&"a", args)]
        )
    }
}
<commit_msg>Well apparently I had Map parsing all along<commit_after>
include!(concat!(env!("OUT_DIR"), "/exceptional-grammar.rs"));

#[cfg(test)]
pub mod test_helpers {
    use super::*;
    use ast::*;
    use num::rational::{Ratio};
    use num::{BigInt};

    pub fn l_string(name: &str) -> Literal {
        Literal::CharString(
           name.to_owned()
        )
    }

    pub fn l_number(num: i64, denom: i64) -> Literal {
        Literal::Number(build_ratio(num, denom))
    }

    pub fn l_bool(b: bool) -> Literal {
        match b {
            true => Literal::Boolean(true),
            false => Literal::Boolean(false)
        }
    }

    pub fn l_function(args: Vec<String>, statements: Vec<Statement>) -> Literal {
        Literal::Fn(Box::new(args), Box::new(statements))
    }

    pub fn l_map(pairs: Vec<(Expression, Expression)>) -> Literal {
        Literal::Map(pairs)
    }

    pub fn s_assign(name: &str, literal: Literal) -> Statement {
        Statement::Assign(
            true,
            name.to_owned(),
            Box::new(
                e_literal(
                    literal
                )
            )
        )
    }

    pub fn s_call(name: &str, args: Vec<Expression>) -> Statement {
        Statement::Call(name.to_owned(), args)
    }

    pub fn e_literal(literal: Literal) -> Expression {
        Expression::Literal(literal)
    }

    pub fn e_identifier(name: &str) -> Expression {
        Expression::Identifier(name.to_owned())
    }

    pub fn e_binop(op: &str, left: Expression, right: Expression) -> Expression {
        Expression::BinOp(op.to_owned(), Box::new(left), Box::new(right))
    }

    pub fn build_ratio(num: i64, denom: i64) -> Ratio<BigInt> {
        Ratio::new(
            BigInt::from(num),
            BigInt::from(denom)
        )
    }

    pub fn parse_expression(input: &str) -> Expression {
        expression(input).unwrap()
    }

    pub fn parse_statements(input: &str) -> Vec<Statement> {
        statements(input).unwrap()
    }

    pub fn parse_literal(input: &str) -> Literal {
        literal(input).unwrap()
    }
}

#[cfg(test)]
mod test_literals {
    use super::test_helpers::*;

    #[test]
    fn parses_number() {
        assert_eq!(
            parse_literal(&"1234"),
            l_number(1234, 1)
        );

        assert_eq!(
            parse_literal(&"0011"),
            l_number(11, 1)
        );
    }

    #[test]
    fn parses_strings() {
        assert_eq!(
            parse_literal(&"\"\""),
            l_string(&"")
        );

        assert_eq!(
            parse_literal(&"\"string with more words\""),
            l_string(&"string with more words")
        );
    }

    #[test]
    fn parses_booleans() {
        assert_eq!(
            parse_literal(&"true"),
            l_bool(true)
        );

        assert_eq!(
            parse_literal(&"false"),
            l_bool(false)
        );
    }

    #[test]
    fn parses_maps() {
        assert_eq!(
            parse_literal(&"{ a => b }"),
            l_map(vec![(e_identifier(&"a"), e_identifier(&"b"))])
        )
    }
}

#[cfg(test)]
mod test_expressions {
    use super::test_helpers::*;

    #[test]
    fn parses_simple_literal_expressions() {
        assert_eq!(
            parse_expression(&"1"),
            e_literal(l_number(1, 1))
        );

        assert_eq!(
            parse_expression(&"\"\""),
            e_literal(l_string(&""))
        );

        assert_eq!(
            parse_expression(&"{ \"a\" => 1 }"),
            e_literal(
                l_map(
                    vec![(e_literal(l_string(&"a")), e_literal(l_number(1, 1)))]
                )
            )
        )
    }

    #[test]
    fn parses_math() {
        assert_eq!(
            parse_expression(&"1 + 2 * 3 / 5 - d"),
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_binop(
                    "-",
                    e_binop(
                        "*",
                        e_literal(l_number(2, 1)),
                        e_binop("/", e_literal(l_number(3, 1)), e_literal(l_number(5, 1)))
                    ),
                    e_identifier(&"d")
                )
            )
        );
    }

    #[test]
    fn parses_identifiers() {
        assert_eq!(
            parse_expression(&"toto"),
            e_identifier(&"toto")
        )
    }

    #[test]
    fn parses_simple_functions() {
        assert_eq!(
            parse_expression(&"def() do end"),
            e_literal(
                l_function(vec![], vec![])
            )
        )
    }

    #[test]
    fn parses_functions_with_args() {
        assert_eq!(
            parse_expression(&"def(a, b) do end"),
            e_literal(
                l_function(vec!["a".to_owned(), "b".to_owned()], vec![])
            )
        )
    }

    #[test]
    fn prases_functions_with_bodies() {
        assert_eq!(
            parse_expression(&"def(a, b) do\nlet c = 1\nend"),
            e_literal(
                l_function(
                    vec!["a".to_owned(), "b".to_owned()],
                    vec![s_assign(&"c", l_number(1, 1))]
                )
            )
        )
    }
}

#[cfg(test)]
mod test_statements {
    use super::test_helpers::*;

    #[test]
    fn parses_assigns() {
        assert_eq!(
            parse_statements(&"let a = 1"),
            [s_assign(&"a", l_number(1, 1))]
        )
    }

    #[test]
    fn parses_calls() {
        assert_eq!(
            parse_statements("a()"),
            [s_call(&"a", vec![])]
        )
    }

    #[test]
    fn parses_calls_with_simple_args() {
        assert_eq!(
            parse_statements("a(1, b)"),
            [s_call(&"a", vec![e_literal(l_number(1, 1)), e_identifier(&"b")])]
        )
    }

    #[test]
    fn parses_calls_with_expressive_args() {
        let args = vec![
            e_binop(
                "+",
                e_literal(l_number(1, 1)),
                e_literal(l_number(2, 1)),
            ),
            e_literal(l_function(vec!["x".to_owned()], vec![]))
        ];
        assert_eq!(
            parse_statements("a(1 + 2, def(x) do end)"),
            [s_call(&"a", args)]
        )
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, SubCommand, ErrorKind};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static AFTER_HELP: &'static str = "some text that comes before the help

clap-test v1.4.8
tests clap library

USAGE:
    clap-test

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

some text that comes after the help";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [scpositional]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn after_and_before_help_output() {
    let app = App::new("clap-test")
        .version("v1.4.8")
        .about("tests clap library")
        .before_help("some text that comes before the help")
        .after_help("some text that comes after the help");
    test::check_help(app, AFTER_HELP);
}

#[test]
fn complex_subcommand_help_output() {
    let mut a = test::complex_app();
    let _ = a.get_matches_from_safe_borrow(vec![""]);
    let sc = a.p.subcommands.iter().filter(|s| s.p.meta.name == "subcmd").next().unwrap();
    // Now we check the output of print_help()
    let mut help = vec![];
    sc.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8(help).unwrap(), SC_HELP);
}
<commit_msg>tests: adds tests for multi level help subcommands<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, SubCommand, ErrorKind};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static AFTER_HELP: &'static str = "some text that comes before the help

clap-test v1.4.8
tests clap library

USAGE:
    clap-test

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

some text that comes after the help";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [scpositional]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    ctest subcmd multi [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag       tests flags
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --option <scoption>...    tests options";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn after_and_before_help_output() {
    let app = App::new("clap-test")
        .version("v1.4.8")
        .about("tests clap library")
        .before_help("some text that comes before the help")
        .after_help("some text that comes after the help");
    test::check_help(app, AFTER_HELP);
}

#[test]
fn multi_level_sc_help() {
    let app = App::new("ctest")
        .subcommand(SubCommand::with_name("subcmd")
            .subcommand(SubCommand::with_name("multi")
                .about("tests subcommands")
                .author("Kevin K. <kbknapp@gmail.com>")
                .version("0.1")
                .args_from_usage("
                    -f, --flag                    'tests flags'
                    -o, --option [scoption]...    'tests options'
                ")));
    test::check_err_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false);
}

#[test]
fn complex_subcommand_help_output() {
    let mut a = test::complex_app();
    let _ = a.get_matches_from_safe_borrow(vec![""]);
    let sc = a.p.subcommands.iter().filter(|s| s.p.meta.name == "subcmd").next().unwrap();
    // Now we check the output of print_help()
    let mut help = vec![];
    sc.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8(help).unwrap(), SC_HELP);
}
<|endoftext|>


<commit_before>use futures::sink::{Sink, SinkExt};
use futures::stream::{Stream, StreamExt};
use log::{debug, error, trace, warn};
use std::net::SocketAddr;
use tokio::select;
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Receiver, Sender};
use warp::reply::Reply;
use warp::ws::{Message, WebSocket, Ws};

use crate::server::{ClientId, MessageIn, MessageOut};

pub fn websocket(
    ws: Ws,
    ip_address: Option<SocketAddr>,
    server_tx: Sender<MessageIn>,
) -> impl Reply {
    let ip_address = ip_address.map(|ip_address| format!("{}", ip_address));
    ws.on_upgrade(|websocket| handle_websocket(websocket, ip_address, server_tx))
}

async fn handle_websocket(
    websocket: WebSocket,
    ip_address: Option<String>,
    mut server_tx: Sender<MessageIn>,
) {
    let id = ClientId::new_v4();

    let (messages_tx, messages_rx) = mpsc::channel::<MessageOut>(100);
    let (ws_tx, ws_rx) = websocket.split();

    // send new client
    if let Err(error) = server_tx
        .send(MessageIn::connect(id, ip_address, messages_tx))
        .await
    {
        error!("Failed to send new client to server: {}", error);
        return;
    }

    let in_task = tokio::spawn(handle_in(id, ws_rx, server_tx.clone()));
    let out_task = tokio::spawn(handle_out(messages_rx, ws_tx));

    if let Err(error) = select! {
        out = in_task => out,
        out = out_task => out,
    } {
        error!("Failure occurred while handling websocket: {}", error);
    }

    // send client disconnect
    if let Err(error) = server_tx.send(MessageIn::disconnect(id)).await {
        error!("Failed to send client disconnect to server: {}", error);
    }
}

async fn handle_in(
    id: ClientId,
    mut rx: impl Stream<Item = Result<Message, warp::Error>> + Unpin,
    mut tx: Sender<MessageIn>,
) {
    debug!("Websocket handler (in) created");
    while let Some(message) = rx.next().await {
        let message = match message {
            Ok(message) => message,
            Err(error) => {
                error!("Error occurred in incoming message: {}", error);
                break;
            }
        };

        if message.is_close() {
            trace!("Close received: {:?}", message);
            break;
        }

        let text = match message.to_str() {
            Ok(text) => text,
            Err(()) => {
                trace!("Non-text message received: {:?}", message);
                continue;
            }
        };

        trace!("Text message received: {}", text);
        let message = match MessageIn::from_json(id, text) {
            Ok(message) => message,
            Err(error) => {
                warn!("Failed to parse incoming message ({}): {}", text, error);
                continue;
            }
        };

        tx.send(message)
            .await
            .unwrap_or_else(|error| error!("Failed to send incoming message to server: {}", error))
    }
    debug!("Websocket handler (in) closed");
}

async fn handle_out(mut rx: Receiver<MessageOut>, mut tx: impl Sink<Message> + Unpin) {
    debug!("Websocket handler (out) created");
    while let Some(message) = rx.recv().await {
        let text = match message.to_json() {
            Ok(text) => text,
            Err(error) => {
                error!(
                    "Failed to serialize outgoing message: ({:?}): {}",
                    message, error
                );
                continue;
            }
        };

        if tx.send(Message::text(text)).await.is_err() {
            error!("Failed to send outgoing message")
        }
    }
    debug!("Websocket handler (out) closed");
}
<commit_msg>fixed websocket timeout on network inactivity in production<commit_after>use futures::sink::{Sink, SinkExt};
use futures::stream::{Stream, StreamExt};
use log::{debug, error, trace, warn};
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::select;
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::Mutex;
use tokio::time;
use warp::reply::Reply;
use warp::ws::{Message, WebSocket, Ws};

use crate::server::{ClientId, MessageIn, MessageOut};

const PING_RATE_SECONDS: u64 = 15;

pub fn websocket(
    ws: Ws,
    ip_address: Option<SocketAddr>,
    server_tx: Sender<MessageIn>,
) -> impl Reply {
    let ip_address = ip_address.map(|ip_address| format!("{}", ip_address));
    ws.on_upgrade(|websocket| handle_websocket(websocket, ip_address, server_tx))
}

async fn handle_websocket(
    websocket: WebSocket,
    ip_address: Option<String>,
    mut server_tx: Sender<MessageIn>,
) {
    let id = ClientId::new_v4();

    let (messages_tx, messages_rx) = mpsc::channel::<MessageOut>(100);
    let (ws_tx, ws_rx) = websocket.split();
    let ws_tx = Arc::new(Mutex::new(ws_tx));

    // send new client
    if let Err(error) = server_tx
        .send(MessageIn::connect(id, ip_address, messages_tx))
        .await
    {
        error!("Failed to send new client to server: {}", error);
        return;
    }

    let in_task = tokio::spawn(handle_in(id, ws_rx, server_tx.clone()));
    let out_task = tokio::spawn(handle_out(messages_rx, ws_tx.clone()));
    let ping_task = tokio::spawn(handle_ping(ws_tx));

    if let Err(error) = select! {
        out = in_task => out,
        out = out_task => out,
        out = ping_task => out,
    } {
        error!("Failure occurred while handling websocket: {}", error);
    }

    // send client disconnect
    if let Err(error) = server_tx.send(MessageIn::disconnect(id)).await {
        error!("Failed to send client disconnect to server: {}", error);
    }
}

async fn handle_in(
    id: ClientId,
    mut rx: impl Stream<Item = Result<Message, warp::Error>> + Unpin,
    mut tx: Sender<MessageIn>,
) {
    debug!("Websocket handler (in) created");
    while let Some(message) = rx.next().await {
        let message = match message {
            Ok(message) => message,
            Err(error) => {
                error!("Error occurred in incoming message: {}", error);
                break;
            }
        };

        if message.is_close() {
            trace!("Close received: {:?}", message);
            break;
        }

        let text = match message.to_str() {
            Ok(text) => text,
            Err(()) => {
                trace!("Non-text message received: {:?}", message);
                continue;
            }
        };

        trace!("Text message received: {}", text);
        let message = match MessageIn::from_json(id, text) {
            Ok(message) => message,
            Err(error) => {
                warn!("Failed to parse incoming message ({}): {}", text, error);
                continue;
            }
        };

        tx.send(message)
            .await
            .unwrap_or_else(|error| error!("Failed to send incoming message to server: {}", error))
    }
    debug!("Websocket handler (in) closed");
}

async fn handle_out(mut rx: Receiver<MessageOut>, tx: Arc<Mutex<impl Sink<Message> + Unpin>>) {
    debug!("Websocket handler (out) created");
    while let Some(message) = rx.recv().await {
        let text = match message.to_json() {
            Ok(text) => text,
            Err(error) => {
                error!(
                    "Failed to serialize outgoing message: ({:?}): {}",
                    message, error
                );
                continue;
            }
        };

        if tx.lock().await.send(Message::text(text)).await.is_err() {
            error!("Failed to send outgoing message")
        }
    }
    debug!("Websocket handler (out) closed");
}

async fn handle_ping(tx: Arc<Mutex<impl Sink<Message> + Unpin>>) {
    debug!("Websocket handler (ping) created");
    let mut interval = time::interval(Duration::from_secs(PING_RATE_SECONDS));
    loop {
        interval.tick().await;
        if tx
            .lock()
            .await
            .send(Message::ping(Vec::new()))
            .await
            .is_err()
        {
            error!("Failed to send outgoing ping");
            break;
        }
    }
    debug!("Websocket handler (ping) closed");
}
<|endoftext|>