<commit_before>extern mod opengles;   // FIXME: Should only be for tests.
use glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers, GLint};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{get_uniform_location, link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use core::pipes::{Chan, Port};
use core::pipes;
use libc::{c_int, c_uint};
use io::println;
use ptr::{addr_of, null};
use str::to_bytes;
use task::TaskBuilder;
use vec::raw::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(&po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup: Port<()> = Port();
        let wakeup_chan = Chan(&wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

*/
<commit_msg>Fix tests<commit_after>extern mod opengles;   // FIXME: Should only be for tests.
use glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers, GLint};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{get_uniform_location, link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use core::comm::{Chan, Port};
use libc::{c_int, c_uint};
use io::println;
use ptr::{addr_of, null};
use str::to_bytes;
use task::TaskBuilder;
use vec::raw::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(&po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup: Port<()> = Port();
        let wakeup_chan = Chan(&wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

*/
<|endoftext|>


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

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::env;

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

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

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

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "Invalid options\n{}", f)
        }
    };

    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTION]...

Print the full filename of the current working directory.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        println!("{}", env::current_dir().unwrap().display());
    }

    0
}
<commit_msg>pwd: add support for -L and -P options<commit_after>#![crate_name = "uu_pwd"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::env;
use std::fs;

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

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

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");
    opts.optflag("L", "logical", "use PWD from environment, even if it contains symlinks");
    opts.optflag("P", "physical", "avoid all symlinks");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "Invalid options\n{}", f)
        }
    };

    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTION]...

Print the full filename of the current working directory.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let logical_path = env::current_dir().unwrap();
        if matches.opt_present("logical") {
            println!("{}", logical_path.display());
        } else {
            let physical_path = fs::canonicalize(&logical_path);
            println!("{}", physical_path.unwrap().display());
        }
    }

    0
}
<|endoftext|>


<commit_before>use std::rc::{ Rc, Weak };
use std::fmt;
use std::cell::RefCell;

pub struct Node<T> {
    pub id: u32,
    parent: Option<Weak<RefCell<Node<T>>>>,
    children: Vec<Rc<RefCell<Node<T>>>>,
    data: T
}

impl <T> Drop for Node<T> {
    fn drop(&mut self) {
        println!("Dropping {}", self.id);
    }
}

impl <T> fmt::Display for Node<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.parent {
            Some(_) => "*",
            None => "*root"
        };
        write!(f, "{} ->(id: {})", p, self.id);
        Ok(())
    }
}

impl <T> Node<T> {

    pub fn create(id: u32, data: T, parent: Option<Rc<RefCell<Node<T>>>>) -> Rc<RefCell<Node<T>>> {
        let prt = match parent {
            Some(ref p) => {
                Some(Rc::downgrade(p))
            },
            None => None
        };

        let node = Rc::new(
            RefCell::new(
                Node::new(id, prt, data)
            )
        );

        match parent {
            Some(ref p) => {
                p.borrow_mut().add_child(node.clone());
            },
            None => {}
        };

        node
    }

    pub fn find_root(node: Rc<RefCell<Node<T>>>) -> Rc<RefCell<Node<T>>> {
        match node.borrow().parent() {
            Some(p) => Node::find_root(p.clone()),
            None => return node.clone()
        }
    }

    fn new(id: u32, parent: Option<Weak<RefCell<Node<T>>>>, data: T) -> Self {
        Node {
            id: id,
            parent: match parent {
                Some(p) => Some(p),
                None => None
            },
            children: Vec::new(),
            data: data
        }
    }

    /// Recursively find if this node is a child of another
    pub fn is_child_of(this: Rc<RefCell<Node<T>>>, parent: Rc<RefCell<Node<T>>>) -> bool {
        match this.borrow().parent() {
            Some(p) => {
                if p.borrow().id == parent.borrow().id {
                    true
                } else {
                    Node::is_child_of(p, parent)
                }
            },
            None => false
        }
    }

    pub fn reparent(child: Rc<RefCell<Node<T>>>, target: Rc<RefCell<Node<T>>>) -> Result<(), String> {
        if child.borrow().id == target.borrow().id {
            return Err("Cannot make node a child of itself.".to_string());
        }
        if  !Node::is_child_of(target.clone(), child.clone()) { // check for cycles
            match child.borrow().parent() {
                Some(old_parent) => {
                    old_parent.borrow_mut().remove_child(child.clone());
                },
                None => {}
            }
            child.borrow_mut().parent = Some(Rc::downgrade(&target.clone()));
            target.borrow_mut().add_child(child.clone());
            Ok(())
        } else {
            Err("Node cycle detected. Child is a parent of reparent target.".to_string()) // format for better debug msg
        }
    }

    pub fn remove_child(&mut self, child: Rc<RefCell<Node<T>>>) {
        let mut idx: Option<usize> = None;
        for i in 0usize..self.children.len() {
            let child_id = self.children[i].borrow().id;
            if child_id == child.borrow().id {
                idx = Some(i);
                break;
            }
        }
        match idx {
            Some(i) => {
                self.children.remove(i);
            },
            _ => {}
        };
    }

    pub fn find_child(&self, id: u32) -> Option<Rc<RefCell<Node<T>>>> {
        let option: Option<&Rc<RefCell<Node<T>>>> =
            self.children.iter().find(|x| x.borrow().id == id);
        match option {
            Some(obj_ref) => Some(obj_ref.clone()),
            None => None
        }
    }

    pub fn siblings(&self) -> Option<Vec<Rc<RefCell<Node<T>>>>> {
        match self.parent() {
            Some(p) => {
                Some(
                    p.borrow().children.iter()
                        .filter(|x| x.borrow().id != self.id)
                        .map(|x| x.clone())
                        .collect()
                )
            },
            None => None
        }
    }

    pub fn children(&mut self) -> &mut Vec<Rc<RefCell<Node<T>>>> {
        &mut self.children
    }

    pub fn is_leaf(&self) -> bool {
        self.children.len() == 0
    }

    // intentionally private for the time being (Node::new() specifies a parent)
    fn add_child(&mut self, child: Rc<RefCell<Node<T>>>) {
        if self.id != child.borrow().id {
            self.children.push(child);
        }
    }

    pub fn parent(&self) -> Option<Rc<RefCell<Node<T>>>> {
        match self.parent {
            Some(ref p) => Some(p.upgrade().unwrap()),
            None => None
        }
    }

    pub fn debug_draw(&self, lvl: u32) {
        if lvl == 0 {
            println!("-- Hierarchy Dump --");
        }
        let c = if self.children.len() > 0 {
            "..."
        } else {
            ".leaf*"
        };
        println!(
            "{}{}{}",
            (0..lvl).map(|_| "....").collect::<String>(),
            self,
            c
        );
        for child in &self.children {
            child.borrow().debug_draw(lvl+1);
        }
    }

}
<commit_msg>RcNode<T> type alias<commit_after>use std::rc::{ Rc, Weak };
use std::fmt;
use std::cell::RefCell;

type NodeMut<T> = RefCell<Node<T>>;
pub type RcNode<T> = Rc<NodeMut<T>>;
pub type WeakNode<T> = Weak<NodeMut<T>>;

pub struct Node<T> {
    pub id: u32,
    parent: Option<WeakNode<T>>,
    children: Vec<RcNode<T>>,
    data: T
}

impl <T> Drop for Node<T> {
    fn drop(&mut self) {
        println!("Dropping {}", self.id);
    }
}

impl <T> fmt::Display for Node<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.parent {
            Some(_) => "*",
            None => "*root"
        };
        write!(f, "{} ->(id: {})", p, self.id);
        Ok(())
    }
}

impl <T> Node<T> {

    pub fn create(id: u32, data: T, parent: Option<RcNode<T>>) -> RcNode<T> {
        let prt = match parent {
            Some(ref p) => {
                Some(Rc::downgrade(p))
            },
            None => None
        };

        let node = Rc::new(
            RefCell::new(
                Node::new(id, prt, data)
            )
        );

        match parent {
            Some(ref p) => {
                p.borrow_mut().add_child(node.clone());
            },
            None => {}
        };

        node
    }

    pub fn find_root(node: RcNode<T>) -> RcNode<T> {
        match node.borrow().parent() {
            Some(p) => Node::find_root(p.clone()),
            None => return node.clone()
        }
    }

    fn new(id: u32, parent: Option<WeakNode<T>>, data: T) -> Self {
        Node {
            id: id,
            parent: match parent {
                Some(p) => Some(p),
                None => None
            },
            children: Vec::new(),
            data: data
        }
    }

    /// Recursively find if this node is a child of another
    pub fn is_child_of(this: RcNode<T>, parent: RcNode<T>) -> bool {
        match this.borrow().parent() {
            Some(p) => {
                if p.borrow().id == parent.borrow().id {
                    true
                } else {
                    Node::is_child_of(p, parent)
                }
            },
            None => false
        }
    }

    pub fn reparent(child: RcNode<T>, target: RcNode<T>) -> Result<(), String> {
        if child.borrow().id == target.borrow().id {
            return Err("Cannot make node a child of itself.".to_string());
        }
        if  !Node::is_child_of(target.clone(), child.clone()) { // check for cycles
            match child.borrow().parent() {
                Some(old_parent) => {
                    old_parent.borrow_mut().remove_child(child.clone());
                },
                None => {}
            }
            child.borrow_mut().parent = Some(Rc::downgrade(&target.clone()));
            target.borrow_mut().add_child(child.clone());
            Ok(())
        } else {
            Err("Node cycle detected. Child is a parent of reparent target.".to_string()) // format for better debug msg
        }
    }

    pub fn remove_child(&mut self, child: RcNode<T>) {
        let mut idx: Option<usize> = None;
        for i in 0usize..self.children.len() {
            let child_id = self.children[i].borrow().id;
            if child_id == child.borrow().id {
                idx = Some(i);
                break;
            }
        }
        match idx {
            Some(i) => {
                self.children.remove(i);
            },
            _ => {}
        };
    }

    pub fn find_child(&self, id: u32) -> Option<RcNode<T>> {
        let option: Option<&RcNode<T>> =
            self.children.iter().find(|x| x.borrow().id == id);
        match option {
            Some(obj_ref) => Some(obj_ref.clone()),
            None => None
        }
    }

    pub fn siblings(&self) -> Option<Vec<RcNode<T>>> {
        match self.parent() {
            Some(p) => {
                Some(
                    p.borrow().children.iter()
                        .filter(|x| x.borrow().id != self.id)
                        .map(|x| x.clone())
                        .collect()
                )
            },
            None => None
        }
    }

    pub fn children(&mut self) -> &mut Vec<RcNode<T>> {
        &mut self.children
    }

    pub fn is_leaf(&self) -> bool {
        self.children.len() == 0
    }

    // intentionally private for the time being (Node::new() specifies a parent)
    fn add_child(&mut self, child: RcNode<T>) {
        if self.id != child.borrow().id {
            self.children.push(child);
        }
    }

    pub fn parent(&self) -> Option<RcNode<T>> {
        match self.parent {
            Some(ref p) => Some(p.upgrade().unwrap()),
            None => None
        }
    }

    pub fn debug_draw(&self, lvl: u32) {
        if lvl == 0 {
            println!("-- Hierarchy Dump --");
        }
        let c = if self.children.len() > 0 {
            "..."
        } else {
            ".leaf*"
        };
        println!(
            "{}{}{}",
            (0..lvl).map(|_| "....").collect::<String>(),
            self,
            c
        );
        for child in &self.children {
            child.borrow().debug_draw(lvl+1);
        }
    }

}
<|endoftext|>


<commit_before>//! The module that contains the request code.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::reactor::Handle;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// The default low byte rate threshold.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold in seconds.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_TIME: u32 = 10;

/// The default redirect threshold for a single request.
///
/// cURL will follow this many redirects by default before aborting
/// the request. See [`Request::max_redirects`](struct.Request.html#method.max_redirects)
/// for more information.
pub const MAX_REDIRECTS: u32 = 15;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, Duration)>,
    max_redirects: u32,
    method: Method,
    params: HashMap<String, Vec<String>>,
    timeout: Option<Duration>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Self {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, Duration::from_secs(LOW_SPEED_TIME as u64))),
            max_redirects: MAX_REDIRECTS,
            method: method,
            params: HashMap::new(),
            timeout: None,
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Self {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Self {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Self {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            self.headers.insert(name.to_owned(), value.to_owned());
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Self {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Serialize>(self, body: &T) -> Self {
        self.set_json(serde_json::to_vec(body).unwrap())
    }

    /// Sets the thresholds which, when reached, aborts a download due to too
    /// low speeds.
    ///
    /// Pass 0 for either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_duration`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to [`LOW_SPEED_LIMIT`](constant.LOW_SPEED_LIMIT.html) and
    /// [`LOW_SPEED_TIME`](constant.LOW_SPEED_TIME.html).
    pub fn lowspeed_limit(mut self, bytes: u32, per_duration: Duration) -> Self {
        self.lowspeed_limits = if bytes > 0 && per_duration > Duration::from_secs(0) {
            Some((bytes, per_duration))
        } else {
            None
        };
        self
    }

    /// Sets the maximum amount of redirects cURL will follow when
    /// [`Request::follow_redirects`](#method.follow_redirects) is
    /// enabled.
    pub fn max_redirects(mut self, max_redirects: u32) -> Self {
        self.max_redirects = max_redirects;
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Self {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    pub fn send(self, h: Handle) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(h))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let max_redirects = self.max_redirects;
            let method = self.method;
            let timeout = self.timeout;
            let url = self.url;
            let mut first_header = true;

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                        .and_then(|_| easy.max_redirections(max_redirects))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 { // First header is HTTP status line, don't want that
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_time)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(per_time))
                } else {
                    Ok(())
                })
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(timeout) = timeout {
                    easy.timeout(timeout)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                (ez, headers, body)
                            })
                            .map(|(ez, headers, body)| Response::new(ez, headers, body))
                            .map_err(|err| err.into_error())
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Set the maximum time the request is allowed to take.
    ///
    /// Disabled by default in favor of [`lowspeed_limit`]
    pub fn timeout(mut self, duration: Duration) -> Self {
        self.timeout = Some(duration);
        self
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Self {
        self.handle = Some(handle);
        self
    }

    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn set_json(mut self, body: Vec<u8>) -> Self {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(stringify!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "serde-serialization")]
    use serde_json;

    #[cfg_attr(feature = "rustc-serialization", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }

    #[cfg(feature = "serde-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        serde_json::to_vec(&TestPayload { a: 10, b: 15}).unwrap()
    }
}<commit_msg>Document panics on request<commit_after>//! The module that contains the request code.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::io::Error;
use std::str::from_utf8;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::Method;
use curl::easy::{Easy, List};
use futures::{BoxFuture, failed, Future};
use response::Response;
use tokio_core::reactor::Handle;
use tokio_curl::Session;
use url::Url;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// The default low byte rate threshold.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_LIMIT: u32 = 10;

/// The default low speed time threshold in seconds.
///
/// See [`Request::lowspeed_limit`](struct.Request.html#method.lowspeed_limit)
/// for more information.
pub const LOW_SPEED_TIME: u32 = 10;

/// The default redirect threshold for a single request.
///
/// cURL will follow this many redirects by default before aborting
/// the request. See [`Request::max_redirects`](struct.Request.html#method.max_redirects)
/// for more information.
pub const MAX_REDIRECTS: u32 = 15;

/// Represents an HTTP request.
///
/// While this can be used directly (and _must_ be for special HTTP verbs, it is
/// preferred to use the [`get`](fn.get.html), [`post`](fn.post.html), etc. functions
/// since they are shorter.
pub struct Request {
    body: Option<Vec<u8>>,
    follow_redirects: bool,
    handle: Option<Easy>,
    headers: HashMap<String, String>,
    lowspeed_limits: Option<(u32, Duration)>,
    max_redirects: u32,
    method: Method,
    params: HashMap<String, Vec<String>>,
    timeout: Option<Duration>,
    url: Url
}

impl Request {
    /// Creates a new instance of `Request`.
    pub fn new(url: &Url, method: Method) -> Self {
        Request {
            body: None,
            follow_redirects: true,
            handle: None,
            headers: HashMap::new(),
            lowspeed_limits: Some((LOW_SPEED_LIMIT, Duration::from_secs(LOW_SPEED_TIME as u64))),
            max_redirects: MAX_REDIRECTS,
            method: method,
            params: HashMap::new(),
            timeout: None,
            url: url.clone()
        }
    }

    /// Sets the body of the request as raw byte array.
    pub fn body(mut self, body: &AsRef<[u8]>) -> Self {
        self.body = Some(Vec::from(body.as_ref()));
        self
    }

    /// Sets the option whether to follow 3xx-redirects or not.
    ///
    /// Defaults to `true`.
    pub fn follow_redirects(mut self, follow: bool) -> Self {
        self.follow_redirects = follow;
        self
    }

    /// Sets an HTTP header for the request. Remove headers by passing
    /// an empty value.
    ///
    /// ## Duplicates
    /// In spite of the W3C allowing multiple headers with the same name
    /// (https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
    /// we do not so that we get a cleaner and leaner API.
    ///
    /// If you really need to specify multiple header values for a single
    /// header, just set a comma-separated list here, as that, as per standards,
    /// is equivalent to sending multiple headers with the same name (see link).
    /// If your server code can't deal with that, go and burn. :P
    pub fn header(mut self, name: &str, value: &str) -> Self {
        if value.is_empty() {
            self.headers.remove(name);
        } else {
            self.headers.insert(name.to_owned(), value.to_owned());
        }
        self
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Encodable>(self, body: &T) -> Self {
        self.set_json(rustc_serialize::json::encode(body).unwrap().into_bytes())
    }

    /// Serializes the given object to JSON and uses that as the request body.
    /// Also automatically sets the `Content-Type` to `application/json`.
    ///
    /// ## Panics
    /// Panics if serialization is not successful.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Serialize>(self, body: &T) -> Self {
        self.set_json(serde_json::to_vec(body).unwrap())
    }

    /// Sets the thresholds which, when reached, aborts a download due to too
    /// low speeds.
    ///
    /// Pass 0 for either parameter to disable lowspeed limiting.
    ///
    /// ## Remarks
    /// `bytes` sets the minimum average amount of bytes transferred in `per_duration`
    /// time. If this number is not reached, cURL will abort the transfer because the transfer
    /// speed is too low.
    ///
    /// The values here default to [`LOW_SPEED_LIMIT`](constant.LOW_SPEED_LIMIT.html) and
    /// [`LOW_SPEED_TIME`](constant.LOW_SPEED_TIME.html).
    pub fn lowspeed_limit(mut self, bytes: u32, per_duration: Duration) -> Self {
        self.lowspeed_limits = if bytes > 0 && per_duration > Duration::from_secs(0) {
            Some((bytes, per_duration))
        } else {
            None
        };
        self
    }

    /// Sets the maximum amount of redirects cURL will follow when
    /// [`Request::follow_redirects`](#method.follow_redirects) is
    /// enabled.
    pub fn max_redirects(mut self, max_redirects: u32) -> Self {
        self.max_redirects = max_redirects;
        self
    }

    /// Adds a URL parameter to the request.
    ///
    /// ## Duplicates
    /// Duplicates are allowed to enable things like query parameters that use
    /// PHP array syntax (`&key[]=value`).
    pub fn param(mut self, name: &str, value: &str) -> Self {
        let value = value.to_owned();
        match self.params.entry(name.to_owned()) {
            Entry::Occupied(mut e) => e.get_mut().push(value),
            Entry::Vacant(e) => { e.insert(vec![value]); () }
        };
        self
    }

    /// Creates a new `Session` on the specified event loop to send the HTTP request through
    /// and returns a future that fires off the request, parses the response and resolves to
    /// a `Response`-struct on success.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    pub fn send(self, h: Handle) -> BoxFuture<Response, Error> {
        self.send_with_session(&Session::new(h))
    }

    /// Uses the given `Session` to send the HTTP request through and returns a future that
    /// fires off the request, parses the response and resolves to a `Response`-struct on success.
    ///
    /// ## Panics
    /// Panics in case of native exceptions in cURL.
    pub fn send_with_session(mut self, session: &Session) -> BoxFuture<Response, Error> {
        {
            let mut query_pairs = self.url.query_pairs_mut();
            for (key, values) in self.params {
                for value in values {
                    query_pairs.append_pair(&key, &value);
                }
            }
        }
        let headers = {
            let mut list = List::new();
            for (key, value) in self.headers {
                list.append(&format!("{}: {}", key.trim(), value.trim())).expect("Failed to append header value to (native cURL) header list.");
            }
            list
        };

        let mut easy = self.handle.unwrap_or_else(|| Easy::new());
        let (header_tx, header_rx) = channel();
        let (body_tx, body_rx) = channel();

        let config_res = {
            // Make the borrow checker happy
            let body = self.body;
            let follow_redirects = self.follow_redirects;
            let lowspeed_limits = self.lowspeed_limits;
            let max_redirects = self.max_redirects;
            let method = self.method;
            let timeout = self.timeout;
            let url = self.url;
            let mut first_header = true;

            // We cannot use try! here, since we're dealing with futures, not with Results
            Ok(())
                .and_then(|_| easy.accept_encoding(""))
                .and_then(|_| easy.custom_request(method.as_ref()))
                .and_then(|_| if follow_redirects {
                    easy.follow_location(true)
                        .and_then(|_| easy.max_redirections(max_redirects))
                } else {
                    Ok(())
                })
                .and_then(|_| easy.header_function(move |header| {
                    match from_utf8(header) {
                        Ok(s) => {
                            let s = s.trim(); // Headers are \n-separated
                            if !first_header && s.len() > 0 { // First header is HTTP status line, don't want that
                                let _ = header_tx.send(s.to_owned());
                            }
                            first_header = false;
                            true
                        },
                        Err(_) => false
                    }
                }))
                .and_then(|_| easy.http_headers(headers))
                .and_then(|_| if let Some((bytes, per_time)) = lowspeed_limits {
                    easy.low_speed_limit(bytes)
                        .and_then(|_| easy.low_speed_time(per_time))
                } else {
                    Ok(())
                })
                .and_then(|_| if method == Method::Head {
                    easy.nobody(true)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(ref body) = body {
                    easy.post_fields_copy(body)
                } else {
                    Ok(())
                })
                .and_then(|_| if let Some(timeout) = timeout {
                    easy.timeout(timeout)
                } else {
                    Ok(())
                })
                .and_then(|_| easy.url(url.as_str()))
                .and_then(|_| easy.write_function(move |data| {
                    let _ = body_tx.send(Vec::from(data));
                    Ok(data.len())
                }))
        };

        match config_res {
            Ok(_) => session.perform(easy)
                            .map_err(|err| err.into_error())
                            .map(move |ez| {
                                let body = body_rx.try_iter().fold(Vec::new(), |mut data, slice| {
                                    data.extend(slice);
                                    data
                                });
                                let headers = header_rx.try_iter().collect::<Vec<_>>();
                                Response::new(ez, headers, body)
                            })
                            .boxed(),
            Err(error) => failed(error.into()).boxed()
        }
    }

    /// Set the maximum time the request is allowed to take.
    ///
    /// Disabled by default in favor of [`lowspeed_limit`]
    pub fn timeout(mut self, duration: Duration) -> Self {
        self.timeout = Some(duration);
        self
    }

    /// Uses the given cURL handle in the request process reusing its resources
    /// and improving performance.
    ///
    /// This is solely a way to improve performance, it is not necessary to call
    /// this method prior to firing off the request. The easy handle will be created
    /// automatically if necessary.
    pub fn use_handle(mut self, handle: Easy) -> Self {
        self.handle = Some(handle);
        self
    }

    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn set_json(mut self, body: Vec<u8>) -> Self {
        self.body = Some(body);
        self.header("Content-Type", "application/json")
    }
}

impl Debug for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        let len = if let Some(ref body) = self.body {
            body.len() as isize
        } else {
            -1isize
        };
        fmt.debug_struct(stringify!(Request))
            .field("body_len", &len)
            .field("follow_redirects", &self.follow_redirects)
            .field("headers", &self.headers)
            .field("method", &self.method)
            .field("params", &self.params)
            .field("reuses_handle", &self.handle.is_some())
            .field("url", &self.url)
            .finish()
    }
}

impl Display for Request {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{} {}", self.method, self.url)
    }
}

#[cfg(test)]
mod tests {
    use ::{Method, Request};
    use url::Url;

    #[cfg(feature = "rustc-serialization")]
    use rustc_serialize;

    #[cfg(feature = "serde-serialization")]
    use serde_json;

    #[cfg_attr(feature = "rustc-serialization", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    struct TestPayload {
        a: u32,
        b: u32
    }

    #[test]
    #[cfg(any(feature = "rustc-serialization", feature = "serde-serialization"))]
    fn test_payload() {
        let r = Request::new(&Url::parse("http://google.com/").unwrap(), Method::Get)
            .body(&get_serialized_payload());
        assert!(r.body.is_some());
    }

    #[cfg(feature = "rustc-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        rustc_serialize::json::encode(&TestPayload { a: 10, b: 15 }).unwrap().into_bytes()
    }

    #[cfg(feature = "serde-serialization")]
    fn get_serialized_payload() -> Vec<u8> {
        serde_json::to_vec(&TestPayload { a: 10, b: 15}).unwrap()
    }
}<|endoftext|>


<commit_before>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

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

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }

    #[test]
    fn route_path() {
        let table = RoutingTable(vec![
            ("ex.com".parse().unwrap(), vec![
                (None , 0),
                (Some("/one".into()), 1),
                (Some("/two".into()) , 2),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "/one", "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/one", "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "/two", "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/two", "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "", "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "", "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<commit_msg>Adds full-star routing test<commit_after>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

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

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }

    #[test]
    fn route_star() {
        // Routing table
        //   example.com: 1
        //   *: 2
        //   */path: 3
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*".parse().unwrap(), vec![
                (None, 2),
                (Some("/path".into()), 3),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/path", &table),
                   Some((&1, "", "/path")));
        assert_eq!(route("example.com", "/path/hello", &table),
                   Some((&1, "", "/path/hello")));
        assert_eq!(route("localhost", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("localhost", "/path/hello", &table),
                   Some((&3, "/path", "/hello")));
        assert_eq!(route("localhost", "/path", &table),
                   Some((&3, "/path", "")));
    }

    #[test]
    fn route_path() {
        let table = RoutingTable(vec![
            ("ex.com".parse().unwrap(), vec![
                (None , 0),
                (Some("/one".into()), 1),
                (Some("/two".into()) , 2),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "/one", "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/one", "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "/two", "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/two", "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "", "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "", "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the WinPcap library

extern crate libc;
extern crate winapi;

use bindings::{bpf, winpcap};
use {DataLinkReceiver, DataLinkSender, MacAddr, NetworkInterface};

use ipnetwork::{ip_mask_to_prefix, IpNetwork};

use std::cmp;
use std::collections::VecDeque;
use std::ffi::{CStr, CString};
use std::io;
use std::mem;
use std::slice;
use std::str::from_utf8_unchecked;
use std::sync::Arc;

struct WinPcapAdapter {
    adapter: winpcap::LPADAPTER,
}

impl Drop for WinPcapAdapter {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketCloseAdapter(self.adapter);
        }
    }
}

struct WinPcapPacket {
    packet: winpcap::LPPACKET,
}

impl Drop for WinPcapPacket {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketFreePacket(self.packet);
        }
    }
}

/// WinPcap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when writing packets. Defaults to 4096
    pub write_buffer_size: usize,

    /// The size of buffer to use when reading packets. Defaults to 4096
    pub read_buffer_size: usize,
}

impl<'a> From<&'a super::Config> for Config {
    fn from(config: &super::Config) -> Config {
        Config {
            write_buffer_size: config.write_buffer_size,
            read_buffer_size: config.read_buffer_size,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            write_buffer_size: 4096,
            read_buffer_size: 4096,
        }
    }
}

/// Create a datalink channel using the WinPcap library
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config)
    -> io::Result<super::Channel> {
    let mut read_buffer = Vec::new();
    read_buffer.resize(config.read_buffer_size, 0u8);

    let mut write_buffer = Vec::new();
    write_buffer.resize(config.write_buffer_size, 0u8);

    let adapter = unsafe {
        let net_if_str = CString::new(network_interface.name.as_bytes()).unwrap();
        winpcap::PacketOpenAdapter(net_if_str.as_ptr() as *mut libc::c_char)
    };
    if adapter.is_null() {
        return Err(io::Error::last_os_error());
    }

    let ret = unsafe { winpcap::PacketSetHwFilter(adapter, winpcap::NDIS_PACKET_TYPE_PROMISCUOUS) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    // Set kernel buffer size
    let ret = unsafe { winpcap::PacketSetBuff(adapter, config.read_buffer_size as libc::c_int) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    // Immediate mode
    let ret = unsafe { winpcap::PacketSetMinToCopy(adapter, 1) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    let read_packet = unsafe { winpcap::PacketAllocatePacket() };
    if read_packet.is_null() {
        unsafe {
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(io::Error::last_os_error());
    }

    unsafe {
        winpcap::PacketInitPacket(read_packet,
                                  read_buffer.as_mut_ptr() as winpcap::PVOID,
                                  config.read_buffer_size as winpcap::UINT)
    }

    let write_packet = unsafe { winpcap::PacketAllocatePacket() };
    if write_packet.is_null() {
        unsafe {
            winpcap::PacketFreePacket(read_packet);
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(io::Error::last_os_error());
    }

    unsafe {
        winpcap::PacketInitPacket(write_packet,
                                  write_buffer.as_mut_ptr() as winpcap::PVOID,
                                  config.write_buffer_size as winpcap::UINT)
    }

    let adapter = Arc::new(WinPcapAdapter { adapter: adapter });
    let sender = Box::new(DataLinkSenderImpl {
        adapter: adapter.clone(),
        _write_buffer: write_buffer,
        packet: WinPcapPacket { packet: write_packet },
    });
    let receiver = Box::new(DataLinkReceiverImpl {
        adapter: adapter,
        _read_buffer: read_buffer,
        packet: WinPcapPacket { packet: read_packet },
        // Enough room for minimally sized packets without reallocating
        packets: VecDeque::with_capacity(unsafe { (*read_packet).Length } as usize / 64),
    });
    Ok(super::Channel::Ethernet(sender, receiver))
}

struct DataLinkSenderImpl {
    adapter: Arc<WinPcapAdapter>,
    _write_buffer: Vec<u8>,
    packet: WinPcapPacket,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(&mut [u8]))
        -> Option<io::Result<()>> {
        let len = num_packets * packet_size;
        if len >= unsafe { (*self.packet.packet).Length } as usize {
            None
        } else {
            let min = unsafe { cmp::min((*self.packet.packet).Length as usize, len) };
            let slice: &mut [u8] =
                unsafe { slice::from_raw_parts_mut((*self.packet.packet).Buffer as *mut u8, min) };
            for chunk in slice.chunks_mut(packet_size) {
                func(chunk);

                // Make sure the right length of packet is sent
                let old_len = unsafe { (*self.packet.packet).Length };
                unsafe {
                    (*self.packet.packet).Length = packet_size as u32;
                }

                let ret = unsafe {
                    winpcap::PacketSendPacket(self.adapter.adapter, self.packet.packet, 0)
                };

                unsafe {
                    (*self.packet.packet).Length = old_len;
                }

                if ret == 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
            }
            Some(Ok(()))
        }
    }

    #[inline]
    fn send_to(&mut self,
               packet: &[u8],
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        self.build_and_send(1,
                            packet.len(),
                            &mut |eh: &mut [u8]| {
                                eh.copy_from_slice(packet);
                            })
    }
}

unsafe impl Send for DataLinkSenderImpl {}
unsafe impl Sync for DataLinkSenderImpl {}

struct DataLinkReceiverImpl {
    adapter: Arc<WinPcapAdapter>,
    _read_buffer: Vec<u8>,
    packet: WinPcapPacket,
    packets: VecDeque<(usize, usize)>,
}

unsafe impl Send for DataLinkReceiverImpl {}
unsafe impl Sync for DataLinkReceiverImpl {}

impl DataLinkReceiver for DataLinkReceiverImpl {
    fn next(&mut self) -> io::Result<&[u8]> {
        // NOTE Most of the logic here is identical to FreeBSD/OS X
        while self.packets.is_empty() {
            let ret = unsafe {
                winpcap::PacketReceivePacket(self.adapter.adapter, self.packet.packet, 0)
            };
            let buflen = match ret {
                0 => return Err(io::Error::last_os_error()),
                _ => unsafe { (*self.packet.packet).ulBytesReceived as isize },
            };
            let mut ptr = unsafe { (*self.packet.packet).Buffer };
            let end = unsafe { (*self.packet.packet).Buffer.offset(buflen) };
            while ptr < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as isize + (*packet).bh_hdrlen as isize -
                                (*self.packet.packet).Buffer as isize;
                    self.packets.push_back((start as usize, (*packet).bh_caplen as usize));
                    let offset = (*packet).bh_hdrlen as isize + (*packet).bh_caplen as isize;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, len) = self.packets.pop_front().unwrap();
        let slice = unsafe {
            let data = (*self.packet.packet).Buffer as usize + start;
            slice::from_raw_parts(data as *const u8, len)
        };
        Ok(slice)
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use
        // GetAdaptersAddresses
        winpcap::GetAdaptersInfo(&mut tmp, &mut adapters_size);
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as usize);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as usize);
    while !cursor.is_null() {
        let mac = unsafe {
            MacAddr((*cursor).Address[0],
                    (*cursor).Address[1],
                    (*cursor).Address[2],
                    (*cursor).Address[3],
                    (*cursor).Address[4],
                    (*cursor).Address[5])
        };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING };
        let mut ips = Vec::new();
        while !ip_cursor.is_null() {
            if let Ok(ip_network) = parse_ip_network(ip_cursor) {
                ips.push(ip_network);
            }
            ip_cursor = unsafe { (*ip_cursor).Next };
        }

        unsafe {
            let name_str_ptr = (*cursor).AdapterName.as_ptr() as *const i8;

            let bytes = CStr::from_ptr(name_str_ptr).to_bytes();
            let name_str = from_utf8_unchecked(bytes).to_owned();

            all_ifaces.push(NetworkInterface {
                name: name_str,
                index: (*cursor).Index,
                mac: Some(mac),
                ips: ips,
                // flags: (*cursor).Type, // FIXME [windows]
                flags: 0,
            });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8; 4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        panic!("FIXME [windows] unable to get interface list");
    }

    let buf_str = unsafe { from_utf8_unchecked(&buf) };
    let iface_names = buf_str.split("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_owned();
                let next = all_ifaces.iter().filter(|x| name[..].ends_with(&x.name[..])).next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        }
        None => (),
    };

    vec
}

fn parse_ip_network(ip_cursor: winpcap::PIP_ADDR_STRING) -> Result<IpNetwork, ()> {
    let ip_str_ptr = unsafe { &(*ip_cursor) }.IpAddress.String.as_ptr() as *const i8;
    let ip_bytes = unsafe { CStr::from_ptr(ip_str_ptr).to_bytes() };
    let ip_str = unsafe { from_utf8_unchecked(ip_bytes).to_owned() };
    let ip = ip_str.parse().map_err(|_| ())?;

    let mask_str_ptr = unsafe { &(*ip_cursor) }.IpMask.String.as_ptr() as *const i8;
    let mask_bytes = unsafe { CStr::from_ptr(mask_str_ptr).to_bytes() };
    let mask_str = unsafe { from_utf8_unchecked(mask_bytes).to_owned() };
    let mask = mask_str.parse().map_err(|_| ())?;

    let prefix = ip_mask_to_prefix(mask).map_err(|_| ())?;
    IpNetwork::new(ip, prefix).map_err(|_| ())
}
<commit_msg>Fixed bug when pulling Windows net interfaces<commit_after>// Copyright (c) 2014-2016 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets using the WinPcap library

extern crate libc;
extern crate winapi;

use bindings::{bpf, winpcap};
use {DataLinkReceiver, DataLinkSender, MacAddr, NetworkInterface};

use ipnetwork::{ip_mask_to_prefix, IpNetwork};

use std::cmp;
use std::collections::VecDeque;
use std::ffi::{CStr, CString};
use std::io;
use std::mem;
use std::slice;
use std::str::from_utf8_unchecked;
use std::sync::Arc;

struct WinPcapAdapter {
    adapter: winpcap::LPADAPTER,
}

impl Drop for WinPcapAdapter {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketCloseAdapter(self.adapter);
        }
    }
}

struct WinPcapPacket {
    packet: winpcap::LPPACKET,
}

impl Drop for WinPcapPacket {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketFreePacket(self.packet);
        }
    }
}

/// WinPcap specific configuration
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when writing packets. Defaults to 4096
    pub write_buffer_size: usize,

    /// The size of buffer to use when reading packets. Defaults to 4096
    pub read_buffer_size: usize,
}

impl<'a> From<&'a super::Config> for Config {
    fn from(config: &super::Config) -> Config {
        Config {
            write_buffer_size: config.write_buffer_size,
            read_buffer_size: config.read_buffer_size,
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            write_buffer_size: 4096,
            read_buffer_size: 4096,
        }
    }
}

/// Create a datalink channel using the WinPcap library
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config)
    -> io::Result<super::Channel> {
    let mut read_buffer = Vec::new();
    read_buffer.resize(config.read_buffer_size, 0u8);

    let mut write_buffer = Vec::new();
    write_buffer.resize(config.write_buffer_size, 0u8);

    let adapter = unsafe {
        let net_if_str = CString::new(network_interface.name.as_bytes()).unwrap();
        winpcap::PacketOpenAdapter(net_if_str.as_ptr() as *mut libc::c_char)
    };
    if adapter.is_null() {
        return Err(io::Error::last_os_error());
    }

    let ret = unsafe { winpcap::PacketSetHwFilter(adapter, winpcap::NDIS_PACKET_TYPE_PROMISCUOUS) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    // Set kernel buffer size
    let ret = unsafe { winpcap::PacketSetBuff(adapter, config.read_buffer_size as libc::c_int) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    // Immediate mode
    let ret = unsafe { winpcap::PacketSetMinToCopy(adapter, 1) };
    if ret == 0 {
        return Err(io::Error::last_os_error());
    }

    let read_packet = unsafe { winpcap::PacketAllocatePacket() };
    if read_packet.is_null() {
        unsafe {
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(io::Error::last_os_error());
    }

    unsafe {
        winpcap::PacketInitPacket(read_packet,
                                  read_buffer.as_mut_ptr() as winpcap::PVOID,
                                  config.read_buffer_size as winpcap::UINT)
    }

    let write_packet = unsafe { winpcap::PacketAllocatePacket() };
    if write_packet.is_null() {
        unsafe {
            winpcap::PacketFreePacket(read_packet);
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(io::Error::last_os_error());
    }

    unsafe {
        winpcap::PacketInitPacket(write_packet,
                                  write_buffer.as_mut_ptr() as winpcap::PVOID,
                                  config.write_buffer_size as winpcap::UINT)
    }

    let adapter = Arc::new(WinPcapAdapter { adapter: adapter });
    let sender = Box::new(DataLinkSenderImpl {
        adapter: adapter.clone(),
        _write_buffer: write_buffer,
        packet: WinPcapPacket { packet: write_packet },
    });
    let receiver = Box::new(DataLinkReceiverImpl {
        adapter: adapter,
        _read_buffer: read_buffer,
        packet: WinPcapPacket { packet: read_packet },
        // Enough room for minimally sized packets without reallocating
        packets: VecDeque::with_capacity(unsafe { (*read_packet).Length } as usize / 64),
    });
    Ok(super::Channel::Ethernet(sender, receiver))
}

struct DataLinkSenderImpl {
    adapter: Arc<WinPcapAdapter>,
    _write_buffer: Vec<u8>,
    packet: WinPcapPacket,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(&mut [u8]))
        -> Option<io::Result<()>> {
        let len = num_packets * packet_size;
        if len >= unsafe { (*self.packet.packet).Length } as usize {
            None
        } else {
            let min = unsafe { cmp::min((*self.packet.packet).Length as usize, len) };
            let slice: &mut [u8] =
                unsafe { slice::from_raw_parts_mut((*self.packet.packet).Buffer as *mut u8, min) };
            for chunk in slice.chunks_mut(packet_size) {
                func(chunk);

                // Make sure the right length of packet is sent
                let old_len = unsafe { (*self.packet.packet).Length };
                unsafe {
                    (*self.packet.packet).Length = packet_size as u32;
                }

                let ret = unsafe {
                    winpcap::PacketSendPacket(self.adapter.adapter, self.packet.packet, 0)
                };

                unsafe {
                    (*self.packet.packet).Length = old_len;
                }

                if ret == 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
            }
            Some(Ok(()))
        }
    }

    #[inline]
    fn send_to(&mut self,
               packet: &[u8],
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        self.build_and_send(1,
                            packet.len(),
                            &mut |eh: &mut [u8]| {
                                eh.copy_from_slice(packet);
                            })
    }
}

unsafe impl Send for DataLinkSenderImpl {}
unsafe impl Sync for DataLinkSenderImpl {}

struct DataLinkReceiverImpl {
    adapter: Arc<WinPcapAdapter>,
    _read_buffer: Vec<u8>,
    packet: WinPcapPacket,
    packets: VecDeque<(usize, usize)>,
}

unsafe impl Send for DataLinkReceiverImpl {}
unsafe impl Sync for DataLinkReceiverImpl {}

impl DataLinkReceiver for DataLinkReceiverImpl {
    fn next(&mut self) -> io::Result<&[u8]> {
        // NOTE Most of the logic here is identical to FreeBSD/OS X
        while self.packets.is_empty() {
            let ret = unsafe {
                winpcap::PacketReceivePacket(self.adapter.adapter, self.packet.packet, 0)
            };
            let buflen = match ret {
                0 => return Err(io::Error::last_os_error()),
                _ => unsafe { (*self.packet.packet).ulBytesReceived as isize },
            };
            let mut ptr = unsafe { (*self.packet.packet).Buffer };
            let end = unsafe { (*self.packet.packet).Buffer.offset(buflen) };
            while ptr < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as isize + (*packet).bh_hdrlen as isize -
                                (*self.packet.packet).Buffer as isize;
                    self.packets.push_back((start as usize, (*packet).bh_caplen as usize));
                    let offset = (*packet).bh_hdrlen as isize + (*packet).bh_caplen as isize;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, len) = self.packets.pop_front().unwrap();
        let slice = unsafe {
            let data = (*self.packet.packet).Buffer as usize + start;
            slice::from_raw_parts(data as *const u8, len)
        };
        Ok(slice)
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use
        // GetAdaptersAddresses
        winpcap::GetAdaptersInfo(&mut tmp, &mut adapters_size);
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as usize);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as usize);
    while !cursor.is_null() {
        let mac = unsafe {
            MacAddr((*cursor).Address[0],
                    (*cursor).Address[1],
                    (*cursor).Address[2],
                    (*cursor).Address[3],
                    (*cursor).Address[4],
                    (*cursor).Address[5])
        };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING };
        let mut ips = Vec::new();
        while !ip_cursor.is_null() {
            if let Ok(ip_network) = parse_ip_network(ip_cursor) {
                ips.push(ip_network);
            }
            ip_cursor = unsafe { (*ip_cursor).Next };
        }

        unsafe {
            let name_str_ptr = (*cursor).AdapterName.as_ptr() as *const i8;

            let bytes = CStr::from_ptr(name_str_ptr).to_bytes();
            let name_str = from_utf8_unchecked(bytes).to_owned();

            all_ifaces.push(NetworkInterface {
                name: name_str,
                index: (*cursor).Index,
                mac: Some(mac),
                ips: ips,
                // flags: (*cursor).Type, // FIXME [windows]
                flags: 0,
            });

            cursor = (*cursor).Next;
        }
    }

    const IFACE_BUF_LEN: usize = 4096;
    let mut buf = vec![0u8; IFACE_BUF_LEN];
    let mut buflen = buf.len() as u32;

    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {

        buf = vec![0u8; IFACE_BUF_LEN + buflen as usize];
        unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) };
    }

    let buf_str = unsafe { from_utf8_unchecked(&buf) };
    let iface_names = buf_str.split("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_owned();
                let next = all_ifaces.iter().filter(|x| name[..].ends_with(&x.name[..])).next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        }
        None => (),
    };

    vec
}

fn parse_ip_network(ip_cursor: winpcap::PIP_ADDR_STRING) -> Result<IpNetwork, ()> {
    let ip_str_ptr = unsafe { &(*ip_cursor) }.IpAddress.String.as_ptr() as *const i8;
    let ip_bytes = unsafe { CStr::from_ptr(ip_str_ptr).to_bytes() };
    let ip_str = unsafe { from_utf8_unchecked(ip_bytes).to_owned() };
    let ip = ip_str.parse().map_err(|_| ())?;

    let mask_str_ptr = unsafe { &(*ip_cursor) }.IpMask.String.as_ptr() as *const i8;
    let mask_bytes = unsafe { CStr::from_ptr(mask_str_ptr).to_bytes() };
    let mask_str = unsafe { from_utf8_unchecked(mask_bytes).to_owned() };
    let mask = mask_str.parse().map_err(|_| ())?;

    let prefix = ip_mask_to_prefix(mask).map_err(|_| ())?;
    IpNetwork::new(ip, prefix).map_err(|_| ())
}
<|endoftext|>