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

/// A single token representing a Markdown element.
///
/// A Markdown document is, thus, a Vec of `Token`s.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    /// The most simple element, containing a String
    Str(String),
    /// A paragraph, containing a list of elements
    Paragraph(Vec<Token>),
    /// A header with a header number and the title
    Header(i32, Vec<Token>),
    /// *Emphasis*, a.k.a. italics
    Emphasis(Vec<Token>),
    /// **Strong**, a.k.a. bold
    Strong(Vec<Token>),
    /// `Code`, a.k.a. verbatim
    Code(Vec<Token>),
    /// > A quote
    BlockQuote(Vec<Token>),
    /// Code block with language and content
    CodeBlock(String, Vec<Token>),

    /// Unordered list, with a vector of `Item`s
    List(Vec<Token>),
    /// Ordered list, with a starting number, and a list of `Item`s
    OrderedList(usize, Vec<Token>),
    /// Item of a list
    Item(Vec<Token>),

    /// Table with number of rows, and a list of `TableHead` and `TableRows`
    Table(i32, Vec<Token>),
    /// Table header, contains `TableCell`s
    TableHead(Vec<Token>),
    /// Row of a table, contains `TableCell`s
    TableRow(Vec<Token>),
    /// Cell of a table
    TableCell(Vec<Token>),

    /// A footnote, contains the content it is pointing to.
    Footnote(Vec<Token>),

    /// Horizontal rule
    Rule,
    /// Softbreak, usually rendered by a space
    SoftBreak,
    /// Hardbreak
    HardBreak,

    /// A link with an url, a title, and the linked text
    Link(String, String, Vec<Token>),
    /// An image with a source url, a title and an alt tex
    Image(String, String, Vec<Token>),
    /// Similar to previous, but when image is in a standalone paragraph
    StandaloneImage(String, String, Vec<Token>),
}

use Token::*;

impl Token {
    /// Returns the inner list of tokens contained in this token (if any)
    pub fn inner(&self) -> Option<&[Token]> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref v)
                | Header(_, ref v)
                | Emphasis(ref v)
                | Strong(ref v)
                | Code(ref v)
                | BlockQuote(ref v)
                | CodeBlock(_, ref v)
                | List(ref v)
                | OrderedList(_, ref v)
                | Item(ref v)
                | Table(_, ref v)
                | TableHead(ref v)
                | TableRow(ref v)
                | TableCell(ref v)
                | Footnote(ref v)
                | Link(_,_,ref v)
                | Image(_,_,ref v)
                | StandaloneImage(_,_,ref v) => Some(v)
        }
    }

    /// Returns the inner list of tokens contained in this token (if any) (mutable version)
    pub fn inner_mut(&mut self) -> Option<&mut Vec<Token>> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref mut v)
                | Header(_, ref mut v)
                | Emphasis(ref mut v)
                | Strong(ref mut v)
                | Code(ref mut v)
                | BlockQuote(ref mut v)
                | CodeBlock(_, ref mut v)
                | List(ref mut v)
                | OrderedList(_, ref mut v)
                | Item(ref mut v)
                | Table(_, ref mut v)
                | TableHead(ref mut v)
                | TableRow(ref mut v)
                | TableCell(ref mut v)
                | Footnote(ref mut v)
                | Link(_,_,ref mut v)
                | Image(_,_,ref mut v)
                | StandaloneImage(_,_,ref mut v) => Some(v)
        }
    }
}

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

/// A single token representing a Markdown element.
///
/// A Markdown document is, thus, a Vec of `Token`s.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    /// The most simple element, containing a String
    Str(String),
    /// A paragraph, containing a list of elements
    Paragraph(Vec<Token>),
    /// A header with a header number and the title
    Header(i32, Vec<Token>),
    /// *Emphasis*, a.k.a. italics
    Emphasis(Vec<Token>),
    /// **Strong**, a.k.a. bold
    Strong(Vec<Token>),
    /// `Code`, a.k.a. verbatim
    Code(Vec<Token>),
    /// > A quote
    BlockQuote(Vec<Token>),
    /// Code block with language and content
    CodeBlock(String, Vec<Token>),

    /// Unordered list, with a vector of `Item`s
    List(Vec<Token>),
    /// Ordered list, with a starting number, and a list of `Item`s
    OrderedList(usize, Vec<Token>),
    /// Item of a list
    Item(Vec<Token>),

    /// Table with number of rows, and a list of `TableHead` and `TableRows`
    Table(i32, Vec<Token>),
    /// Table header, contains `TableCell`s
    TableHead(Vec<Token>),
    /// Row of a table, contains `TableCell`s
    TableRow(Vec<Token>),
    /// Cell of a table
    TableCell(Vec<Token>),

    /// A footnote, contains the content it is pointing to.
    Footnote(Vec<Token>),

    /// Horizontal rule
    Rule,
    /// Softbreak, usually rendered by a space
    SoftBreak,
    /// Hardbreak
    HardBreak,

    /// A link with an url, a title, and the linked text
    Link(String, String, Vec<Token>),
    /// An image with a source url, a title and an alt tex
    Image(String, String, Vec<Token>),
    /// Similar to previous, but when image is in a standalone paragraph
    StandaloneImage(String, String, Vec<Token>),
}

use Token::*;

impl Token {
    /// Returns the inner list of tokens contained in this token (if any)
    pub fn inner(&self) -> Option<&[Token]> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref v)
                | Header(_, ref v)
                | Emphasis(ref v)
                | Strong(ref v)
                | Code(ref v)
                | BlockQuote(ref v)
                | CodeBlock(_, ref v)
                | List(ref v)
                | OrderedList(_, ref v)
                | Item(ref v)
                | Table(_, ref v)
                | TableHead(ref v)
                | TableRow(ref v)
                | TableCell(ref v)
                | Footnote(ref v)
                | Link(_,_,ref v)
                | Image(_,_,ref v)
                | StandaloneImage(_,_,ref v) => Some(v)
        }
    }

    /// Returns the inner list of tokens contained in this token (if any) (mutable version)
    pub fn inner_mut(&mut self) -> Option<&mut Vec<Token>> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref mut v)
                | Header(_, ref mut v)
                | Emphasis(ref mut v)
                | Strong(ref mut v)
                | Code(ref mut v)
                | BlockQuote(ref mut v)
                | CodeBlock(_, ref mut v)
                | List(ref mut v)
                | OrderedList(_, ref mut v)
                | Item(ref mut v)
                | Table(_, ref mut v)
                | TableHead(ref mut v)
                | TableRow(ref mut v)
                | TableCell(ref mut v)
                | Footnote(ref mut v)
                | Link(_,_,ref mut v)
                | Image(_,_,ref mut v)
                | StandaloneImage(_,_,ref mut v) => Some(v)
        }
    }

    /// Checks whether token is an image
    pub fn is_image(&self) -> bool {
        if let Token::Image(_, _, _) = *self { true } else { false }
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use rand::{thread_rng, Rng};
use std::fmt;
use std::io::{Read, Write};
use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE, PARAMETER_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        println!("Sending on {}", self);
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway (using bogus data)
                            let blank = vec![0u8; PARAMETER_SIZE];

                            if let Ok(_) = super::u2f_register(device, &blank, &blank) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    // report_tx_ptr is deallocated by maybe_remove_device
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    let mut nonce = [0u8; 8];
    thread_rng().fill_bytes(&mut nonce);
    if let Err(_) = super::init_device(&mut dev, nonce) {
        return;
    }

    let mut random = [0u8; 8];
    thread_rng().fill_bytes(&mut random);
    if let Err(_) = super::ping_device(&mut dev, random) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    println!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    match devs.remove(&device_ref) {
        Some(dev) => {
            println!("removing U2F device {}", dev);
            // Re-allocate this raw pointer for destruction
            let _ = unsafe { Box::from_raw(dev.report_send_void) };
        },
        None => { println!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        println!("Sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    println!("Sending success? = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        println!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            println!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<commit_msg>Fix #1 - Minimize races that might access removed devices on OSX<commit_after>extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use rand::{thread_rng, Rng};
use std::fmt;
use std::io::{Read, Write};
use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE, PARAMETER_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        println!("Sending on {}", self);
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            'top: while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    // Check to see if monitor.events has any hotplug events that we'll need to handle
                    if monitor.events().size_hint().0 > 0 {
                        println!("Hotplug event; restarting loop");
                        continue 'top;
                    }

                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway (using bogus data)
                            let blank = vec![0u8; PARAMETER_SIZE];

                            if let Ok(_) = super::u2f_register(device, &blank, &blank) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    // report_tx_ptr is deallocated by maybe_remove_device
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    let mut nonce = [0u8; 8];
    thread_rng().fill_bytes(&mut nonce);
    if let Err(_) = super::init_device(&mut dev, nonce) {
        return;
    }

    let mut random = [0u8; 8];
    thread_rng().fill_bytes(&mut random);
    if let Err(_) = super::ping_device(&mut dev, random) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    println!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    match devs.remove(&device_ref) {
        Some(dev) => {
            println!("removing U2F device {}", dev);
            // Re-allocate this raw pointer for destruction
            let _ = unsafe { Box::from_raw(dev.report_send_void) };
        },
        None => { println!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        println!("Sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    println!("Sending success? = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        println!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            println!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use std::io::{Read, Write};
use std::io;
use std::fmt;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        println!("Sending on {}", self);
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway
                            // TODO: transmit garbage challenge and application
                            if let Ok(_) = super::u2f_register(device, &challenge, &application) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    if let Err(_) = super::init_device(&mut dev) {
        return;
    }
    if let Err(_) = super::ping_device(&mut dev) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    println!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    // TODO: When we deregister a device, also drop the report_send_void
    match devs.remove(&device_ref) {
        Some(dev) => { println!("removing U2F device {}", dev); },
        None => { println!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        println!("Sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    println!("Sending success? = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        println!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            println!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<commit_msg>Cleanup OSX Device Boxed Pointer<commit_after>extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use std::io::{Read, Write};
use std::io;
use std::fmt;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        println!("Sending on {}", self);
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway
                            // TODO: transmit garbage challenge and application
                            if let Ok(_) = super::u2f_register(device, &challenge, &application) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    // report_tx_ptr is deallocated by maybe_remove_device
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    if let Err(_) = super::init_device(&mut dev) {
        return;
    }
    if let Err(_) = super::ping_device(&mut dev) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    println!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    match devs.remove(&device_ref) {
        Some(dev) => {
            println!("removing U2F device {}", dev);
            // Re-allocate this raw pointer for destruction
            let _ = unsafe { Box::from_raw(dev.report_send_void) };
        },
        None => { println!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        println!("Sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    println!("Sending success? = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        println!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            println!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<|endoftext|>


<commit_before>use std::env;
use std::io::Read;
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use tendril::SliceExt;
use url::{Url, ParseError};
use hyper::header::UserAgent;
use hyper::Client as HyperClient;
use hyper::client::Response as HttpResponse;
use hyper::status::StatusCode;
use robotparser::RobotFileParser;
use html5ever::tokenizer::{TokenSink, Token, TagToken, Tokenizer};
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::{Job, JobOpts, create_redis_pool};
use serde_json::value::Value;
use serde_json::builder::ObjectBuilder;

#[macro_export]
macro_rules! maman_name {
    () => ( "Maman" )
}
#[macro_export]
macro_rules! maman_version {
    () => ( env!("CARGO_PKG_VERSION") )
}
#[macro_export]
macro_rules! maman_version_string {
    () => ( concat!(maman_name!(), " v", maman_version!()) )
}
#[macro_export]
macro_rules! maman_user_agent {
    () => ( concat!(maman_version_string!(), " (https://crates.io/crates/maman)") )
}

const MAMAN_ENV: &'static str = "MAMAN_ENV";

pub struct Spider<'a> {
    pub base_url: String,
    pub visited_urls: Vec<String>,
    pub unvisited_urls: Vec<String>,
    pub extra: Vec<String>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

pub struct Page {
    pub url: String,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub urls: Vec<String>,
    pub extra: Vec<String>,
}

impl TokenSink for Page {
    fn process_token(&mut self, token: Token) {
        match token {
            TagToken(tag) => {
                match tag.name {
                    atom!("a") => {
                        for attr in tag.attrs.iter() {
                            if attr.name.local.to_string() == "href" {
                                match self.can_enqueue(&attr.value) {
                                    Some(u) => {
                                        self.urls.push(u.to_string());
                                    }
                                    None => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

impl Page {
    pub fn new(url: String,
               document: String,
               headers: BTreeMap<String, String>,
               extra: Vec<String>)
               -> Self {
        Page {
            url: url,
            document: document,
            headers: headers,
            urls: Vec::new(),
            extra: extra,
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts =
            JobOpts { queue: maman_name!().to_string().to_lowercase(), ..Default::default() };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        ObjectBuilder::new()
            .insert("url".to_string(), &self.url)
            .insert("document".to_string(), &self.document)
            .insert("headers".to_string(), &self.headers)
            .insert("urls".to_string(), &self.urls)
            .insert("extra".to_string(), &self.extra)
            .build()
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.parsed_url().join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn parsed_url(&self) -> Url {
        Url::parse(&self.url).unwrap()
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.parsed_url() == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.parsed_url().domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}

impl<'a> Spider<'a> {
    pub fn new(base_url: String, limit: isize, extra: Vec<String>) -> Spider<'a> {
        let maman_env = env::var(&MAMAN_ENV.to_string()).unwrap_or("development".to_string());
        let robots_txt = format!("{}/{}", base_url, "robots.txt");
        let robot_parser = RobotFileParser::new(robots_txt);
        let client_opts =
            SidekiqClientOpts { namespace: Some(maman_env.to_string()), ..Default::default() };
        let sidekiq = SidekiqClient::new(create_redis_pool(), client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            extra: extra,
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in page.urls.iter() {
            self.unvisited_urls.push(u.clone());
        }
        match self.sidekiq.push(page.to_job()) {
            Err(err) => {
                println!("SidekiqClient push failed: {}", err);
            }
            Ok(_) => {}
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(&base_url) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.limit == 0 || (self.visited_urls.len() as isize) < self.limit {
                    if !self.visited_urls.contains(&url) {
                        let url_ser = &url.to_string();
                        if let Some(response) = Spider::load_url(url_ser) {
                            self.visit(url_ser, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        tok.feed(document.to_tendril());
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &str, response: HttpResponse) {
        match Url::parse(page_url) {
            Ok(u) => {
                if self.can_visit(u.clone()) {
                    if let Some(page) = Spider::read_response(u.to_string(),
                                                              response,
                                                              self.extra.clone()) {
                        self.visit_page(page);
                    }
                }
            }
            Err(_) => {}
        }
    }

    fn can_visit(&self, page_url: Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: String,
                     mut response: HttpResponse,
                     extra: Vec<String>)
                     -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers.iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = String::new();
        // handle CharsError::NotUtf8
        match response.read_to_string(&mut document) {
            Ok(_) => {
                let page = Page::new(page_url, document.to_string(), headers.clone(), extra);
                let read = Spider::read_page(page, &document).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let client = HyperClient::new();
        let request = client.get(url).header(UserAgent(maman_user_agent!().to_owned()));
        match request.send() {
            Ok(response) => {
                match response.status {
                    StatusCode::Ok | StatusCode::NotModified => Some(response),
                    _ => None,
                }
            }
            Err(_) => None,
        }
    }
}
<commit_msg>Dont follow redirect on crawling<commit_after>use std::env;
use std::io::Read;
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use tendril::SliceExt;
use url::{Url, ParseError};
use hyper::header::UserAgent;
use hyper::Client as HyperClient;
use hyper::client::RedirectPolicy;
use hyper::client::Response as HttpResponse;
use hyper::status::StatusCode;
use robotparser::RobotFileParser;
use html5ever::tokenizer::{TokenSink, Token, TagToken, Tokenizer};
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::{Job, JobOpts, create_redis_pool};
use serde_json::value::Value;
use serde_json::builder::ObjectBuilder;

#[macro_export]
macro_rules! maman_name {
    () => ( "Maman" )
}
#[macro_export]
macro_rules! maman_version {
    () => ( env!("CARGO_PKG_VERSION") )
}
#[macro_export]
macro_rules! maman_version_string {
    () => ( concat!(maman_name!(), " v", maman_version!()) )
}
#[macro_export]
macro_rules! maman_user_agent {
    () => ( concat!(maman_version_string!(), " (https://crates.io/crates/maman)") )
}

const MAMAN_ENV: &'static str = "MAMAN_ENV";

pub struct Spider<'a> {
    pub base_url: String,
    pub visited_urls: Vec<String>,
    pub unvisited_urls: Vec<String>,
    pub extra: Vec<String>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

pub struct Page {
    pub url: String,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub urls: Vec<String>,
    pub extra: Vec<String>,
}

impl TokenSink for Page {
    fn process_token(&mut self, token: Token) {
        match token {
            TagToken(tag) => {
                match tag.name {
                    atom!("a") => {
                        for attr in tag.attrs.iter() {
                            if attr.name.local.to_string() == "href" {
                                match self.can_enqueue(&attr.value) {
                                    Some(u) => {
                                        self.urls.push(u.to_string());
                                    }
                                    None => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

impl Page {
    pub fn new(url: String,
               document: String,
               headers: BTreeMap<String, String>,
               extra: Vec<String>)
               -> Self {
        Page {
            url: url,
            document: document,
            headers: headers,
            urls: Vec::new(),
            extra: extra,
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts =
            JobOpts { queue: maman_name!().to_string().to_lowercase(), ..Default::default() };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        ObjectBuilder::new()
            .insert("url".to_string(), &self.url)
            .insert("document".to_string(), &self.document)
            .insert("headers".to_string(), &self.headers)
            .insert("urls".to_string(), &self.urls)
            .insert("extra".to_string(), &self.extra)
            .build()
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.parsed_url().join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn parsed_url(&self) -> Url {
        Url::parse(&self.url).unwrap()
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.parsed_url() == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.parsed_url().domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}

impl<'a> Spider<'a> {
    pub fn new(base_url: String, limit: isize, extra: Vec<String>) -> Spider<'a> {
        let maman_env = env::var(&MAMAN_ENV.to_string()).unwrap_or("development".to_string());
        let robots_txt = format!("{}/{}", base_url, "robots.txt");
        let robot_parser = RobotFileParser::new(robots_txt);
        let client_opts =
            SidekiqClientOpts { namespace: Some(maman_env.to_string()), ..Default::default() };
        let sidekiq = SidekiqClient::new(create_redis_pool(), client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            extra: extra,
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in page.urls.iter() {
            self.unvisited_urls.push(u.clone());
        }
        match self.sidekiq.push(page.to_job()) {
            Err(err) => {
                println!("SidekiqClient push failed: {}", err);
            }
            Ok(_) => {}
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(&base_url) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.limit == 0 || (self.visited_urls.len() as isize) < self.limit {
                    if !self.visited_urls.contains(&url) {
                        let url_ser = &url.to_string();
                        if let Some(response) = Spider::load_url(url_ser) {
                            self.visit(url_ser, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        tok.feed(document.to_tendril());
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &str, response: HttpResponse) {
        match Url::parse(page_url) {
            Ok(u) => {
                if self.can_visit(u.clone()) {
                    if let Some(page) = Spider::read_response(u.to_string(),
                                                              response,
                                                              self.extra.clone()) {
                        self.visit_page(page);
                    }
                }
            }
            Err(_) => {}
        }
    }

    fn can_visit(&self, page_url: Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: String,
                     mut response: HttpResponse,
                     extra: Vec<String>)
                     -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers.iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = String::new();
        // handle CharsError::NotUtf8
        match response.read_to_string(&mut document) {
            Ok(_) => {
                let page = Page::new(page_url, document.to_string(), headers.clone(), extra);
                let read = Spider::read_page(page, &document).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let mut client = HyperClient::new();
        client.set_redirect_policy(RedirectPolicy::FollowNone);
        let request = client.get(url).header(UserAgent(maman_user_agent!().to_owned()));
        match request.send() {
            Ok(response) => {
                match response.status {
                    StatusCode::Ok | StatusCode::NotModified => Some(response),
                    _ => None,
                }
            }
            Err(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>extern crate difference;
extern crate quickcheck;

use difference::{Changeset, Difference};
use quickcheck::{TestResult, quickcheck, QuickCheck};
use std::fmt;

const DEBUG: bool = false;

struct Check<'a> {
    old: &'a str,
    new: &'a str,
    changeset: Changeset,
}

impl<'a> fmt::Display for Check<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Changeset::new({:?}, {:?}, {:?}) -> [",
            self.old,
            self.new,
            self.changeset.split
        )?;

        let mut iter = self.changeset.diffs.iter();
        if let Some(d) = iter.next() {
            write!(f, "{:?}", d)?;
        }
        for d in iter {
            write!(f, " {:?}", d)?;
        }
        write!(f, "]")
    }
}

fn check_changeset(old: &str, new: &str, split: &str) -> TestResult {
    Check::new(old, new, split).check()
}

impl<'a> Check<'a> {
    fn new(old: &'a str, new: &'a str, split: &'a str) -> Check<'a> {
        Check {
            old: old,
            new: new,
            changeset: Changeset::new(old, new, split),
        }
    }

    fn check(&self) -> TestResult {
        let split = &self.changeset.split;

        let mut old: Vec<&str> = Vec::new();
        let mut new: Vec<&str> = Vec::new();

        for d in &self.changeset.diffs {
            if DEBUG {
                println!("assert `{:?}` (old: {:?}, new: {:?})", d, old, new);
            }

            match *d {
                Difference::Same(ref x) => {
                    old.push(x);
                    new.push(x);
                }
                Difference::Add(ref x) => {
                    new.push(x);
                }
                Difference::Rem(ref x) => {
                    old.push(x);
                }
            }
        }
        let got_old = old.join(split);
        let got_new = new.join(split);
        if got_old != self.old {
            return TestResult::error(format!("Diff output implies old=`{:?}`, not `{:?}` in {}",
                        got_old, self.old, self,
                ));
        }
        if got_new != self.new {
            return TestResult::error(format!("Diff output implies new=`{:?}`, not `{:?}` in {}",
                        got_new, self.new, self,
                ));
        }

        TestResult::passed()
    }
}

#[test]
fn simple() {
    quickcheck(check_changeset("a", "a a", " "));
}

#[test]
#[ignore]
fn issue_19() {
    // this should work but it doesn't
    // https://github.com/johannhof/difference.rs/issues/19
    quickcheck(check_changeset("a b : g", "b a : b b : g g", " "));
}

#[test]
#[ignore]
fn fuzzy() {
    fn prop(old: Vec<usize>, new: Vec<usize>, words: Vec<char>) -> TestResult {
        if words.is_empty() {
            return TestResult::discard();
        }

        fn map_to_words(input: &[usize], words: &[char]) -> String {
            input.iter().enumerate().fold(
                String::new(),
                |mut acc, (i, x)| {
                    if i > 0 {
                        acc.push(' ');
                    }
                    acc.push(words[x % words.len()]);
                    acc
                },
            )
        }
        let old = map_to_words(&old, &words);
        let new = map_to_words(&new, &words);

        check_changeset(&old, &new, " ")
    }

    QuickCheck::new()
        .tests(100) // max successful tests
        .max_tests(10000) // max attempts
        .quickcheck(prop as fn(Vec<usize>, Vec<usize>, Vec<char>) -> TestResult);
}
<commit_msg>Re-enable quickcheck tests.<commit_after>extern crate difference;
extern crate quickcheck;

use difference::{Changeset, Difference};
use quickcheck::{TestResult, quickcheck, QuickCheck};
use std::fmt;

const DEBUG: bool = false;

struct Check<'a> {
    old: &'a str,
    new: &'a str,
    changeset: Changeset,
}

impl<'a> fmt::Display for Check<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Changeset::new({:?}, {:?}, {:?}) -> [",
            self.old,
            self.new,
            self.changeset.split
        )?;

        let mut iter = self.changeset.diffs.iter();
        if let Some(d) = iter.next() {
            write!(f, "{:?}", d)?;
        }
        for d in iter {
            write!(f, " {:?}", d)?;
        }
        write!(f, "]")
    }
}

fn check_changeset(old: &str, new: &str, split: &str) -> TestResult {
    Check::new(old, new, split).check()
}

impl<'a> Check<'a> {
    fn new(old: &'a str, new: &'a str, split: &'a str) -> Check<'a> {
        Check {
            old: old,
            new: new,
            changeset: Changeset::new(old, new, split),
        }
    }

    fn check(&self) -> TestResult {
        let split = &self.changeset.split;

        let mut old: Vec<&str> = Vec::new();
        let mut new: Vec<&str> = Vec::new();

        for d in &self.changeset.diffs {
            if DEBUG {
                println!("assert `{:?}` (old: {:?}, new: {:?})", d, old, new);
            }

            match *d {
                Difference::Same(ref x) => {
                    old.push(x);
                    new.push(x);
                }
                Difference::Add(ref x) => {
                    new.push(x);
                }
                Difference::Rem(ref x) => {
                    old.push(x);
                }
            }
        }
        let got_old = old.join(split);
        let got_new = new.join(split);
        if got_old != self.old {
            return TestResult::error(format!("Diff output implies old=`{:?}`, not `{:?}` in {}",
                        got_old, self.old, self,
                ));
        }
        if got_new != self.new {
            return TestResult::error(format!("Diff output implies new=`{:?}`, not `{:?}` in {}",
                        got_new, self.new, self,
                ));
        }

        TestResult::passed()
    }
}

#[test]
fn simple() {
    quickcheck(check_changeset("a", "a a", " "));
}

#[test]
fn issue_19() {
    // https://github.com/johannhof/difference.rs/issues/19
    quickcheck(check_changeset("a b : g", "b a : b b : g g", " "));
}

#[test]
fn fuzzy() {
    fn prop(old: Vec<usize>, new: Vec<usize>, words: Vec<char>) -> TestResult {
        if words.is_empty() {
            return TestResult::discard();
        }

        fn map_to_words(input: &[usize], words: &[char]) -> String {
            input.iter().enumerate().fold(
                String::new(),
                |mut acc, (i, x)| {
                    if i > 0 {
                        acc.push(' ');
                    }
                    acc.push(words[x % words.len()]);
                    acc
                },
            )
        }
        let old = map_to_words(&old, &words);
        let new = map_to_words(&new, &words);

        check_changeset(&old, &new, " ")
    }

    QuickCheck::new()
        .tests(100) // max successful tests
        .max_tests(10000) // max attempts
        .quickcheck(prop as fn(Vec<usize>, Vec<usize>, Vec<char>) -> TestResult);
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// compile-flags: -Z lower_128bit_ops -C debug_assertions=yes

#![feature(i128_type)]
#![feature(lang_items)]

#[lang="i128_div"]
fn i128_div(_x: i128, _y: i128) -> i128 { 3 }
#[lang="u128_div"]
fn u128_div(_x: i128, _y: i128) -> i128 { 4 }
#[lang="i128_rem"]
fn i128_rem(_x: i128, _y: i128) -> i128 { 5 }
#[lang="u128_rem"]
fn u128_rem(_x: i128, _y: i128) -> i128 { 6 }

#[lang="i128_addo"]
fn i128_addo(_x: i128, _y: i128) -> (i128, bool) { (0, false) }
#[lang="u128_addo"]
fn u128_addo(_x: i128, _y: i128) -> (i128, bool) { (1, false) }
#[lang="i128_subo"]
fn i128_subo(_x: i128, _y: i128) -> (i128, bool) { (2, false) }
#[lang="u128_subo"]
fn u128_subo(_x: i128, _y: i128) -> (i128, bool) { (3, false) }
#[lang="i128_mulo"]
fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) }
#[lang="u128_mulo"]
fn u128_mulo(_x: i128, _y: i128) -> (i128, bool) { (5, false) }
#[lang="i128_shlo"]
fn i128_shlo(_x: i128, _y: u32) -> (i128, bool) { (6, false) }
#[lang="i128_shro"]
fn i128_shro(_x: i128, _y: u32) -> (i128, bool) { (7, false) }
#[lang="u128_shro"]
fn u128_shro(_x: i128, _y: u32) -> (i128, bool) { (8, false) }

fn test_signed(mut x: i128) -> i128 {
    x += 1;
    x -= 2;
    x *= 3;
    x /= 4;
    x %= 5;
    x <<= 6;
    x >>= 7;
    x
}

fn test_unsigned(mut x: u128) -> u128 {
    x += 1;
    x -= 2;
    x *= 3;
    x /= 4;
    x %= 5;
    x <<= 6;
    x >>= 7;
    x
}

fn main() {
    test_signed(-200);
    test_unsigned(200);
}

// END RUST SOURCE

// START rustc.test_signed.Lower128Bit.after.mir
//     _2 = const i128_addo(_1, const 1i128) -> bb10;
//     ...
//     _3 = const i128_subo(_1, const 2i128) -> bb11;
//     ...
//     _4 = const i128_mulo(_1, const 3i128) -> bb12;
//     ...
//     _1 = const i128_div(_1, const 4i128) -> bb13;
//     ...
//     _1 = const i128_rem(_1, const 5i128) -> bb15;
//     ...
//     _14 = const i128_shro(_1, const 7i32) -> bb16;
//     ...
//     _13 = const i128_shlo(_1, const 6i32) -> bb14;
// END rustc.test_signed.Lower128Bit.after.mir

// START rustc.test_unsigned.Lower128Bit.after.mir
//     _2 = const u128_addo(_1, const 1u128) -> bb8;
//     ...
//     _3 = const u128_subo(_1, const 2u128) -> bb9;
//     ...
//     _4 = const u128_mulo(_1, const 3u128) -> bb10;
//     ...
//     _1 = const u128_div(_1, const 4u128) -> bb11;
//     ...
//     _1 = const u128_rem(_1, const 5u128) -> bb13;
//     ...
//     _8 = const u128_shro(_1, const 7i32) -> bb14;
//     ...
//     _7 = const i128_shlo(_1, const 6i32) -> bb12;
// END rustc.test_unsigned.Lower128Bit.after.mir
<commit_msg>Include tuple projections in MIR tests<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// compile-flags: -Z lower_128bit_ops -C debug_assertions=yes

#![feature(i128_type)]
#![feature(lang_items)]

#[lang="i128_div"]
fn i128_div(_x: i128, _y: i128) -> i128 { 3 }
#[lang="u128_div"]
fn u128_div(_x: i128, _y: i128) -> i128 { 4 }
#[lang="i128_rem"]
fn i128_rem(_x: i128, _y: i128) -> i128 { 5 }
#[lang="u128_rem"]
fn u128_rem(_x: i128, _y: i128) -> i128 { 6 }

#[lang="i128_addo"]
fn i128_addo(_x: i128, _y: i128) -> (i128, bool) { (0, false) }
#[lang="u128_addo"]
fn u128_addo(_x: i128, _y: i128) -> (i128, bool) { (1, false) }
#[lang="i128_subo"]
fn i128_subo(_x: i128, _y: i128) -> (i128, bool) { (2, false) }
#[lang="u128_subo"]
fn u128_subo(_x: i128, _y: i128) -> (i128, bool) { (3, false) }
#[lang="i128_mulo"]
fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) }
#[lang="u128_mulo"]
fn u128_mulo(_x: i128, _y: i128) -> (i128, bool) { (5, false) }
#[lang="i128_shlo"]
fn i128_shlo(_x: i128, _y: u32) -> (i128, bool) { (6, false) }
#[lang="i128_shro"]
fn i128_shro(_x: i128, _y: u32) -> (i128, bool) { (7, false) }
#[lang="u128_shro"]
fn u128_shro(_x: i128, _y: u32) -> (i128, bool) { (8, false) }

fn test_signed(mut x: i128) -> i128 {
    x += 1;
    x -= 2;
    x *= 3;
    x /= 4;
    x %= 5;
    x <<= 6;
    x >>= 7;
    x
}

fn test_unsigned(mut x: u128) -> u128 {
    x += 1;
    x -= 2;
    x *= 3;
    x /= 4;
    x %= 5;
    x <<= 6;
    x >>= 7;
    x
}

fn main() {
    test_signed(-200);
    test_unsigned(200);
}

// END RUST SOURCE

// START rustc.test_signed.Lower128Bit.after.mir
//     _2 = const i128_addo(_1, const 1i128) -> bb10;
//     ...
//     _1 = (_2.0: i128);
//     _3 = const i128_subo(_1, const 2i128) -> bb11;
//     ...
//     _1 = (_3.0: i128);
//     _4 = const i128_mulo(_1, const 3i128) -> bb12;
//     ...
//     _1 = (_4.0: i128);
//     ...
//     _1 = const i128_div(_1, const 4i128) -> bb13;
//     ...
//     _1 = const i128_rem(_1, const 5i128) -> bb15;
//     ...
//     _1 = (_13.0: i128);
//     _14 = const i128_shro(_1, const 7i32) -> bb16;
//     ...
//     _1 = (_14.0: i128);
//     ...
//     assert(!(_2.1: bool), "attempt to add with overflow") -> bb1;
//     ...
//     assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2;
//     ...
//     assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3;
//     ...
//     assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8;
//     ...
//     _13 = const i128_shlo(_1, const 6i32) -> bb14;
//     ...
//     assert(!(_14.1: bool), "attempt to shift right with overflow") -> bb9;
// END rustc.test_signed.Lower128Bit.after.mir

// START rustc.test_unsigned.Lower128Bit.after.mir
//     _2 = const u128_addo(_1, const 1u128) -> bb8;
//     ...
//     _1 = (_2.0: u128);
//     _3 = const u128_subo(_1, const 2u128) -> bb9;
//     ...
//     _1 = (_3.0: u128);
//     _4 = const u128_mulo(_1, const 3u128) -> bb10;
//     ...
//     _1 = (_4.0: u128);
//     ...
//     _1 = const u128_div(_1, const 4u128) -> bb11;
//     ...
//     _1 = const u128_rem(_1, const 5u128) -> bb13;
//     ...
//     _1 = (_7.0: u128);
//     _8 = const u128_shro(_1, const 7i32) -> bb14;
//     ...
//     _1 = (_8.0: u128);
//     ...
//     assert(!(_2.1: bool), "attempt to add with overflow") -> bb1;
//     ...
//     assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2;
//     ...
//     assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3;
//     ...
//     assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6;
//     ...
//     _7 = const i128_shlo(_1, const 6i32) -> bb12;
//     ...
//     assert(!(_8.1: bool), "attempt to shift right with overflow") -> bb7;
// END rustc.test_unsigned.Lower128Bit.after.mir
<|endoftext|>


<commit_before>extern crate hyper;
extern crate tus;

use hyper::Client;
use hyper::status::StatusCode;
use hyper::header::Headers;

#[test]
fn bad_version_good_method_return_412() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.1".to_vec()]);

    let response = client.head("http://localhost:4000").headers(headers).send().unwrap();

    assert_eq!(response.status, StatusCode::PreconditionFailed)
}

#[test]
fn good_version_bad_method_return_405() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.0".to_vec()]);

    let response = client.put("http://localhost:4000").headers(headers).send().unwrap();

    assert_eq!(response.status, StatusCode::MethodNotAllowed)
}

#[test]
fn bad_version_bad_method_return_405() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.1".to_vec()]);

    let response = client.put("http://localhost:4000").headers(headers).send().unwrap();

    assert_eq!(response.status, StatusCode::MethodNotAllowed)
}
<commit_msg>fixed test for bad_version precondition failed<commit_after>extern crate hyper;
extern crate tus;

use hyper::Client;
use hyper::status::StatusCode;
use hyper::header::Headers;

#[test]
fn bad_version_good_method_return_412() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.1".to_vec()]);

    let response = client.head("http://localhost:4000").headers(headers).send().unwrap();
    let raw_tus_version = response.headers.get_raw("Tus-Version").unwrap();

    assert_eq!(response.status, StatusCode::PreconditionFailed);
    assert_eq!(raw_tus_version, &[b"1.0.0"])
}

#[test]
fn good_version_bad_method_return_405() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.0".to_vec()]);

    let response = client.put("http://localhost:4000").headers(headers).send().unwrap();

    assert_eq!(response.status, StatusCode::MethodNotAllowed)
}

#[test]
fn bad_version_bad_method_return_405() {
    let client = Client::new();
    let mut headers = Headers::new();
    headers.set_raw("Tus-Resumable", vec![b"1.0.1".to_vec()]);

    let response = client.put("http://localhost:4000").headers(headers).send().unwrap();

    assert_eq!(response.status, StatusCode::MethodNotAllowed)
}
<|endoftext|>