<commit_before>/// Common code for printing the backtrace in the same way across the different
/// supported platforms.

use crate::env;
use crate::fmt;
use crate::io;
use crate::io::prelude::*;
use crate::path::{self, Path};
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;

use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt};

/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;

/// Prints the current backtrace.
pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
    static LOCK: Mutex = Mutex::new();

    // There are issues currently linking libbacktrace into tests, and in
    // general during libstd's own unit tests we're not testing this path. In
    // test mode immediately return here to optimize away any references to the
    // libbacktrace symbols
    if cfg!(test) {
        return Ok(());
    }

    // Use a lock to prevent mixed output in multithreading context.
    // Some platforms also requires it, like `SymFromAddr` on Windows.
    unsafe {
        LOCK.lock();
        let res = _print(w, format);
        LOCK.unlock();
        res
    }
}

fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
    struct DisplayBacktrace {
        format: PrintFmt,
    }
    impl fmt::Display for DisplayBacktrace {
        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
            _print_fmt(fmt, self.format)
        }
    }
    write!(w, "{}", DisplayBacktrace { format })
}

fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
    let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
        output_filename(fmt, bows, print_fmt)
    };
    let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
    bt_fmt.add_context()?;
    let mut skipped = false;
    unsafe {
        let mut idx = 0;
        let mut res = Ok(());
        backtrace::trace_unsynchronized(|frame| {
            if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
                skipped = true;
                return false;
            }

            let mut hit = false;
            let mut stop = false;
            backtrace::resolve_frame_unsynchronized(frame, |symbol| {
                hit = true;
                if print_fmt == PrintFmt::Short {
                    if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
                        if sym.contains("__rust_begin_short_backtrace") {
                            skipped = true;
                            stop = true;
                            return;
                        }
                    }
                }

                res = bt_fmt.frame().symbol(frame, symbol);
            });
            if stop {
                return false;
            }
            if !hit {
                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
            }

            idx += 1;
            res.is_ok()
        });
        res?;
    }
    bt_fmt.finish()?;
    if skipped {
        writeln!(
            fmt,
            "note: Some details are omitted, \
             run with `RUST_BACKTRACE=full` for a verbose backtrace."
        )?;
    }
    Ok(())
}

/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
where
    F: FnOnce() -> T,
    F: Send,
    T: Send,
{
    f()
}

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> Option<PrintFmt> {
    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        0 => {}
        1 => return None,
        2 => return Some(PrintFmt::Short),
        _ => return Some(PrintFmt::Full),
    }

    let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
        if &x == "0" {
            None
        } else if &x == "full" {
            Some(PrintFmt::Full)
        } else {
            Some(PrintFmt::Short)
        }
    });
    ENABLED.store(
        match val {
            Some(v) => v as isize,
            None => 1,
        },
        Ordering::SeqCst,
    );
    val
}

/// Prints the filename of the backtrace frame.
///
/// See also `output`.
fn output_filename(
    fmt: &mut fmt::Formatter<'_>,
    bows: BytesOrWideString<'_>,
    print_fmt: PrintFmt,
) -> fmt::Result {
    #[cfg(windows)]
    let path_buf;
    let file = match bows {
        #[cfg(unix)]
        BytesOrWideString::Bytes(bytes) => {
            use crate::os::unix::prelude::*;
            Path::new(crate::ffi::OsStr::from_bytes(bytes))
        }
        #[cfg(not(unix))]
        BytesOrWideString::Bytes(bytes) => {
            Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
        }
        #[cfg(windows)]
        BytesOrWideString::Wide(wide) => {
            use crate::os::windows::prelude::*;
            path_buf = crate::ffi::OsString::from_wide(wide);
            Path::new(&path_buf)
        }
        #[cfg(not(windows))]
        BytesOrWideString::Wide(_wide) => {
            Path::new("<unknown>")
        }
    };
    if print_fmt == PrintFmt::Short && file.is_absolute() {
        if let Ok(cwd) = env::current_dir() {
            if let Ok(stripped) = file.strip_prefix(&cwd) {
                if let Some(s) = stripped.to_str() {
                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
                }
            }
        }
    }
    fmt::Display::fmt(&file.display(), fmt)
}
<commit_msg>Rollup merge of #64323 - cramertj:fuchsia-rust-backtrace-noop, r=alexcrichton<commit_after>/// Common code for printing the backtrace in the same way across the different
/// supported platforms.

use crate::env;
use crate::fmt;
use crate::io;
use crate::io::prelude::*;
use crate::path::{self, Path};
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;

use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt};

/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;

/// Prints the current backtrace.
pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
    static LOCK: Mutex = Mutex::new();

    // There are issues currently linking libbacktrace into tests, and in
    // general during libstd's own unit tests we're not testing this path. In
    // test mode immediately return here to optimize away any references to the
    // libbacktrace symbols
    if cfg!(test) {
        return Ok(());
    }

    // Use a lock to prevent mixed output in multithreading context.
    // Some platforms also requires it, like `SymFromAddr` on Windows.
    unsafe {
        LOCK.lock();
        let res = _print(w, format);
        LOCK.unlock();
        res
    }
}

fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
    struct DisplayBacktrace {
        format: PrintFmt,
    }
    impl fmt::Display for DisplayBacktrace {
        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
            _print_fmt(fmt, self.format)
        }
    }
    write!(w, "{}", DisplayBacktrace { format })
}

fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
    let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
        output_filename(fmt, bows, print_fmt)
    };
    let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
    bt_fmt.add_context()?;
    let mut skipped = false;
    unsafe {
        let mut idx = 0;
        let mut res = Ok(());
        backtrace::trace_unsynchronized(|frame| {
            if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
                skipped = true;
                return false;
            }

            let mut hit = false;
            let mut stop = false;
            backtrace::resolve_frame_unsynchronized(frame, |symbol| {
                hit = true;
                if print_fmt == PrintFmt::Short {
                    if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
                        if sym.contains("__rust_begin_short_backtrace") {
                            skipped = true;
                            stop = true;
                            return;
                        }
                    }
                }

                res = bt_fmt.frame().symbol(frame, symbol);
            });
            if stop {
                return false;
            }
            if !hit {
                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
            }

            idx += 1;
            res.is_ok()
        });
        res?;
    }
    bt_fmt.finish()?;
    if skipped {
        writeln!(
            fmt,
            "note: Some details are omitted, \
             run with `RUST_BACKTRACE=full` for a verbose backtrace."
        )?;
    }
    Ok(())
}

/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
where
    F: FnOnce() -> T,
    F: Send,
    T: Send,
{
    f()
}

// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> Option<PrintFmt> {
    // Setting environment variables for Fuchsia components isn't a standard
    // or easily supported workflow. For now, always display backtraces.
    if cfg!(target_os = "fuchsia") {
        return Some(PrintFmt::Full);
    }

    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
    match ENABLED.load(Ordering::SeqCst) {
        0 => {}
        1 => return None,
        2 => return Some(PrintFmt::Short),
        _ => return Some(PrintFmt::Full),
    }

    let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
        if &x == "0" {
            None
        } else if &x == "full" {
            Some(PrintFmt::Full)
        } else {
            Some(PrintFmt::Short)
        }
    });
    ENABLED.store(
        match val {
            Some(v) => v as isize,
            None => 1,
        },
        Ordering::SeqCst,
    );
    val
}

/// Prints the filename of the backtrace frame.
///
/// See also `output`.
fn output_filename(
    fmt: &mut fmt::Formatter<'_>,
    bows: BytesOrWideString<'_>,
    print_fmt: PrintFmt,
) -> fmt::Result {
    #[cfg(windows)]
    let path_buf;
    let file = match bows {
        #[cfg(unix)]
        BytesOrWideString::Bytes(bytes) => {
            use crate::os::unix::prelude::*;
            Path::new(crate::ffi::OsStr::from_bytes(bytes))
        }
        #[cfg(not(unix))]
        BytesOrWideString::Bytes(bytes) => {
            Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
        }
        #[cfg(windows)]
        BytesOrWideString::Wide(wide) => {
            use crate::os::windows::prelude::*;
            path_buf = crate::ffi::OsString::from_wide(wide);
            Path::new(&path_buf)
        }
        #[cfg(not(windows))]
        BytesOrWideString::Wide(_wide) => {
            Path::new("<unknown>")
        }
    };
    if print_fmt == PrintFmt::Short && file.is_absolute() {
        if let Ok(cwd) = env::current_dir() {
            if let Ok(stripped) = file.strip_prefix(&cwd) {
                if let Some(s) = stripped.to_str() {
                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
                }
            }
        }
    }
    fmt::Display::fmt(&file.display(), fmt)
}
<|endoftext|>


<commit_before>//! Iron's HTTP Request representation and associated methods.

use std::io::{self, Read};
use std::net::SocketAddr;
use std::fmt::{self, Debug};

use hyper::uri::RequestUri::{AbsoluteUri, AbsolutePath};
use hyper::net::NetworkStream;
use hyper::http::h1::HttpReader;

use typemap::TypeMap;
use plugin::Extensible;
use method::Method;

pub use hyper::server::request::Request as HttpRequest;
use hyper::buffer;

pub use self::url::Url;

use {Protocol, Plugin, Headers, Set, headers};

mod url;

/// The `Request` given to all `Middleware`.
///
/// Stores all the properties of the client's request plus
/// an `TypeMap` for data communication between middleware.
pub struct Request<'a, 'b: 'a> {
    /// The requested URL.
    pub url: Url,

    /// The originating address of the request.
    pub remote_addr: SocketAddr,

    /// The local address of the request.
    pub local_addr: SocketAddr,

    /// The request headers.
    pub headers: Headers,

    /// The request body as a reader.
    pub body: Body<'a, 'b>,

    /// The request method.
    pub method: Method,

    /// Extensible storage for data passed between middleware.
    pub extensions: TypeMap
}

impl<'a, 'b> Debug for Request<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "Request {{"));

        try!(writeln!(f, "    url: {:?}", self.url));
        try!(writeln!(f, "    method: {:?}", self.method));
        try!(writeln!(f, "    remote_addr: {:?}", self.remote_addr));
        try!(writeln!(f, "    local_addr: {:?}", self.local_addr));

        try!(write!(f, "}}"));
        Ok(())
    }
}

impl<'a, 'b> Request<'a, 'b> {
    /// Create a request from an HttpRequest.
    ///
    /// This constructor consumes the HttpRequest.
    pub fn from_http(req: HttpRequest<'a, 'b>, local_addr: SocketAddr, protocol: &Protocol)
                     -> Result<Request<'a, 'b>, String> {
        let (addr, method, headers, uri, _, reader) = req.deconstruct();

        let url = match uri {
            AbsoluteUri(ref url) => {
                match Url::from_generic_url(url.clone()) {
                    Ok(url) => url,
                    Err(e) => return Err(e)
                }
            },

            AbsolutePath(ref path) => {
                // Attempt to prepend the Host header (mandatory in HTTP/1.1)
                let url_string = match headers.get::<headers::Host>() {
                    Some(ref host) => {
                        format!("{}://{}:{}{}", protocol.name(), host.hostname, local_addr.port(),
                                path)
                    },
                    None => return Err("No host specified in request".into())
                };

                match Url::parse(&url_string) {
                    Ok(url) => url,
                    Err(e) => return Err(format!("Couldn't parse requested URL: {}", e))
                }
            },
            _ => return Err("Unsupported request URI".into())
        };

        Ok(Request {
            url: url,
            remote_addr: addr,
            local_addr: local_addr,
            headers: headers,
            body: Body::new(reader),
            method: method,
            extensions: TypeMap::new()
        })
    }
}

/// The body of an Iron request,
pub struct Body<'a, 'b: 'a>(HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>);

impl<'a, 'b> Body<'a, 'b> {
    /// Create a new reader for use in an Iron request from a hyper HttpReader.
    pub fn new(reader: HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>) -> Body<'a, 'b> {
        Body(reader)
    }
}

impl<'a, 'b> Read for Body<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

// Allow plugins to attach to requests.
impl<'a, 'b> Extensible for Request<'a, 'b> {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl<'a, 'b> Plugin for Request<'a, 'b> {}
impl<'a, 'b> Set for Request<'a, 'b> {}
<commit_msg>(fix) Don't reject HTTP <= 1.0 requests without a Host header. [Fixes #327]<commit_after>//! Iron's HTTP Request representation and associated methods.

use std::io::{self, Read};
use std::net::SocketAddr;
use std::fmt::{self, Debug};

use hyper::uri::RequestUri::{AbsoluteUri, AbsolutePath};
use hyper::net::NetworkStream;
use hyper::http::h1::HttpReader;
use hyper::version::HttpVersion;

use typemap::TypeMap;
use plugin::Extensible;
use method::Method;

pub use hyper::server::request::Request as HttpRequest;
use hyper::buffer;

pub use self::url::Url;

use {Protocol, Plugin, Headers, Set, headers};

mod url;

/// The `Request` given to all `Middleware`.
///
/// Stores all the properties of the client's request plus
/// an `TypeMap` for data communication between middleware.
pub struct Request<'a, 'b: 'a> {
    /// The requested URL.
    pub url: Url,

    /// The originating address of the request.
    pub remote_addr: SocketAddr,

    /// The local address of the request.
    pub local_addr: SocketAddr,

    /// The request headers.
    pub headers: Headers,

    /// The request body as a reader.
    pub body: Body<'a, 'b>,

    /// The request method.
    pub method: Method,

    /// Extensible storage for data passed between middleware.
    pub extensions: TypeMap
}

impl<'a, 'b> Debug for Request<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "Request {{"));

        try!(writeln!(f, "    url: {:?}", self.url));
        try!(writeln!(f, "    method: {:?}", self.method));
        try!(writeln!(f, "    remote_addr: {:?}", self.remote_addr));
        try!(writeln!(f, "    local_addr: {:?}", self.local_addr));

        try!(write!(f, "}}"));
        Ok(())
    }
}

impl<'a, 'b> Request<'a, 'b> {
    /// Create a request from an HttpRequest.
    ///
    /// This constructor consumes the HttpRequest.
    pub fn from_http(req: HttpRequest<'a, 'b>, local_addr: SocketAddr, protocol: &Protocol)
                     -> Result<Request<'a, 'b>, String> {
        let (addr, method, headers, uri, version, reader) = req.deconstruct();

        let url = match uri {
            AbsoluteUri(ref url) => {
                match Url::from_generic_url(url.clone()) {
                    Ok(url) => url,
                    Err(e) => return Err(e)
                }
            },

            AbsolutePath(ref path) => {
                let url_string = match (version, headers.get::<headers::Host>()) {
                    (_, Some(ref host)) => {
                        // Attempt to prepend the Host header (mandatory in HTTP/1.1)
                        format!("{}://{}:{}{}", protocol.name(), host.hostname, local_addr.port(), path)
                    },
                    (v, None) if v < HttpVersion::Http11 => {
                        // Attempt to use the local address? (host header is not required in HTTP/1.0).
                        match local_addr {
                            SocketAddr::V4(addr4) => format!("{}://{}:{}{}", protocol.name(), addr4.ip(), local_addr.port(), path),
                            SocketAddr::V6(addr6) => format!("{}://[{}]:{}{}", protocol.name(), addr6.ip(), local_addr.port(), path),
                        }
                    },
                    (_, None) => {
                        return Err("No host specified in request".into())
                    }
                };

                match Url::parse(&url_string) {
                    Ok(url) => url,
                    Err(e) => return Err(format!("Couldn't parse requested URL: {}", e))
                }
            },
            _ => return Err("Unsupported request URI".into())
        };

        Ok(Request {
            url: url,
            remote_addr: addr,
            local_addr: local_addr,
            headers: headers,
            body: Body::new(reader),
            method: method,
            extensions: TypeMap::new()
        })
    }
}

/// The body of an Iron request,
pub struct Body<'a, 'b: 'a>(HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>);

impl<'a, 'b> Body<'a, 'b> {
    /// Create a new reader for use in an Iron request from a hyper HttpReader.
    pub fn new(reader: HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>) -> Body<'a, 'b> {
        Body(reader)
    }
}

impl<'a, 'b> Read for Body<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

// Allow plugins to attach to requests.
impl<'a, 'b> Extensible for Request<'a, 'b> {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl<'a, 'b> Plugin for Request<'a, 'b> {}
impl<'a, 'b> Set for Request<'a, 'b> {}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/the-number-of-weak-characters-in-the-game/
pub fn number_of_weak_characters(mut properties: Vec<Vec<i32>>) -> i32 {
    properties.sort_by_key(|v| (v[0], v[1]));
    let mut suffix_attack = vec![0; properties.len()];
    let mut suffix_defense = vec![0; properties.len()];
    for i in (0..properties.len()).rev() {
        let v = &properties[i];
        if i == properties.len() - 1 {
            suffix_attack[i] = v[0];
            suffix_defense[i] = v[1];
        } else {
            suffix_attack[i] = v[0].max(suffix_attack[i + 1]);
            suffix_defense[i] = v[1].max(suffix_defense[i + 1]);
        }
    }
    let mut answer = 0;
    println!("{:?}", properties);
    println!("{:?}", suffix_attack);
    println!("{:?}", suffix_defense);
    for i in 0..properties.len() - 1 {
        let attack = properties[i][0];
        let defense = properties[i][1];
        if attack < suffix_attack[i + 1] && defense < suffix_defense[i + 1] {
            answer += 1;
        }
    }
    answer
}

fn main() {
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![5, 5], vec![6, 3], vec![3, 6]])
    // ); // 0
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![2, 2], vec![3, 3]])
    // ); // 1
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3]])
    // ); // 1
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3], vec![5, 5]])
    // ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![
            vec![7, 9],
            vec![10, 7],
            vec![6, 9],
            vec![10, 4],
            vec![7, 5],
            vec![7, 10]
        ])
    ); // 2
}
<commit_msg>Update problem 1996<commit_after>use std::collections::BTreeMap;

// https://leetcode.com/problems/the-number-of-weak-characters-in-the-game/
pub fn number_of_weak_characters(mut properties: Vec<Vec<i32>>) -> i32 {
    let mut map: BTreeMap<i32, Vec<i32>> = BTreeMap::new();
    for prop in properties.iter() {
        map.entry(prop[0]).or_insert(vec![]).push(prop[1]);
    }
    let mut suffix_defense = vec![0; map.len()];
    for (i, (_, defenses)) in map.iter().enumerate().rev() {
        let max_defense = defenses.iter().max().unwrap();
        if i == map.len() - 1 {
            suffix_defense[i] = *max_defense;
        } else {
            suffix_defense[i] = *max_defense.max(&suffix_defense[i + 1]);
        }
    }
    let mut answer = 0;
    for (i, (_, defenses)) in map.iter().enumerate() {
        for defense in defenses.iter() {
            if i + 1 < map.len() && *defense < suffix_defense[i + 1] {
                answer += 1;
            }
        }
    }
    answer
}

fn main() {
    println!(
        "{}",
        number_of_weak_characters(vec![vec![5, 5], vec![6, 3], vec![3, 6]])
    ); // 0
    println!(
        "{}",
        number_of_weak_characters(vec![vec![2, 2], vec![3, 3]])
    ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3]])
    ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3], vec![5, 5]])
    ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![
            vec![7, 9],
            vec![10, 7],
            vec![6, 9],
            vec![10, 4],
            vec![7, 5],
            vec![7, 10]
        ])
    ); // 2
}
<|endoftext|>


<commit_before>use regex::{Regex, Captures};

static PARAMS: Regex = regex!(r":([a-zA-Z0-9_-]*)");

pub fn deglob(glob: String) -> Regex {
    // Replace glob patterns with corresponding regexs.
    let deglobbed = glob
        // Have to do this because the ** regex contains *
        .replace("**", "___DOUBLE_WILDCARD___")
        // Now only __DOUBLE_WILDCARD___ remains.
        .replace("*", "[a-zA-Z0-9_-]*")
        // Replace ** with its associated regex.
        .replace("___DOUBLE_WILDCARD___", "[/a-zA-Z0-9_-]*");
    // Replace :param patterns with corresponding regexs.
    let debound = PARAMS
        .replace_all(deglobbed.as_slice(), |cap: &Captures| {
            "(?P<".to_string().append(cap.at(1)).append(">[a-zA-Z0-9_-]*)")
        });
    Regex::new("^".to_string().append(debound.as_slice()).append("$").as_slice()).unwrap()
}

<commit_msg>(test) Added tests for de-globbing of routes.<commit_after>use regex::{Regex, Captures};

static PARAMS: Regex = regex!(r":([a-zA-Z0-9_-]*)");

pub fn deglob(glob: String) -> Regex {
    // Replace glob patterns with corresponding regexs.
    let deglobbed = glob
        // Have to do this because the ** regex contains *
        .replace("**", "___DOUBLE_WILDCARD___")
        // Now only __DOUBLE_WILDCARD___ remains.
        .replace("*", "[a-zA-Z0-9_-]*")
        // Replace ** with its associated regex.
        .replace("___DOUBLE_WILDCARD___", "[/a-zA-Z0-9_-]*");
    // Replace :param patterns with corresponding regexs.
    let debound = PARAMS
        .replace_all(deglobbed.as_slice(), |cap: &Captures| {
            "(?P<".to_string().append(cap.at(1)).append(">[a-zA-Z0-9_-]*)")
        });
    Regex::new("^".to_string().append(debound.as_slice()).append("$").as_slice()).unwrap()
}

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

    #[test]
    fn test_segment_match() {
        // Do literal matches work?
        let glob_regex = deglob("/users/nested/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(!glob_regex.is_match("/notusers/hello"))
    }

    #[test]
    fn test_wildcard_match() {
        // Do wilcard matches work?
        let glob_regex = deglob("/users/*/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/users/deeply/nested/groups"));
    }

    #[test]
    fn test_double_wildcard_match() {
        // Do double wildcard matches work?
        let glob_regex = deglob("/users/**/groups".to_string());
        assert!(glob_regex.is_match("/users/deeply/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/notusers/groups/"))
    }

    #[test]
    fn test_params_match() {
        // Does param matching work?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert!(glob_regex.is_match("/users/73564/87684"));
        assert!(!glob_regex.is_match("/users/234/groups/2343"));
    }

    #[test]
    fn test_params_value() {
        // Do params have the correct value?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("userid"), "234");
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("groupid"), "7374");
    }
}

<|endoftext|>


<commit_before>#[macro_use(handler)]
extern crate chatbot;
extern crate getopts;

use std::env;

use chatbot::Chatbot;
use chatbot::adapter::{CliAdapter, SlackAdapter, IrcAdapter};

use getopts::Options;
use getopts::ParsingStyle;

fn main() {
    let args = env::args().collect::<Vec<String>>();
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);
    opts.optopt("a", "adapter", "Chat Adapter to use", "slack|cli");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };

    let adapter_name = matches.opt_str("a").unwrap_or("cli".to_owned());

    let name = "chatbotbot";
    let mut bot = Chatbot::new(name);

    // Add adapter based on command line argument
    match adapter_name.as_ref() {
        "slack" => bot.add_adapter(SlackAdapter::new()),
        "cli" => bot.add_adapter(CliAdapter::new(name)),
        "irc" => {
            let config = chatbot::adapter::IrcConfig {
                nickname: Some(format!("{}", name)),
                alt_nicks: Some(vec![format!("{}_", name), format!("{}__", name)]),
                server: Some(format!("irc.mozilla.org")),
                channels: Some(vec![format!("#chatbot")]),
                .. Default::default()
            };
            bot.add_adapter(IrcAdapter::new(config, name))
        },
        _ => panic!("Unexpected adapter name. Use 'cli' or 'slack'.")
    };

    let ping = handler!("PingHandler", r"ping", |_, _| { Some("pong".to_owned()) });

    let trout = handler!("TroutSlap", r"slap (?P<user>.+)", move |matches, _| {
        match matches.name("user") {
            Some(user) => {
                Some(format!("{} slaps {} around a bit with a large trout",
                             name, user))
            },
            None => None
        }
    });

    let echo = handler!("EchoHandler", r"echo (?P<msg>.+)", |matches, _| {
        matches.name("msg").map(|msg| { msg.to_owned() })
    });

    bot.add_handler(ping);
    bot.add_addressed_handler(trout);
    bot.add_handler(echo);

    bot.run();
}
<commit_msg>example: pass in bot_name for slack adapter<commit_after>#[macro_use(handler)]
extern crate chatbot;
extern crate getopts;

use std::env;

use chatbot::Chatbot;
use chatbot::adapter::{CliAdapter, SlackAdapter, IrcAdapter};

use getopts::Options;
use getopts::ParsingStyle;

fn main() {
    let args = env::args().collect::<Vec<String>>();
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);
    opts.optopt("a", "adapter", "Chat Adapter to use", "slack|cli");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };

    let adapter_name = matches.opt_str("a").unwrap_or("cli".to_owned());

    let name = "chatbotbot";
    let mut bot = Chatbot::new(name);

    // Add adapter based on command line argument
    match adapter_name.as_ref() {
        "slack" => bot.add_adapter(SlackAdapter::new(name)),
        "cli" => bot.add_adapter(CliAdapter::new(name)),
        "irc" => {
            let config = chatbot::adapter::IrcConfig {
                nickname: Some(format!("{}", name)),
                alt_nicks: Some(vec![format!("{}_", name), format!("{}__", name)]),
                server: Some(format!("irc.mozilla.org")),
                channels: Some(vec![format!("#chatbot")]),
                .. Default::default()
            };
            bot.add_adapter(IrcAdapter::new(config, name))
        },
        _ => panic!("Unexpected adapter name. Use 'cli' or 'slack'.")
    };

    let ping = handler!("PingHandler", r"ping", |_, _| { Some("pong".to_owned()) });

    let trout = handler!("TroutSlap", r"slap (?P<user>.+)", move |matches, _| {
        match matches.name("user") {
            Some(user) => {
                Some(format!("{} slaps {} around a bit with a large trout",
                             name, user))
            },
            None => None
        }
    });

    let echo = handler!("EchoHandler", r"echo (?P<msg>.+)", |matches, _| {
        matches.name("msg").map(|msg| { msg.to_owned() })
    });

    bot.add_handler(ping);
    bot.add_addressed_handler(trout);
    bot.add_handler(echo);

    bot.run();
}
<|endoftext|>


<commit_before>const STEP_TABLE: [u32; 89] = [
    7,     8,     9,     10,    11,    12,     13,    14,    16,
    17,    19,    21,    23,    25,    28,     31,    34,    37,
    41,    45,    50,    55,    60,    66,     73,    80,    88,
    97,    107,   118,   130,   143,   157,    173,   190,   209,
    230,   253,   279,   307,   337,   371,    408,   449,   494,
    544,   598,   658,   724,   796,   876,    963,   1060,  1166,
    1282,  1411,  1552,  1707,  1878,  2066,   2272,  2499,  2749,
    3024,  3327,  3660,  4026,  4428,  4871,   5358,  5894,  6484,
    7132,  7845,  8630,  9493,  10442, 11487,  12635, 13899, 15289,
    16818, 18500, 20350, 22385, 24623, 27086,  29794, 32767
];

const INDEX_ADJUSTMENT: [i32; 16] = [
    -1, -1, -1, -1, 2, 4, 6, 8,
    -1, -1, -1, -1, 2, 4, 6, 8
];

pub struct CodecState {
    sample: i32,
    index: i32
}

impl CodecState {
    pub fn new() -> CodecState {
        CodecState {
            sample: 0,
            index: 0
        }
    }
}

/// Decompress samples of a _single_ audio channel.
///
/// Pass in a separate `state` for each channel
pub fn decompress(state: &mut CodecState, input: &[u8]) -> Box<[u16]> {
    let mut buffer = Vec::with_capacity(input.len() * 2);
    let mut low_nibble = true;
    let mut i = 0;

    while i < input.len() {
        let mut code;
        if low_nibble {
            code = input[i] & 0xf;
        } else {
            code = (input[i] >> 4) & 0xf;
            i += 1;
        };
        low_nibble = !low_nibble;

        let sb = if code & 0x8 != 0 { 1 } else { 0 };
        code &= 0x7;
        let mut delta = ((STEP_TABLE[state.index as usize]*code as u32) / 4 + STEP_TABLE[state.index as usize] / 8) as i32;
        if sb == 1 { delta = -delta; }

        state.sample += delta;
        if state.sample > 32767 { state.sample = 32767; }
        else if state.sample < -32768 { state.sample = -32768; }

        buffer.push(state.sample as u16);

        state.index += INDEX_ADJUSTMENT[code as usize];
        if state.index < 0 { state.index = 0; }
        else if state.index > 88 { state.index = 88; }
    }

    buffer.into_boxed_slice()
}
<commit_msg>document algorithm used in codec::decompress<commit_after>const STEP_TABLE: [u32; 89] = [
    7,     8,     9,     10,    11,    12,     13,    14,    16,
    17,    19,    21,    23,    25,    28,     31,    34,    37,
    41,    45,    50,    55,    60,    66,     73,    80,    88,
    97,    107,   118,   130,   143,   157,    173,   190,   209,
    230,   253,   279,   307,   337,   371,    408,   449,   494,
    544,   598,   658,   724,   796,   876,    963,   1060,  1166,
    1282,  1411,  1552,  1707,  1878,  2066,   2272,  2499,  2749,
    3024,  3327,  3660,  4026,  4428,  4871,   5358,  5894,  6484,
    7132,  7845,  8630,  9493,  10442, 11487,  12635, 13899, 15289,
    16818, 18500, 20350, 22385, 24623, 27086,  29794, 32767
];

const INDEX_ADJUSTMENT: [i32; 16] = [
    -1, -1, -1, -1, 2, 4, 6, 8,
    -1, -1, -1, -1, 2, 4, 6, 8
];

pub struct CodecState {
    sample: i32,
    index: i32
}

impl CodecState {
    pub fn new() -> CodecState {
        CodecState {
            sample: 0,
            index: 0
        }
    }
}

/// Decompress samples of a _single_ audio channel using the IMA ADPCM algorithm.
///
/// Pass in a separate `state` for each channel
pub fn decompress(state: &mut CodecState, input: &[u8]) -> Box<[u16]> {
    let mut buffer = Vec::with_capacity(input.len() * 2);
    let mut low_nibble = true;
    let mut i = 0;

    while i < input.len() {
        let mut code;
        if low_nibble {
            code = input[i] & 0xf;
        } else {
            code = (input[i] >> 4) & 0xf;
            i += 1;
        };
        low_nibble = !low_nibble;

        let sb = if code & 0x8 != 0 { 1 } else { 0 };
        code &= 0x7;
        let mut delta = ((STEP_TABLE[state.index as usize]*code as u32) / 4 + STEP_TABLE[state.index as usize] / 8) as i32;
        if sb == 1 { delta = -delta; }

        state.sample += delta;
        if state.sample > 32767 { state.sample = 32767; }
        else if state.sample < -32768 { state.sample = -32768; }

        buffer.push(state.sample as u16);

        state.index += INDEX_ADJUSTMENT[code as usize];
        if state.index < 0 { state.index = 0; }
        else if state.index > 88 { state.index = 88; }
    }

    buffer.into_boxed_slice()
}
<|endoftext|>


<commit_before>//! The ssh communication server, decisions will be made here, of how to interact with
//! the clients, is basically still taken from trussh example (with corrections)
use super::super::data::DataSession;
use bincode;
use futures;
use libp2p::PeerId;
use std;
use thrussh::{
    self,
    server::{self, Auth, Session},
    ChannelId,
};
use thrussh_keys::{self, key};

#[derive(Clone)]
pub struct ComServer {
    pub peer_id: PeerId,
}

impl server::Server for ComServer {
    type Handler = Self;
    fn new(&mut self) -> Self {
        self.clone()
    }
}

impl thrussh::server::Handler for ComServer {
    type Error = std::io::Error;
    type FutureAuth = futures::Finished<(Self, server::Auth), Self::Error>;
    type FutureUnit = futures::Finished<(Self, server::Session), Self::Error>;
    type FutureBool = futures::Finished<(Self, server::Session, bool), Self::Error>;

    fn finished_auth(self, auth: Auth) -> Self::FutureAuth {
        futures::finished((self, auth))
    }
    fn finished_bool(self, session: Session, b: bool) -> Self::FutureBool {
        futures::finished((self, session, b))
    }
    fn finished(self, session: Session) -> Self::FutureUnit {
        futures::finished((self, session))
    }

    fn auth_publickey(self, _: &str, _: &key::PublicKey) -> Self::FutureAuth {
        futures::finished((self, server::Auth::Accept))
    }
    fn data(
        self,
        channel: ChannelId,
        data: &[u8],
        mut session: server::Session,
    ) -> Self::FutureUnit {
        let session_data: Result<DataSession, _> = bincode::deserialize_from(data);
        match session_data {
            Ok(deserialized) => match deserialized {
                DataSession::Auth { ref auth } => {
                    let client_id_string = format!("{:?}", auth.get_id());
                    let client_version = auth.get_version();
                    info!(
                        "Srv[{:?}]: auth from channel {:?}: with id {:?} and version {:?}",
                        self.peer_id.to_string(),
                        channel,
                        client_id_string,
                        client_version
                    );
                }
                DataSession::Data { .. } => {
                    info!(
                        "Srv[{:?}]: data from channel {:?}: {:?}",
                        self.peer_id.to_string(),
                        channel,
                        std::str::from_utf8(data)
                    );
                }
            },
            Err(_) => {
                info!(
                    "Srv[{:?}]: not valid session data on channel {:?}: {:?}",
                    self.peer_id.to_string(),
                    channel,
                    std::str::from_utf8(data)
                );
            }
        }
        session.data(channel, None, data);
        futures::finished((self, session))
    }
}

impl ComServer {
    pub fn create_key_file(_name: &str) -> Result<(), thrussh_keys::Error> {
        match key::KeyPair::generate_ed25519() {
            Some(key::KeyPair::Ed25519(..)) => {
                //println!("{:?}",edkey);
            }
            Some(key::KeyPair::RSA { .. }) => {
                // to be done
            }
            None => {}
        }
        //
        Ok(())
    }
}
<commit_msg>[libp2p migration] removed unneeded key generation<commit_after>//! The ssh communication server, decisions will be made here, of how to interact with
//! the clients, is basically still taken from trussh example (with corrections)
use super::super::data::DataSession;
use bincode;
use futures;
use libp2p::PeerId;
use std;
use thrussh::{
    self,
    server::{self, Auth, Session},
    ChannelId,
};
use thrussh_keys::{self, key};

#[derive(Clone)]
pub struct ComServer {
    pub peer_id: PeerId,
}

impl server::Server for ComServer {
    type Handler = Self;
    fn new(&mut self) -> Self {
        self.clone()
    }
}

impl thrussh::server::Handler for ComServer {
    type Error = std::io::Error;
    type FutureAuth = futures::Finished<(Self, server::Auth), Self::Error>;
    type FutureUnit = futures::Finished<(Self, server::Session), Self::Error>;
    type FutureBool = futures::Finished<(Self, server::Session, bool), Self::Error>;

    fn finished_auth(self, auth: Auth) -> Self::FutureAuth {
        futures::finished((self, auth))
    }
    fn finished_bool(self, session: Session, b: bool) -> Self::FutureBool {
        futures::finished((self, session, b))
    }
    fn finished(self, session: Session) -> Self::FutureUnit {
        futures::finished((self, session))
    }

    fn auth_publickey(self, _: &str, _: &key::PublicKey) -> Self::FutureAuth {
        futures::finished((self, server::Auth::Accept))
    }
    fn data(
        self,
        channel: ChannelId,
        data: &[u8],
        mut session: server::Session,
    ) -> Self::FutureUnit {
        let session_data: Result<DataSession, _> = bincode::deserialize_from(data);
        match session_data {
            Ok(deserialized) => match deserialized {
                DataSession::Auth { ref auth } => {
                    let client_id_string = format!("{:?}", auth.get_id());
                    let client_version = auth.get_version();
                    info!(
                        "Srv[{:?}]: auth from channel {:?}: with id {:?} and version {:?}",
                        self.peer_id.to_string(),
                        channel,
                        client_id_string,
                        client_version
                    );
                }
                DataSession::Data { .. } => {
                    info!(
                        "Srv[{:?}]: data from channel {:?}: {:?}",
                        self.peer_id.to_string(),
                        channel,
                        std::str::from_utf8(data)
                    );
                }
            },
            Err(_) => {
                info!(
                    "Srv[{:?}]: not valid session data on channel {:?}: {:?}",
                    self.peer_id.to_string(),
                    channel,
                    std::str::from_utf8(data)
                );
            }
        }
        session.data(channel, None, data);
        futures::finished((self, session))
    }
}
<|endoftext|>


<commit_before>//! Aead Ciphers

use crate::crypto::cipher::{CipherCategory, CipherResult, CipherType};

#[cfg(feature = "ring-aead-ciphers")]
use crate::crypto::ring::RingAeadCipher;
#[cfg(feature = "aes-pmac-siv")]
use crate::crypto::siv::MiscreantCipher;
#[cfg(feature = "sodium")]
use crate::crypto::sodium::SodiumAeadCipher;

use bytes::{Bytes, BytesMut};
use hkdf::Hkdf;
use sha1::Sha1;

/// Encryptor API for AEAD ciphers
pub trait AeadEncryptor {
    /// Encrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() + tag.len()`.
    /// ```plain
    /// +----------------------------------------+-----------------------+
    /// | ENCRYPTED TEXT (length = input.len())  | TAG                   |
    /// +----------------------------------------+-----------------------+
    /// ```
    fn encrypt(&mut self, input: &[u8], output: &mut [u8]);
}

/// Decryptor API for AEAD ciphers
pub trait AeadDecryptor {
    /// Decrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() - tag.len()`.
    /// ```plain
    /// +----------------------------------------+-----------------------+
    /// | ENCRYPTED TEXT (length = output.len()) | TAG                   |
    /// +----------------------------------------+-----------------------+
    /// ```
    fn decrypt(&mut self, input: &[u8], output: &mut [u8]) -> CipherResult<()>;
}

/// Variant `AeadDecryptor`
pub type BoxAeadDecryptor = Box<dyn AeadDecryptor + Send + 'static>;

/// Variant `AeadEncryptor`
pub type BoxAeadEncryptor = Box<dyn AeadEncryptor + Send + 'static>;

/// Generate a specific AEAD cipher encryptor
pub fn new_aead_encryptor(t: CipherType, key: &[u8], nonce: &[u8]) -> BoxAeadEncryptor {
    assert!(t.category() == CipherCategory::Aead);

    match t {
        #[cfg(feature = "ring-aead-ciphers")]
        CipherType::Aes128Gcm | CipherType::Aes256Gcm | CipherType::ChaCha20IetfPoly1305 => {
            Box::new(RingAeadCipher::new(t, key, nonce, true))
        }

        #[cfg(feature = "sodium")]
        CipherType::XChaCha20IetfPoly1305 => Box::new(SodiumAeadCipher::new(t, key, nonce)),

        #[cfg(feature = "aes-pmac-siv")]
        CipherType::Aes128PmacSiv | CipherType::Aes256PmacSiv => Box::new(MiscreantCipher::new(t, key, nonce)),

        _ => unreachable!(),
    }
}

/// Generate a specific AEAD cipher decryptor
pub fn new_aead_decryptor(t: CipherType, key: &[u8], nonce: &[u8]) -> BoxAeadDecryptor {
    assert!(t.category() == CipherCategory::Aead);

    match t {
        #[cfg(feature = "ring-aead-ciphers")]
        CipherType::Aes128Gcm | CipherType::Aes256Gcm | CipherType::ChaCha20IetfPoly1305 => {
            Box::new(RingAeadCipher::new(t, key, nonce, false))
        }

        #[cfg(feature = "sodium")]
        CipherType::XChaCha20IetfPoly1305 => Box::new(SodiumAeadCipher::new(t, key, nonce)),

        #[cfg(feature = "aes-pmac-siv")]
        CipherType::Aes128PmacSiv | CipherType::Aes256PmacSiv => Box::new(MiscreantCipher::new(t, key, nonce)),

        _ => unreachable!(),
    }
}

const SUBKEY_INFO: &[u8] = b"ss-subkey";

/// Make Session key
///
/// ## Session key (SIP007)
///
/// AEAD ciphers require a per-session subkey derived from the pre-shared master key using HKDF, and use the subkey
/// to encrypt/decrypt. Essentially it means we are moving from (M+N)-bit (PSK, nonce) pair to
/// (M+N)-bit (HKDF(PSK, salt), nonce) pair. Because HKDF is a PRF, the new construction significantly expands the
/// amount of randomness (from N to at least M where M is much greater than N), thus correcting the previously
/// mentioned design flaw.
///
/// Assuming we already have a user-supplied pre-shared master key PSK.
///
/// Function HKDF_SHA1 is a HKDF constructed using SHA1 hash. Its signature is
///
/// ```plain
/// HKDF_SHA1(secret_key, salt, info)
/// ```
///
/// The "info" string argument allows us to bind the derived subkey to a specific application context.
///
/// For AEAD ciphers, the encryption scheme is:
///
/// 1. Pick a random R-bit salt (R = max(128, len(SK)))
/// 2. Derive subkey SK = HKDF_SHA1(PSK, salt, "ss-subkey")
/// 3. Send salt
/// 4. For each chunk, encrypt and authenticate payload using SK with a counting nonce
///    (starting from 0 and increment by 1 after each use)
/// 5. Send encrypted chunk
pub fn make_skey(t: CipherType, key: &[u8], salt: &[u8]) -> Bytes {
    assert!(t.category() == CipherCategory::Aead);

    let hkdf = Hkdf::<Sha1>::new(Some(salt), key);

    let mut skey = BytesMut::with_capacity(key.len());
    unsafe {
        skey.set_len(key.len());
    }

    hkdf.expand(SUBKEY_INFO, &mut skey).unwrap();

    skey.freeze()
}

/// Increase nonce by 1
///
/// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk
#[cfg(feature = "sodium")]
pub fn increase_nonce(nonce: &mut [u8]) {
    use libsodium_sys::sodium_increment;

    unsafe {
        sodium_increment(nonce.as_mut_ptr(), nonce.len());
    }
}

/// Increase nonce by 1
///
/// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk
#[cfg(not(feature = "sodium"))]
pub fn increase_nonce(nonce: &mut [u8]) {
    for i in nonce {
        if std::u8::MAX == *i {
            *i = 0;
        } else {
            *i += 1;
            return;
        }
    }
}
<commit_msg>Impl increase_nonce with native Rust<commit_after>//! Aead Ciphers

use crate::crypto::cipher::{CipherCategory, CipherResult, CipherType};

#[cfg(feature = "ring-aead-ciphers")]
use crate::crypto::ring::RingAeadCipher;
#[cfg(feature = "aes-pmac-siv")]
use crate::crypto::siv::MiscreantCipher;
#[cfg(feature = "sodium")]
use crate::crypto::sodium::SodiumAeadCipher;

use bytes::{Bytes, BytesMut};
use cfg_if::cfg_if;
use hkdf::Hkdf;
use sha1::Sha1;

/// Encryptor API for AEAD ciphers
pub trait AeadEncryptor {
    /// Encrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() + tag.len()`.
    /// ```plain
    /// +----------------------------------------+-----------------------+
    /// | ENCRYPTED TEXT (length = input.len())  | TAG                   |
    /// +----------------------------------------+-----------------------+
    /// ```
    fn encrypt(&mut self, input: &[u8], output: &mut [u8]);
}

/// Decryptor API for AEAD ciphers
pub trait AeadDecryptor {
    /// Decrypt `input` to `output` with `tag`. `output.len()` should equals to `input.len() - tag.len()`.
    /// ```plain
    /// +----------------------------------------+-----------------------+
    /// | ENCRYPTED TEXT (length = output.len()) | TAG                   |
    /// +----------------------------------------+-----------------------+
    /// ```
    fn decrypt(&mut self, input: &[u8], output: &mut [u8]) -> CipherResult<()>;
}

/// Variant `AeadDecryptor`
pub type BoxAeadDecryptor = Box<dyn AeadDecryptor + Send + 'static>;

/// Variant `AeadEncryptor`
pub type BoxAeadEncryptor = Box<dyn AeadEncryptor + Send + 'static>;

/// Generate a specific AEAD cipher encryptor
pub fn new_aead_encryptor(t: CipherType, key: &[u8], nonce: &[u8]) -> BoxAeadEncryptor {
    assert!(t.category() == CipherCategory::Aead);

    match t {
        #[cfg(feature = "ring-aead-ciphers")]
        CipherType::Aes128Gcm | CipherType::Aes256Gcm | CipherType::ChaCha20IetfPoly1305 => {
            Box::new(RingAeadCipher::new(t, key, nonce, true))
        }

        #[cfg(feature = "sodium")]
        CipherType::XChaCha20IetfPoly1305 => Box::new(SodiumAeadCipher::new(t, key, nonce)),

        #[cfg(feature = "aes-pmac-siv")]
        CipherType::Aes128PmacSiv | CipherType::Aes256PmacSiv => Box::new(MiscreantCipher::new(t, key, nonce)),

        _ => unreachable!(),
    }
}

/// Generate a specific AEAD cipher decryptor
pub fn new_aead_decryptor(t: CipherType, key: &[u8], nonce: &[u8]) -> BoxAeadDecryptor {
    assert!(t.category() == CipherCategory::Aead);

    match t {
        #[cfg(feature = "ring-aead-ciphers")]
        CipherType::Aes128Gcm | CipherType::Aes256Gcm | CipherType::ChaCha20IetfPoly1305 => {
            Box::new(RingAeadCipher::new(t, key, nonce, false))
        }

        #[cfg(feature = "sodium")]
        CipherType::XChaCha20IetfPoly1305 => Box::new(SodiumAeadCipher::new(t, key, nonce)),

        #[cfg(feature = "aes-pmac-siv")]
        CipherType::Aes128PmacSiv | CipherType::Aes256PmacSiv => Box::new(MiscreantCipher::new(t, key, nonce)),

        _ => unreachable!(),
    }
}

const SUBKEY_INFO: &[u8] = b"ss-subkey";

/// Make Session key
///
/// ## Session key (SIP007)
///
/// AEAD ciphers require a per-session subkey derived from the pre-shared master key using HKDF, and use the subkey
/// to encrypt/decrypt. Essentially it means we are moving from (M+N)-bit (PSK, nonce) pair to
/// (M+N)-bit (HKDF(PSK, salt), nonce) pair. Because HKDF is a PRF, the new construction significantly expands the
/// amount of randomness (from N to at least M where M is much greater than N), thus correcting the previously
/// mentioned design flaw.
///
/// Assuming we already have a user-supplied pre-shared master key PSK.
///
/// Function HKDF_SHA1 is a HKDF constructed using SHA1 hash. Its signature is
///
/// ```plain
/// HKDF_SHA1(secret_key, salt, info)
/// ```
///
/// The "info" string argument allows us to bind the derived subkey to a specific application context.
///
/// For AEAD ciphers, the encryption scheme is:
///
/// 1. Pick a random R-bit salt (R = max(128, len(SK)))
/// 2. Derive subkey SK = HKDF_SHA1(PSK, salt, "ss-subkey")
/// 3. Send salt
/// 4. For each chunk, encrypt and authenticate payload using SK with a counting nonce
///    (starting from 0 and increment by 1 after each use)
/// 5. Send encrypted chunk
pub fn make_skey(t: CipherType, key: &[u8], salt: &[u8]) -> Bytes {
    assert!(t.category() == CipherCategory::Aead);

    let hkdf = Hkdf::<Sha1>::new(Some(salt), key);

    let mut skey = BytesMut::with_capacity(key.len());
    unsafe {
        skey.set_len(key.len());
    }

    hkdf.expand(SUBKEY_INFO, &mut skey).unwrap();

    skey.freeze()
}

cfg_if! {
    if #[cfg(feature = "sodium")] {
        /// Increase nonce by 1
        ///
        /// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk (Little-Endian)
        pub fn increase_nonce(nonce: &mut [u8]) {
            use libsodium_sys::sodium_increment;

            unsafe {
                sodium_increment(nonce.as_mut_ptr(), nonce.len());
            }
        }
    } else {
        if #[cfg(target_endian = "little")] {
            if #[cfg(target_pointer_width = "32")] {
                /// Increase nonce by 1
                ///
                /// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk (Little-Endian)
                #[inline]
                pub fn increase_nonce(nonce: &mut [u8]) {
                    increase_nonce_32_le(nonce);
                }

            } else if #[cfg(target_pointer_width = "64")] {
                /// Increase nonce by 1
                ///
                /// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk (Little-Endian)
                #[inline]
                pub fn increase_nonce(nonce: &mut [u8]) {
                    increase_nonce_64_le(nonce);
                }
            } else {
                /// Increase nonce by 1
                ///
                /// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk (Little-Endian)
                #[inline]
                pub fn increase_nonce(nonce: &mut [u8]) {
                    increase_nonce_classic_le(nonce);
                }
            }

        } else {
            /// Increase nonce by 1
            ///
            /// AEAD ciphers requires to increase nonce after encrypt/decrypt every chunk (Little-Endian)
            #[inline]
            pub fn increase_nonce(nonce: &mut [u8]) {
                // Since current arthitecture is BE, integer add operations must be called after bswap operation.
                // bswap operation in most platforms are combinations of many instructions.
                increase_nonce_classic_le(nonce);
            }
        }
    }
}

#[allow(dead_code)]
fn increase_nonce_classic_le(nonce: &mut [u8]) {
    for i in nonce {
        if u8::MAX == *i {
            *i = 0;
        } else {
            *i += 1;
            return;
        }
    }
}

#[allow(dead_code)]
fn increase_nonce_32_le(nonce: &mut [u8]) {
    let data = nonce.as_mut_ptr();

    let mut i = 0;
    while i + 4 < nonce.len() {
        let v = unsafe { &mut *(data.offset(i as isize) as *mut u32) };
        if *v == u32::MAX {
            *v = 0;
        } else {
            *v += 1;
            return;
        }
        i += 4;
    }

    if i < nonce.len() {
        increase_nonce_classic_le(&mut nonce[i..]);
    }
}

#[allow(dead_code)]
fn increase_nonce_64_le(nonce: &mut [u8]) {
    let data = nonce.as_mut_ptr();

    let mut i = 0;
    while i + 8 < nonce.len() {
        let v = unsafe { &mut *(data.offset(i as isize) as *mut u64) };
        if *v == u64::MAX {
            *v = 0;
        } else {
            *v += 1;
            return;
        }
        i += 8;
    }

    if i + 4 < nonce.len() {
        increase_nonce_32_le(&mut nonce[i..]);
    } else if i < nonce.len() {
        increase_nonce_classic_le(&mut nonce[i..]);
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn increase_nonce_classic_le() {
        let mut v1 = [0, 0, 0, 0];
        super::increase_nonce_classic_le(&mut v1);
        assert_eq!(v1, [1, 0, 0, 0]);

        let mut v2 = [0xff, 0, 0, 0];
        super::increase_nonce_classic_le(&mut v2);
        assert_eq!(v2, [0, 1, 0, 0]);

        let mut v3 = [0xff, 0xff, 0xff, 0xff];
        super::increase_nonce_classic_le(&mut v3);
        assert_eq!(v3, [0, 0, 0, 0]);
    }

    #[test]
    #[cfg(target_endian = "little")]
    fn increase_nonce_32_le() {
        let mut v1 = [0, 0, 0, 0];
        super::increase_nonce_32_le(&mut v1);
        assert_eq!(v1, [1, 0, 0, 0]);

        let mut v2 = [0xff, 0, 0, 0];
        super::increase_nonce_32_le(&mut v2);
        assert_eq!(v2, [0, 1, 0, 0]);

        let mut v3 = [0xff, 0xff, 0xff, 0xff];
        super::increase_nonce_32_le(&mut v3);
        assert_eq!(v3, [0, 0, 0, 0]);

        let mut v4 = [0, 0, 0, 0, 0, 0];
        super::increase_nonce_32_le(&mut v4);
        assert_eq!(v4, [1, 0, 0, 0, 0, 0]);

        let mut v5 = [0xff, 0xff, 0xff, 0xff, 0, 0];
        super::increase_nonce_32_le(&mut v5);
        assert_eq!(v5, [0, 0, 0, 0, 1, 0]);
    }

    #[test]
    #[cfg(target_endian = "little")]
    fn increase_nonce_64_le() {
        let mut v1 = [0, 0, 0, 0, 0, 0, 0, 0];
        super::increase_nonce_64_le(&mut v1);
        assert_eq!(v1, [1, 0, 0, 0, 0, 0, 0, 0]);

        let mut v2 = [0xff, 0, 0, 0, 0, 0, 0, 0];
        super::increase_nonce_64_le(&mut v2);
        assert_eq!(v2, [0, 1, 0, 0, 0, 0, 0, 0]);

        let mut v3 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
        super::increase_nonce_64_le(&mut v3);
        assert_eq!(v3, [0, 0, 0, 0, 0, 0, 0, 0]);

        let mut v4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        super::increase_nonce_64_le(&mut v4);
        assert_eq!(v4, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

        let mut v5 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0];
        super::increase_nonce_64_le(&mut v5);
        assert_eq!(v5, [0, 0, 0, 0, 0, 0, 0, 0, 1, 0]);

        let mut v6 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0];
        super::increase_nonce_64_le(&mut v6);
        assert_eq!(v6, [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>use self::super::{MAP, StatusCode};
use self::super::super::http;

pub fn close(ctn: u16) -> StatusCode {
    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return StatusCode::ErrInvalid;
    }

    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            StatusCode::ErrHtsi
        }
        Ok(res) => {
            match res.status {
                200 => handle_ok_status(res.body, ctn),
                _ => {
                    error!("Request failed! Server response was not OK!");
                    return StatusCode::ErrHtsi;
                }
            }
        }
    }
}

fn handle_ok_status(body: String, ctn: u16) -> StatusCode {
    match body.parse::<i8>() {
        Ok(status) => {
            match StatusCode::from_i8(status) {
                Ok(code) => {
                    match code {
                        StatusCode::Ok => {
                            // Remove CTN
                            MAP.lock().unwrap().remove(&ctn);
                            debug!("Card terminal has been closed.");
                            code
                        }
                        _ => code,
                    }
                }
                _ => {
                    error!("Unexpected server reponse body!");
                    StatusCode::ErrHtsi
                }
            }
        }
        _ => {
            error!("Unexpected server reponse body!");
            StatusCode::ErrHtsi
        }
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use mockito;
    use mockito::mock;
    use rand;
    use std::env;

    #[test]
    fn call_close_on_closed_terminal_returns_minus_1() {
        let ctn = rand::random::<u16>();
        assert_eq!(-1, close(ctn))
    }

    macro_rules! with_server_response {
        ($($name:ident: $value:expr,)*) => {
            $(
                #[test]
                fn $name() {
                    let (status, body, expected, map_contains_ctn) = $value;

                    let ctn = rand::random::<u16>();
                    let pn = rand::random::<u16>();

                    MAP.lock().unwrap().insert(ctn, pn);

                    let path = format!("/ct_close/{}/{}", ctn, pn);
                    let _mock = mock("POST", path.as_str())
                        .with_status(status)
                        .with_body(body)
                        .create();

                    env::set_var("K2_BASE_URL", mockito::SERVER_URL);

                    assert_eq!(expected, close(ctn));
                    assert_eq!(map_contains_ctn, MAP.lock().unwrap().contains_key(&ctn));

                    mockito::reset();
                }
            )*
        }
    }

    with_server_response! {
        not_found_returns_minus_128: (400, "Not found", -128, true),
        incorrect_response_returns_minus_128: (200, "hello world", -128, true),
        minus_1_response_returns_minus_1: (200, "-1", -1, true),
        zero_response_return_0: (200, "0", 0, false),
    }
}
<commit_msg>add test for ct_close when server is not up<commit_after>use self::super::{MAP, StatusCode};
use self::super::super::http;

pub fn close(ctn: u16) -> StatusCode {
    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return StatusCode::ErrInvalid;
    }

    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            StatusCode::ErrHtsi
        }
        Ok(res) => {
            match res.status {
                200 => handle_ok_status(res.body, ctn),
                _ => {
                    error!("Request failed! Server response was not OK!");
                    return StatusCode::ErrHtsi;
                }
            }
        }
    }
}

fn handle_ok_status(body: String, ctn: u16) -> StatusCode {
    match body.parse::<i8>() {
        Ok(status) => {
            match StatusCode::from_i8(status) {
                Ok(code) => {
                    match code {
                        StatusCode::Ok => {
                            // Remove CTN
                            MAP.lock().unwrap().remove(&ctn);
                            debug!("Card terminal has been closed.");
                            code
                        }
                        _ => code,
                    }
                }
                _ => {
                    error!("Unexpected server reponse body!");
                    StatusCode::ErrHtsi
                }
            }
        }
        _ => {
            error!("Unexpected server reponse body!");
            StatusCode::ErrHtsi
        }
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use mockito;
    use mockito::mock;
    use rand;
    use std::env;

    #[test]
    fn call_close_when_server_not_up_returns_minus_128() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().unwrap().insert(ctn, pn);

        env::set_var("K2_BASE_URL", mockito::SERVER_URL);

        assert_eq!(-128, close(ctn))
    }

    #[test]
    fn call_close_on_closed_terminal_returns_minus_1() {
        let ctn = rand::random::<u16>();
        assert_eq!(-1, close(ctn))
    }

    macro_rules! with_server_response {
        ($($name:ident: $value:expr,)*) => {
            $(
                #[test]
                fn $name() {
                    let (status, body, expected, map_contains_ctn) = $value;

                    let ctn = rand::random::<u16>();
                    let pn = rand::random::<u16>();

                    MAP.lock().unwrap().insert(ctn, pn);

                    let path = format!("/ct_close/{}/{}", ctn, pn);
                    let _mock = mock("POST", path.as_str())
                        .with_status(status)
                        .with_body(body)
                        .create();

                    env::set_var("K2_BASE_URL", mockito::SERVER_URL);

                    assert_eq!(expected, close(ctn));
                    assert_eq!(map_contains_ctn, MAP.lock().unwrap().contains_key(&ctn));

                    mockito::reset();
                }
            )*
        }
    }

    with_server_response! {
        not_found_returns_minus_128: (400, "Not found", -128, true),
        incorrect_response_returns_minus_128: (200, "hello world", -128, true),
        minus_1_response_returns_minus_1: (200, "-1", -1, true),
        zero_response_return_0: (200, "0", 0, false),
    }
}
<|endoftext|>


<commit_before>//! # `local` - operate on the locally stored files and blobs of a given repository.
//!
//! The `Local` type represents a properly configured local (file system) object store.
//! Writing/reading objects in a `Local` store is asynchronous.

use std::collections::HashMap;
use std::fs::{self, File};
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use std::result::Result as StdResult;
use std::sync::{Arc, Mutex};

use futures::prelude::*;
use futures_bufio::BufWriter;
use futures_cpupool::CpuPool;
use memmap::{Mmap, Protection};
use stable_deref_trait::StableDeref;

use arc_slice;
use catalog::{Catalog, CatalogLock};
use errors::*;
use marshal::{Hashed, ObjectHash, Object};
use repository::Paths;
use store::Store;

pub struct LocalBufferFactory {
    catalog_lock: CatalogLock,
    object_hash: ObjectHash,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
    path: PathBuf,
}

impl LocalBufferFactory {
    pub fn with_size(self, sz: usize) -> Result<LocalBuffer> {
        fs::create_dir_all(self.path.parent().unwrap())?;
        let file = File::create(&self.path)?;
        file.set_len(sz as u64)?;
        file.sync_all()?;
        let mmap = Mmap::open(&file, Protection::ReadWrite)?;

        Ok(LocalBuffer {
            catalog_lock: self.catalog_lock,
            object_hash: self.object_hash,
            objects: self.objects,
            mmap,
        })
    }
}

pub struct LocalBuffer {
    catalog_lock: CatalogLock,
    object_hash: ObjectHash,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
    mmap: Mmap,
}

impl LocalBuffer {
    pub fn finish(self) -> Box<Future<Item = Object, Error = Error> + Send> {
        let result = {
            async_block! {
                self.mmap.flush()?;
                let slice = arc_slice::mapped(self.mmap);
                let object = Object::from_bytes(slice)?;
                self.objects.lock().unwrap().insert(self.object_hash, object.clone());
                self.catalog_lock.release();
                Ok(object)
            }
        };

        Box::new(result)
    }
}

unsafe impl StableDeref for LocalBuffer {}

impl Deref for LocalBuffer {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe { self.mmap.as_slice() }
    }
}

impl DerefMut for LocalBuffer {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.mmap.as_mut_slice() }
    }
}

/// The type of a local object store.
// TODO: Store `Weak` references to `Mmap`s in `Local` so that we cut down on the number of file
// descriptors that our process owns.
#[derive(Debug, Clone)]
pub struct Local {
    paths: Arc<Paths>,
    io_pool: CpuPool,
    catalog: Catalog,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
}

impl Local {
    pub fn new(paths: &Arc<Paths>, catalog: &Catalog, io_pool: &CpuPool) -> Self {
        Self {
            paths: paths.clone(),
            io_pool: io_pool.clone(),
            catalog: catalog.clone(),
            objects: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    /// Write an object to the file system. Assuming the file has not yet been written, this will
    /// open and then close a file, and the resulting future will return `true` if the object has
    /// not been written and `false` if the object already exists in the catalog and no I/O was
    /// performed.
    pub fn write_object(&self, hashed: Hashed) -> Box<Future<Item = bool, Error = Error> + Send> {
        match self.catalog.try_lock(*hashed.as_hash()) {
            Ok(lock) => {
                match hashed.into_components() {
                    (hash, Some(bytes)) => {
                        let path = self.paths.blobs.join(hash.to_path());
                        let io_pool = self.io_pool.clone();

                        let result = {
                            async_block! {
                                fs::create_dir_all(path.parent().unwrap())?;
                                let file = File::create(path)?;
                                let bufwriter =
                                    BufWriter::with_pool_and_capacity(io_pool, 4096, file);

                                let bufwriter = match await!(bufwriter.write_all(bytes)) {
                                    Ok((writer, _)) => Ok(writer),
                                    Err((_, _, err)) => Err(err),
                                }?;

                                let bufwriter = await!(bufwriter.flush_buf()).map_err(|(_, err)| err)?;
                                await!(bufwriter.flush_inner()).map_err(|(_, err)| err)?;

                                lock.release();

                                Ok(true)
                            }
                        };

                        return Box::new(result);
                    }

                    (_, None) => {
                        panic!("Attempted to locally write file which should exist locally!");
                    }
                }
            }
            Err(entry) => Box::new(entry.map(|_| false)),
        }
    }

    /// Load an object from the file system. This will open a file if the object has not already
    /// been loaded.
    /// TODO: Make async.
    pub fn read_object(
        &self,
        object_hash: ObjectHash,
    ) -> Box<Future<Item = Object, Error = Error> + Send> {
        let path = self.paths.blobs.join(object_hash.to_path());
        let objects = self.objects.clone();
        let entry_opt = self.catalog.get(object_hash);

        let result = {
            async_block! {
                if let Some(entry) = entry_opt {
                    await!(entry)?;
                }

                if let Some(local) = objects.lock().unwrap().get(&object_hash) {
                    return Ok(local.clone());
                }

                let bytes = arc_slice::mapped(Mmap::open_path(path, Protection::Read)?);
                let object = Object::from_bytes(bytes)?;

                objects.lock().unwrap().insert(object_hash, object.clone());

                Ok(object)
            }
        };

        return Box::new(self.io_pool.spawn(result));
    }

    /// Load an object from the file system, *or*, create a new buffer for writing an object. This
    /// is used for remotes: either load an object from the file system instead of fetching it from
    /// a remote, or create a memory-mapped file buffer, write the serialized object to the buffer,
    /// and then re-protect the buffer as read-only and deserialize the object from it.
    pub fn read_or_allocate_object(
        &self,
        object_hash: ObjectHash,
    ) -> Box<Future<Item = StdResult<Object, LocalBufferFactory>, Error = Error> + Send> {
        let lock_res = self.catalog.try_lock(object_hash);

        match lock_res {
            Ok(lock) => {
                let path = self.paths.blobs.join(object_hash.to_path());
                let objects = self.objects.clone();

                let result = {
                    async_block! {
                        let local_buffer_factory = LocalBufferFactory {
                            catalog_lock: lock,
                            object_hash,
                            objects,
                            path,
                        };

                        Ok(Err(local_buffer_factory))
                    }
                };

                Box::new(result)
            }

            // The object is in the catalog or is currently being written. Defer to `read_object`
            // in order to wait for any potential lock to finish and then do an asynchronous read
            // of the object file.
            Err(_) => Box::new(self.read_object(object_hash).map(Ok)),
        }
    }

    //     /// Write a fully marshalled batch to the local repository.
    //     pub fn write_batch<T: Trace>(
    //         &mut self,
    //         batch: Batch<T::BatchTrace>,
    //     ) -> Box<Future<Item = (), Error = Error>> {
    //         unimplemented!()
    //                 let trace = Arc::new(Mutex::new(self.trace.lock().unwrap().on_write(
    //                     &batch,
    //                     WriteDestination::Local,
    //                 )));
    //
    //                 let local = self.clone();
    //
    //                 let writes = batch
    //                     .into_stream()
    //                     .map(move |hashed| {
    //                         let hash = *hashed.as_hash();
    //                         let trace = trace.clone();
    //
    //                         trace.lock().unwrap().on_begin(&hash);
    //                         let write = local.write_object(hashed).map(move |fresh| {
    //                             trace.lock().unwrap().on_complete(&hash, fresh);
    //                         });
    //                         local.io_pool.spawn(write)
    //                     })
    //                     .buffer_unordered(WRITE_FUTURE_BUFFER_SIZE)
    //                     .for_each(|_| Ok(()));
    //
    //                 Box::new(self.io_pool.spawn(writes))
    //     }
}

impl Store for Local {
    type Read = Box<Future<Item = Object, Error = Error> + Send>;
    type Write = Box<Future<Item = bool, Error = Error> + Send>;

    fn read_object(&self, object_hash: ObjectHash) -> Self::Read {
        self.read_object(object_hash)
    }

    fn write_object(&self, hashed: Hashed) -> Self::Write {
        self.write_object(hashed)
    }
}
<commit_msg>store/local.rs: Clarify error location when reading object<commit_after>//! # `local` - operate on the locally stored files and blobs of a given repository.
//!
//! The `Local` type represents a properly configured local (file system) object store.
//! Writing/reading objects in a `Local` store is asynchronous.

use std::collections::HashMap;
use std::fs::{self, File};
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use std::result::Result as StdResult;
use std::sync::{Arc, Mutex};

use futures::prelude::*;
use futures_bufio::BufWriter;
use futures_cpupool::CpuPool;
use memmap::{Mmap, Protection};
use stable_deref_trait::StableDeref;

use arc_slice;
use catalog::{Catalog, CatalogLock};
use errors::*;
use marshal::{Hashed, ObjectHash, Object};
use repository::Paths;
use store::Store;

pub struct LocalBufferFactory {
    catalog_lock: CatalogLock,
    object_hash: ObjectHash,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
    path: PathBuf,
}

impl LocalBufferFactory {
    pub fn with_size(self, sz: usize) -> Result<LocalBuffer> {
        fs::create_dir_all(self.path.parent().unwrap())?;
        let file = File::create(&self.path)?;
        file.set_len(sz as u64)?;
        file.sync_all()?;
        let mmap = Mmap::open(&file, Protection::ReadWrite)?;

        Ok(LocalBuffer {
            catalog_lock: self.catalog_lock,
            object_hash: self.object_hash,
            objects: self.objects,
            mmap,
        })
    }
}

pub struct LocalBuffer {
    catalog_lock: CatalogLock,
    object_hash: ObjectHash,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
    mmap: Mmap,
}

impl LocalBuffer {
    pub fn finish(self) -> Box<Future<Item = Object, Error = Error> + Send> {
        let result = {
            async_block! {
                self.mmap.flush()?;
                let slice = arc_slice::mapped(self.mmap);
                let object = Object::from_bytes(slice)?;
                self.objects.lock().unwrap().insert(self.object_hash, object.clone());
                self.catalog_lock.release();
                Ok(object)
            }
        };

        Box::new(result)
    }
}

unsafe impl StableDeref for LocalBuffer {}

impl Deref for LocalBuffer {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe { self.mmap.as_slice() }
    }
}

impl DerefMut for LocalBuffer {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.mmap.as_mut_slice() }
    }
}

/// The type of a local object store.
// TODO: Store `Weak` references to `Mmap`s in `Local` so that we cut down on the number of file
// descriptors that our process owns.
#[derive(Debug, Clone)]
pub struct Local {
    paths: Arc<Paths>,
    io_pool: CpuPool,
    catalog: Catalog,
    objects: Arc<Mutex<HashMap<ObjectHash, Object>>>,
}

impl Local {
    pub fn new(paths: &Arc<Paths>, catalog: &Catalog, io_pool: &CpuPool) -> Self {
        Self {
            paths: paths.clone(),
            io_pool: io_pool.clone(),
            catalog: catalog.clone(),
            objects: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    /// Write an object to the file system. Assuming the file has not yet been written, this will
    /// open and then close a file, and the resulting future will return `true` if the object has
    /// not been written and `false` if the object already exists in the catalog and no I/O was
    /// performed.
    pub fn write_object(&self, hashed: Hashed) -> Box<Future<Item = bool, Error = Error> + Send> {
        match self.catalog.try_lock(*hashed.as_hash()) {
            Ok(lock) => {
                match hashed.into_components() {
                    (hash, Some(bytes)) => {
                        let path = self.paths.blobs.join(hash.to_path());
                        let io_pool = self.io_pool.clone();

                        let result = {
                            async_block! {
                                fs::create_dir_all(path.parent().unwrap())?;
                                let file = File::create(path)?;
                                let bufwriter =
                                    BufWriter::with_pool_and_capacity(io_pool, 4096, file);

                                let bufwriter = match await!(bufwriter.write_all(bytes)) {
                                    Ok((writer, _)) => Ok(writer),
                                    Err((_, _, err)) => Err(err),
                                }?;

                                let bufwriter = await!(bufwriter.flush_buf()).map_err(|(_, err)| err)?;
                                await!(bufwriter.flush_inner()).map_err(|(_, err)| err)?;

                                lock.release();

                                Ok(true)
                            }
                        };

                        return Box::new(result);
                    }

                    (_, None) => {
                        panic!("Attempted to locally write file which should exist locally!");
                    }
                }
            }
            Err(entry) => Box::new(entry.map(|_| false)),
        }
    }

    /// Load an object from the file system. This will open a file if the object has not already
    /// been loaded.
    /// TODO: Make async.
    pub fn read_object(
        &self,
        object_hash: ObjectHash,
    ) -> Box<Future<Item = Object, Error = Error> + Send> {
        let path = self.paths.blobs.join(object_hash.to_path());
        let objects = self.objects.clone();
        let entry_opt = self.catalog.get(object_hash);

        let result = {
            async_block! {
                if let Some(entry) = entry_opt {
                    await!(entry)?;
                }

                if let Some(local) = objects.lock().unwrap().get(&object_hash) {
                    return Ok(local.clone());
                }

                let bytes = arc_slice::mapped(Mmap::open_path(path, Protection::Read).chain_err(|| ErrorKind::OpenLocalObject(object_hash))?);
                let object = Object::from_bytes(bytes)?;

                objects.lock().unwrap().insert(object_hash, object.clone());

                Ok(object)
            }
        };

        return Box::new(self.io_pool.spawn(result));
    }

    /// Load an object from the file system, *or*, create a new buffer for writing an object. This
    /// is used for remotes: either load an object from the file system instead of fetching it from
    /// a remote, or create a memory-mapped file buffer, write the serialized object to the buffer,
    /// and then re-protect the buffer as read-only and deserialize the object from it.
    pub fn read_or_allocate_object(
        &self,
        object_hash: ObjectHash,
    ) -> Box<Future<Item = StdResult<Object, LocalBufferFactory>, Error = Error> + Send> {
        let lock_res = self.catalog.try_lock(object_hash);

        match lock_res {
            Ok(lock) => {
                let path = self.paths.blobs.join(object_hash.to_path());
                let objects = self.objects.clone();

                let result = {
                    async_block! {
                        let local_buffer_factory = LocalBufferFactory {
                            catalog_lock: lock,
                            object_hash,
                            objects,
                            path,
                        };

                        Ok(Err(local_buffer_factory))
                    }
                };

                Box::new(result)
            }

            // The object is in the catalog or is currently being written. Defer to `read_object`
            // in order to wait for any potential lock to finish and then do an asynchronous read
            // of the object file.
            Err(_) => Box::new(self.read_object(object_hash).map(Ok)),
        }
    }

    //     /// Write a fully marshalled batch to the local repository.
    //     pub fn write_batch<T: Trace>(
    //         &mut self,
    //         batch: Batch<T::BatchTrace>,
    //     ) -> Box<Future<Item = (), Error = Error>> {
    //         unimplemented!()
    //                 let trace = Arc::new(Mutex::new(self.trace.lock().unwrap().on_write(
    //                     &batch,
    //                     WriteDestination::Local,
    //                 )));
    //
    //                 let local = self.clone();
    //
    //                 let writes = batch
    //                     .into_stream()
    //                     .map(move |hashed| {
    //                         let hash = *hashed.as_hash();
    //                         let trace = trace.clone();
    //
    //                         trace.lock().unwrap().on_begin(&hash);
    //                         let write = local.write_object(hashed).map(move |fresh| {
    //                             trace.lock().unwrap().on_complete(&hash, fresh);
    //                         });
    //                         local.io_pool.spawn(write)
    //                     })
    //                     .buffer_unordered(WRITE_FUTURE_BUFFER_SIZE)
    //                     .for_each(|_| Ok(()));
    //
    //                 Box::new(self.io_pool.spawn(writes))
    //     }
}

impl Store for Local {
    type Read = Box<Future<Item = Object, Error = Error> + Send>;
    type Write = Box<Future<Item = bool, Error = Error> + Send>;

    fn read_object(&self, object_hash: ObjectHash) -> Self::Read {
        self.read_object(object_hash)
    }

    fn write_object(&self, hashed: Hashed) -> Self::Write {
        self.write_object(hashed)
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{DWORD, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<commit_msg>convert slices to WSABUFs on windows<commit_after>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{DWORD, WSABUF, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr(),
                    len: buf.len()
                });
            }
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr(),
                    len: buf.len()
                });
            }
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<|endoftext|>