<commit_before>use std::io::{Read, Write};
use std::ops::{Index, IndexMut};
use std::thread;

use structs::Op;
use structs::Op::*;

static ZERO: u8 = 0;

pub struct State<'a> {
    index: usize,
    memory: Vec<u8>,
    input: &'a mut Read,
    output: &'a mut Write,
}

impl<'a> State<'a> {
    pub fn new<'b>(input: &'b mut Read, output: &'b mut Write) -> State<'b> {
        State {
            index: 0,
            memory: vec![],
            input: input,
            output: output,
        }
    }

    fn rel_index(&self, relative: isize) -> usize {
        (self.index as isize + relative) as usize
    }

    fn step(&mut self, op: &Op) -> bool {
        match *op {
            Add(i) => {
                self[0] = self[0].wrapping_add(i);
            }
            Mov(n) => {
                self.index = self.rel_index(n);
            }
            In => {
                let mut c = [0u8];
                if self.input.read(&mut c).unwrap() == 0 {
                    return false;
                }
                self[0] = c[0];
            }
            Out => {
                let c = &[self[0]];
                self.output.write(c).unwrap();
            }
            Loop(ref ops) => {
                while self[0] != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
            Transfer(d, ref map) => {
                if self[0] == 0 {
                    return true;
                }

                let mut v0 = self[0];
                let mut iterations = 0;

                while v0 != 0 {
                    v0 = v0.wrapping_add(d);
                    if v0 == self[0] {
                        // stalled: the current transfer will never complete
                        loop {
                            thread::park()
                        }
                    }
                    iterations += 1
                }

                self[0] = 0;
                for &(k, v) in &map[..] {
                    self[k] = self[k].wrapping_add(v.wrapping_mul(iterations));
                }
            }
        }
        true
    }

    pub fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        true
    }
}

impl<'a> Index<isize> for State<'a> {
    type Output = u8;
    fn index(&self, index: isize) -> &u8 {
        let idx = self.rel_index(index);
        if idx >= self.memory.len() {
            &ZERO
        } else {
            &self.memory[idx]
        }
    }
}

impl<'a> IndexMut<isize> for State<'a> {
    fn index_mut(&mut self, index: isize) -> &mut u8 {
        let idx = self.rel_index(index);
        if idx >= self.memory.len() {
            self.memory.resize(idx * 2 + 1, 0);
        }
        &mut self.memory[idx]
    }
}

#[cfg(test)]
mod tests {
    use super::State;

    use std::io::{empty, sink};
    use structs::OpStream;
    use structs::Op::*;

    #[test]
    fn test_state_index() {
        let mut state = State {
            index: 0,
            memory: vec![23, 0, 0, 0, 0, 42],
            input: &mut empty(),
            output: &mut sink(),
        };
        assert_eq!(23, state[0]);
        state.index = 5;
        assert_eq!(42, state[0]);
    }

    #[test]
    fn test_state_index_mut() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 23;
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state[0] = 42;
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn test_state_step_add() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state.step(&Add(23));
        assert_eq!(23, state[0]);
        state.step(&Add(42));
        assert_eq!(65, state[0]);
        state.step(&Add(190));
        assert_eq!(255, state[0]);
    }

    #[test]
    fn test_state_step_mov() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn test_state_step_loop() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 23;
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state[0]);
    }

    #[test]
    fn test_state_step_transfer() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 15;
        state[1] = 7;
        state.step(&Transfer(5, vec![(1, 2)]));
        assert_eq!(0, state[0]);
        assert_eq!(1, state[1]);
    }

    #[test]
    fn test_state_step_input() {
        let mut input = &vec![23u8][..];
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.step(&In);
        assert_eq!(true, result);
        assert_eq!(23, state[0]);
    }

    #[test]
    fn test_state_step_input_eof() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.step(&In);
        assert_eq!(false, result);
    }

    #[test]
    fn test_state_step_output() {
        let mut input = empty();
        let mut output = vec![];
        {
            let mut state = State::new(&mut input, &mut output);
            state[0] = 42;
            state.step(&Out);
        }
        assert_eq!(vec![42u8], output);
    }
}
<commit_msg>test: more runner test cases<commit_after>use std::io::{Read, Write};
use std::ops::{Index, IndexMut};
use std::thread;

use structs::Op;
use structs::Op::*;

static ZERO: u8 = 0;

pub struct State<'a> {
    index: usize,
    memory: Vec<u8>,
    input: &'a mut Read,
    output: &'a mut Write,
}

impl<'a> State<'a> {
    pub fn new<'b>(input: &'b mut Read, output: &'b mut Write) -> State<'b> {
        State {
            index: 0,
            memory: vec![],
            input: input,
            output: output,
        }
    }

    fn rel_index(&self, relative: isize) -> usize {
        (self.index as isize + relative) as usize
    }

    fn step(&mut self, op: &Op) -> bool {
        match *op {
            Add(i) => {
                self[0] = self[0].wrapping_add(i);
            }
            Mov(n) => {
                self.index = self.rel_index(n);
            }
            In => {
                let mut c = [0u8];
                if self.input.read(&mut c).unwrap() == 0 {
                    return false;
                }
                self[0] = c[0];
            }
            Out => {
                let c = &[self[0]];
                self.output.write(c).unwrap();
            }
            Loop(ref ops) => {
                while self[0] != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
            Transfer(d, ref map) => {
                if self[0] == 0 {
                    return true;
                }

                let mut v0 = self[0];
                let mut iterations = 0;

                while v0 != 0 {
                    v0 = v0.wrapping_add(d);
                    if v0 == self[0] {
                        // stalled: the current transfer will never complete
                        loop {
                            thread::park()
                        }
                    }
                    iterations += 1
                }

                self[0] = 0;
                for &(k, v) in &map[..] {
                    self[k] = self[k].wrapping_add(v.wrapping_mul(iterations));
                }
            }
        }
        true
    }

    pub fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        true
    }
}

impl<'a> Index<isize> for State<'a> {
    type Output = u8;
    fn index(&self, index: isize) -> &u8 {
        let idx = self.rel_index(index);
        if idx >= self.memory.len() {
            &ZERO
        } else {
            &self.memory[idx]
        }
    }
}

impl<'a> IndexMut<isize> for State<'a> {
    fn index_mut(&mut self, index: isize) -> &mut u8 {
        let idx = self.rel_index(index);
        if idx >= self.memory.len() {
            self.memory.resize(idx * 2 + 1, 0);
        }
        &mut self.memory[idx]
    }
}

#[cfg(test)]
mod tests {
    use super::State;

    use std::io::{empty, sink};
    use structs::OpStream;
    use structs::Op::*;

    #[test]
    fn test_state_index() {
        let mut state = State {
            index: 0,
            memory: vec![23, 0, 0, 0, 0, 42],
            input: &mut empty(),
            output: &mut sink(),
        };
        assert_eq!(23, state[0]);
        state.index = 5;
        assert_eq!(42, state[0]);
    }

    #[test]
    fn test_state_index_mut() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 23;
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state[0] = 42;
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn test_state_run() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.run(&vec![Add(1), Add(1)]);
        assert_eq!(true, result);
        assert_eq!(2, state[0]);
    }

    #[test]
    fn test_state_run_stop() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.run(&vec![Add(1), In]);
        assert_eq!(false, result);
        assert_eq!(1, state[0]);
    }

    #[test]
    fn test_state_run_nested_stop() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 1;
        let result = state.run(&vec![Loop(OpStream { ops: vec![Add(1), In] })]);
        assert_eq!(false, result);
        assert_eq!(2, state[0]);
    }

    #[test]
    fn test_state_step_add() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state.step(&Add(23));
        assert_eq!(23, state[0]);
        state.step(&Add(42));
        assert_eq!(65, state[0]);
        state.step(&Add(190));
        assert_eq!(255, state[0]);
    }

    #[test]
    fn test_state_step_mov() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn test_state_step_loop() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 23;
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state[0]);
    }

    #[test]
    fn test_state_step_transfer() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 15;
        state[1] = 7;
        state.step(&Transfer(5, vec![(1, 2)]));
        assert_eq!(0, state[0]);
        assert_eq!(1, state[1]);
    }

    #[test]
    fn test_state_step_transfer_noiteration() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        state[0] = 0;
        state.step(&Transfer(5, vec![(1, 2)]));
        assert_eq!(0, state[0]);
    }

    #[test]
    fn test_state_step_input() {
        let mut input = &vec![23u8][..];
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.step(&In);
        assert_eq!(true, result);
        assert_eq!(23, state[0]);
    }

    #[test]
    fn test_state_step_input_eof() {
        let mut input = empty();
        let mut output = sink();
        let mut state = State::new(&mut input, &mut output);
        let result = state.step(&In);
        assert_eq!(false, result);
    }

    #[test]
    fn test_state_step_output() {
        let mut input = empty();
        let mut output = vec![];
        {
            let mut state = State::new(&mut input, &mut output);
            state[0] = 42;
            state.step(&Out);
        }
        assert_eq!(vec![42u8], output);
    }
}
<|endoftext|>


<commit_before>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromRaw };

pub struct SV(Owned<raw::SV>);

impl SV {
    pub fn iv(&self) -> IV {
        let r = &*self.0;
        unsafe { r.pthx().sv_iv(r.as_ptr()) }
    }

    pub fn uv(&self) -> UV {
        let r = &*self.0;
        unsafe { r.pthx().sv_uv(r.as_ptr()) }
    }

    pub fn nv(&self) -> NV {
        let r = &*self.0;
        unsafe { r.pthx().sv_nv(r.as_ptr()) }
    }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }
}

impl FromRaw<raw::SV> for IV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromRaw<raw::SV> for SV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw(pthx, svp)
        }
    }
}
<commit_msg>Use helpers to implement SV method.<commit_after>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromRaw };

pub struct SV(Owned<raw::SV>);

impl SV {
    method! { simple fn iv() -> IV = sv_iv() }
    method! { simple fn uv() -> UV = sv_uv() }
    method! { simple fn nv() -> NV = sv_nv() }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromRaw<raw::SV> for SV {
    unsafe fn from_raw(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw(pthx, svp)
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

use curl::http;

use xml;

use gateway::Gateway;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    IoError(io::Error),
    InvalidResponse,
}

impl From<io::Error> for SearchError {
    fn from(err: io::Error) -> SearchError {
        SearchError::IoError(err)
    }
}

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));
    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = str::from_utf8(&buf[..read]).unwrap();
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(location) => {
            Ok(Gateway::new(location.0, match get_control_url(&location) {
                Some(u) => u,
                None => return Err(SearchError::InvalidResponse),
            }))
        },
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_from(Ipv4Addr::new(0, 0, 0, 0))
}

// Parse the result.
fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = regex!(r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)");
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(
                    (SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap()),
                     cap.at(3).unwrap().to_string()));
            },
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String))
                   -> Option<String> {
    let resp = match http::handle()
        .get(format!("http://{}{}", location.0, location.1))
        .exec() {
            Ok(r) => r,
            Err(_) => return None,
        };
    let text = match str::from_utf8(resp.get_body()) {
        Ok(t) => t,
        Err(_) => return None,
    };
    let text = io::Cursor::new(text.as_bytes());
    let mut parser = xml::EventReader::new(text);
    let mut chain = Vec::<String>::with_capacity(4);

    struct Service {
        service_type: String,
        control_url: String,
    }

    let mut service = Service{
        service_type: "".to_string(),
        control_url: "".to_string(),
    };

    for e in parser.events() {
        match e {
            xml::reader::events::XmlEvent::StartElement { name, .. } => {
                chain.push(name.to_repr());
                let tail = if chain.len() >= 3 {
                    chain.iter().skip(chain.len() - 3)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service"].iter().zip(tail)
                    .all(|(l, r)| l == r) {
                    service.service_type.clear();
                    service.control_url.clear();
                }
            },
            xml::reader::events::XmlEvent::EndElement { .. } => {
                let top = chain.pop();
                let tail = if top == Some("service".to_string())
                    && chain.len() >= 2 {
                    chain.iter().skip(chain.len() - 2)
                } else {
                    continue
                };

                if vec!["device", "serviceList"].iter().zip(tail)
                    .all(|(l, r)| l == r) {
                    if "urn:schemas-upnp-org:service:WANIPConnection:1"
                        == service.service_type
                        && service.control_url.len() != 0 {
                        return Some(service.control_url);
                    }
                }
            },
            xml::reader::events::XmlEvent::Characters(text) => {
                let tail = if chain.len() >= 4 {
                    chain.iter().skip(chain.len() - 4)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service", "serviceType"]
                    .iter().zip(tail.clone()).all(|(l, r)| l == r) {
                    service.service_type.push_str(&text);
                }
                if vec!["device", "serviceList", "service", "controlURL"]
                    .iter().zip(tail).all(|(l, r)| l == r) {
                    service.control_url.push_str(&text);
                }
            },
            xml::reader::events::XmlEvent::Error(_) =>  return None,
            _ => (),
        }
    }
    None
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0,0,0,0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<commit_msg>Standardize the code style<commit_after>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

use curl::http;

use xml::EventReader;
use xml::reader::events::XmlEvent;

use gateway::Gateway;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    IoError(io::Error),
    InvalidResponse,
}

impl From<io::Error> for SearchError {
    fn from(err: io::Error) -> SearchError {
        SearchError::IoError(err)
    }
}

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));
    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = str::from_utf8(&buf[..read]).unwrap();
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(location) => {
            Ok(Gateway::new(location.0, match get_control_url(&location) {
                Some(u) => u,
                None => return Err(SearchError::InvalidResponse),
            }))
        },
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_from(Ipv4Addr::new(0, 0, 0, 0))
}

// Parse the result.
fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = regex!(r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)");
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(
                    (SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap()),
                     cap.at(3).unwrap().to_string()));
            },
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String))
                   -> Option<String> {
    let resp = match http::handle()
        .get(format!("http://{}{}", location.0, location.1))
        .exec() {
            Ok(r) => r,
            Err(_) => return None,
        };
    let text = match str::from_utf8(resp.get_body()) {
        Ok(t) => t,
        Err(_) => return None,
    };

    let text = io::Cursor::new(text.as_bytes());
    let mut parser = EventReader::new(text);
    let mut chain = Vec::<String>::with_capacity(4);

    struct Service {
        service_type: String,
        control_url: String,
    }

    let mut service = Service{
        service_type: "".to_string(),
        control_url: "".to_string(),
    };

    for e in parser.events() {
        match e {
            XmlEvent::StartElement { name, .. } => {
                chain.push(name.to_repr());
                let tail = if chain.len() >= 3 {
                    chain.iter().skip(chain.len() - 3)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    service.service_type.clear();
                    service.control_url.clear();
                }
            },
            XmlEvent::EndElement { .. } => {
                let top = chain.pop();
                let tail = if top == Some("service".to_string())
                        && chain.len() >= 2 {
                    chain.iter().skip(chain.len() - 2)
                } else {
                    continue
                };

                if vec!["device", "serviceList"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    if "urn:schemas-upnp-org:service:WANIPConnection:1"
                        == service.service_type
                        && service.control_url.len() != 0 {
                        return Some(service.control_url);
                    }
                }
            },
            XmlEvent::Characters(text) => {
                let tail = if chain.len() >= 4 {
                    chain.iter().skip(chain.len() - 4)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service", "serviceType"]
                    .iter().zip(tail.clone()).all(|(l, r)| l == r) {
                    service.service_type.push_str(&text);
                }
                if vec!["device", "serviceList", "service", "controlURL"]
                    .iter().zip(tail).all(|(l, r)| l == r) {
                    service.control_url.push_str(&text);
                }
            },
            XmlEvent::Error(_) =>  return None,
            _ => (),
        }
    }
    None
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0,0,0,0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<|endoftext|>


<commit_before>use anyhow::*;
use rocket;
use rocket_contrib::serve::StaticFiles;
use std::path::PathBuf;
use std::sync::Arc;

use crate::db::DB;
use crate::index::CommandSender;

pub fn get_server(
	port: u16,
	auth_secret: Option<&[u8]>,
	api_url: &str,
	web_url: &str,
	web_dir_path: &PathBuf,
	swagger_url: &str,
	swagger_dir_path: &PathBuf,
	db: Arc<DB>,
	command_sender: Arc<CommandSender>,
) -> Result<rocket::Rocket> {
	let mut config = rocket::Config::build(rocket::config::Environment::Production)
		.port(port)
		.keep_alive(0)
		.finalize()?;

	if let Some(secret) = auth_secret {
		let encoded = base64::encode(secret);
		config.set_secret_key(encoded)?;
	}

	let swagger_routes_rank = 0;
	let web_routes_rank = swagger_routes_rank + 1;

	Ok(rocket::custom(config)
		.manage(db)
		.manage(command_sender)
		.mount(&api_url, crate::api::get_routes())
		.mount(
			&swagger_url,
			StaticFiles::from(swagger_dir_path).rank(swagger_routes_rank),
		)
		.mount(
			&web_url,
			StaticFiles::from(web_dir_path).rank(web_routes_rank),
		))
}
<commit_msg>Enforce normal logging level<commit_after>use anyhow::*;
use rocket;
use rocket::config::{Environment, LoggingLevel};
use rocket_contrib::serve::StaticFiles;
use std::path::PathBuf;
use std::sync::Arc;

use crate::db::DB;
use crate::index::CommandSender;

pub fn get_server(
	port: u16,
	auth_secret: Option<&[u8]>,
	api_url: &str,
	web_url: &str,
	web_dir_path: &PathBuf,
	swagger_url: &str,
	swagger_dir_path: &PathBuf,
	db: Arc<DB>,
	command_sender: Arc<CommandSender>,
) -> Result<rocket::Rocket> {
	let mut config = rocket::Config::build(Environment::Production)
		.log_level(LoggingLevel::Normal)
		.port(port)
		.keep_alive(0)
		.finalize()?;

	if let Some(secret) = auth_secret {
		let encoded = base64::encode(secret);
		config.set_secret_key(encoded)?;
	}

	let swagger_routes_rank = 0;
	let web_routes_rank = swagger_routes_rank + 1;

	Ok(rocket::custom(config)
		.manage(db)
		.manage(command_sender)
		.mount(&api_url, crate::api::get_routes())
		.mount(
			&swagger_url,
			StaticFiles::from(swagger_dir_path).rank(swagger_routes_rank),
		)
		.mount(
			&web_url,
			StaticFiles::from(web_dir_path).rank(web_routes_rank),
		))
}
<|endoftext|>


<commit_before>use http::StatusCode;
use hyper::{Body, Error as HyperError, Request as HyperRequest, Response as HyperResponse, Server};
use hyper::rt::Future;
use hyper::rt::Stream;
use hyper::service::NewService;
use hyper::service::Service;
use itertools::Itertools;
use pact_matching::{self, Mismatch};
use pact_matching::models::{Interaction, Pact, Request, Response};
use pact_matching::models::OptionalBody;
use pact_support;
use std::sync::Arc;
use tokio::prelude::Async;
use tokio::prelude::future;
use tokio::prelude::future::FutureResult;
use tokio::prelude::IntoFuture;
use tokio::runtime::Runtime;

#[derive(Clone)]
pub struct ServerHandler {
  sources: Arc<Vec<Pact>>,
  auto_cors: bool
}

fn method_supports_payload(request: &Request) -> bool {
  match request.method.to_uppercase().as_str() {
    "POST" | "PUT" | "PATCH" => true,
    _ => false
  }
}

fn find_matching_request(request: &Request, auto_cors: bool, sources: &Vec<Pact>) -> Result<Response, String> {
    let match_results = sources
        .iter()
        .flat_map(|pact| pact.interactions.clone())
        .map(|i| (i.clone(), pact_matching::match_request(i.request, request.clone())))
        .filter(|&(_, ref mismatches)| mismatches.iter().all(|mismatch|{
            match mismatch {
                &Mismatch::MethodMismatch { .. } => false,
                &Mismatch::PathMismatch { .. } => false,
                &Mismatch::QueryMismatch { .. } => false,
                &Mismatch::BodyMismatch { .. } => !(method_supports_payload(request) && request.body.is_present()),
                _ => true
            }
        }))
        .sorted_by(|a, b| Ord::cmp(&a.1.len(), &b.1.len()))
        .iter()
        .map(|&(ref i, _)| i)
        .cloned()
        .collect::<Vec<Interaction>>();

    if match_results.len() > 1 {
        warn!("Found more than one pact request for method {} and path '{}', using the first one",
              request.method, request.path);
    }

    match match_results.first() {
        Some(interaction) => Ok(pact_matching::generate_response(&interaction.response)),
        None => {
            if auto_cors && request.method.to_uppercase() == "OPTIONS" {
                Ok(Response {
                    headers: Some(hashmap!{
                    s!("Access-Control-Allow-Headers") => s!("authorization,Content-Type"),
                    s!("Access-Control-Allow-Methods") => s!("GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH"),
                    s!("Access-Control-Allow-Origin") => s!("*")
                  }),
                    .. Response::default_response()
                })
            } else {
                Err(s!("No matching request found"))
            }
        }
    }
}

fn handle_request(request: Request, auto_cors: bool, sources: Arc<Vec<Pact>>) -> Response {
    info! ("===> Received {}", request);
    debug!("     body: '{}'", request.body.str_value());
    debug!("     matching_rules: {:?}", request.matching_rules);
    debug!("     generators: {:?}", request.generators);
    match find_matching_request(&request, auto_cors, &sources) {
        Ok(response) => response,
        Err(msg) => {
            warn!("{}, sending {}", msg, StatusCode::NOT_FOUND);
            let mut response = Response {
                status: StatusCode::NOT_FOUND.as_u16(),
                .. Response::default_response()
            };
            if auto_cors {
                response.headers = Some(hashmap!{ s!("Access-Control-Allow-Origin") => s!("*") })
            }
            response
        }
    }
}

impl ServerHandler {
    pub fn new(sources: Vec<Pact>, auto_cors: bool) -> ServerHandler {
        ServerHandler {
          sources: Arc::new(sources),
          auto_cors
        }
    }
}

impl Service for ServerHandler {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = HyperError;
    type Future = ServerHandlerFuture;

    fn call(&mut self, req: HyperRequest<Body>) -> <Self as Service>::Future {
        let auto_cors = self.auto_cors;
        let sources = self.sources.clone();
        let (parts, body) = req.into_parts();
        let future = body.concat2()
            .then(|body| future::ok(match body {
                Ok(chunk) => if chunk.is_empty() {
                    OptionalBody::Empty
                } else {
                    OptionalBody::Present(chunk.iter().cloned().collect())
                },
                Err(err) => {
                    warn!("Failed to read request body: {}", err);
                    OptionalBody::Empty
                }
            }))
            .map(move |body| pact_support::hyper_request_to_pact_request(parts, body))
            .map(move |req| handle_request(req, auto_cors, sources))
            .map(|res| pact_support::pact_response_to_hyper_response(&res))
            .into_future();
        ServerHandlerFuture { future: Box::new(future) }
    }
}

pub struct ServerHandlerFuture {
    future: Box<Future<Item=HyperResponse<Body>, Error=HyperError> + Send>
}

impl Future for ServerHandlerFuture {
    type Item = HyperResponse<Body>;
    type Error = HyperError;

    fn poll(&mut self) -> Result<Async<<Self as Future>::Item>, <Self as Future>::Error> {
        self.future.poll()
    }
}

impl NewService for ServerHandler {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = HyperError;
    type Service = ServerHandler;
    type Future = FutureResult<ServerHandler, HyperError>;
    type InitError = HyperError;

    fn new_service(&self) -> <Self as NewService>::Future {
        future::ok(self.clone())
    }
}

pub fn start_server(port: u16, sources: Vec<Pact>, auto_cors: bool, runtime: &mut Runtime) -> Result<(), i32> {
    let addr = ([0, 0, 0, 0], port).into();
    match Server::try_bind(&addr) {
        Ok(builder) => {
            let server = builder.http1_keepalive(false)
                .serve(ServerHandler::new(sources, auto_cors));
            info!("Server started on port {}", server.local_addr().port());
            runtime.block_on(server.map_err(|err| error!("could not start server: {}", err)))
                .map_err(|_| {
                    format!("error occurred scheduling server future on Tokio runtime");
                    2
                })
        },
        Err(err) => {
            error!("could not start server: {}", err);
            Err(1)
        }
    }
}

#[cfg(test)]
mod test {
    use expectest::prelude::*;
    use pact_matching::models::{Interaction, OptionalBody, Pact, Request, Response};
    use pact_matching::models::matchingrules::*;

    #[test]
    fn match_request_finds_the_most_appropriate_response() {
        let interaction1 = Interaction::default();

        let interaction2 = Interaction::default();

        let pact1 = Pact { interactions: vec![ interaction1.clone() ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request::default_request();

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_ok().value(interaction1.response));
    }

    #[test]
    fn match_request_excludes_requests_with_different_methods() {
        let interaction1 = Interaction { request: Request { method: s!("PUT"),
            .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { method: s!("POST"), .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_requests_with_different_paths() {
        let interaction1 = Interaction { request: Request { path: s!("/one"), .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { path: s!("/two"), .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_requests_with_different_query_params() {
        let interaction1 = Interaction { request: Request {
            query: Some(hashmap!{ s!("A") => vec![ s!("B") ] }),
            .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request {
            query: Some(hashmap!{ s!("A") => vec![ s!("C") ] }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_put_or_post_requests_with_different_bodies() {
        let interaction1 = Interaction { request: Request {
            method: s!("PUT"),
            body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 200, .. Response::default_response() },
            .. Interaction::default() };

        let interaction2 = Interaction { request: Request {
            method: s!("PUT"),
            body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 6}".as_bytes().into()),
            matching_rules: matchingrules!{
                "body" => {
                    "$.c" => [ MatchingRule::Integer ]
                }
            },
            .. Request::default_request() },
            response: Response { status: 201, .. Response::default_response() },
            .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() };
        let request2 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 2, \"b\": 5, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() };
        let request3 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 16}".as_bytes().into()),
            .. Request::default_request() };
        let request4 = Request { method: s!("PUT"), headers: Some(hashmap!{ s!("Content-Type") => s!("application/json") }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request2, false, &vec![pact1.clone(), pact2.clone()])).to(be_err());
        expect!(super::find_matching_request(&request3, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request4, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
    }

    #[test]
    fn match_request_returns_the_closest_match() {
        let interaction1 = Interaction { request: Request {
            body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 200, .. Response::default_response() },
            .. Interaction::default() };

        let interaction2 = Interaction { request: Request {
            body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 6}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 201, .. Response::default_response() },
            .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2.clone() ], .. Pact::default() };

        let request1 = Request {
            body: OptionalBody::Present("{\"a\": 1, \"b\": 4, \"c\": 6}".as_bytes().into()),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_ok().value(interaction2.response));
    }

    #[test]
    fn with_auto_cors_return_200_with_an_option_request() {
        let interaction1 = Interaction::default();
        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };

        let request1 = Request {
            method: s!("OPTIONS"),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, true, &vec![pact1.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request1, false, &vec![pact1.clone()])).to(be_err());
    }

    #[test]
    fn match_request_with_query_params() {
        let matching_rules = matchingrules!{
            "query" => {
                "page[0]" => [ MatchingRule::Type ]
            }
        };
        let interaction1 = Interaction {
            request: Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("1") ] }),
            .. Request::default_request()
            },
            .. Interaction::default()
        };

        let interaction2 = Interaction {
            request: Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("1") ] }),
            matching_rules,
            .. Request::default_request()
            },
            .. Interaction::default()
        };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("3") ] }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2.clone()])).to(be_ok());
    }

}
<commit_msg>fix: make warning message more explicit about what it is doing #24<commit_after>use http::StatusCode;
use hyper::{Body, Error as HyperError, Request as HyperRequest, Response as HyperResponse, Server};
use hyper::rt::Future;
use hyper::rt::Stream;
use hyper::service::NewService;
use hyper::service::Service;
use itertools::Itertools;
use pact_matching::{self, Mismatch};
use pact_matching::models::{Interaction, Pact, Request, Response};
use pact_matching::models::OptionalBody;
use pact_support;
use std::sync::Arc;
use tokio::prelude::Async;
use tokio::prelude::future;
use tokio::prelude::future::FutureResult;
use tokio::prelude::IntoFuture;
use tokio::runtime::Runtime;

#[derive(Clone)]
pub struct ServerHandler {
  sources: Arc<Vec<Pact>>,
  auto_cors: bool
}

fn method_supports_payload(request: &Request) -> bool {
  match request.method.to_uppercase().as_str() {
    "POST" | "PUT" | "PATCH" => true,
    _ => false
  }
}

fn find_matching_request(request: &Request, auto_cors: bool, sources: &Vec<Pact>) -> Result<Response, String> {
    let match_results = sources
        .iter()
        .flat_map(|pact| pact.interactions.clone())
        .map(|i| (i.clone(), pact_matching::match_request(i.request, request.clone())))
        .filter(|&(_, ref mismatches)| mismatches.iter().all(|mismatch|{
            match mismatch {
                &Mismatch::MethodMismatch { .. } => false,
                &Mismatch::PathMismatch { .. } => false,
                &Mismatch::QueryMismatch { .. } => false,
                &Mismatch::BodyMismatch { .. } => !(method_supports_payload(request) && request.body.is_present()),
                _ => true
            }
        }))
        .sorted_by(|a, b| Ord::cmp(&a.1.len(), &b.1.len()))
        .iter()
        .map(|&(ref i, _)| i)
        .cloned()
        .collect::<Vec<Interaction>>();

    if match_results.len() > 1 {
        warn!("Found more than one pact request for method {} and path '{}', using the first one with the least number of mismatches",
              request.method, request.path);
    }

    match match_results.first() {
        Some(interaction) => Ok(pact_matching::generate_response(&interaction.response)),
        None => {
            if auto_cors && request.method.to_uppercase() == "OPTIONS" {
                Ok(Response {
                    headers: Some(hashmap!{
                    s!("Access-Control-Allow-Headers") => s!("authorization,Content-Type"),
                    s!("Access-Control-Allow-Methods") => s!("GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH"),
                    s!("Access-Control-Allow-Origin") => s!("*")
                  }),
                    .. Response::default_response()
                })
            } else {
                Err(s!("No matching request found"))
            }
        }
    }
}

fn handle_request(request: Request, auto_cors: bool, sources: Arc<Vec<Pact>>) -> Response {
    info! ("===> Received {}", request);
    debug!("     body: '{}'", request.body.str_value());
    debug!("     matching_rules: {:?}", request.matching_rules);
    debug!("     generators: {:?}", request.generators);
    match find_matching_request(&request, auto_cors, &sources) {
        Ok(response) => response,
        Err(msg) => {
            warn!("{}, sending {}", msg, StatusCode::NOT_FOUND);
            let mut response = Response {
                status: StatusCode::NOT_FOUND.as_u16(),
                .. Response::default_response()
            };
            if auto_cors {
                response.headers = Some(hashmap!{ s!("Access-Control-Allow-Origin") => s!("*") })
            }
            response
        }
    }
}

impl ServerHandler {
    pub fn new(sources: Vec<Pact>, auto_cors: bool) -> ServerHandler {
        ServerHandler {
          sources: Arc::new(sources),
          auto_cors
        }
    }
}

impl Service for ServerHandler {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = HyperError;
    type Future = ServerHandlerFuture;

    fn call(&mut self, req: HyperRequest<Body>) -> <Self as Service>::Future {
        let auto_cors = self.auto_cors;
        let sources = self.sources.clone();
        let (parts, body) = req.into_parts();
        let future = body.concat2()
            .then(|body| future::ok(match body {
                Ok(chunk) => if chunk.is_empty() {
                    OptionalBody::Empty
                } else {
                    OptionalBody::Present(chunk.iter().cloned().collect())
                },
                Err(err) => {
                    warn!("Failed to read request body: {}", err);
                    OptionalBody::Empty
                }
            }))
            .map(move |body| pact_support::hyper_request_to_pact_request(parts, body))
            .map(move |req| handle_request(req, auto_cors, sources))
            .map(|res| pact_support::pact_response_to_hyper_response(&res))
            .into_future();
        ServerHandlerFuture { future: Box::new(future) }
    }
}

pub struct ServerHandlerFuture {
    future: Box<Future<Item=HyperResponse<Body>, Error=HyperError> + Send>
}

impl Future for ServerHandlerFuture {
    type Item = HyperResponse<Body>;
    type Error = HyperError;

    fn poll(&mut self) -> Result<Async<<Self as Future>::Item>, <Self as Future>::Error> {
        self.future.poll()
    }
}

impl NewService for ServerHandler {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = HyperError;
    type Service = ServerHandler;
    type Future = FutureResult<ServerHandler, HyperError>;
    type InitError = HyperError;

    fn new_service(&self) -> <Self as NewService>::Future {
        future::ok(self.clone())
    }
}

pub fn start_server(port: u16, sources: Vec<Pact>, auto_cors: bool, runtime: &mut Runtime) -> Result<(), i32> {
    let addr = ([0, 0, 0, 0], port).into();
    match Server::try_bind(&addr) {
        Ok(builder) => {
            let server = builder.http1_keepalive(false)
                .serve(ServerHandler::new(sources, auto_cors));
            info!("Server started on port {}", server.local_addr().port());
            runtime.block_on(server.map_err(|err| error!("could not start server: {}", err)))
                .map_err(|_| {
                    format!("error occurred scheduling server future on Tokio runtime");
                    2
                })
        },
        Err(err) => {
            error!("could not start server: {}", err);
            Err(1)
        }
    }
}

#[cfg(test)]
mod test {
    use expectest::prelude::*;
    use pact_matching::models::{Interaction, OptionalBody, Pact, Request, Response};
    use pact_matching::models::matchingrules::*;

    #[test]
    fn match_request_finds_the_most_appropriate_response() {
        let interaction1 = Interaction::default();

        let interaction2 = Interaction::default();

        let pact1 = Pact { interactions: vec![ interaction1.clone() ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request::default_request();

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_ok().value(interaction1.response));
    }

    #[test]
    fn match_request_excludes_requests_with_different_methods() {
        let interaction1 = Interaction { request: Request { method: s!("PUT"),
            .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { method: s!("POST"), .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_requests_with_different_paths() {
        let interaction1 = Interaction { request: Request { path: s!("/one"), .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { path: s!("/two"), .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_requests_with_different_query_params() {
        let interaction1 = Interaction { request: Request {
            query: Some(hashmap!{ s!("A") => vec![ s!("B") ] }),
            .. Request::default_request() }, .. Interaction::default() };

        let interaction2 = Interaction { .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request {
            query: Some(hashmap!{ s!("A") => vec![ s!("C") ] }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_err());
    }

    #[test]
    fn match_request_excludes_put_or_post_requests_with_different_bodies() {
        let interaction1 = Interaction { request: Request {
            method: s!("PUT"),
            body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 200, .. Response::default_response() },
            .. Interaction::default() };

        let interaction2 = Interaction { request: Request {
            method: s!("PUT"),
            body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 6}".as_bytes().into()),
            matching_rules: matchingrules!{
                "body" => {
                    "$.c" => [ MatchingRule::Integer ]
                }
            },
            .. Request::default_request() },
            response: Response { status: 201, .. Response::default_response() },
            .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() };
        let request2 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 2, \"b\": 5, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() };
        let request3 = Request { method: s!("PUT"), body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 16}".as_bytes().into()),
            .. Request::default_request() };
        let request4 = Request { method: s!("PUT"), headers: Some(hashmap!{ s!("Content-Type") => s!("application/json") }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request2, false, &vec![pact1.clone(), pact2.clone()])).to(be_err());
        expect!(super::find_matching_request(&request3, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request4, false, &vec![pact1.clone(), pact2.clone()])).to(be_ok());
    }

    #[test]
    fn match_request_returns_the_closest_match() {
        let interaction1 = Interaction { request: Request {
            body: OptionalBody::Present("{\"a\": 1, \"b\": 2, \"c\": 3}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 200, .. Response::default_response() },
            .. Interaction::default() };

        let interaction2 = Interaction { request: Request {
            body: OptionalBody::Present("{\"a\": 2, \"b\": 4, \"c\": 6}".as_bytes().into()),
            .. Request::default_request() },
            response: Response { status: 201, .. Response::default_response() },
            .. Interaction::default() };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2.clone() ], .. Pact::default() };

        let request1 = Request {
            body: OptionalBody::Present("{\"a\": 1, \"b\": 4, \"c\": 6}".as_bytes().into()),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2])).to(be_ok().value(interaction2.response));
    }

    #[test]
    fn with_auto_cors_return_200_with_an_option_request() {
        let interaction1 = Interaction::default();
        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };

        let request1 = Request {
            method: s!("OPTIONS"),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, true, &vec![pact1.clone()])).to(be_ok());
        expect!(super::find_matching_request(&request1, false, &vec![pact1.clone()])).to(be_err());
    }

    #[test]
    fn match_request_with_query_params() {
        let matching_rules = matchingrules!{
            "query" => {
                "page[0]" => [ MatchingRule::Type ]
            }
        };
        let interaction1 = Interaction {
            request: Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("1") ] }),
            .. Request::default_request()
            },
            .. Interaction::default()
        };

        let interaction2 = Interaction {
            request: Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("1") ] }),
            matching_rules,
            .. Request::default_request()
            },
            .. Interaction::default()
        };

        let pact1 = Pact { interactions: vec![ interaction1 ], .. Pact::default() };
        let pact2 = Pact { interactions: vec![ interaction2 ], .. Pact::default() };

        let request1 = Request {
            path: s!("/api/objects"),
            query: Some(hashmap!{ s!("page") => vec![ s!("3") ] }),
            .. Request::default_request() };

        expect!(super::find_matching_request(&request1, false, &vec![pact1, pact2.clone()])).to(be_ok());
    }

}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-alpha2/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use log::{debug, trace};
use mio::{Events, Interest, Poll, Token};
use tcp_stream::HandshakeError;

use std::io;

/// Re-export TcpStream
pub use tcp_stream::{Identity, TcpStream};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
    ) -> io::Result<S>
    where
        Self: Sized,
    {
        self.connect_full(f, None, None)
    }
    /// connect to a TcpStream, registering it to the given Poll with the given Token to handle the
    /// handshake process. You should reregister it afterwards to better fit your needs
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S>;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S> {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!("Connecting to {}", uri);
        let mut stream = TcpStream::connect(uri)?;

        if let Some((poll, token)) = poll.as_ref() {
            trace!("Registering for mio events");
            poll.registry().register(
                &mut stream,
                *token,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }

        match self.scheme {
            AMQPScheme::AMQP => Ok((stream, poll)),
            AMQPScheme::AMQPS => connect_amqps(stream, &self.authority.host, poll, identity),
        }
        .map(|(s, poll)| f(s, self, poll))
    }
}

fn connect_amqps(
    stream: TcpStream,
    host: &str,
    mut poll: Option<(Poll, Token)>,
    identity: Option<Identity<'_, '_>>,
) -> io::Result<(TcpStream, Option<(Poll, Token)>)> {
    trace!("Enabling TLS");
    let mut events = Events::with_capacity(1024);
    let mut res = stream.into_tls(host, identity);

    while let Err(error) = res {
        debug!("Got error when enabling TLS: {:?}", error);
        match error {
            HandshakeError::Failure(io_err) => return Err(io_err),
            HandshakeError::WouldBlock(mid) => {
                if let Some((poll, _)) = poll.as_mut() {
                    trace!("Waiting for mio events");
                    poll.poll(&mut events, None)?;
                }
                trace!("Retrying TLS");
                res = mid.handshake()
            }
        };
    }

    trace!("TLS enabled");
    Ok((res.unwrap(), poll))
}

impl AMQPUriTcpExt for &str {
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S> {
        self.parse::<AMQPUri>()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
            .connect_full(f, poll, identity)
    }
}
<commit_msg>tcp: downgrade log to trace<commit_after>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-alpha2/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use log::trace;
use mio::{Events, Interest, Poll, Token};
use tcp_stream::HandshakeError;

use std::io;

/// Re-export TcpStream
pub use tcp_stream::{Identity, TcpStream};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
    ) -> io::Result<S>
    where
        Self: Sized,
    {
        self.connect_full(f, None, None)
    }
    /// connect to a TcpStream, registering it to the given Poll with the given Token to handle the
    /// handshake process. You should reregister it afterwards to better fit your needs
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S>;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S> {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!("Connecting to {}", uri);
        let mut stream = TcpStream::connect(uri)?;

        if let Some((poll, token)) = poll.as_ref() {
            trace!("Registering for mio events");
            poll.registry().register(
                &mut stream,
                *token,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }

        match self.scheme {
            AMQPScheme::AMQP => Ok((stream, poll)),
            AMQPScheme::AMQPS => connect_amqps(stream, &self.authority.host, poll, identity),
        }
        .map(|(s, poll)| f(s, self, poll))
    }
}

fn connect_amqps(
    stream: TcpStream,
    host: &str,
    mut poll: Option<(Poll, Token)>,
    identity: Option<Identity<'_, '_>>,
) -> io::Result<(TcpStream, Option<(Poll, Token)>)> {
    trace!("Enabling TLS");
    let mut events = Events::with_capacity(1024);
    let mut res = stream.into_tls(host, identity);

    while let Err(error) = res {
        trace!("Got error when enabling TLS: {:?}", error);
        match error {
            HandshakeError::Failure(io_err) => return Err(io_err),
            HandshakeError::WouldBlock(mid) => {
                if let Some((poll, _)) = poll.as_mut() {
                    trace!("Waiting for mio events");
                    poll.poll(&mut events, None)?;
                }
                trace!("Retrying TLS");
                res = mid.handshake()
            }
        };
    }

    trace!("TLS enabled");
    Ok((res.unwrap(), poll))
}

impl AMQPUriTcpExt for &str {
    fn connect_full<S, F: FnOnce(TcpStream, AMQPUri, Option<(Poll, Token)>) -> S>(
        self,
        f: F,
        poll: Option<(Poll, Token)>,
        identity: Option<Identity<'_, '_>>,
    ) -> io::Result<S> {
        self.parse::<AMQPUri>()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
            .connect_full(f, poll, identity)
    }
}
<|endoftext|>


<commit_before>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::ops::{ Add, Div, Mul, Neg, Rem, Sub };
use std::num::{ Float, Int, NumCast };
use std::marker::Reflect;

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> + Neg<Output=Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<Output=A> + Sub<Output=A> + Mul<Output=A> + Div<Output=A> + Rem<Output=A> + Neg<Output=A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Output=Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(usize, 0usize);
zero_impl!(u8,   0u8);
zero_impl!(u16,  0u16);
zero_impl!(u32,  0u32);
zero_impl!(u64,  0u64);
zero_impl!(isize, 0isize);
zero_impl!(i8,  0i8);
zero_impl!(i16, 0i16);
zero_impl!(i32, 0i32);
zero_impl!(i64, 0i64);
zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Reflect {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for usize {
    fn max_value() -> usize { Int::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { Int::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { Int::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { Int::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { Int::max_value() }
}
impl Primitive for isize {
    fn max_value() -> isize { Int::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { Int::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { Int::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { Int::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { Int::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Output=Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(usize, 1usize);
one_impl!(u8,  1u8);
one_impl!(u16, 1u16);
one_impl!(u32, 1u32);
one_impl!(u64, 1u64);
one_impl!(isize, 1isize);
one_impl!(i8,  1i8);
one_impl!(i16, 1i16);
one_impl!(i32, 1i32);
one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);
<commit_msg>Remove Neg from Num trait<commit_after>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::ops::{ Add, Div, Mul, Rem, Sub };
use std::num::{ Float, Int, NumCast };
use std::marker::Reflect;

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<Output=A> + Sub<Output=A> + Mul<Output=A> + Div<Output=A> + Rem<Output=A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Output=Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(usize, 0usize);
zero_impl!(u8,   0u8);
zero_impl!(u16,  0u16);
zero_impl!(u32,  0u32);
zero_impl!(u64,  0u64);
zero_impl!(isize, 0isize);
zero_impl!(i8,  0i8);
zero_impl!(i16, 0i16);
zero_impl!(i32, 0i32);
zero_impl!(i64, 0i64);
zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Reflect {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for usize {
    fn max_value() -> usize { Int::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { Int::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { Int::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { Int::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { Int::max_value() }
}
impl Primitive for isize {
    fn max_value() -> isize { Int::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { Int::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { Int::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { Int::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { Int::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Output=Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(usize, 1usize);
one_impl!(u8,  1u8);
one_impl!(u16, 1u16);
one_impl!(u32, 1u32);
one_impl!(u64, 1u64);
one_impl!(isize, 1isize);
one_impl!(i8,  1i8);
one_impl!(i16, 1i16);
one_impl!(i32, 1i32);
one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);
<|endoftext|>