<commit_before>//! A simple connection pool

use std::sync::{Arc, Mutex};

use {PostgresNotifications,
     PostgresConnectParams,
     IntoConnectParams,
     PostgresResult,
     PostgresCancelData,
     PostgresConnection,
     PostgresStatement,
     PostgresTransaction,
     SslMode};
use error::PostgresConnectError;
use types::ToSql;

struct InnerConnectionPool {
    params: PostgresConnectParams,
    ssl: SslMode,
    pool: Vec<PostgresConnection>,
}

impl InnerConnectionPool {
    fn add_connection(&mut self) -> Result<(), PostgresConnectError> {
        PostgresConnection::connect(self.params.clone(), &self.ssl)
            .map(|c| self.pool.push(c))
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
///
/// # Example
///
/// ```rust,no_run
/// # use postgres::NoSsl;
/// # use postgres::pool::PostgresConnectionPool;
/// let pool = PostgresConnectionPool::new("postgres://postgres@localhost",
///                                        NoSsl, 5).unwrap();
/// for _ in range(0, 10) {
///     let pool = pool.clone();
///     spawn(proc() {
///         let conn = pool.get_connection();
///         conn.execute("UPDATE foo SET bar = 1", []).unwrap();
///     });
/// }
/// ```
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    pool: Arc<Mutex<InnerConnectionPool>>
}

impl PostgresConnectionPool {
    /// Creates a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn new<T: IntoConnectParams>(params: T, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            params: try!(params.into_connect_params()),
            ssl: ssl,
            pool: vec![],
        };

        for _ in range(0, pool_size) {
            try!(pool.add_connection());
        }

        Ok(PostgresConnectionPool {
            pool: Arc::new(Mutex::new(pool))
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let mut pool = self.pool.lock();

        loop {
            match pool.pool.pop() {
                Some(conn) => {
                    return PooledPostgresConnection {
                        pool: self.clone(),
                        conn: Some(conn),
                    };
                }
                None => pool.cond.wait()
            }
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        pool.pool.push(self.conn.take_unwrap());
        pool.cond.signal();
    }
}

impl PooledPostgresConnection {
    /// Like `PostgresConnection::prepare`.
    pub fn prepare<'a>(&'a self, query: &str)
            -> PostgresResult<PostgresStatement<'a>> {
        self.conn.get_ref().prepare(query)
    }

    /// Like `PostgresConnection::execute`.
    pub fn execute(&self, query: &str, params: &[&ToSql])
            -> PostgresResult<uint> {
        self.conn.get_ref().execute(query, params)
    }

    /// Like `PostgresConnection::batch_execute`.
    pub fn batch_execute(&self, query: &str) -> PostgresResult<()> {
        self.conn.get_ref().batch_execute(query)
    }

    /// Like `PostgresConnection::transaction`.
    pub fn transaction<'a>(&'a self)
            -> PostgresResult<PostgresTransaction<'a>> {
        self.conn.get_ref().transaction()
    }

    /// Like `PostgresConnection::notifications`.
    pub fn notifications<'a>(&'a self) -> PostgresNotifications<'a> {
        self.conn.get_ref().notifications()
    }

    /// Like `PostgresConnection::cancel_data`.
    pub fn cancel_data(&self) -> PostgresCancelData {
        self.conn.get_ref().cancel_data()
    }

    /// Like `PostgresConnection::is_desynchronized`.
    pub fn is_desynchronized(&self) -> bool {
        self.conn.get_ref().is_desynchronized()
    }
}
<commit_msg>Make PooledPostgresConnection use Deref<commit_after>//! A simple connection pool

use std::sync::{Arc, Mutex};

use {PostgresConnectParams, IntoConnectParams, PostgresConnection, SslMode};
use error::PostgresConnectError;

struct InnerConnectionPool {
    params: PostgresConnectParams,
    ssl: SslMode,
    pool: Vec<PostgresConnection>,
}

impl InnerConnectionPool {
    fn add_connection(&mut self) -> Result<(), PostgresConnectError> {
        PostgresConnection::connect(self.params.clone(), &self.ssl)
            .map(|c| self.pool.push(c))
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
///
/// # Example
///
/// ```rust,no_run
/// # use postgres::NoSsl;
/// # use postgres::pool::PostgresConnectionPool;
/// let pool = PostgresConnectionPool::new("postgres://postgres@localhost",
///                                        NoSsl, 5).unwrap();
/// for _ in range(0, 10) {
///     let pool = pool.clone();
///     spawn(proc() {
///         let conn = pool.get_connection();
///         conn.execute("UPDATE foo SET bar = 1", []).unwrap();
///     });
/// }
/// ```
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    pool: Arc<Mutex<InnerConnectionPool>>
}

impl PostgresConnectionPool {
    /// Creates a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn new<T: IntoConnectParams>(params: T, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            params: try!(params.into_connect_params()),
            ssl: ssl,
            pool: vec![],
        };

        for _ in range(0, pool_size) {
            try!(pool.add_connection());
        }

        Ok(PostgresConnectionPool {
            pool: Arc::new(Mutex::new(pool))
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let mut pool = self.pool.lock();

        loop {
            match pool.pool.pop() {
                Some(conn) => {
                    return PooledPostgresConnection {
                        pool: self.clone(),
                        conn: Some(conn),
                    };
                }
                None => pool.cond.wait()
            }
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        pool.pool.push(self.conn.take_unwrap());
        pool.cond.signal();
    }
}

impl Deref<PostgresConnection> for PooledPostgresConnection {
    fn deref<'a>(&'a self) -> &'a PostgresConnection {
        self.conn.get_ref()
    }
}
<|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/.

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::fs;
use std::io::{Read, Write};
use std::os::unix::net::{UnixListener, UnixStream};
use std::path::Path;
use std::thread;

#[derive(Debug, Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Debug, Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
pub struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
pub enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
pub struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure_as_iron(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_response_as_iron(response: &PdnsResponse) -> IronResult<Response> {
    match serde_json::to_string(response) {
        Ok(serialized) => {
            debug!("Response is: {}", serialized);
            let mut response = Response::with(serialized);
            response.status = Some(Status::Ok);
            response.headers.set(ContentType::json());

            Ok(response)
        }
        Err(err) => {
            error!("{}", err);
            EndpointError::with(status::InternalServerError, 501)
        }
    }
}

// Returns a SOA record for a given qname.
pub fn soa_response(qname: &str, config: &Config) -> PdnsLookupResponse {
    PdnsLookupResponse {
        qtype: "SOA".to_owned(),
        qname: qname.to_owned(),
        content: config.soa_content.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    }
}

pub fn pakegite_query(qname: &str, qtype: &str, config: &Config) -> Result<PdnsResponse, String> {
    // Pagekite sends dns requests to qnames like:
    // dd7251eef7c773a192feb06c0e07ac6020ac.tc730a6b9e2f28f407bb3871e98d3fe4e60c.625558ecb0d283a5b058ba88fb3d9aa11d48.https-4443.fabrice.box.knilxof.org.box.knilxof.org
    // See https://pagekite.net/wiki/Howto/DnsBasedAuthentication
    debug!("PageKite query for {} {}", qtype, qname);

    let mut pdns_response = PdnsResponse { result: Vec::new() };

    if qtype == "SOA" {
        pdns_response
            .result
            .push(PdnsResponseParams::Lookup(soa_response(qname, config)));
        return Ok(pdns_response);
    }

    if qtype != "A" && qtype != "ANY" {
        return Err(format!("Unsupported PageKite request type: {}", qtype));
    }

    // Split up the qname.
    let parts: Vec<&str> = qname.split('.').collect();
    let subdomain = format!("{}.box.{}.", parts[4], config.domain);
    let ip = match config
              .domain_db
              .get_record_by_name(&subdomain)
              .recv()
              .unwrap() {
        Ok(record) => {
            let srand = parts[0];
            let token = parts[1];
            let sign = parts[2];
            let proto = parts[3];
            let kite_domain = format!("{}.box.{}", parts[4], config.domain);
            let payload = format!("{}:{}:{}:{}", proto, kite_domain, srand, token);
            let salt = sign[..8].to_owned();

            debug!("{} {} {} {} {}", srand, token, sign, proto, kite_domain);

            let mut hasher = Sha1::new();
            hasher.input_str(&format!("{}{}{}", record.token, payload, salt));
            let calc = hasher.result_str();

            let calc_sub = calc[..28].to_owned();
            let sign_sub = sign[8..36].to_owned();

            debug!("Signatures: {} {}", calc_sub, sign_sub);

            if calc_sub == sign_sub {
                "255.255.254.255"
            } else {
                "255.255.255.1"
            }
        }
        Err(_) => {
            // Return 255.255.255.0 to PageKite to indicate failure.
            "255.255.255.0"
        }
    };

    let ns_record = PdnsLookupResponse {
        qtype: "A".to_owned(),
        qname: qname.to_owned(),
        content: ip.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    };
    pdns_response
        .result
        .push(PdnsResponseParams::Lookup(ns_record));

    Ok(pdns_response)
}

fn process_request(req: PdnsRequest, config: &Config) -> Result<PdnsResponse, String> {
    debug!("pdns request is {:?}", req);

    if req.method == "lookup" {
        let original_qname = req.parameters.qname.unwrap().to_lowercase();
        let mut qname = original_qname.clone();
        let qtype = req.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, original_qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname ends up with .box.$domain.box.$domain. we consider that it's a
        // PageKite request and process it separately.
        if qname.ends_with(&format!(".box.{}.box.{}.", config.domain, config.domain)) {
            return pakegite_query(&qname, &qtype, config);
        }

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }

        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return Err("No local_ip".to_owned());
                }

                // Choose either the local or public ip based on the parameters.remote one.
                let a_record = if record.public_ip.is_some() &&
                                  req.parameters.remote.unwrap() == record.public_ip.unwrap() {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(soa_response(&original_qname, config)));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: original_qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "TXT".to_owned(),
                        qname: original_qname.to_owned(),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                return Ok(pdns_response);
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return Err("No record for this name.".to_owned());
            }
        }
    }

    Err(format!("Unsupported method: {}", req.method))
}

// Answers to an HTTP request when using the HTTP remote backend.
pub fn pdns(req: &mut Request, config: &Config) -> IronResult<Response> {
    use std::net::SocketAddr::V4;
    use std::net::Ipv4Addr;

    info!("GET /pdns");
    // Only allow clients from localhost.
    match req.remote_addr {
        V4(addr) => {
            if addr.ip() != &Ipv4Addr::new(127, 0, 0, 1) {
                return EndpointError::with(status::BadRequest, 400);
            }
        }
        _ => return EndpointError::with(status::BadRequest, 400),
    }

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    match process_request(input, config) {
        Ok(ref response) => pdns_response_as_iron(response),
        Err(err) => pdns_failure_as_iron(&err),
    }

}

// Custom method to read just enough characters from the stream to
// build a JSON object.
// Directly using read_to_string or serde_json::from_reader cause
// the stream to reach EOF and subsequent write fail with a
// "Broken Pipe" error.
fn read_json_from_stream(mut stream: &UnixStream) -> String {
    let mut buffer = [0; 1];
    let mut balance_count = 0;
    let mut result = String::new();
    loop {
        match stream.read(&mut buffer) {
            Ok(_) => {
                if buffer[0] == b'{' {
                    balance_count += 1;
                } else if buffer[0] == b'}' {
                    balance_count -= 1;
                }
                result.push(buffer[0] as char);
            }
            Err(err) => {
                error!("Stream reading error: {}", err);
            }
        }

        if balance_count == 0 {
            break;
        }
    }

    // Read the trailing \n
    #[allow(unused_must_use)]
    {
        stream.read(&mut buffer);
    }

    result
}

fn handle_socket_request(mut stream: UnixStream, config: &Config) {
    let error_response = b"{\"result\":false}";

    macro_rules! send {
        ($content:expr) => (
            stream.write_all($content).expect("Failed to write answer to the pdns socket");
        )
    }

    loop {
        let mut s = read_json_from_stream(&stream);
        debug!("JSON String is {}", s);
        let input: PdnsRequest = match serde_json::from_str(&mut s) {
            Ok(value) => value,
            Err(err) => {
                error!("JSON error: {}", err);
                break;
            }
        };

        // Special case for the `initialize` method which is a no-op that
        // just returns success.
        if input.method == "initialize" {
            debug!("Answering to initialization request");
            send!(b"{\"result\":true}");
            continue;
        }

        match process_request(input, config) {
            Ok(ref response) => {
                match serde_json::to_string(response) {
                    Ok(serialized) => {
                        debug!("Response is: {}", serialized);
                        send!(serialized.as_bytes());
                    }
                    Err(err) => {
                        error!("Error serializing JSON: {}", err);
                        send!(error_response);
                    }
                }
            }
            Err(err) => {
                error!("Error processing request: {}", err);
                send!(error_response);
            }
        }
    }
}

pub fn start_socket_endpoint(config: &Config) {
    if config.socket_path.is_none() {
        error!("No socket path configured!");
        return;
    }

    let path = &config.socket_path.clone().unwrap();

    debug!("Starting the pdns socket endpoint at {}", path);

    if Path::exists(Path::new(&path)) {
        #[allow(unused_must_use)]
        {
            fs::remove_file(path.clone());
        }
    }

    let config = config.clone();
    let path = path.clone();
    thread::Builder::new()
        .name("tunnel pdns socket".to_owned())
        .spawn(move || {
            let socket = match UnixListener::bind(path) {
                Ok(sock) => sock,
                Err(e) => {
                    error!("Couldn't bind: {:?}", e);
                    return;
                }
            };
            for stream in socket.incoming() {
                match stream {
                    Ok(stream) => {
                        let config = config.clone();
                        thread::spawn(move || handle_socket_request(stream, &config));
                    }
                    Err(_) => {
                        break;
                    }
                }
            }
        })
        .expect("Failed to start pdns socket thread.");
}
<commit_msg>Fix the local/remote detection<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/.

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::fs;
use std::io::{Read, Write};
use std::os::unix::net::{UnixListener, UnixStream};
use std::path::Path;
use std::thread;

#[derive(Debug, Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Debug, Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
pub struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
pub enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
pub struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure_as_iron(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_response_as_iron(response: &PdnsResponse) -> IronResult<Response> {
    match serde_json::to_string(response) {
        Ok(serialized) => {
            debug!("Response is: {}", serialized);
            let mut response = Response::with(serialized);
            response.status = Some(Status::Ok);
            response.headers.set(ContentType::json());

            Ok(response)
        }
        Err(err) => {
            error!("{}", err);
            EndpointError::with(status::InternalServerError, 501)
        }
    }
}

// Returns a SOA record for a given qname.
pub fn soa_response(qname: &str, config: &Config) -> PdnsLookupResponse {
    PdnsLookupResponse {
        qtype: "SOA".to_owned(),
        qname: qname.to_owned(),
        content: config.soa_content.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    }
}

pub fn pakegite_query(qname: &str, qtype: &str, config: &Config) -> Result<PdnsResponse, String> {
    // Pagekite sends dns requests to qnames like:
    // dd7251eef7c773a192feb06c0e07ac6020ac.tc730a6b9e2f28f407bb3871e98d3fe4e60c.625558ecb0d283a5b058ba88fb3d9aa11d48.https-4443.fabrice.box.knilxof.org.box.knilxof.org
    // See https://pagekite.net/wiki/Howto/DnsBasedAuthentication
    debug!("PageKite query for {} {}", qtype, qname);

    let mut pdns_response = PdnsResponse { result: Vec::new() };

    if qtype == "SOA" {
        pdns_response
            .result
            .push(PdnsResponseParams::Lookup(soa_response(qname, config)));
        return Ok(pdns_response);
    }

    if qtype != "A" && qtype != "ANY" {
        return Err(format!("Unsupported PageKite request type: {}", qtype));
    }

    // Split up the qname.
    let parts: Vec<&str> = qname.split('.').collect();
    let subdomain = format!("{}.box.{}.", parts[4], config.domain);
    let ip = match config
              .domain_db
              .get_record_by_name(&subdomain)
              .recv()
              .unwrap() {
        Ok(record) => {
            let srand = parts[0];
            let token = parts[1];
            let sign = parts[2];
            let proto = parts[3];
            let kite_domain = format!("{}.box.{}", parts[4], config.domain);
            let payload = format!("{}:{}:{}:{}", proto, kite_domain, srand, token);
            let salt = sign[..8].to_owned();

            debug!("{} {} {} {} {}", srand, token, sign, proto, kite_domain);

            let mut hasher = Sha1::new();
            hasher.input_str(&format!("{}{}{}", record.token, payload, salt));
            let calc = hasher.result_str();

            let calc_sub = calc[..28].to_owned();
            let sign_sub = sign[8..36].to_owned();

            debug!("Signatures: {} {}", calc_sub, sign_sub);

            if calc_sub == sign_sub {
                "255.255.254.255"
            } else {
                "255.255.255.1"
            }
        }
        Err(_) => {
            // Return 255.255.255.0 to PageKite to indicate failure.
            "255.255.255.0"
        }
    };

    let ns_record = PdnsLookupResponse {
        qtype: "A".to_owned(),
        qname: qname.to_owned(),
        content: ip.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    };
    pdns_response
        .result
        .push(PdnsResponseParams::Lookup(ns_record));

    Ok(pdns_response)
}

fn process_request(req: PdnsRequest, config: &Config) -> Result<PdnsResponse, String> {
    debug!("pdns request is {:?}", req);

    if req.method == "lookup" {
        let original_qname = req.parameters.qname.unwrap().to_lowercase();
        let mut qname = original_qname.clone();
        let qtype = req.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, original_qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname ends up with .box.$domain.box.$domain. we consider that it's a
        // PageKite request and process it separately.
        if qname.ends_with(&format!(".box.{}.box.{}.", config.domain, config.domain)) {
            return pakegite_query(&qname, &qtype, config);
        }

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }

        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return Err("No local_ip".to_owned());
                }

                // Choose either the local or public ip based on wether the qname matches
                // the local_name or remote_name.
                let a_record = if record.local_ip.is_some() && qname == record.local_name {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(soa_response(&original_qname, config)));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: original_qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "TXT".to_owned(),
                        qname: original_qname.to_owned(),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                return Ok(pdns_response);
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return Err("No record for this name.".to_owned());
            }
        }
    }

    Err(format!("Unsupported method: {}", req.method))
}

// Answers to an HTTP request when using the HTTP remote backend.
pub fn pdns(req: &mut Request, config: &Config) -> IronResult<Response> {
    use std::net::SocketAddr::V4;
    use std::net::Ipv4Addr;

    info!("GET /pdns");
    // Only allow clients from localhost.
    match req.remote_addr {
        V4(addr) => {
            if addr.ip() != &Ipv4Addr::new(127, 0, 0, 1) {
                return EndpointError::with(status::BadRequest, 400);
            }
        }
        _ => return EndpointError::with(status::BadRequest, 400),
    }

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    match process_request(input, config) {
        Ok(ref response) => pdns_response_as_iron(response),
        Err(err) => pdns_failure_as_iron(&err),
    }

}

// Custom method to read just enough characters from the stream to
// build a JSON object.
// Directly using read_to_string or serde_json::from_reader cause
// the stream to reach EOF and subsequent write fail with a
// "Broken Pipe" error.
fn read_json_from_stream(mut stream: &UnixStream) -> String {
    let mut buffer = [0; 1];
    let mut balance_count = 0;
    let mut result = String::new();
    loop {
        match stream.read(&mut buffer) {
            Ok(_) => {
                if buffer[0] == b'{' {
                    balance_count += 1;
                } else if buffer[0] == b'}' {
                    balance_count -= 1;
                }
                result.push(buffer[0] as char);
            }
            Err(err) => {
                error!("Stream reading error: {}", err);
            }
        }

        if balance_count == 0 {
            break;
        }
    }

    // Read the trailing \n
    #[allow(unused_must_use)]
    {
        stream.read(&mut buffer);
    }

    result
}

fn handle_socket_request(mut stream: UnixStream, config: &Config) {
    let error_response = b"{\"result\":false}";

    macro_rules! send {
        ($content:expr) => (
            stream.write_all($content).expect("Failed to write answer to the pdns socket");
        )
    }

    loop {
        let mut s = read_json_from_stream(&stream);
        debug!("JSON String is {}", s);
        let input: PdnsRequest = match serde_json::from_str(&mut s) {
            Ok(value) => value,
            Err(err) => {
                error!("JSON error: {}", err);
                break;
            }
        };

        // Special case for the `initialize` method which is a no-op that
        // just returns success.
        if input.method == "initialize" {
            debug!("Answering to initialization request");
            send!(b"{\"result\":true}");
            continue;
        }

        match process_request(input, config) {
            Ok(ref response) => {
                match serde_json::to_string(response) {
                    Ok(serialized) => {
                        debug!("Response is: {}", serialized);
                        send!(serialized.as_bytes());
                    }
                    Err(err) => {
                        error!("Error serializing JSON: {}", err);
                        send!(error_response);
                    }
                }
            }
            Err(err) => {
                error!("Error processing request: {}", err);
                send!(error_response);
            }
        }
    }
}

pub fn start_socket_endpoint(config: &Config) {
    if config.socket_path.is_none() {
        error!("No socket path configured!");
        return;
    }

    let path = &config.socket_path.clone().unwrap();

    debug!("Starting the pdns socket endpoint at {}", path);

    if Path::exists(Path::new(&path)) {
        #[allow(unused_must_use)]
        {
            fs::remove_file(path.clone());
        }
    }

    let config = config.clone();
    let path = path.clone();
    thread::Builder::new()
        .name("tunnel pdns socket".to_owned())
        .spawn(move || {
            let socket = match UnixListener::bind(path) {
                Ok(sock) => sock,
                Err(e) => {
                    error!("Couldn't bind: {:?}", e);
                    return;
                }
            };
            for stream in socket.incoming() {
                match stream {
                    Ok(stream) => {
                        let config = config.clone();
                        thread::spawn(move || handle_socket_request(stream, &config));
                    }
                    Err(_) => {
                        break;
                    }
                }
            }
        })
        .expect("Failed to start pdns socket thread.");
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For your conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::Button reexported as GtkButtonTrait,
                                // its trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]
#![feature(associated_types)]

extern crate libc;

pub use glib::traits::Connect;
pub use gtk::widgets::GValuePublic;

pub use gtk::BoxTrait as GtkBoxTrait;
pub use gtk::ActionableTrait as GtkActionableTrait;
pub use gtk::AppChooserTrait as GtkAppChooserTrait;
pub use gtk::BinTrait as GtkBinTrait;
pub use gtk::ButtonTrait as GtkButtonTrait;
pub use gtk::CellEditableTrait as GtkCellEditableTrait;
pub use gtk::CellLayoutTrait as GtkCellLayoutTrait;
pub use gtk::CellRendererTrait as GtkCellRendererTrait;
pub use gtk::CheckMenuItemTrait as GtkCheckMenuItemTrait;
pub use gtk::ColorChooserTrait as GtkColorChooserTrait;
pub use gtk::ComboBoxTrait as GtkComboBoxTrait;
pub use gtk::ContainerTrait as GtkContainerTrait;
pub use gtk::DialogTrait as GtkDialogTrait;
pub use gtk::EditableTrait as GtkEditableTrait;
pub use gtk::EntryTrait as GtkEntryTrait;
pub use gtk::FileChooserTrait as GtkFileChooserTrait;
pub use gtk::FontChooserTrait as GtkFontChooserTrait;
pub use gtk::FrameTrait as GtkFrameTrait;
pub use gtk::LabelTrait as GtkLabelTrait;
pub use gtk::MenuItemTrait as GtkMenuItemTrait;
pub use gtk::MenuShellTrait as GtkMenuShellTrait;
pub use gtk::MiscTrait as GtkMiscTrait;
pub use gtk::OrientableTrait as GtkOrientableTrait;
pub use gtk::RangeTrait as GtkRangeTrait;
pub use gtk::RecentChooserTrait as GtkRecentChooserTrait;
pub use gtk::ScaleButtonTrait as GtkScaleButtonTrait;
pub use gtk::ScrollableTrait as GtkScrollableTrait;
pub use gtk::ScrolledWindowTrait as GtkScrolledWindowTrait;
pub use gtk::TextBufferTrait as GtkTextBufferTrait;
pub use gtk::ToggleButtonTrait as GtkToggleButtonTrait;
pub use gtk::ToggleToolButtonTrait as GtkToggleToolButtonTrait;
pub use gtk::ToolButtonTrait as GtkToolButtonTrait;
pub use gtk::ToolItemTrait as GtkToolItemTrait;
pub use gtk::ToolShellTrait as GtkToolShellTrait;
pub use gtk::WidgetTrait as GtkWidgetTrait;
pub use gtk::WindowTrait as GtkWindowTrait;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<commit_msg>Add glob feature<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For your conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::Button reexported as GtkButtonTrait,
                                // its trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![feature(globs)]

extern crate libc;

pub use glib::traits::Connect;
pub use gtk::widgets::GValuePublic;

pub use gtk::BoxTrait as GtkBoxTrait;
pub use gtk::ActionableTrait as GtkActionableTrait;
pub use gtk::AppChooserTrait as GtkAppChooserTrait;
pub use gtk::BinTrait as GtkBinTrait;
pub use gtk::ButtonTrait as GtkButtonTrait;
pub use gtk::CellEditableTrait as GtkCellEditableTrait;
pub use gtk::CellLayoutTrait as GtkCellLayoutTrait;
pub use gtk::CellRendererTrait as GtkCellRendererTrait;
pub use gtk::CheckMenuItemTrait as GtkCheckMenuItemTrait;
pub use gtk::ColorChooserTrait as GtkColorChooserTrait;
pub use gtk::ComboBoxTrait as GtkComboBoxTrait;
pub use gtk::ContainerTrait as GtkContainerTrait;
pub use gtk::DialogTrait as GtkDialogTrait;
pub use gtk::EditableTrait as GtkEditableTrait;
pub use gtk::EntryTrait as GtkEntryTrait;
pub use gtk::FileChooserTrait as GtkFileChooserTrait;
pub use gtk::FontChooserTrait as GtkFontChooserTrait;
pub use gtk::FrameTrait as GtkFrameTrait;
pub use gtk::LabelTrait as GtkLabelTrait;
pub use gtk::MenuItemTrait as GtkMenuItemTrait;
pub use gtk::MenuShellTrait as GtkMenuShellTrait;
pub use gtk::MiscTrait as GtkMiscTrait;
pub use gtk::OrientableTrait as GtkOrientableTrait;
pub use gtk::RangeTrait as GtkRangeTrait;
pub use gtk::RecentChooserTrait as GtkRecentChooserTrait;
pub use gtk::ScaleButtonTrait as GtkScaleButtonTrait;
pub use gtk::ScrollableTrait as GtkScrollableTrait;
pub use gtk::ScrolledWindowTrait as GtkScrolledWindowTrait;
pub use gtk::TextBufferTrait as GtkTextBufferTrait;
pub use gtk::ToggleButtonTrait as GtkToggleButtonTrait;
pub use gtk::ToggleToolButtonTrait as GtkToggleToolButtonTrait;
pub use gtk::ToolButtonTrait as GtkToolButtonTrait;
pub use gtk::ToolItemTrait as GtkToolItemTrait;
pub use gtk::ToolShellTrait as GtkToolShellTrait;
pub use gtk::WidgetTrait as GtkWidgetTrait;
pub use gtk::WindowTrait as GtkWindowTrait;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;
use nom::IResult;
use parsers;
use error::Error;

/// A Term can represent a Terminal or Nonterminal node
#[derive(PartialEq, Debug, Clone)]
pub enum Term {
    Terminal(String),
    Nonterminal(String),
}

impl Term {
    // Get `Term` by parsing a string
    pub fn from_str(s: &str) -> Result<Self, Error> {
        match parsers::term_complete(s.as_bytes()) {
            IResult::Done(_, o) => Ok(o),
            IResult::Incomplete(n) => Err(Error::from(n)),
            IResult::Error(e) => Err(Error::from(e)),
        }
    }
}

impl FromStr for Term {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_str(s)
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Terminal(ref s) => {
                if s.contains('"') {
                    write!(f, "'{}'", s)
                } else {
                    write!(f, "\"{}\"", s)
                }
            }
            Term::Nonterminal(ref s) => write!(f, "<{}>", s),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;

    use self::quickcheck::{Arbitrary, Gen, QuickCheck, StdGen, TestResult};
    use super::*;

    impl Arbitrary for Term {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            if bool::arbitrary(g) {
                Term::Nonterminal(String::arbitrary(g))
            } else {
                let mut term = String::arbitrary(g);
                if term.contains('"') {
                    term = term.chars().filter(|&c| c != '\'').collect();
                } else if term.contains('\'') {
                    term = term.chars().filter(|&c| c != '"').collect();
                }
                Term::Terminal(term)
            }
        }
    }

    fn prop_to_string_and_back(term: Term) -> TestResult {
        let to_string = term.to_string();
        let from_str = Term::from_str(&to_string);
        match from_str {
            Ok(from_term) => TestResult::from_bool(from_term == term),
            _ => TestResult::error(format!("{} to string and back should be safe", term)),
        }
    }

    #[test]
    fn parse_complete() {
        assert_eq!(
            Ok(Term::Nonterminal(String::from("dna"))),
            Term::from_str("<dna>")
        );
    }

    #[test]
    fn parse_error() {
        let incomplete = Term::from_str("<dna");
        assert!(incomplete.is_err());

        let error = incomplete.unwrap_err();
        match error {
            Error::ParseError(ref s) => assert!(s.starts_with("Parsing error:")),
            _ => panic!("Incomplete term should be parse error"),
        }
    }

    #[test]
    fn parse_incomplete() {
        let result = Term::from_str("");
        assert!(result.is_err(), "{:?} should be err", result);
        match result {
            Err(e) => {
                match e {
                    Error::ParseIncomplete(_) => (),
                    e => panic!("should should be Error::ParseIncomplete: {:?}", e),
                }
            }
            Ok(s) => panic!("should should be Error::ParseIncomplete: {}", s),
        }
    }

    #[test]
    fn parse_error_display() {
        let incomplete = Term::from_str("<dna");
        assert!(incomplete.is_err());

        let error = incomplete.unwrap_err().to_string();
        assert!(!error.is_empty());
    }

    #[test]
    fn parse_whitespace_nonterm() {
        let some_space = String::from(" some space ");
        assert_eq!(
            Ok(Term::Nonterminal(some_space.clone())),
            Term::from_str(&format!("<{}>", some_space))
        );
    }

    #[test]
    fn parse_whitespace_term() {
        let some_space = String::from(" some space ");
        assert_eq!(
            Ok(Term::Terminal(some_space.clone())),
            Term::from_str(&format!("\"{}\"", some_space))
        );
    }

    #[test]
    fn parse_quote_term() {
        let quote_term = Term::from_str("'\"'");
        assert_eq!(Ok(Term::Terminal(String::from("\""))), quote_term);
    }

    #[test]
    fn parse_single_quote_term() {
        let quote_term = Term::from_str("\"'\"");
        assert_eq!(Ok(Term::Terminal(String::from("'"))), quote_term);
    }

    #[test]
    fn quote_term_to_string_and_back() {
        let quote = Term::Terminal(String::from("\""));
        let to_string = quote.to_string();
        let from_string = Term::from_str(&to_string);
        assert_eq!(Ok(Term::Terminal(String::from("\""))), from_string);
    }
}
<commit_msg>Test term to_string and from_str property<commit_after>use std::fmt;
use std::str::FromStr;
use nom::IResult;
use parsers;
use error::Error;

/// A Term can represent a Terminal or Nonterminal node
#[derive(PartialEq, Debug, Clone)]
pub enum Term {
    Terminal(String),
    Nonterminal(String),
}

impl Term {
    // Get `Term` by parsing a string
    pub fn from_str(s: &str) -> Result<Self, Error> {
        match parsers::term_complete(s.as_bytes()) {
            IResult::Done(_, o) => Ok(o),
            IResult::Incomplete(n) => Err(Error::from(n)),
            IResult::Error(e) => Err(Error::from(e)),
        }
    }
}

impl FromStr for Term {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::from_str(s)
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Terminal(ref s) => {
                if s.contains('"') {
                    write!(f, "'{}'", s)
                } else {
                    write!(f, "\"{}\"", s)
                }
            }
            Term::Nonterminal(ref s) => write!(f, "<{}>", s),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;

    use self::quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
    use super::*;

    impl Arbitrary for Term {
        fn arbitrary<G: Gen>(g: &mut G) -> Self {
            let mut term = String::arbitrary(g);
            if bool::arbitrary(g) {
                term = term.chars().filter(|&c| (c != '>')).collect();
                Term::Nonterminal(term)
            } else {
                if term.contains('"') {
                    term = term.chars().filter(|&c| c != '\'').collect();
                } else if term.contains('\'') {
                    term = term.chars().filter(|&c| c != '"').collect();
                }
                Term::Terminal(term)
            }
        }
    }

    fn prop_to_string_and_back(term: Term) -> TestResult {
        let to_string = term.to_string();
        let from_str = Term::from_str(&to_string);
        match from_str {
            Ok(from_term) => TestResult::from_bool(from_term == term),
            _ => TestResult::error(format!("{} to string and back should be safe", term)),
        }
    }

    #[test]
    fn term_to_string_and_back() {
        QuickCheck::new().quickcheck(prop_to_string_and_back as fn(Term) -> TestResult)
    }

    #[test]
    fn parse_complete() {
        assert_eq!(
            Ok(Term::Nonterminal(String::from("dna"))),
            Term::from_str("<dna>")
        );
    }

    #[test]
    fn parse_error() {
        let incomplete = Term::from_str("<dna");
        assert!(incomplete.is_err());

        let error = incomplete.unwrap_err();
        match error {
            Error::ParseError(ref s) => assert!(s.starts_with("Parsing error:")),
            _ => panic!("Incomplete term should be parse error"),
        }
    }

    #[test]
    fn parse_incomplete() {
        let result = Term::from_str("");
        assert!(result.is_err(), "{:?} should be err", result);
        match result {
            Err(e) => {
                match e {
                    Error::ParseIncomplete(_) => (),
                    e => panic!("should should be Error::ParseIncomplete: {:?}", e),
                }
            }
            Ok(s) => panic!("should should be Error::ParseIncomplete: {}", s),
        }
    }

    #[test]
    fn parse_error_display() {
        let incomplete = Term::from_str("<dna");
        assert!(incomplete.is_err());

        let error = incomplete.unwrap_err().to_string();
        assert!(!error.is_empty());
    }

    #[test]
    fn parse_whitespace_nonterm() {
        let some_space = String::from(" some space ");
        assert_eq!(
            Ok(Term::Nonterminal(some_space.clone())),
            Term::from_str(&format!("<{}>", some_space))
        );
    }

    #[test]
    fn parse_whitespace_term() {
        let some_space = String::from(" some space ");
        assert_eq!(
            Ok(Term::Terminal(some_space.clone())),
            Term::from_str(&format!("\"{}\"", some_space))
        );
    }

    #[test]
    fn parse_quote_term() {
        let quote_term = Term::from_str("'\"'");
        assert_eq!(Ok(Term::Terminal(String::from("\""))), quote_term);
    }

    #[test]
    fn parse_single_quote_term() {
        let quote_term = Term::from_str("\"'\"");
        assert_eq!(Ok(Term::Terminal(String::from("'"))), quote_term);
    }

    #[test]
    fn quote_term_to_string_and_back() {
        let quote = Term::Terminal(String::from("\""));
        let to_string = quote.to_string();
        let from_string = Term::from_str(&to_string);
        assert_eq!(Ok(Term::Terminal(String::from("\""))), from_string);
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[cfg(target_os = "windows")]
    #[test]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<commit_msg>Fix tests build<commit_after>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    use super::*;

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[cfg(target_os = "windows")]
    #[test]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<|endoftext|>


<commit_before>// Copyright 2015 The Noise-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Use PrimInt + Signed instead of SignedInt + NumCast once num has
// PrimInt implementations
use num::{NumCast,Signed,PrimInt};
use rand::{Rand, Rng, SeedableRng, XorShiftRng};

use math;

const TABLE_SIZE: usize = 256;

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these and reuse it everywhere.
#[allow(missing_copy_implementations)]
pub struct Seed {
    values: [u8; TABLE_SIZE],
}

impl Rand for Seed {
    /// Generates a random seed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::Seed;
    ///
    /// # fn main() {
    /// let seed = rand::random::<Seed>();
    /// # }
    /// ```
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::Seed;
    /// use rand::{SeedableRng, Rng, XorShiftRng};
    ///
    /// # fn main() {
    /// let mut rng: XorShiftRng = SeedableRng::from_seed([1, 2, 3, 4]);
    /// let seed = rng.gen::<Seed>();
    /// # }
    /// ```
    fn rand<R: Rng>(rng: &mut R) -> Seed {
        let mut seq: Vec<u8> = (0 .. TABLE_SIZE).map(|x| x as u8).collect();
        rng.shuffle(&mut *seq);

        // It's unfortunate that this double-initializes the array, but Rust doesn't currently provide a
        // clean way to do this in one pass. Hopefully won't matter, as Seed creation will usually be a
        // one-time event.
        let mut seed = Seed { values: [0; TABLE_SIZE] };
        let seq_it = seq.iter();
        for (x, y) in seed.values.iter_mut().zip(seq_it) { *x = *y }
        seed
    }
}

impl Seed {
    /// Deterministically generates a new seed table based on a `u32` value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    ///
    /// # Example
    ///
    /// ```rust
    /// use noise::Seed;
    ///
    /// let seed = Seed::new(12);
    /// ```
    pub fn new(seed: u32) -> Seed {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: Signed + PrimInt + NumCast>(&self, x: T) -> usize {
        let x: usize = math::cast(x & math::cast(0xff));
        self.values[x] as usize
    }

    #[inline(always)]
    pub fn get2<T: Signed + PrimInt + NumCast>(&self, pos: math::Point2<T>) -> usize {
        let y: usize = math::cast(pos[1] & math::cast(0xff));
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    #[inline(always)]
    pub fn get3<T: Signed + PrimInt + NumCast>(&self, pos: math::Point3<T>) -> usize {
        let z: usize = math::cast(pos[2] & math::cast(0xff));
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    #[inline(always)]
    pub fn get4<T: Signed + PrimInt + NumCast>(&self, pos: math::Point4<T>) -> usize {
        let w: usize = math::cast(pos[3] & math::cast(0xff));
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

#[cfg(test)]
mod tests {
    use rand::random;
    use perlin::perlin3;
    use super::Seed;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&Seed::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<commit_msg>Implement Clone and Debug for Seed<commit_after>// Copyright 2015 The Noise-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Use PrimInt + Signed instead of SignedInt + NumCast once num has
// PrimInt implementations
use num::{NumCast,Signed,PrimInt};
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
use std::fmt;

use math;

const TABLE_SIZE: usize = 256;

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these and reuse it everywhere.
#[allow(missing_copy_implementations)]
pub struct Seed {
    values: [u8; TABLE_SIZE],
}

impl Rand for Seed {
    /// Generates a random seed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::Seed;
    ///
    /// # fn main() {
    /// let seed = rand::random::<Seed>();
    /// # }
    /// ```
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::Seed;
    /// use rand::{SeedableRng, Rng, XorShiftRng};
    ///
    /// # fn main() {
    /// let mut rng: XorShiftRng = SeedableRng::from_seed([1, 2, 3, 4]);
    /// let seed = rng.gen::<Seed>();
    /// # }
    /// ```
    fn rand<R: Rng>(rng: &mut R) -> Seed {
        let mut seq: Vec<u8> = (0 .. TABLE_SIZE).map(|x| x as u8).collect();
        rng.shuffle(&mut *seq);

        // It's unfortunate that this double-initializes the array, but Rust doesn't currently provide a
        // clean way to do this in one pass. Hopefully won't matter, as Seed creation will usually be a
        // one-time event.
        let mut seed = Seed { values: [0; TABLE_SIZE] };
        let seq_it = seq.iter();
        for (x, y) in seed.values.iter_mut().zip(seq_it) { *x = *y }
        seed
    }
}

impl Seed {
    /// Deterministically generates a new seed table based on a `u32` value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    ///
    /// # Example
    ///
    /// ```rust
    /// use noise::Seed;
    ///
    /// let seed = Seed::new(12);
    /// ```
    pub fn new(seed: u32) -> Seed {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: Signed + PrimInt + NumCast>(&self, x: T) -> usize {
        let x: usize = math::cast(x & math::cast(0xff));
        self.values[x] as usize
    }

    #[inline(always)]
    pub fn get2<T: Signed + PrimInt + NumCast>(&self, pos: math::Point2<T>) -> usize {
        let y: usize = math::cast(pos[1] & math::cast(0xff));
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    #[inline(always)]
    pub fn get3<T: Signed + PrimInt + NumCast>(&self, pos: math::Point3<T>) -> usize {
        let z: usize = math::cast(pos[2] & math::cast(0xff));
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    #[inline(always)]
    pub fn get4<T: Signed + PrimInt + NumCast>(&self, pos: math::Point4<T>) -> usize {
        let w: usize = math::cast(pos[3] & math::cast(0xff));
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

impl Clone for Seed {
    fn clone(&self) -> Seed {
        Seed { values: self.values }
    }
}

impl fmt::Debug for Seed {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Seed {{ .. }}")
    }
}

#[cfg(test)]
mod tests {
    use rand::random;
    use perlin::perlin3;
    use super::Seed;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&Seed::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use serde_json::value::Value;

use priority::TaskPriority;

pub type DateTime= String; // FIXME
pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

#[derive(Debug, Clone)]
pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime,
    modified: DateTime,
    priority: TaskPriority,
    project: Project,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64, desc: String, entry: DateTime, modified: DateTime,
        priority: TaskPriority, project: Project, status: Status,
        tags: Vec<Tag>, uuid: UUID, urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            return None;
        }

        let map = v.as_object().unwrap();

        let keys = [ "id", "description", "modified", "priority", "project",
            "status", "tags", "uuid", "urgency"];

        if keys.iter().any(|x| map.contains_key(*x)) {
            return None
        }

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : get_entry(&map),
            modified : get_modified(&map),
            priority : TaskPriority::from(get_priority(&map)),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

}

impl Into<Value> for Task {

    fn into(self) -> Value {
        unimplemented!()
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> String {
    map.get("entry").unwrap().as_string().map(String::from).unwrap()
}

fn get_modified(map: &BTreeMap<String, Value>) -> String {
    map.get("modified").unwrap().as_string().map(String::from).unwrap()
}

fn get_priority(map: &BTreeMap<String, Value>) -> &str {
    map.get("priority").unwrap().as_string().unwrap()
}

fn get_project(map: &BTreeMap<String, Value>) -> String {
    map.get("project").unwrap().as_string().map(String::from).unwrap()
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

<commit_msg>Impl Into<Value> for Task<commit_after>use std::collections::BTreeMap;

use serde_json::value::Value;

use priority::TaskPriority;

pub type DateTime= String; // FIXME
pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

#[derive(Debug, Clone)]
pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime,
    modified: DateTime,
    priority: TaskPriority,
    project: Project,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64, desc: String, entry: DateTime, modified: DateTime,
        priority: TaskPriority, project: Project, status: Status,
        tags: Vec<Tag>, uuid: UUID, urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            return None;
        }

        let map = v.as_object().unwrap();

        let keys = [ "id", "description", "modified", "priority", "project",
            "status", "tags", "uuid", "urgency"];

        if keys.iter().any(|x| map.contains_key(*x)) {
            return None
        }

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : get_entry(&map),
            modified : get_modified(&map),
            priority : TaskPriority::from(get_priority(&map)),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

}

impl Into<Value> for Task {

    fn into(self) -> Value {
        let id       = Value::U64(self.id);
        let desc     = Value::String(self.desc);
        let entry    = Value::String(self.entry);
        let modified = Value::String(self.modified);
        let priority = Value::String(self.priority.into());
        let project  = Value::String(self.project);
        let status   = Value::String(self.status);
        let tags     = Value::Array(self.tags
                                        .into_iter()
                                        .map(|s| Value::String(String::from(s)))
                                        .collect());
        let uuid     = Value::String(self.uuid);
        let urgency  = Value::F64(self.urgency);

        let mut map = BTreeMap::new();
        map.insert(String::from("id")       , id);
        map.insert(String::from("desc")     , desc);
        map.insert(String::from("entry")    , entry);
        map.insert(String::from("modified") , modified);
        map.insert(String::from("priority") , priority);
        map.insert(String::from("project")  , project);
        map.insert(String::from("status")   , status);
        map.insert(String::from("tags")     , tags);
        map.insert(String::from("uuid")     , uuid);
        map.insert(String::from("urgency")  , urgency);

        Value::Object(map)
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> String {
    map.get("entry").unwrap().as_string().map(String::from).unwrap()
}

fn get_modified(map: &BTreeMap<String, Value>) -> String {
    map.get("modified").unwrap().as_string().map(String::from).unwrap()
}

fn get_priority(map: &BTreeMap<String, Value>) -> &str {
    map.get("priority").unwrap().as_string().unwrap()
}

fn get_project(map: &BTreeMap<String, Value>) -> String {
    map.get("project").unwrap().as_string().map(String::from).unwrap()
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

<|endoftext|>