<commit_before>use document::Document;
use formatted::to_table_key_value;
use std::ops;
use table::{value, Item, Table};
use value::{InlineTable, Value};

// copied from
// https://github.com/serde-rs/json/blob/master/src/value/index.rs

// Prevent users from implementing the Index trait.
mod private {
    pub trait Sealed {}
    impl Sealed for usize {}
    impl Sealed for str {}
    impl Sealed for String {}
    impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {}
}

pub trait Index: private::Sealed {
    /// Return `Option::None` if the key is not already in the array or table.
    #[doc(hidden)]
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item>;

    /// Panic if array index out of bounds. If key is not already in the table,
    /// insert it with a value of `Item::None`. Panic if `v` has a type that cannot be
    /// indexed into, except if `v` is `Item::None` then it can be treated as an empty
    /// inline table.
    #[doc(hidden)]
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item;
}

impl Index for usize {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        match *v {
            Item::ArrayOfTables(ref aot) => aot.values.get(*self),
            Item::Value(ref a) if a.is_array() => a.as_array().unwrap().values.get(*self),
            _ => None,
        }
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        match *v {
            Item::ArrayOfTables(ref mut vec) => {
                vec.values.get_mut(*self).expect("index out of bounds")
            }
            Item::Value(ref mut a) if a.is_array() => a
                .as_array_mut()
                .unwrap()
                .values
                .get_mut(*self)
                .expect("index out of bounds"),
            _ => panic!("cannot access index {} in {:?}", self, v),
        }
    }
}

impl Index for str {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        match *v {
            Item::Table(ref t) => t.get(self),
            Item::Value(ref v) if v.is_inline_table() => v
                .as_inline_table()
                .and_then(|t| t.items.get(self).map(|kv| &kv.value)),
            _ => None,
        }
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        if let Item::None = *v {
            let mut t = InlineTable::default();
            t.items
                .insert(self.to_owned(), to_table_key_value(self, Item::None));
            *v = value(Value::InlineTable(t));
        }
        match *v {
            Item::Table(ref mut t) => t.entry(self).or_insert(Item::None),
            Item::Value(ref mut v) if v.is_inline_table() => {
                &mut v
                    .as_inline_table_mut()
                    .unwrap()
                    .items
                    .entry(self.to_owned())
                    .or_insert(to_table_key_value(self, Item::None))
                    .value
            }
            _ => panic!("cannot access key {} in {:?}", self, v),
        }
    }
}

impl Index for String {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        self[..].index(v)
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        self[..].index_or_insert(v)
    }
}

impl<'a, T: ?Sized> Index for &'a T
where
    T: Index,
{
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        (**self).index(v)
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        (**self).index_or_insert(v)
    }
}

impl<I> ops::Index<I> for Item
where
    I: Index,
{
    type Output = Item;

    fn index(&self, index: I) -> &Item {
        static NONE: Item = Item::None;
        index.index(self).unwrap_or(&NONE)
    }
}

impl<I> ops::IndexMut<I> for Item
where
    I: Index,
{
    fn index_mut(&mut self, index: I) -> &mut Item {
        index.index_or_insert(self)
    }
}

impl<'s> ops::Index<&'s str> for Table {
    type Output = Item;

    fn index(&self, key: &'s str) -> &Item {
        static NONE: Item = Item::None;
        self.get(key).unwrap_or(&NONE)
    }
}

impl<'s> ops::IndexMut<&'s str> for Table {
    fn index_mut(&mut self, key: &'s str) -> &mut Item {
        self.entry(key).or_insert(Item::None)
    }
}

impl<'s> ops::Index<&'s str> for Document {
    type Output = Item;

    fn index(&self, key: &'s str) -> &Item {
        self.root.index(key)
    }
}

impl<'s> ops::IndexMut<&'s str> for Document {
    fn index_mut(&mut self, key: &'s str) -> &mut Item {
        self.root.index_mut(key)
    }
}
<commit_msg>index: workaround for a NULL bug on nightly<commit_after>use document::Document;
use formatted::to_table_key_value;
use std::ops;
use table::{value, Item, Table};
use value::{InlineTable, Value};

// copied from
// https://github.com/serde-rs/json/blob/master/src/value/index.rs

// Prevent users from implementing the Index trait.
mod private {
    pub trait Sealed {}
    impl Sealed for usize {}
    impl Sealed for str {}
    impl Sealed for String {}
    impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {}
}

pub trait Index: private::Sealed {
    /// Return `Option::None` if the key is not already in the array or table.
    #[doc(hidden)]
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item>;

    /// Panic if array index out of bounds. If key is not already in the table,
    /// insert it with a value of `Item::None`. Panic if `v` has a type that cannot be
    /// indexed into, except if `v` is `Item::None` then it can be treated as an empty
    /// inline table.
    #[doc(hidden)]
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item;
}

impl Index for usize {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        match *v {
            Item::ArrayOfTables(ref aot) => aot.values.get(*self),
            Item::Value(ref a) if a.is_array() => a.as_array().unwrap().values.get(*self),
            _ => None,
        }
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        match *v {
            Item::ArrayOfTables(ref mut vec) => {
                vec.values.get_mut(*self).expect("index out of bounds")
            }
            Item::Value(ref mut a) if a.is_array() => a
                .as_array_mut()
                .unwrap()
                .values
                .get_mut(*self)
                .expect("index out of bounds"),
            _ => panic!("cannot access index {}", self),
        }
    }
}

impl Index for str {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        match *v {
            Item::Table(ref t) => t.get(self),
            Item::Value(ref v) if v.is_inline_table() => v
                .as_inline_table()
                .and_then(|t| t.items.get(self).map(|kv| &kv.value)),
            _ => None,
        }
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        if let Item::None = *v {
            let mut t = InlineTable::default();
            t.items
                .insert(self.to_owned(), to_table_key_value(self, Item::None));
            *v = value(Value::InlineTable(t));
        }
        match *v {
            Item::Table(ref mut t) => t.entry(self).or_insert(Item::None),
            Item::Value(ref mut v) if v.is_inline_table() => {
                &mut v
                    .as_inline_table_mut()
                    .unwrap()
                    .items
                    .entry(self.to_owned())
                    .or_insert(to_table_key_value(self, Item::None))
                    .value
            }
            _ => panic!("cannot access key {}", self),
        }
    }
}

impl Index for String {
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        self[..].index(v)
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        self[..].index_or_insert(v)
    }
}

impl<'a, T: ?Sized> Index for &'a T
where
    T: Index,
{
    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
        (**self).index(v)
    }
    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
        (**self).index_or_insert(v)
    }
}

impl<I> ops::Index<I> for Item
where
    I: Index,
{
    type Output = Item;

    fn index(&self, index: I) -> &Item {
        static NONE: Item = Item::None;
        index.index(self).unwrap_or(&NONE)
    }
}

impl<I> ops::IndexMut<I> for Item
where
    I: Index,
{
    fn index_mut(&mut self, index: I) -> &mut Item {
        index.index_or_insert(self)
    }
}

impl<'s> ops::Index<&'s str> for Table {
    type Output = Item;

    fn index(&self, key: &'s str) -> &Item {
        static NONE: Item = Item::None;
        self.get(key).unwrap_or(&NONE)
    }
}

impl<'s> ops::IndexMut<&'s str> for Table {
    fn index_mut(&mut self, key: &'s str) -> &mut Item {
        self.entry(key).or_insert(Item::None)
    }
}

impl<'s> ops::Index<&'s str> for Document {
    type Output = Item;

    fn index(&self, key: &'s str) -> &Item {
        self.root.index(key)
    }
}

impl<'s> ops::IndexMut<&'s str> for Document {
    fn index_mut(&mut self, key: &'s str) -> &mut Item {
        self.root.index_mut(key)
    }
}
<|endoftext|>


<commit_before>use libc::{c_uint, c_char, c_uchar};
use std::fmt::{Show, Error, Formatter};
use connection::{mpd_connection, MpdConnection, FromConn};
use error::MpdResult;
use std::str::FromStr;

bitflags! {
    #[deriving(Encodable)]
    #[repr(C)]
    flags MpdEvent: c_uint {
        const DATABASE = 0x1,
        const PLAYLIST = 0x2,
        const QUEUE = 0x4,
        const PLAYER = 0x8,
        const MIXER = 0x10,
        const OUTPUT = 0x20,
        const OPTIONS = 0x40,
        const UPDATE = 0x80,
        const STICKER = 0x100,
        const SUBSCRIPTION = 0x200,
        const MESSAGE = 0x400,
    }
}

impl Show for MpdEvent {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(f.write(b"MpdEvent("));
        let name = unsafe { mpd_idle_name(*self) };
        try!(if name.is_null() {
            self.bits.fmt(f)
        } else {
            unsafe { String::from_raw_buf(name).fmt(f) }
        })
        try!(f.write(b")"));
        Ok(())
    }
}

impl FromStr for MpdEvent {
    fn from_str(s: &str) -> Option<MpdEvent> {
        let ev = s.with_c_str(|s| unsafe { mpd_idle_name_parse(s) });
        if ev.is_empty() {
            None
        } else {
            Some(ev)
        }
    }
}

#[link(name = "mpdclient")]
extern {
    fn mpd_idle_name(idle: MpdEvent) -> *const c_uchar;
    fn mpd_idle_name_parse(name: *const c_char) -> MpdEvent;
    fn mpd_run_idle(connection: *mut mpd_connection) -> MpdEvent;
    fn mpd_run_idle_mask(connection: *mut mpd_connection, mask: MpdEvent) -> MpdEvent;
    fn mpd_run_noidle(connection: *mut mpd_connection) -> bool;
}

pub struct MpdIdle<'a> {
    conn: &'a MpdConnection,
    mask: Option<MpdEvent>
}

impl<'a> Iterator<MpdResult<MpdEvent>> for MpdIdle<'a> {
    fn next(&mut self) -> Option<MpdResult<MpdEvent>> {
        let idle = unsafe {
            match self.mask {
                Some(m) => mpd_run_idle_mask(self.conn.conn, m),
                None => mpd_run_idle(self.conn.conn)
            }
        };

        if idle.is_empty() {
            FromConn::from_conn(self.conn).map(|e| Err(e))
        } else {
            Some(Ok(idle))
        }
    }
}

impl<'a> MpdIdle<'a> {
    pub fn from_conn<'a>(conn: &'a MpdConnection, mask: Option<MpdEvent>) -> MpdIdle<'a> {
        MpdIdle { conn: conn, mask: mask }
    }
}

<commit_msg>add stop method to idle<commit_after>use libc::{c_uint, c_char, c_uchar};
use std::fmt::{Show, Error, Formatter};
use connection::{mpd_connection, MpdConnection, FromConn};
use error::MpdResult;
use std::str::FromStr;

bitflags! {
    #[deriving(Encodable)]
    #[repr(C)]
    flags MpdEvent: c_uint {
        const DATABASE = 0x1,
        const PLAYLIST = 0x2,
        const QUEUE = 0x4,
        const PLAYER = 0x8,
        const MIXER = 0x10,
        const OUTPUT = 0x20,
        const OPTIONS = 0x40,
        const UPDATE = 0x80,
        const STICKER = 0x100,
        const SUBSCRIPTION = 0x200,
        const MESSAGE = 0x400,
    }
}

impl Show for MpdEvent {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        try!(f.write(b"MpdEvent("));
        let name = unsafe { mpd_idle_name(*self) };
        try!(if name.is_null() {
            self.bits.fmt(f)
        } else {
            unsafe { String::from_raw_buf(name).fmt(f) }
        })
        try!(f.write(b")"));
        Ok(())
    }
}

impl FromStr for MpdEvent {
    fn from_str(s: &str) -> Option<MpdEvent> {
        let ev = s.with_c_str(|s| unsafe { mpd_idle_name_parse(s) });
        if ev.is_empty() {
            None
        } else {
            Some(ev)
        }
    }
}

#[link(name = "mpdclient")]
extern {
    fn mpd_idle_name(idle: MpdEvent) -> *const c_uchar;
    fn mpd_idle_name_parse(name: *const c_char) -> MpdEvent;
    fn mpd_run_idle(connection: *mut mpd_connection) -> MpdEvent;
    fn mpd_run_idle_mask(connection: *mut mpd_connection, mask: MpdEvent) -> MpdEvent;
    fn mpd_run_noidle(connection: *mut mpd_connection) -> bool;
}

pub struct MpdIdle<'a> {
    conn: &'a MpdConnection,
    mask: Option<MpdEvent>
}

impl<'a> Iterator<MpdResult<MpdEvent>> for MpdIdle<'a> {
    fn next(&mut self) -> Option<MpdResult<MpdEvent>> {
        let idle = unsafe {
            match self.mask {
                Some(m) => mpd_run_idle_mask(self.conn.conn, m),
                None => mpd_run_idle(self.conn.conn)
            }
        };

        if idle.is_empty() {
            FromConn::from_conn(self.conn).map(|e| Err(e))
        } else {
            Some(Ok(idle))
        }
    }
}

impl<'a> MpdIdle<'a> {
    pub fn from_conn<'a>(conn: &'a MpdConnection, mask: Option<MpdEvent>) -> MpdIdle<'a> {
        MpdIdle { conn: conn, mask: mask }
    }

    pub fn stop(self) -> MpdResult<()> {
        if unsafe { mpd_run_noidle(self.conn.conn) } {
            Ok(())
        } else {
            Err(FromConn::from_conn(self.conn).unwrap())
        }
    }
}

<|endoftext|>


<commit_before>
use libc::{c_char, c_int};
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use std::ptr;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::SeekFrom;
use std::io::prelude::*;
use std::process::{Command, Stdio};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fmt;
use std::path::Path;
use openssl;
use bindings::*;
use openssl::sign::Verifier;
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;
use toml;
use toml::Value;
use uuid::Uuid;

#[no_mangle]
pub fn pam_sm_authenticate(
    pamh: *mut pam_handle_t,
    flags: c_int,
    _: c_int,
    _: *mut *const c_char,
) -> c_int {
    authenticate_via_hello(pamh).unwrap_or_else(|err| {
        if (flags & PAM_SILENT) == 0 {
            println!("WSL Hello error: {}", err);
        }
        match err {
            HelloAuthenticationError::PublicKeyFileError(ref err)
                if err.kind() == io::ErrorKind::NotFound =>
            {
                PAM_USER_UNKNOWN
            }
            HelloAuthenticationError::AuthenticatorLaunchError(_) => PAM_AUTHINFO_UNAVAIL,
            HelloAuthenticationError::AuthenticatorConnectionError(_) => PAM_AUTHINFO_UNAVAIL,
            HelloAuthenticationError::AuthenticatorSignalled => PAM_AUTHINFO_UNAVAIL,
            _ => PAM_AUTH_ERR,
        }
    })
}

fn get_user(pamh: *mut pam_handle_t, prompt: Option<&str>) -> Result<Cow<str>, i32> {
    let mut c_user: *const c_char = ptr::null();
    let c_prompt = match prompt {
        Some(prompt_str) => CString::new(prompt_str).unwrap().as_ptr(),
        None => ptr::null(),
    };
    let err;
    unsafe {
        err = pam_get_user(pamh, &mut c_user, c_prompt);
    }
    match err {
        PAM_SUCCESS => unsafe {
            let c_user_str = CStr::from_ptr(c_user);
            Ok(c_user_str.to_string_lossy())
        },
        err => Err(err),
    }
}

#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    Toml(toml::de::Error),
    MissingField(String),
    InvalidValueType(String),
}

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

impl From<toml::de::Error> for ConfigError {
    fn from(err: toml::de::Error) -> ConfigError {
        ConfigError::Toml(err)
    }
}

impl fmt::Display for ConfigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConfigError::Io(ref ioerr) => write!(f, "{}", ioerr),
            ConfigError::Toml(_) => write!(f, "TOML format error"),
            ConfigError::MissingField(ref field) => write!(f, "field: '{}' is not found", field),
            ConfigError::InvalidValueType(ref field) => {
                write!(f, "field: '{}' has an invalid value type", field)
            }
        }
    }
}

fn get_authenticator_path() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let authenticator_path = config_value
        .get("authenticator_path")
        .ok_or(ConfigError::MissingField("authenticator_path".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType(
            "authenticator_path".to_owned(),
        ))?;
    Ok(authenticator_path.to_owned())
}

fn get_win_mnt() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let win_mnt = config_value
        .get("win_mnt")
        .ok_or(ConfigError::MissingField("win_mnt".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType("win_mnt".to_owned()))?;
    Ok(win_mnt.to_owned())
}

#[derive(Debug)]
enum HelloAuthenticationError {
    GetUserError(i32),
    ConfigError(ConfigError),
    PublicKeyFileError(io::Error),
    Io(io::Error),
    InvalidPublicKey(openssl::error::ErrorStack),
    OpenSSLError(openssl::error::ErrorStack),
    AuthenticatorLaunchError(io::Error),
    AuthenticatorConnectionError(io::Error),
    AuthenticatorSignalled,
    HelloAuthenticationFail(String),
    SignAuthenticationFail,
}

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

impl From<ConfigError> for HelloAuthenticationError {
    fn from(err: ConfigError) -> HelloAuthenticationError {
        HelloAuthenticationError::ConfigError(err)
    }
}

impl fmt::Display for HelloAuthenticationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HelloAuthenticationError::ConfigError(ref err) => write!(f, "config error; {}", err),
            HelloAuthenticationError::PublicKeyFileError(ref err) => match err.kind() {
                io::ErrorKind::NotFound => {
                    write!(f, "cannot find the credential public key for this user")
                }
                _ => write!(f, "{}", err),
            },
            HelloAuthenticationError::Io(ref err) => write!(f, "{}", err),
            HelloAuthenticationError::InvalidPublicKey(_) => {
                write!(f, "the pem file of the public key is invalid")
            }
            HelloAuthenticationError::AuthenticatorLaunchError(ref err) => {
                write!(f, "cannot launch Windows Hello; {}", err)
            }
            HelloAuthenticationError::AuthenticatorConnectionError(ref err) => {
                write!(f, "cannot communicate with Windows Hello; {}", err)
            }
            HelloAuthenticationError::HelloAuthenticationFail(ref msg) => {
                write!(f, "authentication failed; {}", msg)
            }
            HelloAuthenticationError::SignAuthenticationFail => write!(
                f,
                "the result of signature verification of the credential is failure"
            ),
            ref err => write!(f, "internal error; {:?}", err),
        }
    }
}

fn authenticate_via_hello(pamh: *mut pam_handle_t) -> Result<i32, HelloAuthenticationError> {
    let user_name = get_user(pamh, None).map_err(|e| HelloAuthenticationError::GetUserError(e))?;
    let credential_key_name = format!("pam_wsl_hello_{}", user_name);

    let mut hello_public_key_file =
        File::open(format!(
            "/etc/pam_wsl_hello/public_keys/{}.pem",
            credential_key_name
        )).map_err(|io| HelloAuthenticationError::PublicKeyFileError(io))?;
    let mut key_str = String::new();
    hello_public_key_file.read_to_string(&mut key_str)?;
    let hello_public_key = PKey::public_key_from_pem(key_str.as_bytes())
        .map_err(|e| HelloAuthenticationError::InvalidPublicKey(e))?;

    let challenge = format!("pam_wsl_hello:{}:{}", user_name, Uuid::new_v4());

    let auth_res;
    let challenge_tmpfile_path = &format!("/tmp/{}", challenge);
    {
        // Since there seems to be a bug that C# applications cannot read from pipes on WSL,
        // we create a temporary file to redirect
        let mut challenge_tmpfile = OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .open(challenge_tmpfile_path)?;
        challenge_tmpfile.write_all(challenge.as_bytes())?;
        challenge_tmpfile.seek(SeekFrom::Start(0))?;
        let challenge_tmpfile_in = unsafe { Stdio::from_raw_fd(challenge_tmpfile.as_raw_fd()) };

        let authenticator_path = get_authenticator_path()?;
        let authenticator = Command::new(&authenticator_path)
            .arg(credential_key_name)
            .current_dir(Path::new(&get_win_mnt()?))
            .stdin(challenge_tmpfile_in)
            .stdout(Stdio::piped())
            .spawn()
            .map_err(|e| HelloAuthenticationError::AuthenticatorLaunchError(e))?;

        auth_res = authenticator.wait_with_output().map_err(|e| {
            HelloAuthenticationError::AuthenticatorConnectionError(e)
        })?;
    }
    fs::remove_file(challenge_tmpfile_path)?;

    match auth_res.status.code() {
        Some(code) if code == 0 => { /* Success */ }
        Some(_) => {
            return Err(HelloAuthenticationError::HelloAuthenticationFail(
                String::from_utf8(auth_res.stdout).unwrap_or("invalid utf8 output".to_string()),
            ))
        }
        None => return Err(HelloAuthenticationError::AuthenticatorSignalled),
    }
    let signature = auth_res.stdout;

    let mut verifier = Verifier::new(MessageDigest::sha256(), &hello_public_key).unwrap();
    verifier
        .update(challenge.as_bytes())
        .map_err(|e| HelloAuthenticationError::OpenSSLError(e))?;

    match verifier
        .verify(&signature)
        .map_err(|e| HelloAuthenticationError::OpenSSLError(e))?
    {
        true => Ok(PAM_SUCCESS),
        false => Err(HelloAuthenticationError::SignAuthenticationFail),
    }
}
<commit_msg>fix: Fix warning that pointer doesn't outlive temporary CString (#23)<commit_after>
use libc::{c_char, c_int};
use std::ffi::{CStr, CString};
use std::borrow::Cow;
use std::ptr;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::SeekFrom;
use std::io::prelude::*;
use std::process::{Command, Stdio};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fmt;
use std::path::Path;
use openssl;
use bindings::*;
use openssl::sign::Verifier;
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;
use toml;
use toml::Value;
use uuid::Uuid;

#[no_mangle]
pub fn pam_sm_authenticate(
    pamh: *mut pam_handle_t,
    flags: c_int,
    _: c_int,
    _: *mut *const c_char,
) -> c_int {
    authenticate_via_hello(pamh).unwrap_or_else(|err| {
        if (flags & PAM_SILENT) == 0 {
            println!("WSL Hello error: {}", err);
        }
        match err {
            HelloAuthenticationError::PublicKeyFileError(ref err)
                if err.kind() == io::ErrorKind::NotFound =>
            {
                PAM_USER_UNKNOWN
            }
            HelloAuthenticationError::AuthenticatorLaunchError(_) => PAM_AUTHINFO_UNAVAIL,
            HelloAuthenticationError::AuthenticatorConnectionError(_) => PAM_AUTHINFO_UNAVAIL,
            HelloAuthenticationError::AuthenticatorSignalled => PAM_AUTHINFO_UNAVAIL,
            _ => PAM_AUTH_ERR,
        }
    })
}

fn get_user(pamh: *mut pam_handle_t, prompt: Option<&str>) -> Result<Cow<str>, i32> {
    let mut c_user: *const c_char = ptr::null();
    let tmp_prompt_str: CString;
    let c_prompt = match prompt {
        Some(prompt_str) => {
            tmp_prompt_str = CString::new(prompt_str).unwrap();
            tmp_prompt_str.as_ptr()
        },
        None => ptr::null(),
    };
    let err;
    unsafe {
        err = pam_get_user(pamh, &mut c_user, c_prompt);
    }
    match err {
        PAM_SUCCESS => unsafe {
            let c_user_str = CStr::from_ptr(c_user);
            Ok(c_user_str.to_string_lossy())
        },
        err => Err(err),
    }
}

#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    Toml(toml::de::Error),
    MissingField(String),
    InvalidValueType(String),
}

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

impl From<toml::de::Error> for ConfigError {
    fn from(err: toml::de::Error) -> ConfigError {
        ConfigError::Toml(err)
    }
}

impl fmt::Display for ConfigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConfigError::Io(ref ioerr) => write!(f, "{}", ioerr),
            ConfigError::Toml(_) => write!(f, "TOML format error"),
            ConfigError::MissingField(ref field) => write!(f, "field: '{}' is not found", field),
            ConfigError::InvalidValueType(ref field) => {
                write!(f, "field: '{}' has an invalid value type", field)
            }
        }
    }
}

fn get_authenticator_path() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let authenticator_path = config_value
        .get("authenticator_path")
        .ok_or(ConfigError::MissingField("authenticator_path".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType(
            "authenticator_path".to_owned(),
        ))?;
    Ok(authenticator_path.to_owned())
}

fn get_win_mnt() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let win_mnt = config_value
        .get("win_mnt")
        .ok_or(ConfigError::MissingField("win_mnt".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType("win_mnt".to_owned()))?;
    Ok(win_mnt.to_owned())
}

#[derive(Debug)]
enum HelloAuthenticationError {
    GetUserError(i32),
    ConfigError(ConfigError),
    PublicKeyFileError(io::Error),
    Io(io::Error),
    InvalidPublicKey(openssl::error::ErrorStack),
    OpenSSLError(openssl::error::ErrorStack),
    AuthenticatorLaunchError(io::Error),
    AuthenticatorConnectionError(io::Error),
    AuthenticatorSignalled,
    HelloAuthenticationFail(String),
    SignAuthenticationFail,
}

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

impl From<ConfigError> for HelloAuthenticationError {
    fn from(err: ConfigError) -> HelloAuthenticationError {
        HelloAuthenticationError::ConfigError(err)
    }
}

impl fmt::Display for HelloAuthenticationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HelloAuthenticationError::ConfigError(ref err) => write!(f, "config error; {}", err),
            HelloAuthenticationError::PublicKeyFileError(ref err) => match err.kind() {
                io::ErrorKind::NotFound => {
                    write!(f, "cannot find the credential public key for this user")
                }
                _ => write!(f, "{}", err),
            },
            HelloAuthenticationError::Io(ref err) => write!(f, "{}", err),
            HelloAuthenticationError::InvalidPublicKey(_) => {
                write!(f, "the pem file of the public key is invalid")
            }
            HelloAuthenticationError::AuthenticatorLaunchError(ref err) => {
                write!(f, "cannot launch Windows Hello; {}", err)
            }
            HelloAuthenticationError::AuthenticatorConnectionError(ref err) => {
                write!(f, "cannot communicate with Windows Hello; {}", err)
            }
            HelloAuthenticationError::HelloAuthenticationFail(ref msg) => {
                write!(f, "authentication failed; {}", msg)
            }
            HelloAuthenticationError::SignAuthenticationFail => write!(
                f,
                "the result of signature verification of the credential is failure"
            ),
            ref err => write!(f, "internal error; {:?}", err),
        }
    }
}

fn authenticate_via_hello(pamh: *mut pam_handle_t) -> Result<i32, HelloAuthenticationError> {
    let user_name = get_user(pamh, None).map_err(|e| HelloAuthenticationError::GetUserError(e))?;
    let credential_key_name = format!("pam_wsl_hello_{}", user_name);

    let mut hello_public_key_file =
        File::open(format!(
            "/etc/pam_wsl_hello/public_keys/{}.pem",
            credential_key_name
        )).map_err(|io| HelloAuthenticationError::PublicKeyFileError(io))?;
    let mut key_str = String::new();
    hello_public_key_file.read_to_string(&mut key_str)?;
    let hello_public_key = PKey::public_key_from_pem(key_str.as_bytes())
        .map_err(|e| HelloAuthenticationError::InvalidPublicKey(e))?;

    let challenge = format!("pam_wsl_hello:{}:{}", user_name, Uuid::new_v4());

    let auth_res;
    let challenge_tmpfile_path = &format!("/tmp/{}", challenge);
    {
        // Since there seems to be a bug that C# applications cannot read from pipes on WSL,
        // we create a temporary file to redirect
        let mut challenge_tmpfile = OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .open(challenge_tmpfile_path)?;
        challenge_tmpfile.write_all(challenge.as_bytes())?;
        challenge_tmpfile.seek(SeekFrom::Start(0))?;
        let challenge_tmpfile_in = unsafe { Stdio::from_raw_fd(challenge_tmpfile.as_raw_fd()) };

        let authenticator_path = get_authenticator_path()?;
        let authenticator = Command::new(&authenticator_path)
            .arg(credential_key_name)
            .current_dir(Path::new(&get_win_mnt()?))
            .stdin(challenge_tmpfile_in)
            .stdout(Stdio::piped())
            .spawn()
            .map_err(|e| HelloAuthenticationError::AuthenticatorLaunchError(e))?;

        auth_res = authenticator.wait_with_output().map_err(|e| {
            HelloAuthenticationError::AuthenticatorConnectionError(e)
        })?;
    }
    fs::remove_file(challenge_tmpfile_path)?;

    match auth_res.status.code() {
        Some(code) if code == 0 => { /* Success */ }
        Some(_) => {
            return Err(HelloAuthenticationError::HelloAuthenticationFail(
                String::from_utf8(auth_res.stdout).unwrap_or("invalid utf8 output".to_string()),
            ))
        }
        None => return Err(HelloAuthenticationError::AuthenticatorSignalled),
    }
    let signature = auth_res.stdout;

    let mut verifier = Verifier::new(MessageDigest::sha256(), &hello_public_key).unwrap();
    verifier
        .update(challenge.as_bytes())
        .map_err(|e| HelloAuthenticationError::OpenSSLError(e))?;

    match verifier
        .verify(&signature)
        .map_err(|e| HelloAuthenticationError::OpenSSLError(e))?
    {
        true => Ok(PAM_SUCCESS),
        false => Err(HelloAuthenticationError::SignAuthenticationFail),
    }
}
<|endoftext|>


<commit_before>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedStream, IoResult, MemWriter, TcpStream};
#[cfg(feature = "ssl")] use std::io::{IoError, OtherIoError};
use data::kinds::{IrcReader, IrcStream, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T> where T: IrcStream {
    stream: Mutex<T>
}

impl Connection<BufferedStream<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(BufferedStream::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    #[cfg(feature = "ssl")]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, None)
    }

    #[experimental]
    #[cfg(feature = "ssl")]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(BufferedStream::new(NetStream::SslTcpStream(ssl_socket))))
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

impl<T: IrcStream> Connection<T> {
    /// Creates a new connection from any arbitrary IrcStream.
    #[experimental]
    pub fn new(stream: T) -> Connection<T> {
        Connection {
            stream: Mutex::new(stream),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut stream = self.stream.lock();
        try!(stream.write_str(message.into_string()[]));
        stream.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.stream.lock().read_line()
    }

    /// Acquires the Stream lock.
    #[experimental]
    pub fn stream<'a>(&'a self) -> MutexGuard<'a, T> {
        self.stream.lock()
    }
}

/// An IrcStream built from an IrcWriter and an IrcReader.
#[experimental]
pub struct IoStream<T: IrcWriter, U: IrcReader> {
    writer: T,
    reader: U,
}

impl<T: IrcWriter, U: IrcReader> IoStream<T, U> {
    /// Creates a new IoStream from the given IrcWriter and IrcReader.
    #[experimental]
    pub fn new(writer: T, reader: U) -> IoStream<T, U> {
        IoStream { writer: writer, reader: reader }
    }
}

impl<U: IrcReader> IoStream<MemWriter, U> {
    pub fn value(&self) -> Vec<u8> {
        self.writer.get_ref().to_vec()
    }
}

impl<T: IrcWriter, U: IrcReader> Buffer for IoStream<T, U> {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        self.reader.fill_buf()
    }

    fn consume(&mut self, amt: uint) {
        self.reader.consume(amt)
    }
}

impl<T: IrcWriter, U: IrcReader> Reader for IoStream<T, U> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.reader.read(buf)
    }
}

impl<T: IrcWriter, U: IrcReader> Writer for IoStream<T, U> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.writer.write(buf)
    }
}

#[cfg(test)]
mod test {
    use super::{Connection, IoStream};
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(IoStream::new(MemWriter::new(), NullReader));
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.stream().value()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(IoStream::new(
            NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec())
        ));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<commit_msg>Fixed SSL timeout implementation.<commit_after>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedStream, IoResult, MemWriter, TcpStream};
#[cfg(feature = "ssl")] use std::io::{IoError, OtherIoError};
use data::kinds::{IrcReader, IrcStream, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T> where T: IrcStream {
    stream: Mutex<T>
}

impl Connection<BufferedStream<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(BufferedStream::new(NetStream::UnsecuredTcpStream(socket))))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specificed server over SSL with a given timeout
    /// in milliseconds. If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<Connection<BufferedStream<NetStream>>> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Panics because SSL support was not included at compilation.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<Connection<BufferedStream<NetStream>>> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(BufferedStream::new(NetStream::SslTcpStream(ssl_socket))))
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

impl<T: IrcStream> Connection<T> {
    /// Creates a new connection from any arbitrary IrcStream.
    #[experimental]
    pub fn new(stream: T) -> Connection<T> {
        Connection {
            stream: Mutex::new(stream),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut stream = self.stream.lock();
        try!(stream.write_str(message.into_string()[]));
        stream.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.stream.lock().read_line()
    }

    /// Acquires the Stream lock.
    #[experimental]
    pub fn stream<'a>(&'a self) -> MutexGuard<'a, T> {
        self.stream.lock()
    }
}

/// An IrcStream built from an IrcWriter and an IrcReader.
#[experimental]
pub struct IoStream<T: IrcWriter, U: IrcReader> {
    writer: T,
    reader: U,
}

impl<T: IrcWriter, U: IrcReader> IoStream<T, U> {
    /// Creates a new IoStream from the given IrcWriter and IrcReader.
    #[experimental]
    pub fn new(writer: T, reader: U) -> IoStream<T, U> {
        IoStream { writer: writer, reader: reader }
    }
}

impl<U: IrcReader> IoStream<MemWriter, U> {
    pub fn value(&self) -> Vec<u8> {
        self.writer.get_ref().to_vec()
    }
}

impl<T: IrcWriter, U: IrcReader> Buffer for IoStream<T, U> {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        self.reader.fill_buf()
    }

    fn consume(&mut self, amt: uint) {
        self.reader.consume(amt)
    }
}

impl<T: IrcWriter, U: IrcReader> Reader for IoStream<T, U> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.reader.read(buf)
    }
}

impl<T: IrcWriter, U: IrcReader> Writer for IoStream<T, U> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.writer.write(buf)
    }
}

#[cfg(test)]
mod test {
    use super::{Connection, IoStream};
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(IoStream::new(MemWriter::new(), NullReader));
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.stream().value()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(IoStream::new(
            NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec())
        ));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<|endoftext|>


<commit_before>use std;
use tuple_utils::Split;
use bitset::{BitIter, BitSetAnd, BitSetLike};
use Index;

/// BitAnd is a helper method to & bitsets togather resulting in a tree
pub trait BitAnd {
    type Value: BitSetLike;
    fn and(self) -> Self::Value;
}

/// This needs to be special cased
impl<A> BitAnd for (A,)
    where A: BitSetLike
{
    type Value = A;
    fn and(self) -> Self::Value {
        self.0
    }
}

macro_rules! bitset_and {
    // use variables to indicate the arity of the tuple
    ($($from:ident),*) => {
        impl<$($from),*> BitAnd for ($($from),*)
            where $($from: BitSetLike),*
        {
            type Value = BitSetAnd<
                <<Self as Split>::Left as BitAnd>::Value,
                <<Self as Split>::Right as BitAnd>::Value
            >;
            fn and(self) -> Self::Value {
              let (l, r) = self.split();
              BitSetAnd(l.and(), r.and())
            }
        }
    }
}

bitset_and!{A, B}
bitset_and!{A, B, C}
bitset_and!{A, B, C, D}
bitset_and!{A, B, C, D, E}
bitset_and!{A, B, C, D, E, F}
bitset_and!{A, B, C, D, E, F, G}
bitset_and!{A, B, C, D, E, F, G, H}
bitset_and!{A, B, C, D, E, F, G, H, I}
bitset_and!{A, B, C, D, E, F, G, H, I, J}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P}

/// The only purpose of the `Open` trait is to provide a way
/// to access the `open` or `open_mut` trait in a generic way
/// This way the fact that the type is immutable or mutable
/// is not lost when it is used later.
pub trait Open {
    type Type;
    type Value;
    type Mask: BitSetLike;
    fn open(self) -> (Self::Mask, Self::Value);
    unsafe fn get(Self::Value, Index) -> Self::Type;
}

/*impl<'a, T> Open for &'a std::sync::RwLockReadGuard<'a, T>
    where T: Storage
{
    type Value = GetRef<'a, T::UnprotectedStorage>;
    type Mask = &'a BitSet;
    fn open(self) -> (Self::Mask, Self::Value) {
        let (l, r) = (**self).open();
        (l, GetRef(r))
    }
}

impl<'b, 'a:'b, T> Open for &'b mut std::sync::RwLockWriteGuard<'a, T>
    where T: Storage
{
    type Value = GetMut<'b, T::UnprotectedStorage>;
    type Mask = &'b BitSet;
    fn open(self) -> (Self::Mask, Self::Value) {
        let (l, r) = (**self).open_mut();
        (l, GetMut(r))
    }
}*/

/*pub struct GetRef<'a, T: 'a>(&'a T);
impl<'a, T: Component> Get for GetRef<'a, T::Storage> {
    type Value = &'a T;
    unsafe fn get(&self, idx: Index) -> Self::Value {
        self.0.get(idx)
    }
}

pub struct GetMut<'a, T: 'a>(&'a mut T);
impl<'a, T: Component> Get for GetMut<'a, T::Storage> {
    type Value = &'a mut T;
    #[allow(mutable_transmutes)]
    unsafe fn get(&self, idx: Index) -> Self::Value {
        // This is obviously unsafe and is one of the reasons this
        // trait is marked as unsafe to being with. It is safe
        // an an external api point of view because the bitmask
        // iterator never visits the same index twice, otherwise
        // this would provide multiple aliased mutable pointers which
        // is illegal in rust.
        let x: &mut Self = std::mem::transmute(self);
        x.0.get_mut(idx)
    }
}*/

/// Join is an Iterator over a group of `Storages`
pub struct Join<O: Open> {
    keys: BitIter<O::Mask>,
    values: O::Value,
}

impl<O: Open> From<O> for Join<O> {
    fn from(o: O) -> Self {
        let (keys, values) = o.open();
        Join {
            keys: keys.iter(),
            values: values,
        }
    }
}

impl<O: Open> std::iter::Iterator for Join<O> {
    type Item = O::Type;
    fn next(&mut self) -> Option<O::Type> {
        self.keys.next().map(|idx| unsafe {
            // This is obviously unsafe and is one of the reasons this
            // trait is marked as unsafe to being with. It is safe
            // an an external api point of view because the bitmask
            // iterator never visits the same index twice, otherwise
            // this would provide multiple aliased mutable pointers which
            // is illegal in rust.
            let values: O::Value = std::mem::transmute_copy(&self.values);
            O::get(values, idx)
        })
    }
}

macro_rules! define_open {
    // use variables to indicate the arity of the tuple
    ($($from:ident),*) => {
        impl<'a, $($from,)*> Open for ($($from),*,)
            where $($from: Open),*,
                  ($(<$from as Open>::Mask,)*): BitAnd,
        {
            type Type = ($($from::Type),*,);
            type Value = ($($from::Value),*,);
            type Mask = <($($from::Mask,)*) as BitAnd>::Value;
            #[allow(non_snake_case)]
            fn open(self) -> (Self::Mask, Self::Value) {
                let ($($from,)*) = self;
                let ($($from,)*) = ($($from.open(),)*);
                (
                    ($($from.0),*,).and(),
                    ($($from.1),*,)
                )
            }
            #[allow(non_snake_case)]
            unsafe fn get(v: Self::Value, i: Index) -> Self::Type {
                let ($($from,)*) = v;
                ($($from::get($from, i),)*)
            }
        }

        /*impl<'a, $($value,)*, $($from,)*> Get<($($value),*,)> for ($($from),*,)
            where $($from: Get<$value>),*,
        {
            #[allow(non_snake_case)]
            unsafe fn get(&self, idx: Index) -> ($($value),*,) {
                let &($(ref $from,)*) = self;
                ($($from.get(idx)),*,)
            }
        }*/

        /*impl<'a, $($from,)*> Join for ($($from),*,)
            where $($from: Open),*,
                  ($(<$from as Open>::Mask),*,): BitAnd,
        {
            type Mask = <($($from::Mask),*,) as BitAnd>::Value;
            type Types = ($($from::Type),*,);
            type Values = ($($from::Value),*,);

            fn join(self) -> Joined<Self::Mask, Self::Types, Self::Values> {
                let (mask, value) = self.open();
                Joined::new(mask, value)
            }
        }*/
    }
}

define_open!{A}
define_open!{A, B}
define_open!{A, B, C}
define_open!{A, B, C, D}
define_open!{A, B, C, D, E}
define_open!{A, B, C, D, E, F}
define_open!{A, B, C, D, E, F, G}
define_open!{A, B, C, D, E, F, G, H}
define_open!{A, B, C, D, E, F, G, H, I}
define_open!{A, B, C, D, E, F, G, H, I, J}
define_open!{A, B, C, D, E, F, G, H, I, J, K}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P}
<commit_msg>Cleaned up the old Join code<commit_after>use std;
use tuple_utils::Split;
use bitset::{BitIter, BitSetAnd, BitSetLike};
use Index;

/// BitAnd is a helper method to & bitsets togather resulting in a tree
pub trait BitAnd {
    type Value: BitSetLike;
    fn and(self) -> Self::Value;
}

/// This needs to be special cased
impl<A> BitAnd for (A,)
    where A: BitSetLike
{
    type Value = A;
    fn and(self) -> Self::Value {
        self.0
    }
}

macro_rules! bitset_and {
    // use variables to indicate the arity of the tuple
    ($($from:ident),*) => {
        impl<$($from),*> BitAnd for ($($from),*)
            where $($from: BitSetLike),*
        {
            type Value = BitSetAnd<
                <<Self as Split>::Left as BitAnd>::Value,
                <<Self as Split>::Right as BitAnd>::Value
            >;
            fn and(self) -> Self::Value {
              let (l, r) = self.split();
              BitSetAnd(l.and(), r.and())
            }
        }
    }
}

bitset_and!{A, B}
bitset_and!{A, B, C}
bitset_and!{A, B, C, D}
bitset_and!{A, B, C, D, E}
bitset_and!{A, B, C, D, E, F}
bitset_and!{A, B, C, D, E, F, G}
bitset_and!{A, B, C, D, E, F, G, H}
bitset_and!{A, B, C, D, E, F, G, H, I}
bitset_and!{A, B, C, D, E, F, G, H, I, J}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O}
bitset_and!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P}

/// The only purpose of the `Open` trait is to provide a way
/// to access the `open` or `open_mut` trait in a generic way
/// This way the fact that the type is immutable or mutable
/// is not lost when it is used later.
pub trait Open {
    type Type;
    type Value;
    type Mask: BitSetLike;
    fn open(self) -> (Self::Mask, Self::Value);
    unsafe fn get(Self::Value, Index) -> Self::Type;
}

/// Join is an Iterator over a group of `Storages`
pub struct Join<O: Open> {
    keys: BitIter<O::Mask>,
    values: O::Value,
}

impl<O: Open> From<O> for Join<O> {
    fn from(o: O) -> Self {
        let (keys, values) = o.open();
        Join {
            keys: keys.iter(),
            values: values,
        }
    }
}

impl<O: Open> std::iter::Iterator for Join<O> {
    type Item = O::Type;
    fn next(&mut self) -> Option<O::Type> {
        self.keys.next().map(|idx| unsafe {
            // We only transmute and copy during iteration, which is safe and serves
            // as a poor man's replacement for the missing re-borrowing semantic.
            let values: O::Value = std::mem::transmute_copy(&self.values);
            O::get(values, idx)
        })
    }
}

macro_rules! define_open {
    // use variables to indicate the arity of the tuple
    ($($from:ident),*) => {
        impl<'a, $($from,)*> Open for ($($from),*,)
            where $($from: Open),*,
                  ($(<$from as Open>::Mask,)*): BitAnd,
        {
            type Type = ($($from::Type),*,);
            type Value = ($($from::Value),*,);
            type Mask = <($($from::Mask,)*) as BitAnd>::Value;
            #[allow(non_snake_case)]
            fn open(self) -> (Self::Mask, Self::Value) {
                let ($($from,)*) = self;
                let ($($from,)*) = ($($from.open(),)*);
                (
                    ($($from.0),*,).and(),
                    ($($from.1),*,)
                )
            }
            #[allow(non_snake_case)]
            unsafe fn get(v: Self::Value, i: Index) -> Self::Type {
                let ($($from,)*) = v;
                ($($from::get($from, i),)*)
            }
        }
    }
}

define_open!{A}
define_open!{A, B}
define_open!{A, B, C}
define_open!{A, B, C, D}
define_open!{A, B, C, D, E}
define_open!{A, B, C, D, E, F}
define_open!{A, B, C, D, E, F, G}
define_open!{A, B, C, D, E, F, G, H}
define_open!{A, B, C, D, E, F, G, H, I}
define_open!{A, B, C, D, E, F, G, H, I, J}
define_open!{A, B, C, D, E, F, G, H, I, J, K}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O}
define_open!{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P}
<|endoftext|>


<commit_before>use syscall::common::*;

#[path="../../kernel/syscall/common.rs"]
pub mod common;

#[cold]
#[inline(never)]
#[cfg(target_arch = "x86")]
pub unsafe fn syscall(mut a: usize, b: usize, c: usize, d: usize) -> usize {
    asm!("int 0x80"
        : "={eax}"(a)
        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
        : "memory"
        : "intel", "volatile");

    a
}

#[cold]
#[inline(never)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn syscall(mut a: usize, b: usize, c: usize, d: usize) -> usize {
    asm!("int 0x80"
        : "={rax}"(a)
        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
        : "memory"
        : "intel", "volatile");

    a
}

pub unsafe fn sys_debug(byte: u8) {
    syscall(SYS_DEBUG, byte as usize, 0, 0);
}

pub unsafe fn sys_brk(addr: usize) -> usize {
    syscall(SYS_BRK, addr, 0, 0)
}

pub unsafe fn sys_chdir(path: *const u8) -> usize {
    syscall(SYS_CHDIR, path as usize, 0, 0)
}

pub unsafe fn sys_clone(flags: usize) -> usize {
    syscall(SYS_CLONE, flags, 0, 0)
}

pub unsafe fn sys_close(fd: usize) -> usize {
    syscall(SYS_CLOSE, fd, 0, 0)
}

pub unsafe fn sys_clock_gettime(clock: usize, tp: *mut TimeSpec) -> usize{
    syscall(SYS_CLOCK_GETTIME, clock, tp as usize, 0)
}

pub unsafe fn sys_dup(fd: usize) -> usize {
    syscall(SYS_DUP, fd, 0, 0)
}

pub unsafe fn sys_execve(path: *const u8, args: *const *const u8) -> usize {
    syscall(SYS_EXECVE, path as usize, args as usize, 0)
}

pub unsafe fn sys_exit(status: isize) {
    syscall(SYS_EXIT, status as usize, 0, 0);
}

pub unsafe fn sys_fpath(fd: usize, buf: *mut u8, len: usize) -> usize {
    syscall(SYS_FPATH, fd, buf as usize, len)
}

//TODO: FSTAT

pub unsafe fn sys_fsync(fd: usize) -> usize {
    syscall(SYS_FSYNC, fd, 0, 0)
}

pub unsafe fn sys_ftruncate(fd: usize, len: usize) -> usize {
    syscall(SYS_FTRUNCATE, fd, len, 0)
}

pub unsafe fn sys_link(old: *const u8, new: *const u8) -> usize {
    syscall(SYS_LINK, old as usize, new as usize, 0)
}

pub unsafe fn sys_lseek(fd: usize, offset: isize, whence: usize) -> usize {
    syscall(SYS_LSEEK, fd, offset as usize, whence)
}

pub unsafe fn sys_mkdir(path: *const u8, mode: usize) -> usize{
    syscall(SYS_MKDIR, path, mode)
}

pub unsafe fn sys_nanosleep(req: *const TimeSpec, rem: *mut TimeSpec) -> usize{
    syscall(SYS_NANOSLEEP, req as usize, rem as usize, 0)
}

pub unsafe fn sys_open(path: *const u8, flags: usize, mode: usize) -> usize {
    syscall(SYS_OPEN, path as usize, flags, mode)
}

pub unsafe fn sys_read(fd: usize, buf: *mut u8, count: usize) -> usize {
    syscall(SYS_READ, fd, buf as usize, count)
}

pub unsafe fn sys_unlink(path: *const u8) -> usize {
    syscall(SYS_UNLINK, path as usize, 0, 0)
}

pub unsafe fn sys_write(fd: usize, buf: *const u8, count: usize) -> usize {
    syscall(SYS_WRITE, fd, buf as usize, count)
}

pub unsafe fn sys_yield() {
    syscall(SYS_YIELD, 0, 0, 0);
}

pub unsafe fn sys_alloc(size: usize) -> usize {
    syscall(SYS_ALLOC, size, 0, 0)
}

pub unsafe fn sys_realloc(ptr: usize, size: usize) -> usize {
    syscall(SYS_REALLOC, ptr, size, 0)
}

pub unsafe fn sys_realloc_inplace(ptr: usize, size: usize) -> usize {
    syscall(SYS_REALLOC_INPLACE, ptr, size, 0)
}

pub unsafe fn sys_unalloc(ptr: usize) {
    syscall(SYS_UNALLOC, ptr, 0, 0);
}
<commit_msg>Debugging<commit_after>use syscall::common::*;

#[path="../../kernel/syscall/common.rs"]
pub mod common;

#[cold]
#[inline(never)]
#[cfg(target_arch = "x86")]
pub unsafe fn syscall(mut a: usize, b: usize, c: usize, d: usize) -> usize {
    asm!("int 0x80"
        : "={eax}"(a)
        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
        : "memory"
        : "intel", "volatile");

    a
}

#[cold]
#[inline(never)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn syscall(mut a: usize, b: usize, c: usize, d: usize) -> usize {
    asm!("int 0x80"
        : "={rax}"(a)
        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
        : "memory"
        : "intel", "volatile");

    a
}

pub unsafe fn sys_debug(byte: u8) {
    syscall(SYS_DEBUG, byte as usize, 0, 0);
}

pub unsafe fn sys_brk(addr: usize) -> usize {
    syscall(SYS_BRK, addr, 0, 0)
}

pub unsafe fn sys_chdir(path: *const u8) -> usize {
    syscall(SYS_CHDIR, path as usize, 0, 0)
}

pub unsafe fn sys_clone(flags: usize) -> usize {
    syscall(SYS_CLONE, flags, 0, 0)
}

pub unsafe fn sys_close(fd: usize) -> usize {
    syscall(SYS_CLOSE, fd, 0, 0)
}

pub unsafe fn sys_clock_gettime(clock: usize, tp: *mut TimeSpec) -> usize{
    syscall(SYS_CLOCK_GETTIME, clock, tp as usize, 0)
}

pub unsafe fn sys_dup(fd: usize) -> usize {
    syscall(SYS_DUP, fd, 0, 0)
}

pub unsafe fn sys_execve(path: *const u8, args: *const *const u8) -> usize {
    syscall(SYS_EXECVE, path as usize, args as usize, 0)
}

pub unsafe fn sys_exit(status: isize) {
    syscall(SYS_EXIT, status as usize, 0, 0);
}

pub unsafe fn sys_fpath(fd: usize, buf: *mut u8, len: usize) -> usize {
    syscall(SYS_FPATH, fd, buf as usize, len)
}

//TODO: FSTAT

pub unsafe fn sys_fsync(fd: usize) -> usize {
    syscall(SYS_FSYNC, fd, 0, 0)
}

pub unsafe fn sys_ftruncate(fd: usize, len: usize) -> usize {
    syscall(SYS_FTRUNCATE, fd, len, 0)
}

pub unsafe fn sys_link(old: *const u8, new: *const u8) -> usize {
    syscall(SYS_LINK, old as usize, new as usize, 0)
}

pub unsafe fn sys_lseek(fd: usize, offset: isize, whence: usize) -> usize {
    syscall(SYS_LSEEK, fd, offset as usize, whence)
}

pub unsafe fn sys_mkdir(path: *const u8, mode: usize) -> usize{
    syscall(SYS_MKDIR, path as usize, 0, mode)
}

pub unsafe fn sys_nanosleep(req: *const TimeSpec, rem: *mut TimeSpec) -> usize{
    syscall(SYS_NANOSLEEP, req as usize, rem as usize, 0)
}

pub unsafe fn sys_open(path: *const u8, flags: usize, mode: usize) -> usize {
    syscall(SYS_OPEN, path as usize, flags, mode)
}

pub unsafe fn sys_read(fd: usize, buf: *mut u8, count: usize) -> usize {
    syscall(SYS_READ, fd, buf as usize, count)
}

pub unsafe fn sys_unlink(path: *const u8) -> usize {
    syscall(SYS_UNLINK, path as usize, 0, 0)
}

pub unsafe fn sys_write(fd: usize, buf: *const u8, count: usize) -> usize {
    syscall(SYS_WRITE, fd, buf as usize, count)
}

pub unsafe fn sys_yield() {
    syscall(SYS_YIELD, 0, 0, 0);
}

pub unsafe fn sys_alloc(size: usize) -> usize {
    syscall(SYS_ALLOC, size, 0, 0)
}

pub unsafe fn sys_realloc(ptr: usize, size: usize) -> usize {
    syscall(SYS_REALLOC, ptr, size, 0)
}

pub unsafe fn sys_realloc_inplace(ptr: usize, size: usize) -> usize {
    syscall(SYS_REALLOC_INPLACE, ptr, size, 0)
}

pub unsafe fn sys_unalloc(ptr: usize) {
    syscall(SYS_UNALLOC, ptr, 0, 0);
}
<|endoftext|>


<commit_before>use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::Serialize;

use crate::{
    dev::Payload, error::ErrorInternalServerError, extract::FromRequest, request::HttpRequest,
    Error,
};

/// Data factory.
pub(crate) trait DataFactory {
    /// Return true if modifications were made to extensions map.
    fn create(&self, extensions: &mut Extensions) -> bool;
}

pub(crate) type FnDataFactory =
    Box<dyn Fn() -> LocalBoxFuture<'static, Result<Box<dyn DataFactory>, ()>>>;

/// Application data.
///
/// Application level data is a piece of arbitrary data attached to the app, scope, or resource.
/// Application data is available to all routes and can be added during the application
/// configuration process via `App::data()`.
///
/// Application data can be accessed by using `Data<T>` extractor where `T` is data type.
///
/// **Note**: HTTP server accepts an application factory rather than an application instance. HTTP
/// server constructs an application instance for each thread, thus application data must be
/// constructed multiple times. If you want to share data between different threads, a shareable
/// object should be used, e.g. `Send + Sync`. Application data does not need to be `Send`
/// or `Sync`. Internally `Data` uses `Arc`.
///
/// If route data is not set for a handler, using `Data<T>` extractor would cause *Internal
/// Server Error* response.
///
// TODO: document `dyn T` functionality through converting an Arc
// TODO: note equivalence of req.app_data<Data<T>> and Data<T> extractor
// TODO: note that data must be inserted using Data<T> in order to extract it
///
/// # Examples
/// ```
/// use std::sync::Mutex;
/// use actix_web::{web, App, HttpResponse, Responder};
///
/// struct MyData {
///     counter: usize,
/// }
///
/// /// Use the `Data<T>` extractor to access data in a handler.
/// async fn index(data: web::Data<Mutex<MyData>>) -> impl Responder {
///     let mut data = data.lock().unwrap();
///     data.counter += 1;
///     HttpResponse::Ok()
/// }
///
/// fn main() {
///     let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
///
///     let app = App::new()
///         // Store `MyData` in application storage.
///         .app_data(data.clone())
///         .service(
///             web::resource("/index.html").route(
///                 web::get().to(index)));
/// }
/// ```
#[derive(Debug)]
pub struct Data<T: ?Sized>(Arc<T>);

impl<T> Data<T> {
    /// Create new `Data` instance.
    pub fn new(state: T) -> Data<T> {
        Data(Arc::new(state))
    }
}

impl<T: ?Sized> Data<T> {
    /// Get reference to inner app data.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }

    /// Convert to the internal Arc<T>
    pub fn into_inner(self) -> Arc<T> {
        self.0
    }
}

impl<T: ?Sized> Deref for Data<T> {
    type Target = Arc<T>;

    fn deref(&self) -> &Arc<T> {
        &self.0
    }
}

impl<T: ?Sized> Clone for Data<T> {
    fn clone(&self) -> Data<T> {
        Data(self.0.clone())
    }
}

impl<T: ?Sized> From<Arc<T>> for Data<T> {
    fn from(arc: Arc<T>) -> Self {
        Data(arc)
    }
}

impl<T> Serialize for Data<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<T: ?Sized + 'static> FromRequest for Data<T> {
    type Error = Error;
    type Future = Ready<Result<Self, Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.app_data::<Data<T>>() {
            ok(st.clone())
        } else {
            log::debug!(
                "Failed to construct App-level Data extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            err(ErrorInternalServerError(
                "App data is not configured, to configure use App::data()",
            ))
        }
    }
}

impl<T: ?Sized + 'static> DataFactory for Data<T> {
    fn create(&self, extensions: &mut Extensions) -> bool {
        extensions.insert(Data(self.0.clone()));
        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        dev::Service,
        http::StatusCode,
        test::{init_service, TestRequest},
        web, App, HttpResponse,
    };

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_data_extractor() {
        let srv = init_service(App::new().data("TEST".to_string()).service(
            web::resource("/").to(|data: web::Data<String>| {
                assert_eq!(data.to_lowercase(), "test");
                HttpResponse::Ok()
            }),
        ))
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .data(10u32)
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);

        let srv = init_service(
            App::new()
                .data(10u32)
                .data(13u32)
                .app_data(12u64)
                .app_data(15u64)
                .default_service(web::to(|n: web::Data<u32>, req: HttpRequest| {
                    // in each case, the latter insertion should be preserved
                    assert_eq!(*req.app_data::<u64>().unwrap(), 15);
                    assert_eq!(*n.into_inner(), 13);
                    HttpResponse::Ok()
                })),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_app_data_extractor() {
        let srv = init_service(
            App::new()
                .app_data(Data::new(10usize))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .app_data(Data::new(10u32))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_route_data_extractor() {
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10usize)
                    .route(web::get().to(|_data: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        // different type
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10u32)
                    .route(web::get().to(|_: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_override_data() {
        let srv =
            init_service(App::new().data(1usize).service(
                web::resource("/").data(10usize).route(web::get().to(
                    |data: web::Data<usize>| {
                        assert_eq!(**data, 10);
                        HttpResponse::Ok()
                    },
                )),
            ))
            .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_data_from_arc() {
        let data_new = Data::new(String::from("test-123"));
        let data_from_arc = Data::from(Arc::new(String::from("test-123")));
        assert_eq!(data_new.0, data_from_arc.0)
    }

    #[actix_rt::test]
    async fn test_data_from_dyn_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        // This works when Sized is required
        let dyn_arc_box: Arc<Box<dyn TestTrait>> = Arc::new(Box::new(A {}));
        let data_arc_box = Data::from(dyn_arc_box);
        // This works when Data Sized Bound is removed
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        assert_eq!(data_arc_box.get_num(), data_arc.get_num())
    }

    #[actix_rt::test]
    async fn test_dyn_data_into_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let arc_from_data = data_arc.clone().into_inner();
        assert_eq!(data_arc.get_num(), arc_from_data.get_num())
    }

    #[actix_rt::test]
    async fn test_get_ref_from_dyn_data() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let ref_data = data_arc.get_ref();
        assert_eq!(data_arc.get_num(), ref_data.get_num())
    }
}
<commit_msg>improve "data no configured" message (#2429)<commit_after>use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::Serialize;

use crate::{
    dev::Payload, error::ErrorInternalServerError, extract::FromRequest, request::HttpRequest,
    Error,
};

/// Data factory.
pub(crate) trait DataFactory {
    /// Return true if modifications were made to extensions map.
    fn create(&self, extensions: &mut Extensions) -> bool;
}

pub(crate) type FnDataFactory =
    Box<dyn Fn() -> LocalBoxFuture<'static, Result<Box<dyn DataFactory>, ()>>>;

/// Application data.
///
/// Application level data is a piece of arbitrary data attached to the app, scope, or resource.
/// Application data is available to all routes and can be added during the application
/// configuration process via `App::data()`.
///
/// Application data can be accessed by using `Data<T>` extractor where `T` is data type.
///
/// **Note**: HTTP server accepts an application factory rather than an application instance. HTTP
/// server constructs an application instance for each thread, thus application data must be
/// constructed multiple times. If you want to share data between different threads, a shareable
/// object should be used, e.g. `Send + Sync`. Application data does not need to be `Send`
/// or `Sync`. Internally `Data` uses `Arc`.
///
/// If route data is not set for a handler, using `Data<T>` extractor would cause *Internal
/// Server Error* response.
///
// TODO: document `dyn T` functionality through converting an Arc
// TODO: note equivalence of req.app_data<Data<T>> and Data<T> extractor
// TODO: note that data must be inserted using Data<T> in order to extract it
///
/// # Examples
/// ```
/// use std::sync::Mutex;
/// use actix_web::{web, App, HttpResponse, Responder};
///
/// struct MyData {
///     counter: usize,
/// }
///
/// /// Use the `Data<T>` extractor to access data in a handler.
/// async fn index(data: web::Data<Mutex<MyData>>) -> impl Responder {
///     let mut data = data.lock().unwrap();
///     data.counter += 1;
///     HttpResponse::Ok()
/// }
///
/// fn main() {
///     let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
///
///     let app = App::new()
///         // Store `MyData` in application storage.
///         .app_data(data.clone())
///         .service(
///             web::resource("/index.html").route(
///                 web::get().to(index)));
/// }
/// ```
#[derive(Debug)]
pub struct Data<T: ?Sized>(Arc<T>);

impl<T> Data<T> {
    /// Create new `Data` instance.
    pub fn new(state: T) -> Data<T> {
        Data(Arc::new(state))
    }
}

impl<T: ?Sized> Data<T> {
    /// Get reference to inner app data.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }

    /// Convert to the internal Arc<T>
    pub fn into_inner(self) -> Arc<T> {
        self.0
    }
}

impl<T: ?Sized> Deref for Data<T> {
    type Target = Arc<T>;

    fn deref(&self) -> &Arc<T> {
        &self.0
    }
}

impl<T: ?Sized> Clone for Data<T> {
    fn clone(&self) -> Data<T> {
        Data(self.0.clone())
    }
}

impl<T: ?Sized> From<Arc<T>> for Data<T> {
    fn from(arc: Arc<T>) -> Self {
        Data(arc)
    }
}

impl<T> Serialize for Data<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<T: ?Sized + 'static> FromRequest for Data<T> {
    type Error = Error;
    type Future = Ready<Result<Self, Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.app_data::<Data<T>>() {
            ok(st.clone())
        } else {
            log::debug!(
                "Failed to construct App-level Data extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            err(ErrorInternalServerError(
                "App data is not configured, to configure construct it with web::Data::new() and pass it to App::app_data()",
            ))
        }
    }
}

impl<T: ?Sized + 'static> DataFactory for Data<T> {
    fn create(&self, extensions: &mut Extensions) -> bool {
        extensions.insert(Data(self.0.clone()));
        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        dev::Service,
        http::StatusCode,
        test::{init_service, TestRequest},
        web, App, HttpResponse,
    };

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_data_extractor() {
        let srv = init_service(App::new().data("TEST".to_string()).service(
            web::resource("/").to(|data: web::Data<String>| {
                assert_eq!(data.to_lowercase(), "test");
                HttpResponse::Ok()
            }),
        ))
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .data(10u32)
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);

        let srv = init_service(
            App::new()
                .data(10u32)
                .data(13u32)
                .app_data(12u64)
                .app_data(15u64)
                .default_service(web::to(|n: web::Data<u32>, req: HttpRequest| {
                    // in each case, the latter insertion should be preserved
                    assert_eq!(*req.app_data::<u64>().unwrap(), 15);
                    assert_eq!(*n.into_inner(), 13);
                    HttpResponse::Ok()
                })),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_app_data_extractor() {
        let srv = init_service(
            App::new()
                .app_data(Data::new(10usize))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .app_data(Data::new(10u32))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_route_data_extractor() {
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10usize)
                    .route(web::get().to(|_data: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        // different type
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10u32)
                    .route(web::get().to(|_: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_override_data() {
        let srv =
            init_service(App::new().data(1usize).service(
                web::resource("/").data(10usize).route(web::get().to(
                    |data: web::Data<usize>| {
                        assert_eq!(**data, 10);
                        HttpResponse::Ok()
                    },
                )),
            ))
            .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_data_from_arc() {
        let data_new = Data::new(String::from("test-123"));
        let data_from_arc = Data::from(Arc::new(String::from("test-123")));
        assert_eq!(data_new.0, data_from_arc.0)
    }

    #[actix_rt::test]
    async fn test_data_from_dyn_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        // This works when Sized is required
        let dyn_arc_box: Arc<Box<dyn TestTrait>> = Arc::new(Box::new(A {}));
        let data_arc_box = Data::from(dyn_arc_box);
        // This works when Data Sized Bound is removed
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        assert_eq!(data_arc_box.get_num(), data_arc.get_num())
    }

    #[actix_rt::test]
    async fn test_dyn_data_into_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let arc_from_data = data_arc.clone().into_inner();
        assert_eq!(data_arc.get_num(), arc_from_data.get_num())
    }

    #[actix_rt::test]
    async fn test_get_ref_from_dyn_data() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let ref_data = data_arc.get_ref();
        assert_eq!(data_arc.get_num(), ref_data.get_num())
    }
}
<|endoftext|>