<commit_before>#![allow(clippy::zero_prefixed_literal)]

use crate::{
    wire,
    wire::{find_byte, Cmd, Msg, Pfx},
    Event, ServerInfo,
};

use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::Sender;

#[derive(Clone)]
pub struct State {
    inner: Arc<Mutex<StateInner>>,
}

impl State {
    pub(crate) fn new(server_info: ServerInfo) -> State {
        State {
            inner: Arc::new(Mutex::new(StateInner::new(server_info))),
        }
    }

    pub(crate) fn reset(&self) {
        self.inner.lock().unwrap().reset()
    }

    pub(crate) fn update(
        &self,
        msg: &Msg,
        snd_ev: &mut Sender<Event>,
        snd_irc_msg: &mut Sender<String>,
    ) {
        self.inner.lock().unwrap().update(msg, snd_ev, snd_irc_msg)
    }

    pub(crate) fn introduce(&self, snd_irc_msg: &mut Sender<String>) {
        self.inner.lock().unwrap().introduce(snd_irc_msg)
    }

    // FIXME: This allocates a new String
    pub(crate) fn get_nick(&self) -> String {
        self.inner.lock().unwrap().current_nick.clone()
    }

    // FIXME: Maybe use RwLock instead of Mutex
    pub(crate) fn is_nick_accepted(&self) -> bool {
        self.inner.lock().unwrap().nick_accepted
    }

    pub(crate) fn get_usermask(&self) -> Option<String> {
        self.inner.lock().unwrap().usermask.clone()
    }

    pub(crate) fn set_away(&self, msg: Option<&str>) {
        self.inner.lock().unwrap().away_status = msg.map(str::to_owned);
    }
}

struct StateInner {
    /// Nicks to try, with this order.
    nicks: Vec<String>,

    /// NickServ passowrd.
    nickserv_ident: Option<String>,

    /// An index to `nicks`. When out of range we add `current_nick_idx - nicks.length()`
    /// underscores to the last nick in `nicks`
    current_nick_idx: usize,

    /// A cache of current nick, to avoid allocating new nicks when inventing new nicks with
    /// underscores.
    current_nick: String,

    /// Currently joined channels. Every channel we join will be added here to be able to re-join
    /// automatically on reconnect and channels we leave will be removed.
    ///
    /// Technically a set but we want to join channels in the order given by the user, so using
    /// `Vec` here.
    chans: Vec<String>,

    /// Away reason if away mode is on. `None` otherwise. TODO: I don't think the message is used?
    away_status: Option<String>,

    /// servername to be used in PING messages. Read from 002 RPL_YOURHOST. `None` until 002.
    servername: Option<String>,

    /// Our usermask given by the server. Currently only parsed after a JOIN, reply 396.
    ///
    /// Note that RPL_USERHOST (302) does not take cloaks into account, so we don't parse USERHOST
    /// responses to set this field.
    usermask: Option<String>,

    /// Do we have a nick yet? Try another nick on ERR_NICKNAMEINUSE (433) until we've got a nick.
    nick_accepted: bool,

    /// Server information
    server_info: ServerInfo,
}

impl StateInner {
    fn new(server_info: ServerInfo) -> StateInner {
        let current_nick = server_info.nicks[0].to_owned();
        let chans = server_info.auto_join.clone();
        StateInner {
            nicks: server_info.nicks.clone(),
            nickserv_ident: server_info.nickserv_ident.clone(),
            current_nick_idx: 0,
            current_nick,
            chans,
            away_status: None,
            servername: None,
            usermask: None,
            nick_accepted: false,
            server_info,
        }
    }

    fn reset(&mut self) {
        self.nicks = self.server_info.nicks.clone();
        self.current_nick_idx = 0;
        self.current_nick = self.nicks[0].clone();
        self.chans = self.server_info.auto_join.clone();
        self.servername = None;
        self.usermask = None;
    }

    fn introduce(&mut self, snd_irc_msg: &mut Sender<String>) {
        if let Some(ref pass) = self.server_info.pass {
            snd_irc_msg.try_send(wire::pass(pass)).unwrap();
        }
        snd_irc_msg
            .try_send(wire::nick(&self.current_nick))
            .unwrap();
        snd_irc_msg
            .try_send(wire::user(
                &self.server_info.hostname,
                &self.server_info.realname,
            ))
            .unwrap();
    }

    fn get_next_nick(&mut self) -> &str {
        self.current_nick_idx += 1;
        // println!("current_nick_idx: {}", self.current_nick_idx);
        if self.current_nick_idx >= self.nicks.len() {
            let n_underscores = self.current_nick_idx - self.nicks.len() + 1;
            let mut new_nick = self.nicks.last().unwrap().to_string();
            for _ in 0..n_underscores {
                new_nick.push('_');
            }
            self.current_nick = new_nick;
        } else {
            self.current_nick = self.nicks[self.current_nick_idx].clone();
        }
        &self.current_nick
    }

    fn update(&mut self, msg: &Msg, snd_ev: &mut Sender<Event>, snd_irc_msg: &mut Sender<String>) {
        let Msg { ref pfx, ref cmd } = msg;

        use Cmd::*;
        match cmd {
            PING { server } => {
                snd_irc_msg.try_send(wire::pong(server)).unwrap();
            }

            //
            // Setting usermask using JOIN, RPL_USERHOST and 396 (?)
            //
            JOIN { .. } => {
                if let Some(Pfx::User { nick, user }) = pfx {
                    if nick == &self.current_nick {
                        let usermask = format!("{}!{}", nick, user);
                        self.usermask = Some(usermask);
                    }
                }
            }

            Reply { num: 396, params } => {
                // :hobana.freenode.net 396 osa1 haskell/developer/osa1
                // :is now your hidden host (set by services.)
                if params.len() == 3 {
                    let usermask = format!(
                        "{}!~{}@{}",
                        self.current_nick, self.server_info.hostname, params[1]
                    );
                    self.usermask = Some(usermask);
                }
            }

            Reply { num: 302, params } => {
                // 302 RPL_USERHOST
                // :ircd.stealth.net 302 yournick :syrk=+syrk@millennium.stealth.net
                //
                // We know there will be only one nick because /userhost cmd sends
                // one parameter (our nick)
                //
                // Example args: ["osa1", "osa1=+omer@moz-s8a.9ac.93.91.IP "]

                let param = &params[1];
                match find_byte(param.as_bytes(), b'=') {
                    None => {
                        // TODO: Log this
                    }
                    Some(mut i) => {
                        if param.as_bytes().get(i + 1) == Some(&b'+')
                            || param.as_bytes().get(i + 1) == Some(&b'-')
                        {
                            i += 1;
                        }
                        let usermask = (&param[i..]).trim();
                        self.usermask = Some(usermask.to_owned());
                    }
                }
            }

            //
            // RPL_WELCOME
            //
            Reply { num: 001, .. } => {
                snd_ev.try_send(Event::Connected).unwrap();
                snd_ev
                    .try_send(Event::NickChange(self.current_nick.clone()))
                    .unwrap();
                self.nick_accepted = true;
                if let Some(ref pwd) = self.nickserv_ident {
                    snd_irc_msg
                        .try_send(wire::privmsg("NickServ", &format!("identify {}", pwd)))
                        .unwrap();
                }
            }

            //
            // RPL_YOURHOST
            //
            Reply { num: 002, params } => {
                // 002    RPL_YOURHOST
                //        "Your host is <servername>, running version <ver>"

                // An example <servername>: cherryh.freenode.net[149.56.134.238/8001]

                match parse_servername(params) {
                    None => {
                        // TODO: Log
                    }
                    Some(servername) => {
                        self.servername = Some(servername);
                    }
                }
            }

            //
            // ERR_NICKNAMEINUSE
            //
            Reply { num: 433, .. } => {
                // ERR_NICKNAMEINUSE. If we don't have a nick already try next nick.
                if !self.nick_accepted {
                    let new_nick = self.get_next_nick();
                    // println!("new nick: {}", new_nick);
                    snd_ev
                        .try_send(Event::NickChange(new_nick.to_owned()))
                        .unwrap();
                    snd_irc_msg.try_send(wire::nick(new_nick)).unwrap();
                }
            }

            //
            // NICK message sent from the server when our nick change request was successful
            //
            NICK { nick: new_nick } => {
                if let Some(Pfx::User { nick: old_nick, .. }) = pfx {
                    if old_nick == &self.current_nick {
                        snd_ev
                            .try_send(Event::NickChange(new_nick.to_owned()))
                            .unwrap();
                        if !self.nicks.contains(new_nick) {
                            self.nicks.push(new_nick.to_owned());
                            self.current_nick_idx = self.nicks.len() - 1;
                        }
                    }
                }
            }

            //
            // RPL_ENDOFMOTD, join channels, set away status (TODO)
            //
            Reply { num: 376, .. } => {
                if !self.chans.is_empty() {
                    snd_irc_msg
                        .try_send(format!("JOIN {}\r\n", self.chans.join(",")))
                        .unwrap();
                }
            }

            //
            // RPL_TOPIC, we've successfully joined a channel
            //
            Reply { num: 332, params } => {
                if params.len() == 2 || params.len() == 3 {
                    let chan = &params[params.len() - 2];
                    if !self.chans.contains(chan) {
                        self.chans.push(chan.to_owned());
                    }
                }
            }

            //
            // SASL authentication
            //
            CAP {
                client: _,
                subcommand,
                params,
            } => {
                match subcommand.as_ref() {
                    "ACK" => {
                        if params.iter().any(|cap| cap.as_str() == "sasl") {
                            snd_irc_msg.try_send(wire::authenticate("PLAIN")).unwrap();
                        }
                    }
                    "NAK" => {
                        snd_irc_msg.try_send(wire::cap_end()).unwrap();
                    }
                    "LS" => {
                        self.introduce(snd_irc_msg);
                        if params.iter().any(|cap| cap == "sasl") {
                            snd_irc_msg.try_send(wire::cap_req(&["sasl"])).unwrap();
                            // Will wait for CAP ... ACK from server before authentication.
                        }
                    }
                    _ => {}
                }
            }

            AUTHENTICATE { ref param } => {
                if param.as_str() == "+" {
                    // Empty AUTHENTICATE response; server accepted the specified SASL mechanism
                    // (PLAIN)
                    if let Some(ref auth) = self.server_info.sasl_auth {
                        let msg = format!(
                            "{}\x00{}\x00{}",
                            auth.username, auth.username, auth.password
                        );
                        snd_irc_msg
                            .try_send(wire::authenticate(&base64::encode(&msg)))
                            .unwrap();
                    }
                }
            }

            _ => {}
        }
    }
}

/// Try to parse servername in a 002 RPL_YOURHOST reply
fn parse_servername(params: &[String]) -> Option<String> {
    let msg = params.get(1).or_else(|| params.get(0))?;
    let slice1 = &msg[13..];
    let servername_ends =
        find_byte(slice1.as_bytes(), b'[').or_else(|| find_byte(slice1.as_bytes(), b','))?;
    Some((&slice1[..servername_ends]).to_owned())
}

////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn test_parse_servername_1() {
        let args = vec![
            "tiny_test".to_owned(),
            "Your host is adams.freenode.net[94.125.182.252/8001], \
             running version ircd-seven-1.1.4"
                .to_owned(),
        ];
        assert_eq!(
            parse_servername(&args),
            Some("adams.freenode.net".to_owned())
        );
    }

    #[test]
    fn test_parse_servername_2() {
        let args = vec![
            "tiny_test".to_owned(),
            "Your host is belew.mozilla.org, running version InspIRCd-2.0".to_owned(),
        ];
        assert_eq!(
            parse_servername(&args),
            Some("belew.mozilla.org".to_owned())
        );
    }
}
<commit_msg>Fix SASL auth<commit_after>#![allow(clippy::zero_prefixed_literal)]

use crate::{
    wire,
    wire::{find_byte, Cmd, Msg, Pfx},
    Event, ServerInfo,
};

use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::Sender;

#[derive(Clone)]
pub struct State {
    inner: Arc<Mutex<StateInner>>,
}

impl State {
    pub(crate) fn new(server_info: ServerInfo) -> State {
        State {
            inner: Arc::new(Mutex::new(StateInner::new(server_info))),
        }
    }

    pub(crate) fn reset(&self) {
        self.inner.lock().unwrap().reset()
    }

    pub(crate) fn update(
        &self,
        msg: &Msg,
        snd_ev: &mut Sender<Event>,
        snd_irc_msg: &mut Sender<String>,
    ) {
        self.inner.lock().unwrap().update(msg, snd_ev, snd_irc_msg)
    }

    pub(crate) fn introduce(&self, snd_irc_msg: &mut Sender<String>) {
        self.inner.lock().unwrap().introduce(snd_irc_msg)
    }

    // FIXME: This allocates a new String
    pub(crate) fn get_nick(&self) -> String {
        self.inner.lock().unwrap().current_nick.clone()
    }

    // FIXME: Maybe use RwLock instead of Mutex
    pub(crate) fn is_nick_accepted(&self) -> bool {
        self.inner.lock().unwrap().nick_accepted
    }

    pub(crate) fn get_usermask(&self) -> Option<String> {
        self.inner.lock().unwrap().usermask.clone()
    }

    pub(crate) fn set_away(&self, msg: Option<&str>) {
        self.inner.lock().unwrap().away_status = msg.map(str::to_owned);
    }
}

struct StateInner {
    /// Nicks to try, with this order.
    nicks: Vec<String>,

    /// NickServ passowrd.
    nickserv_ident: Option<String>,

    /// An index to `nicks`. When out of range we add `current_nick_idx - nicks.length()`
    /// underscores to the last nick in `nicks`
    current_nick_idx: usize,

    /// A cache of current nick, to avoid allocating new nicks when inventing new nicks with
    /// underscores.
    current_nick: String,

    /// Currently joined channels. Every channel we join will be added here to be able to re-join
    /// automatically on reconnect and channels we leave will be removed.
    ///
    /// Technically a set but we want to join channels in the order given by the user, so using
    /// `Vec` here.
    chans: Vec<String>,

    /// Away reason if away mode is on. `None` otherwise. TODO: I don't think the message is used?
    away_status: Option<String>,

    /// servername to be used in PING messages. Read from 002 RPL_YOURHOST. `None` until 002.
    servername: Option<String>,

    /// Our usermask given by the server. Currently only parsed after a JOIN, reply 396.
    ///
    /// Note that RPL_USERHOST (302) does not take cloaks into account, so we don't parse USERHOST
    /// responses to set this field.
    usermask: Option<String>,

    /// Do we have a nick yet? Try another nick on ERR_NICKNAMEINUSE (433) until we've got a nick.
    nick_accepted: bool,

    /// Server information
    server_info: ServerInfo,
}

impl StateInner {
    fn new(server_info: ServerInfo) -> StateInner {
        let current_nick = server_info.nicks[0].to_owned();
        let chans = server_info.auto_join.clone();
        StateInner {
            nicks: server_info.nicks.clone(),
            nickserv_ident: server_info.nickserv_ident.clone(),
            current_nick_idx: 0,
            current_nick,
            chans,
            away_status: None,
            servername: None,
            usermask: None,
            nick_accepted: false,
            server_info,
        }
    }

    fn reset(&mut self) {
        self.nicks = self.server_info.nicks.clone();
        self.current_nick_idx = 0;
        self.current_nick = self.nicks[0].clone();
        self.chans = self.server_info.auto_join.clone();
        self.servername = None;
        self.usermask = None;
    }

    fn introduce(&mut self, snd_irc_msg: &mut Sender<String>) {
        if let Some(ref pass) = self.server_info.pass {
            snd_irc_msg.try_send(wire::pass(pass)).unwrap();
        }
        snd_irc_msg
            .try_send(wire::nick(&self.current_nick))
            .unwrap();
        snd_irc_msg
            .try_send(wire::user(
                &self.server_info.hostname,
                &self.server_info.realname,
            ))
            .unwrap();
    }

    fn get_next_nick(&mut self) -> &str {
        self.current_nick_idx += 1;
        // println!("current_nick_idx: {}", self.current_nick_idx);
        if self.current_nick_idx >= self.nicks.len() {
            let n_underscores = self.current_nick_idx - self.nicks.len() + 1;
            let mut new_nick = self.nicks.last().unwrap().to_string();
            for _ in 0..n_underscores {
                new_nick.push('_');
            }
            self.current_nick = new_nick;
        } else {
            self.current_nick = self.nicks[self.current_nick_idx].clone();
        }
        &self.current_nick
    }

    fn update(&mut self, msg: &Msg, snd_ev: &mut Sender<Event>, snd_irc_msg: &mut Sender<String>) {
        let Msg { ref pfx, ref cmd } = msg;

        use Cmd::*;
        match cmd {
            PING { server } => {
                snd_irc_msg.try_send(wire::pong(server)).unwrap();
            }

            //
            // Setting usermask using JOIN, RPL_USERHOST and 396 (?)
            //
            JOIN { .. } => {
                if let Some(Pfx::User { nick, user }) = pfx {
                    if nick == &self.current_nick {
                        let usermask = format!("{}!{}", nick, user);
                        self.usermask = Some(usermask);
                    }
                }
            }

            Reply { num: 396, params } => {
                // :hobana.freenode.net 396 osa1 haskell/developer/osa1
                // :is now your hidden host (set by services.)
                if params.len() == 3 {
                    let usermask = format!(
                        "{}!~{}@{}",
                        self.current_nick, self.server_info.hostname, params[1]
                    );
                    self.usermask = Some(usermask);
                }
            }

            Reply { num: 302, params } => {
                // 302 RPL_USERHOST
                // :ircd.stealth.net 302 yournick :syrk=+syrk@millennium.stealth.net
                //
                // We know there will be only one nick because /userhost cmd sends
                // one parameter (our nick)
                //
                // Example args: ["osa1", "osa1=+omer@moz-s8a.9ac.93.91.IP "]

                let param = &params[1];
                match find_byte(param.as_bytes(), b'=') {
                    None => {
                        // TODO: Log this
                    }
                    Some(mut i) => {
                        if param.as_bytes().get(i + 1) == Some(&b'+')
                            || param.as_bytes().get(i + 1) == Some(&b'-')
                        {
                            i += 1;
                        }
                        let usermask = (&param[i..]).trim();
                        self.usermask = Some(usermask.to_owned());
                    }
                }
            }

            //
            // RPL_WELCOME
            //
            Reply { num: 001, .. } => {
                snd_ev.try_send(Event::Connected).unwrap();
                snd_ev
                    .try_send(Event::NickChange(self.current_nick.clone()))
                    .unwrap();
                self.nick_accepted = true;
                if let Some(ref pwd) = self.nickserv_ident {
                    snd_irc_msg
                        .try_send(wire::privmsg("NickServ", &format!("identify {}", pwd)))
                        .unwrap();
                }
            }

            //
            // RPL_YOURHOST
            //
            Reply { num: 002, params } => {
                // 002    RPL_YOURHOST
                //        "Your host is <servername>, running version <ver>"

                // An example <servername>: cherryh.freenode.net[149.56.134.238/8001]

                match parse_servername(params) {
                    None => {
                        // TODO: Log
                    }
                    Some(servername) => {
                        self.servername = Some(servername);
                    }
                }
            }

            //
            // ERR_NICKNAMEINUSE
            //
            Reply { num: 433, .. } => {
                // ERR_NICKNAMEINUSE. If we don't have a nick already try next nick.
                if !self.nick_accepted {
                    let new_nick = self.get_next_nick();
                    // println!("new nick: {}", new_nick);
                    snd_ev
                        .try_send(Event::NickChange(new_nick.to_owned()))
                        .unwrap();
                    snd_irc_msg.try_send(wire::nick(new_nick)).unwrap();
                }
            }

            //
            // NICK message sent from the server when our nick change request was successful
            //
            NICK { nick: new_nick } => {
                if let Some(Pfx::User { nick: old_nick, .. }) = pfx {
                    if old_nick == &self.current_nick {
                        snd_ev
                            .try_send(Event::NickChange(new_nick.to_owned()))
                            .unwrap();
                        if !self.nicks.contains(new_nick) {
                            self.nicks.push(new_nick.to_owned());
                            self.current_nick_idx = self.nicks.len() - 1;
                        }
                    }
                }
            }

            //
            // RPL_ENDOFMOTD, join channels, set away status (TODO)
            //
            Reply { num: 376, .. } => {
                if !self.chans.is_empty() {
                    snd_irc_msg
                        .try_send(format!("JOIN {}\r\n", self.chans.join(",")))
                        .unwrap();
                }
            }

            //
            // RPL_TOPIC, we've successfully joined a channel
            //
            Reply { num: 332, params } => {
                if params.len() == 2 || params.len() == 3 {
                    let chan = &params[params.len() - 2];
                    if !self.chans.contains(chan) {
                        self.chans.push(chan.to_owned());
                    }
                }
            }

            //
            // SASL authentication
            //
            CAP {
                client: _,
                subcommand,
                params,
            } => {
                match subcommand.as_ref() {
                    "ACK" => {
                        if params.iter().any(|cap| cap.as_str() == "sasl") {
                            snd_irc_msg.try_send(wire::authenticate("PLAIN")).unwrap();
                        }
                    }
                    "NAK" => {
                        snd_irc_msg.try_send(wire::cap_end()).unwrap();
                    }
                    "LS" => {
                        self.introduce(snd_irc_msg);
                        if params.iter().any(|cap| cap == "sasl") {
                            snd_irc_msg.try_send(wire::cap_req(&["sasl"])).unwrap();
                            // Will wait for CAP ... ACK from server before authentication.
                        }
                    }
                    _ => {}
                }
            }

            AUTHENTICATE { ref param } => {
                if param.as_str() == "+" {
                    // Empty AUTHENTICATE response; server accepted the specified SASL mechanism
                    // (PLAIN)
                    if let Some(ref auth) = self.server_info.sasl_auth {
                        let msg = format!(
                            "{}\x00{}\x00{}",
                            auth.username, auth.username, auth.password
                        );
                        snd_irc_msg
                            .try_send(wire::authenticate(&base64::encode(&msg)))
                            .unwrap();
                    }
                }
            }

            Reply { num: 903, .. } | Reply { num: 904, .. } => {
                // 903: RPL_SASLSUCCESS, 904: ERR_SASLFAIL
                snd_irc_msg.try_send(wire::cap_end()).unwrap();
            }

            //
            // Ignore the rest
            //
            _ => {}
        }
    }
}

/// Try to parse servername in a 002 RPL_YOURHOST reply
fn parse_servername(params: &[String]) -> Option<String> {
    let msg = params.get(1).or_else(|| params.get(0))?;
    let slice1 = &msg[13..];
    let servername_ends =
        find_byte(slice1.as_bytes(), b'[').or_else(|| find_byte(slice1.as_bytes(), b','))?;
    Some((&slice1[..servername_ends]).to_owned())
}

////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn test_parse_servername_1() {
        let args = vec![
            "tiny_test".to_owned(),
            "Your host is adams.freenode.net[94.125.182.252/8001], \
             running version ircd-seven-1.1.4"
                .to_owned(),
        ];
        assert_eq!(
            parse_servername(&args),
            Some("adams.freenode.net".to_owned())
        );
    }

    #[test]
    fn test_parse_servername_2() {
        let args = vec![
            "tiny_test".to_owned(),
            "Your host is belew.mozilla.org, running version InspIRCd-2.0".to_owned(),
        ];
        assert_eq!(
            parse_servername(&args),
            Some("belew.mozilla.org".to_owned())
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2019-2020 Twitter, Inc.
// Licensed under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

use crate::ClientConfig;

use tiny_http::{Method, Response, Server};

use std::net::SocketAddr;

pub(crate) struct Http {
    client_config: ClientConfig,
    server: Server,
}

impl Http {
    pub fn new(address: SocketAddr, client_config: ClientConfig) -> Self {
        let server = tiny_http::Server::http(address);
        if server.is_err() {
            fatal!("Failed to open {} for HTTP Admin listener", address);
        }
        Self {
            client_config,
            server: server.unwrap(),
        }
    }

    pub fn run(&mut self) {
        if let Ok(Some(mut request)) = self.server.try_recv() {
            match request.method() {
                Method::Get => match request.url() {
                    "/" => {
                        debug!("Serving GET on index");
                        let _ = request.respond(Response::from_string(format!(
                            "rpc-perf\nVersion: {}\nAdmin port",
                            crate::config::VERSION
                        )));
                    }
                    "/ratelimit/request" => {
                        if self.client_config.request_ratelimiter.is_some() {
                            let _ = request.respond(Response::from_string(format!(
                                "{}",
                                self.client_config
                                    .request_ratelimiter
                                    .as_ref()
                                    .unwrap()
                                    .rate()
                            )));
                        } else {
                            let _ = request.respond(Response::from_string("None".to_string()));
                        }
                    }
                    url => {
                        debug!("GET on non-existent url: {}", url);
                        let _ = request.respond(Response::empty(404));
                    }
                },
                Method::Put => match request.url() {
                    "/ratelimit/request" => {
                        let mut content = String::new();
                        request.as_reader().read_to_string(&mut content).unwrap();
                        if let Ok(rate) = content.parse() {
                            if let Some(ref ratelimiter) = self.client_config.request_ratelimiter {
                                ratelimiter.set_rate(rate);
                                let _ = request.respond(Response::empty(200));
                            } else {
                                let _ = request.respond(Response::empty(400));
                            }
                        } else {
                            let _ = request.respond(Response::empty(400));
                        }
                    }
                    url => {
                        debug!("PUT on non-existent url: {}", url);
                        let _ = request.respond(Response::empty(404));
                    }
                },
                method => {
                    error!("unsupported request method: {}", method);
                    let _ = request.respond(Response::empty(404));
                }
            }
        }
        std::thread::sleep(std::time::Duration::from_millis(1));
    }
}
<commit_msg>rpc-perf: add newlines to admin GET responses (#295)<commit_after>// Copyright 2019-2020 Twitter, Inc.
// Licensed under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

use crate::ClientConfig;

use tiny_http::{Method, Response, Server};

use std::net::SocketAddr;

pub(crate) struct Http {
    client_config: ClientConfig,
    server: Server,
}

impl Http {
    pub fn new(address: SocketAddr, client_config: ClientConfig) -> Self {
        let server = tiny_http::Server::http(address);
        if server.is_err() {
            fatal!("Failed to open {} for HTTP Admin listener", address);
        }
        Self {
            client_config,
            server: server.unwrap(),
        }
    }

    pub fn run(&mut self) {
        if let Ok(Some(mut request)) = self.server.try_recv() {
            match request.method() {
                Method::Get => match request.url() {
                    "/" => {
                        debug!("Serving GET on index");
                        let _ = request.respond(Response::from_string(format!(
                            "rpc-perf\nVersion: {}\nAdmin port",
                            crate::config::VERSION
                        )));
                    }
                    "/ratelimit/request" => {
                        if self.client_config.request_ratelimiter.is_some() {
                            let _ = request.respond(Response::from_string(format!(
                                "{}\n",
                                self.client_config
                                    .request_ratelimiter
                                    .as_ref()
                                    .unwrap()
                                    .rate()
                            )));
                        } else {
                            let _ = request.respond(Response::from_string("None\n".to_string()));
                        }
                    }
                    url => {
                        debug!("GET on non-existent url: {}", url);
                        let _ = request.respond(Response::empty(404));
                    }
                },
                Method::Put => match request.url() {
                    "/ratelimit/request" => {
                        let mut content = String::new();
                        request.as_reader().read_to_string(&mut content).unwrap();
                        if let Ok(rate) = content.parse() {
                            if let Some(ref ratelimiter) = self.client_config.request_ratelimiter {
                                ratelimiter.set_rate(rate);
                                let _ = request.respond(Response::empty(200));
                            } else {
                                let _ = request.respond(Response::empty(400));
                            }
                        } else {
                            let _ = request.respond(Response::empty(400));
                        }
                    }
                    url => {
                        debug!("PUT on non-existent url: {}", url);
                        let _ = request.respond(Response::empty(404));
                    }
                },
                method => {
                    error!("unsupported request method: {}", method);
                    let _ = request.respond(Response::empty(404));
                }
            }
        }
        std::thread::sleep(std::time::Duration::from_millis(1));
    }
}
<|endoftext|>


<commit_before>#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
#![allow(clippy::too_many_arguments)]
#![warn(unused)]

use ::xml as xml_rs;

pub use crate::color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use crate::dpi::{rsvg_rust_set_default_dpi_x_y, Dpi};

pub use crate::drawing_ctx::RsvgRectangle;

pub use crate::error::{
    rsvg_rust_error_quark, set_gerror, DefsLookupErrorKind, HrefError, LoadingError,
    RenderingError, RSVG_ERROR_FAILED,
};

pub use crate::handle::{
    Handle, LoadOptions, RsvgDimensionData, RsvgPositionData, RsvgSizeFunc, SizeCallback,
};

pub use crate::length::{Length, LengthUnit, RsvgLength};

pub use crate::rect::IRect;

pub use crate::structure::IntrinsicDimensions;

pub use crate::surface_utils::{
    iterators::Pixels,
    shared_surface::{
        SharedImageSurface, SurfaceType,
    },
};

#[macro_use]
pub mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod angle;
mod aspect_ratio;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod document;
mod dpi;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod limits;
mod link;
mod marker;
mod mask;
mod node;
mod number_list;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod properties;
mod property_bag;
mod property_defs;
pub mod rect;
mod shapes;
mod space;
pub mod srgb;
mod structure;
mod style;
pub mod surface_utils;
mod text;
mod transform;
mod unit_interval;
mod util;
mod viewbox;
mod xml;
mod xml2;
mod xml2_load;
<commit_msg>Start documenting the toplevel rsvg_internals/lib.rs<commit_after>//! # The implementation of librsvg
//!
//! The implementation of librsvg is in the `rsvg_internals` crate.  It is not a public
//! crate; instead, it exports the primitives necessary to implement librsvg's public APIs,
//! both the C and Rust APIs.  It has the XML and CSS parsing code, the SVG element
//! definitions and tree of elements, and all the drawing logic.
//!
//! Some interesting parts of rsvg_internals:
//!
//! * [The `Handle` struct](handle/struct.Handle.html) provides the primitives to implement
//! the public APIs, such as loading an SVG file and rendering it.
//!
//! * [The `DrawingCtx` struct](drawing_ctx/struct.DrawingCtx.html) is active while an SVG
//! handle is being drawn or queried for its geometry.  It has all the mutable state related
//! to the drawing process.
//!
//! * [The `Document` struct][document/struct.Document.html] represents a loaded SVG
//! document.  It holds the tree of [`RsvgNode`] elements, and a mapping of `id` attributes
//! to the corresponding element nodes.
//!
//! * [The `node` module](node/index.html) provides the [`RsvgNode`] struct and
//! [`NodeTrait`], which form the basis for the tree of SVG elements.
//!
//! * [The `xml` module](xml/index.html) receives events from the XML parser, and builds a
//! [`Document`] as a tree of [`RsvgNode`].
//!
//! * [The `properties` module](properties/index.html) contains structs that represent
//! collections of CSS properties.
//!
//! * [The `property_defs` module](property_defs/index.html) contains one type for each of
//! the CSS style properties that librsvg supports.
//!
//! [`RsvgNode`]: node/type.RsvgNode.html
//! [`NodeTrait`]: node/trait.NodeTrait.html

#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
#![allow(clippy::too_many_arguments)]
#![warn(unused)]
use ::xml as xml_rs;

pub use crate::color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use crate::dpi::{rsvg_rust_set_default_dpi_x_y, Dpi};

pub use crate::drawing_ctx::RsvgRectangle;

pub use crate::error::{
    rsvg_rust_error_quark, set_gerror, DefsLookupErrorKind, HrefError, LoadingError,
    RenderingError, RSVG_ERROR_FAILED,
};

pub use crate::handle::{
    Handle, LoadOptions, RsvgDimensionData, RsvgPositionData, RsvgSizeFunc, SizeCallback,
};

pub use crate::length::{Length, LengthUnit, RsvgLength};

pub use crate::rect::IRect;

pub use crate::structure::IntrinsicDimensions;

pub use crate::surface_utils::{
    iterators::Pixels,
    shared_surface::{
        SharedImageSurface, SurfaceType,
    },
};

#[macro_use]
pub mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod angle;
mod aspect_ratio;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod document;
mod dpi;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod limits;
mod link;
mod marker;
mod mask;
mod node;
mod number_list;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod properties;
mod property_bag;
mod property_defs;
pub mod rect;
mod shapes;
mod space;
pub mod srgb;
mod structure;
mod style;
pub mod surface_utils;
mod text;
mod transform;
mod unit_interval;
mod util;
mod viewbox;
mod xml;
mod xml2;
mod xml2_load;
<|endoftext|>


<commit_before>use super::Rope;
use std::iter;

#[test]
fn rebalance_test_1() {
    let mut r = Rope::from("This is a large string \
                        that will need to be rebalanced.".to_string());
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn rebalance_test_2() {
    let mut r =
        Rope::from("Lorem ipsum dolor sit amet, consectetur adipiscing eli\
                    t, sed do eiusmod tempor incididunt ut labore et dolor\
                    e magna aliqua. Ut enim ad minim veniam, quis nostrud \
                    exercitation ullamco laboris nisi ut aliquip ex ea com\
                    modo consequat. Duis aute irure dolor in reprehenderit\
                     in voluptate velit esse cillum dolore eu fugiat nulla\
                     pariatur. Excepteur sint occaecat cupidatat non proid\
                    ent, sunt in culpa qui officia deserunt mollit anim id\
                     est laborum.".to_string());
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn big_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn repeated_concat_left_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    for _ in 1..1000 {
        r = r + iter::repeat('a').take(100).collect::<String>();
    }
    assert!(r.is_balanced());
}

#[test]
fn repeated_concat_right_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    for _ in 1..1000 {
        let s2 = iter::repeat('a').take(100).collect::<String>();
        r = Rope::from(s2) + r;
    }
    assert!(r.is_balanced());
}

#[test]
fn merge_rebalance_test() {
    let s = "Lorem ipsum dolor sit amet, consectetur adipiscing eli\
             t, sed do eiusmod tempor incididunt ut labore et dolor\
             e magna aliqua. Ut enim ad minim veniam, quis nostrud \
             exercitation ullamco laboris nisi ut aliquip ex ea com\
             modo consequat. Duis aute irure dolor in reprehenderit\
              in voluptate velit esse cillum dolore eu fugiat nulla\
              pariatur. Excepteur sint occaecat cupidatat non proid\
             ent, sunt in culpa qui officia deserunt mollit anim id\
              est laborum.";

     let t = Rope::from(s.to_owned());
     let mut u = t + s;
     u.rebalance();
     assert!(u.is_balanced());
}

#[test]
fn with_insert_rope_balance_test() {
    let s: String = iter::repeat('a').take(10).collect();
    let mut r_1 = Rope::from(s);
    for _ in 0..99 {
        let t: String = iter::repeat('a').take(10).collect();
        r_1 = r_1.with_insert_rope(5, Rope::from(t));
    }
    //  this isn't necessary, with_insert_rope() will automatically rebalance
    //      - eliza, 12/18/2016
    // r_1.rebalance();
    assert!(r_1.is_balanced());
}

#[test]
fn with_insert_rope_test_1() {
    let s: String = iter::repeat('a').take(1_000).collect();
    let r_1 = Rope::from(s);
    let mut r_2 = Rope::new();
    for _ in 0..100 {
        let t: String = iter::repeat('a').take(10).collect();
        r_2.with_insert_rope(0, Rope::from(t));
    }
    assert_eq!(r_1, r_2);
}

#[test]
fn with_insert_rope_test_2() {
    let s: String = iter::repeat('a').take(10).collect();
    let mut r_1 = Rope::from(s);
    for _ in 0..99 {
        let t: String = iter::repeat('a').take(10).collect();
        r_1 = r_1.with_insert_rope(5, Rope::from(t));
    }

    let q: String = iter::repeat('a').take(1_000).collect();
    let r_2 = Rope::from(q);
    assert_eq!(r_1, r_2);
}

#[test]
fn mutable_insert_rope_test_1() {
    let mut s_1 = Rope::from(String::from("aaaaa"));
    let mut s_2 = Rope::from(String::from("bbbbb"));
    let s_3 = Rope::from(String::from("ccccc"));
    s_2.insert_rope(0, s_3);
    s_1.insert_rope(0, s_2);
    assert_eq!(&s_1, "cccccbbbbbaaaaa");
}

#[test]
fn mutable_insert_str_test_1() {
    let mut s = Rope::from("aaaaa");
    s.insert_str(0, "bbbbb");
    s.insert_str(10, "ccccc");
    assert_eq!(&s, "bbbbbaaaaaccccc");
}

#[test]
fn mutable_insert_char_test_1() {
    let mut s = Rope::from("aaaaa");
    for _ in 0..5 { s.insert(0, 'b')}
    for _ in 0..5 { s.insert(10, 'c')}
    assert_eq!(&s, "bbbbbaaaaaccccc");
}

#[test]
fn with_insert_char_test_1() {
    let s = Rope::from("aaaaa");
    let s_1 = s.with_insert(5, 'b');
    let s_2 = s_1.with_insert(4, 'b');
    let s_3 = s_2.with_insert(3, 'b');
    let s_4 = s_3.with_insert(2, 'b');
    let s_5 = s_4.with_insert(1, 'b');
    assert_eq!(&s, "aaaaa");
    assert_eq!(&s_1, "aaaaab");
    assert_eq!(&s_2, "aaaabab");
    assert_eq!(&s_3, "aaababab");
    assert_eq!(&s_4, "aabababab");
    assert_eq!(&s_5, "ababababab");

}

#[test]
fn with_insert_str_test_1() {
    let s = Rope::from("aaaaa");
    let s_1 = s.with_insert_str(5, "ccccc");
    let s_2 = s_1.with_insert_str(5, "bbbbb");
    assert_eq!(&s, "aaaaa");
    assert_eq!(&s_1, "aaaaccccc");
    assert_eq!(&s_2, "aaaaabbbbbccccc");
}
<commit_msg>rope: fix incorrect expected value in test<commit_after>use super::Rope;
use std::iter;

#[test]
fn rebalance_test_1() {
    let mut r = Rope::from("This is a large string \
                        that will need to be rebalanced.".to_string());
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn rebalance_test_2() {
    let mut r =
        Rope::from("Lorem ipsum dolor sit amet, consectetur adipiscing eli\
                    t, sed do eiusmod tempor incididunt ut labore et dolor\
                    e magna aliqua. Ut enim ad minim veniam, quis nostrud \
                    exercitation ullamco laboris nisi ut aliquip ex ea com\
                    modo consequat. Duis aute irure dolor in reprehenderit\
                     in voluptate velit esse cillum dolore eu fugiat nulla\
                     pariatur. Excepteur sint occaecat cupidatat non proid\
                    ent, sunt in culpa qui officia deserunt mollit anim id\
                     est laborum.".to_string());
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn big_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    r.rebalance();
    assert!(r.is_balanced());
}

#[test]
fn repeated_concat_left_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    for _ in 1..1000 {
        r = r + iter::repeat('a').take(100).collect::<String>();
    }
    assert!(r.is_balanced());
}

#[test]
fn repeated_concat_right_rebalance() {
    let s: String = iter::repeat('a').take(10_000).collect();
    let mut r = Rope::from(s);
    for _ in 1..1000 {
        let s2 = iter::repeat('a').take(100).collect::<String>();
        r = Rope::from(s2) + r;
    }
    assert!(r.is_balanced());
}

#[test]
fn merge_rebalance_test() {
    let s = "Lorem ipsum dolor sit amet, consectetur adipiscing eli\
             t, sed do eiusmod tempor incididunt ut labore et dolor\
             e magna aliqua. Ut enim ad minim veniam, quis nostrud \
             exercitation ullamco laboris nisi ut aliquip ex ea com\
             modo consequat. Duis aute irure dolor in reprehenderit\
              in voluptate velit esse cillum dolore eu fugiat nulla\
              pariatur. Excepteur sint occaecat cupidatat non proid\
             ent, sunt in culpa qui officia deserunt mollit anim id\
              est laborum.";

     let t = Rope::from(s.to_owned());
     let mut u = t + s;
     u.rebalance();
     assert!(u.is_balanced());
}

#[test]
fn with_insert_rope_balance_test() {
    let s: String = iter::repeat('a').take(10).collect();
    let mut r_1 = Rope::from(s);
    for _ in 0..99 {
        let t: String = iter::repeat('a').take(10).collect();
        r_1 = r_1.with_insert_rope(5, Rope::from(t));
    }
    //  this isn't necessary, with_insert_rope() will automatically rebalance
    //      - eliza, 12/18/2016
    // r_1.rebalance();
    assert!(r_1.is_balanced());
}

#[test]
fn with_insert_rope_test_1() {
    let s: String = iter::repeat('a').take(1_000).collect();
    let r_1 = Rope::from(s);
    let mut r_2 = Rope::new();
    for _ in 0..100 {
        let t: String = iter::repeat('a').take(10).collect();
        r_2.with_insert_rope(0, Rope::from(t));
    }
    assert_eq!(r_1, r_2);
}

#[test]
fn with_insert_rope_test_2() {
    let s: String = iter::repeat('a').take(10).collect();
    let mut r_1 = Rope::from(s);
    for _ in 0..99 {
        let t: String = iter::repeat('a').take(10).collect();
        r_1 = r_1.with_insert_rope(5, Rope::from(t));
    }

    let q: String = iter::repeat('a').take(1_000).collect();
    let r_2 = Rope::from(q);
    assert_eq!(r_1, r_2);
}

#[test]
fn mutable_insert_rope_test_1() {
    let mut s_1 = Rope::from(String::from("aaaaa"));
    let mut s_2 = Rope::from(String::from("bbbbb"));
    let s_3 = Rope::from(String::from("ccccc"));
    s_2.insert_rope(0, s_3);
    s_1.insert_rope(0, s_2);
    assert_eq!(&s_1, "cccccbbbbbaaaaa");
}

#[test]
fn mutable_insert_str_test_1() {
    let mut s = Rope::from("aaaaa");
    s.insert_str(0, "bbbbb");
    s.insert_str(10, "ccccc");
    assert_eq!(&s, "bbbbbaaaaaccccc");
}

#[test]
fn mutable_insert_char_test_1() {
    let mut s = Rope::from("aaaaa");
    for _ in 0..5 { s.insert(0, 'b')}
    for _ in 0..5 { s.insert(10, 'c')}
    assert_eq!(&s, "bbbbbaaaaaccccc");
}

#[test]
fn with_insert_char_test_1() {
    let s = Rope::from("aaaaa");
    let s_1 = s.with_insert(5, 'b');
    let s_2 = s_1.with_insert(4, 'b');
    let s_3 = s_2.with_insert(3, 'b');
    let s_4 = s_3.with_insert(2, 'b');
    let s_5 = s_4.with_insert(1, 'b');
    assert_eq!(&s, "aaaaa");
    assert_eq!(&s_1, "aaaaab");
    assert_eq!(&s_2, "aaaabab");
    assert_eq!(&s_3, "aaababab");
    assert_eq!(&s_4, "aabababab");
    assert_eq!(&s_5, "ababababab");

}

#[test]
fn with_insert_str_test_1() {
    let s = Rope::from("aaaaa");
    let s_1 = s.with_insert_str(5, "ccccc");
    let s_2 = s_1.with_insert_str(5, "bbbbb");
    assert_eq!(&s, "aaaaa");
    assert_eq!(&s_1, "aaaaaccccc");
    assert_eq!(&s_2, "aaaaabbbbbccccc");
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() -> std::io::Result<()> {
    let dist = env::var("CODEQL_DIST").expect("CODEQL_DIST not set");
    let db = env::var("CODEQL_EXTRACTOR_RUBY_WIP_DATABASE")
        .expect("CODEQL_EXTRACTOR_RUBY_WIP_DATABASE not set");
    let codeql = if env::consts::OS == "windows" {
        "codeql.exe"
    } else {
        "codeql"
    };
    let codeql: PathBuf = [&dist, codeql].iter().collect();
    let mut cmd = Command::new(codeql);
    cmd.arg("database")
        .arg("index-files")
        .arg("--include-extension=.rb")
        .arg("--include-extension=.erb")
        .arg("--include-extension=.gemspec")
        .arg("--include=**/Gemfile")
        .arg("--size-limit=5m")
        .arg("--language=ruby")
        .arg("--working-dir=.")
        .arg(db);

    for line in env::var("LGTM_INDEX_FILTERS")
        .unwrap_or_default()
        .split('\n')
    {
        if let Some(stripped) = line.strip_prefix("include:") {
            cmd.arg("--also-match=".to_owned() + stripped);
        } else if let Some(stripped) = line.strip_prefix("exclude:") {
            cmd.arg("--exclude=".to_owned() + stripped);
        }
    }
    let exit = &cmd.spawn()?.wait()?;
    std::process::exit(exit.code().unwrap_or(1))
}
<commit_msg>Ruby: skip .git folder<commit_after>use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() -> std::io::Result<()> {
    let dist = env::var("CODEQL_DIST").expect("CODEQL_DIST not set");
    let db = env::var("CODEQL_EXTRACTOR_RUBY_WIP_DATABASE")
        .expect("CODEQL_EXTRACTOR_RUBY_WIP_DATABASE not set");
    let codeql = if env::consts::OS == "windows" {
        "codeql.exe"
    } else {
        "codeql"
    };
    let codeql: PathBuf = [&dist, codeql].iter().collect();
    let mut cmd = Command::new(codeql);
    cmd.arg("database")
        .arg("index-files")
        .arg("--include-extension=.rb")
        .arg("--include-extension=.erb")
        .arg("--include-extension=.gemspec")
        .arg("--include=**/Gemfile")
        .arg("--exclude=**/.git")
        .arg("--size-limit=5m")
        .arg("--language=ruby")
        .arg("--working-dir=.")
        .arg(db);

    for line in env::var("LGTM_INDEX_FILTERS")
        .unwrap_or_default()
        .split('\n')
    {
        if let Some(stripped) = line.strip_prefix("include:") {
            cmd.arg("--also-match=".to_owned() + stripped);
        } else if let Some(stripped) = line.strip_prefix("exclude:") {
            cmd.arg("--exclude=".to_owned() + stripped);
        }
    }
    let exit = &cmd.spawn()?.wait()?;
    std::process::exit(exit.code().unwrap_or(1))
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{Future, Sink, Stream, IntoFuture};
use futures::sync::mpsc;
use tokio_core::reactor::{Handle, Timeout};

use std::io;
use std::time::{Duration, SystemTime};

use super::error::{into_other, other_error};
use super::{InternalRequest, TimeoutRequest, InternalEvent, to_box};

#[derive(Debug)]
pub struct InternalPart {
    pub internal_tx: mpsc::Sender<InternalEvent>,
    pub internal_requests_rx: mpsc::Receiver<InternalRequest>,
}

impl InternalPart {
    pub fn run(self, handle: Handle) -> Box<Future<Item = (), Error = io::Error>> {
        let internal_tx = self.internal_tx.clone();
        let fut = self.internal_requests_rx
            .for_each(move |request| {
                let event = match request {
                    InternalRequest::Timeout(TimeoutRequest(time, timeout)) => {
                        let duration = time.duration_since(SystemTime::now()).unwrap_or_else(|_| {
                            Duration::from_millis(0)
                        });
                        let internal_tx = internal_tx.clone();
                        let fut = Timeout::new(duration, &handle)
                            .expect("Unable to create timeout")
                            .and_then(move |_| {
                                internal_tx
                                    .clone()
                                    .send(InternalEvent::Timeout(timeout))
                                    .map(drop)
                                    .map_err(into_other)
                            })
                            .map_err(|_| panic!("Can't timeout"));
                        to_box(fut)
                    }
                    InternalRequest::JumpToRound(height, round) => {
                        let internal_tx = internal_tx.clone();
                        let fut = Ok(())
                            .into_future()
                            .and_then(move |_| {
                                internal_tx
                                    .send(InternalEvent::JumpToRound(height, round))
                                    .map(drop)
                                    .map_err(into_other)
                            })
                            .map_err(|_| panic!("Can't execute jump to round"));
                        to_box(fut)
                    }
                    InternalRequest::Shutdown => {
                        let internal_tx = internal_tx.clone();
                        let fut = Ok(())
                            .into_future()
                            .and_then(move |_| {
                                internal_tx
                                    .send(InternalEvent::Shutdown)
                                    .map(drop)
                                    .map_err(into_other)
                            })
                            .map_err(|_| panic!("Can't execute shutdown"));
                        to_box(fut)
                    }
                };

                handle.spawn(event);
                Ok(())
            })
            .map_err(|_| other_error("Can't handle timeout request"));
        to_box(fut)
    }
}
<commit_msg>Use futures::lazy<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{self, Future, Sink, Stream};
use futures::sync::mpsc;
use tokio_core::reactor::{Handle, Timeout};

use std::io;
use std::time::{Duration, SystemTime};

use super::error::{into_other, other_error};
use super::{InternalRequest, TimeoutRequest, InternalEvent, to_box};

#[derive(Debug)]
pub struct InternalPart {
    pub internal_tx: mpsc::Sender<InternalEvent>,
    pub internal_requests_rx: mpsc::Receiver<InternalRequest>,
}

impl InternalPart {
    pub fn run(self, handle: Handle) -> Box<Future<Item = (), Error = io::Error>> {
        let internal_tx = self.internal_tx.clone();
        let fut = self.internal_requests_rx
            .for_each(move |request| {
                let event = match request {
                    InternalRequest::Timeout(TimeoutRequest(time, timeout)) => {
                        let duration = time.duration_since(SystemTime::now()).unwrap_or_else(|_| {
                            Duration::from_millis(0)
                        });
                        let internal_tx = internal_tx.clone();
                        let fut = Timeout::new(duration, &handle)
                            .expect("Unable to create timeout")
                            .and_then(move |_| {
                                internal_tx
                                    .clone()
                                    .send(InternalEvent::Timeout(timeout))
                                    .map(drop)
                                    .map_err(into_other)
                            })
                            .map_err(|_| panic!("Can't timeout"));
                        to_box(fut)
                    }
                    InternalRequest::JumpToRound(height, round) => {
                        let internal_tx = internal_tx.clone();
                        let f = futures::lazy(move || {
                            internal_tx
                                .send(InternalEvent::JumpToRound(height, round))
                                .map(drop)
                                .map_err(into_other)
                        }).map_err(|_| panic!("Can't execute jump to round"));
                        to_box(f)
                    }
                    InternalRequest::Shutdown => {
                        let internal_tx = internal_tx.clone();
                        let f = futures::lazy(move || {
                            internal_tx
                                .send(InternalEvent::Shutdown)
                                .map(drop)
                                .map_err(into_other)
                        }).map_err(|_| panic!("Can't execute shutdown"));
                        to_box(f)
                    }
                };

                handle.spawn(event);
                Ok(())
            })
            .map_err(|_| other_error("Can't handle timeout request"));
        to_box(fut)
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::*;
use ucontext::{ucontext_t, mcontext_t};

mod ucontext;

static REG_RBP: usize = 10;
static REG_RSP: usize = 15;
static REG_RIP: usize = 16;

type Fct = extern "C" fn() -> i32;

fn main() {
    unsafe {
        let mut sa: sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        sigemptyset(&mut sa.sa_mask as *mut sigset_t);
        sa.sa_flags = SA_SIGINFO;

        if sigaction(SIGSEGV, &sa as *const sigaction, 0 as *mut sigaction) == -1 {
            perror("sigaction failed".as_ptr() as *const i8);
        }

        // int fct2() { return 4; }
        // int fct2_stub() { <FAIL> }
        // int fct1() { return fct2(); }

        // compiler_stub: mov r10, [9]
        let fct2_stub_code = [ 0x4C, 0x8B, 0x14, 0x25, 9, 0, 0, 0 ];
        let fct2_stub = alloc_code(&fct2_stub_code);
        dump("fct2_stub", fct2_stub as usize, fct2_stub_code.len());

        // (int3)
        // push rbp
        // movabs rax, 0x1122334455667788
        // call rax
        // pop rbp
        // ret
        let fct1_code = [
            0x55,
            0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,
            0xFF, 0xD0,
            0x5D,
            0xC3
        ];

        let fct1 = alloc_code(&fct1_code);
        dump("fct1", fct1 as usize, fct1_code.len());

        println!("invoke fct1:");
        let res1 = fct1();
        println!("res = {}", res1);

        // invoke fct a second time - stub should not be used anymore
        println!("\ninvoke fct1 again:");
        let res2 = fct1();
        println!("res = {}", res2);
    }
}

fn handler(signo: c_int, _: *const siginfo_t, ucontext: *mut ucontext_t) {
    println!("SIGNAL {}!", signo);

    unsafe {
        let mcontext = &mut (*ucontext).uc_mcontext;

        let rip = mcontext.gregs[REG_RIP] as usize;
        println!("\trip = {:x}\n", rip);
        //dump("\trip", rip, 8);

        let rbp = mcontext.gregs[REG_RBP] as usize;
        println!("\trbp = {:x}", rbp);

        let rsp = mcontext.gregs[REG_RSP] as usize;
        println!("\trsp = {:x}", rsp);

        let ra = *(rsp as *mut usize);
        println!("\treturn address = {:x}\n", ra);

        let ra = ra - 12;
        println!("\treturn address before call {:x}\n", ra);

        // push rbp
        // mov eax, 4
        // pop rbp
        // ret
        let code = [
            0x55,
            0xb8, 4, 0, 0, 0,
            0x5D,
            0xc3
        ];

        let fct2 = alloc_code(&code);
        dump("\tfct2", fct2 as usize, code.len());

        let patcher = (ra + 2) as *mut usize;
        *patcher = fct2 as usize;

        dump("\tfct1 patched", ra-1, 15);

        mcontext.gregs[REG_RIP] = ra as i64;
        mcontext.gregs[REG_RSP] = (rsp + 8) as i64;
    }
}

fn alloc_code(code: &[u8]) -> Fct {
    unsafe {
        let pagesize = sysconf(_SC_PAGESIZE) as usize;

        let ptr = mmap(0 as *mut c_void, pagesize,
                       PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_ANON | MAP_PRIVATE, -1, 0);

        std::ptr::copy_nonoverlapping(code.as_ptr(), ptr as *mut u8, code.len());

        std::mem::transmute(ptr)
    }
}

fn dump(name: &'static str, ptr: usize, len: usize) {
    print!("{} @ {:x} ({} bytes) = ", name, ptr, len);

    unsafe {
        let ptr = ptr as *const u8;

        for i in 0..len {
            print!("{:02x} ", *ptr.offset(i as isize));
        }
    }

    println!("");
}

<commit_msg>raise.rs now has right rip<commit_after>extern crate libc;

use libc::*;
use ucontext::{ucontext_t, mcontext_t};

mod ucontext;

static REG_RBP: usize = 10;
static REG_RSP: usize = 15;
static REG_RIP: usize = 16;

type Fct = extern "C" fn() -> i32;

fn main() {
    unsafe {
        let mut sa: sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        sigemptyset(&mut sa.sa_mask as *mut sigset_t);
        sa.sa_flags = SA_SIGINFO;

        if sigaction(SIGSEGV, &sa as *const sigaction, 0 as *mut sigaction) == -1 {
            perror("sigaction failed".as_ptr() as *const i8);
        }

        // int fct2() { return 4; }
        // int fct2_stub() { <FAIL> }
        // int fct1() { return fct2(); }

        // compiler_stub: mov r10, [9]
        let fct2_stub_code = [ 0x4C, 0x8B, 0x14, 0x25, 9, 0, 0, 0 ];
        let fct2_stub = alloc_code(&fct2_stub_code);
        dump("fct2_stub", fct2_stub as usize, fct2_stub_code.len());

        // (int3)
        // push rbp
        // movabs rax, 0x1122334455667788
        // call rax
        // pop rbp
        // ret
        let fct1_code = [
            0x55,
            0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,
            0xFF, 0xD0,
            0x5D,
            0xC3
        ];

        let fct1 = alloc_code(&fct1_code);
        dump("fct1", fct1 as usize, fct1_code.len());

        let patcher = (fct1 as usize) + 3;
        let patcher = patcher as *mut usize;
        *patcher = fct2_stub as usize;

        dump("fct1 patched (1)", fct1 as usize, fct1_code.len());

        println!("invoke fct1:");
        let res1 = fct1();
        println!("res = {}", res1);

        // invoke fct a second time - stub should not be used anymore
        println!("\ninvoke fct1 again:");
        let res2 = fct1();
        println!("res = {}", res2);
    }
}

fn handler(signo: c_int, _: *const siginfo_t, ucontext: *mut ucontext_t) {
    println!("SIGNAL {}!", signo);

    unsafe {
        let mcontext = &mut (*ucontext).uc_mcontext;

        let rip = mcontext.gregs[REG_RIP] as usize;
        dump("\trip", rip, 8);

        let rbp = mcontext.gregs[REG_RBP] as usize;
        println!("\trbp = {:x}", rbp);

        let rsp = mcontext.gregs[REG_RSP] as usize;
        println!("\trsp = {:x}", rsp);

        let ra = *(rsp as *mut usize);
        println!("\treturn address = {:x}\n", ra);

        let ra = ra - 12;
        println!("\treturn address before call {:x}\n", ra);

        // push rbp
        // mov eax, 4
        // pop rbp
        // ret
        let code = [
            0x55,
            0xb8, 4, 0, 0, 0,
            0x5D,
            0xc3
        ];

        let fct2 = alloc_code(&code);
        dump("\tfct2", fct2 as usize, code.len());

        let patcher = (ra + 2) as *mut usize;
        *patcher = fct2 as usize;

        dump("\tfct1 patched (2)", ra-1, 15);

        mcontext.gregs[REG_RIP] = ra as i64;
        mcontext.gregs[REG_RSP] = (rsp + 8) as i64;
    }
}

fn alloc_code(code: &[u8]) -> Fct {
    unsafe {
        let pagesize = sysconf(_SC_PAGESIZE) as usize;

        let ptr = mmap(0 as *mut c_void, pagesize,
                       PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_ANON | MAP_PRIVATE, -1, 0);

        std::ptr::copy_nonoverlapping(code.as_ptr(), ptr as *mut u8, code.len());

        std::mem::transmute(ptr)
    }
}

fn dump(name: &'static str, ptr: usize, len: usize) {
    print!("{} @ {:x} ({} bytes) = ", name, ptr, len);

    unsafe {
        let ptr = ptr as *const u8;

        for i in 0..len {
            print!("{:02x} ", *ptr.offset(i as isize));
        }
    }

    println!("");
}

<|endoftext|>


<commit_before>//! [PUT /_matrix/app/v1/transactions/{txnId}](https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid)

use ruma_api::ruma_api;
use ruma_events::AnyEvent;
use ruma_serde::Raw;

ruma_api! {
    metadata: {
        description: "This API is called by the homeserver when it wants to push an event (or batch of events) to the application service.",
        method: PUT,
        name: "push_events",
        path: "/_matrix/app/v1/transactions/:txn_id",
        rate_limited: false,
        authentication: QueryOnlyAccessToken,
    }

    request: {
        /// The transaction ID for this set of events.
        ///
        /// Homeservers generate these IDs and they are used to ensure idempotency of results.
        #[ruma_api(path)]
        pub txn_id: &'a str,

        /// A list of events.
        pub events: &'a [Raw<AnyEvent>],
    }

    #[derive(Default)]
    response: {}
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID and list of events.
    pub fn new(txn_id: &'a str, events: &'a [Raw<AnyEvent>]) -> Self {
        Self { txn_id, events }
    }
}

impl IncomingRequest {
    /// Creates an `IncomingRequest` with the given transaction ID and list of events.
    pub fn new(txn_id: String, events: Vec<Raw<AnyEvent>>) -> IncomingRequest {
        IncomingRequest { txn_id, events }
    }

    /// Consumes the `IncomingRequest` and tries to convert it to a `sync_events::Response`
    ///
    /// This is a helper conversion in cases where it's easier to work with `sync_events::Response`
    /// instead of the original `push_events::IncomingRequest`. It puts all events with a `room_id`
    /// into the `JoinedRoom`'s `timeline`. The rationale behind that is that incoming Appservice
    /// transactions from the homeserver are not necessarily bound to a specific user but can cover
    /// a multitude of namespaces, and as such the Appservice basically only "observes joined
    /// rooms".
    ///
    /// Note: Currently homeservers only push PDUs to appservices, no EDUs. There's the open
    /// [MSC2409] regarding supporting EDUs in the future, though it seems to be planned to put
    /// EDUs into a different JSON key than `events` to stay backwards compatible.
    ///
    /// [MSC2409]: https://github.com/matrix-org/matrix-doc/pull/2409
    #[cfg(feature = "helper")]
    pub fn try_into_sync_response(
        self,
        next_batch: impl Into<String>,
    ) -> Result<ruma_client_api::r0::sync::sync_events::Response, serde_json::Error> {
        use ruma_client_api::r0::sync::sync_events;
        use ruma_identifiers::RoomId;
        use serde::Deserialize;
        use tracing::warn;

        #[derive(Debug, Deserialize)]
        struct EventDeHelper {
            room_id: Option<RoomId>,
        }

        let mut response = sync_events::Response::new(next_batch.into());

        for raw_event in self.events {
            let helper: EventDeHelper = serde_json::from_str(raw_event.json().get())?;
            let event_json = Raw::into_json(raw_event);

            if let Some(room_id) = helper.room_id {
                let join = response.rooms.join.entry(room_id).or_default();
                join.timeline.events.push(Raw::from_json(event_json));
            } else {
                warn!("Event without room_id: {}", event_json);
            }
        }

        Ok(response)
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Self
    }
}

#[cfg(feature = "helper")]
#[cfg(test)]
mod helper_tests {
    use super::{AnyEvent, IncomingRequest, Raw};
    use ruma_client_api::r0::sync::sync_events;
    use ruma_identifiers::room_id;
    use serde_json::json;

    #[test]
    fn convert_incoming_request_to_sync_response() {
        let txn_id = "any_txn_id".to_owned();
        let state_event: AnyEvent = serde_json::from_value(json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.name"
        }))
        .unwrap();
        let room_event: AnyEvent = serde_json::from_value(json!({
            "type": "m.room.message",
            "event_id": "$143273582443PhrSn:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@user:example.com",
            "content": {
                "body": "test",
                "msgtype": "m.audio",
                "url": "mxc://example.com/AuDi0",
            }
        }))
        .unwrap();

        let events = vec![Raw::from(state_event), Raw::from(room_event)];
        let incoming_request = IncomingRequest { txn_id: txn_id.clone(), events };

        let response: sync_events::Response =
            incoming_request.try_into_sync_response(txn_id).unwrap();

        let response_rooms_join =
            response.rooms.join.get(&room_id!("!roomid:room.com")).expect("joined room response");

        assert_eq!(response_rooms_join.timeline.events.len(), 2);
    }
}

#[cfg(feature = "server")]
#[cfg(test)]
mod tests {
    use ruma_api::{exports::http, OutgoingRequest, SendAccessToken};
    use ruma_events::AnyEvent;
    use ruma_serde::Raw;
    use serde_json::json;

    use super::Request;

    #[test]
    fn decode_request_contains_events_field() {
        let dummy_event: AnyEvent = serde_json::from_value(json!({
            "content": {},
            "type": "m.dummy"
        }))
        .unwrap();
        let dummy_event = Raw::from(dummy_event);
        let events = vec![dummy_event];

        let req: http::Request<Vec<u8>> = Request { events: &events, txn_id: "any_txn_id" }
            .try_into_http_request(
                "https://homeserver.tld",
                SendAccessToken::IfRequired("auth_tok"),
            )
            .unwrap();
        let json_body: serde_json::Value = serde_json::from_slice(req.body()).unwrap();

        assert_eq!(
            1,
            json_body.as_object().unwrap().get("events").unwrap().as_array().unwrap().len()
        );
    }
}
<commit_msg>appservice-api: Replace use of AnyEvent in push_events with AnyRoomEvent<commit_after>//! [PUT /_matrix/app/v1/transactions/{txnId}](https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid)

use ruma_api::ruma_api;
use ruma_events::AnyRoomEvent;
use ruma_serde::Raw;

ruma_api! {
    metadata: {
        description: "This API is called by the homeserver when it wants to push an event (or batch of events) to the application service.",
        method: PUT,
        name: "push_events",
        path: "/_matrix/app/v1/transactions/:txn_id",
        rate_limited: false,
        authentication: QueryOnlyAccessToken,
    }

    request: {
        /// The transaction ID for this set of events.
        ///
        /// Homeservers generate these IDs and they are used to ensure idempotency of results.
        #[ruma_api(path)]
        pub txn_id: &'a str,

        /// A list of events.
        pub events: &'a [Raw<AnyRoomEvent>],
    }

    #[derive(Default)]
    response: {}
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID and list of events.
    pub fn new(txn_id: &'a str, events: &'a [Raw<AnyRoomEvent>]) -> Self {
        Self { txn_id, events }
    }
}

impl IncomingRequest {
    /// Creates an `IncomingRequest` with the given transaction ID and list of events.
    pub fn new(txn_id: String, events: Vec<Raw<AnyRoomEvent>>) -> IncomingRequest {
        IncomingRequest { txn_id, events }
    }

    /// Consumes the `IncomingRequest` and tries to convert it to a `sync_events::Response`
    ///
    /// This is a helper conversion in cases where it's easier to work with `sync_events::Response`
    /// instead of the original `push_events::IncomingRequest`. It puts all events with a `room_id`
    /// into the `JoinedRoom`'s `timeline`. The rationale behind that is that incoming Appservice
    /// transactions from the homeserver are not necessarily bound to a specific user but can cover
    /// a multitude of namespaces, and as such the Appservice basically only "observes joined
    /// rooms".
    ///
    /// Note: Currently homeservers only push PDUs to appservices, no EDUs. There's the open
    /// [MSC2409] regarding supporting EDUs in the future, though it seems to be planned to put
    /// EDUs into a different JSON key than `events` to stay backwards compatible.
    ///
    /// [MSC2409]: https://github.com/matrix-org/matrix-doc/pull/2409
    #[cfg(feature = "helper")]
    pub fn try_into_sync_response(
        self,
        next_batch: impl Into<String>,
    ) -> Result<ruma_client_api::r0::sync::sync_events::Response, serde_json::Error> {
        use ruma_client_api::r0::sync::sync_events;
        use ruma_identifiers::RoomId;
        use serde::Deserialize;
        use tracing::warn;

        #[derive(Debug, Deserialize)]
        struct EventDeHelper {
            room_id: Option<RoomId>,
        }

        let mut response = sync_events::Response::new(next_batch.into());

        for raw_event in self.events {
            let helper: EventDeHelper = serde_json::from_str(raw_event.json().get())?;
            let event_json = Raw::into_json(raw_event);

            if let Some(room_id) = helper.room_id {
                let join = response.rooms.join.entry(room_id).or_default();
                join.timeline.events.push(Raw::from_json(event_json));
            } else {
                warn!("Event without room_id: {}", event_json);
            }
        }

        Ok(response)
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Self
    }
}

#[cfg(feature = "helper")]
#[cfg(test)]
mod helper_tests {
    use super::{AnyRoomEvent, IncomingRequest, Raw};
    use ruma_client_api::r0::sync::sync_events;
    use ruma_identifiers::room_id;
    use serde_json::json;

    #[test]
    fn convert_incoming_request_to_sync_response() {
        let txn_id = "any_txn_id".to_owned();
        let state_event: AnyRoomEvent = serde_json::from_value(json!({
            "content": {},
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.name"
        }))
        .unwrap();
        let message_event: AnyRoomEvent = serde_json::from_value(json!({
            "type": "m.room.message",
            "event_id": "$143273582443PhrSn:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@user:example.com",
            "content": {
                "body": "test",
                "msgtype": "m.audio",
                "url": "mxc://example.com/AuDi0",
            }
        }))
        .unwrap();

        let events = vec![Raw::from(state_event), Raw::from(message_event)];
        let incoming_request = IncomingRequest { txn_id: txn_id.clone(), events };

        let response: sync_events::Response =
            incoming_request.try_into_sync_response(txn_id).unwrap();

        let response_rooms_join =
            response.rooms.join.get(&room_id!("!roomid:room.com")).expect("joined room response");

        assert_eq!(response_rooms_join.timeline.events.len(), 2);
    }
}

#[cfg(feature = "server")]
#[cfg(test)]
mod tests {
    use ruma_api::{exports::http, OutgoingRequest, SendAccessToken};
    use ruma_events::AnyRoomEvent;
    use ruma_serde::Raw;
    use serde_json::json;

    use super::Request;

    #[test]
    fn decode_request_contains_events_field() {
        let dummy_event: AnyRoomEvent = serde_json::from_value(json!({
            "type": "m.room.message",
            "event_id": "$143273582443PhrSn:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@user:example.com",
            "content": {
                "body": "test",
                "msgtype": "m.text",
            },
        }))
        .unwrap();
        let dummy_event = Raw::from(dummy_event);
        let events = vec![dummy_event];

        let req: http::Request<Vec<u8>> = Request { events: &events, txn_id: "any_txn_id" }
            .try_into_http_request(
                "https://homeserver.tld",
                SendAccessToken::IfRequired("auth_tok"),
            )
            .unwrap();
        let json_body: serde_json::Value = serde_json::from_slice(req.body()).unwrap();

        assert_eq!(
            1,
            json_body.as_object().unwrap().get("events").unwrap().as_array().unwrap().len()
        );
    }
}
<|endoftext|>


<commit_before>

fn fizz_buzz(number: i8) -> String {
	if number % 3 == 0 && number % 5 ==0 {
		return "FizzBuzz".to_string();
	} else if number % 3 == 0 {
		return "Fizz".to_string();
	} else if number % 5 == 0 {
		return "Buzz".to_string();
	} else {
		return number.to_string();
	}
}

fn main() {
	for number in 1..100 {
		println!("{}", fizz_buzz(number))
	}
}<commit_msg>Removed additional newlines<commit_after>fn fizz_buzz(number: i8) -> String {
	if number % 3 == 0 && number % 5 ==0 {
		return "FizzBuzz".to_string();
	} else if number % 3 == 0 {
		return "Fizz".to_string();
	} else if number % 5 == 0 {
		return "Buzz".to_string();
	} else {
		return number.to_string();
	}
}

fn main() {
	for number in 1..100 {
		println!("{}", fizz_buzz(number))
	}
}<|endoftext|>


<commit_before>use std::str::FromStr;
use std::num::{FromPrimitive, ToPrimitive};
use serialize::json::{Json, ToJson};

bitflags! {
    #[derive(Show)] flags WSHeader: u16 {
        // Main structure, mask with & to get header parts
        const WS_FIN     = 0b1000000000000000, // final flag
        const WS_RSV     = 0b0111000000000000, // reserved
        const WS_OPCODE  = 0b0000111100000000, // opcode
        const WS_MASK    = 0b0000000010000000, // mask flag
        const WS_LEN     = 0b0000000001111111, // length

        // Opcodes, check for equality after masking with WS_OPCODE
        const WS_OPCONT  = 0b0000000000000000,
        const WS_OPTEXT  = 0b0000000100000000,
        const WS_OPBIN   = 0b0000001000000000,
        const WS_OPTERM  = 0b0000100000000000,
        const WS_OPPING  = 0b0000100100000000,
        const WS_OPPONG  = 0b0000101000000000,

        // Helper masks
        const WS_OPCTRL  = 0b0000100000000000, // if matches with &, this is a control code
        const WS_LEN16   = 0b0000000001111110, // if &WS_LEN equals this, it has 16-bit length
        const WS_LEN64   = 0b0000000001111111, // if &WS_LEN equals this, it has 32-bit length
    }
}

// TODO: use this instead of u16
#[derive(Copy, Show)]
pub enum WSStatusCode {
    NoError, // = 1000,
    GoneAway, // = 1001,
    ProtocolError, // = 1002,
    UnsupportedData, // = 1003,

    // RESERVERD = 1004,
    NoCode, // = 1005, // reserved
    Aborted, // = 1006, // reserved

    InvalidData, // = 1007,
    ClientError, // = 1008,
    TooLargeData, // = 1009,
    ExtensionMissing, // = 1010,
    ServerError, // = 1011,

    TlsError, // = 1015 // reserved

    // Also:
    // 0-999 - cannot be used,
    // 1000-2999 - reserved for protocol,
    ProtocolCode(u16),
    // 3000-3999 - reserved for apps, issued by IANA,
    ApplicationCode(u16),
    // 4000-4999 - for private use
    OtherCode(u16)
}

impl ToPrimitive for WSStatusCode {
    fn to_u64(&self) -> Option<u64> {
        match *self {
            WSStatusCode::NoError => Some(1000u64),
            WSStatusCode::GoneAway => Some(1001u64),
            WSStatusCode::ProtocolError => Some(1002u64),
            WSStatusCode::UnsupportedData => Some(1003u64),

            WSStatusCode::NoCode => Some(1005u64), // reserved
            WSStatusCode::Aborted => Some(1006u64), // reserved

            WSStatusCode::InvalidData => Some(1007u64),
            WSStatusCode::ClientError => Some(1008u64),
            WSStatusCode::TooLargeData => Some(1009u64),
            WSStatusCode::ExtensionMissing => Some(1010u64),
            WSStatusCode::ServerError => Some(1011u64),

            WSStatusCode::TlsError => Some(1015u64), // reserved

            WSStatusCode::ProtocolCode(code) if 1000 <= code && code <= 2999 => Some(code as u64),
            WSStatusCode::ApplicationCode(code) if 3000 <= code && code <= 3999 => Some(code as u64),
            WSStatusCode::OtherCode(code) if 4000 <= code && code <= 4999 => Some(code as u64),
            _ => None
        }
    }
    fn to_i64(&self) -> Option<i64> {
        self.to_u64().map(|v| v as i64)
    }
}

impl FromPrimitive for WSStatusCode {
    fn from_u64(n: u64) -> Option<WSStatusCode> {
        match n {
            1000u64 => Some(WSStatusCode::NoError),
            1001u64 => Some(WSStatusCode::GoneAway),
            1002u64 => Some(WSStatusCode::ProtocolError),
            1003u64 => Some(WSStatusCode::UnsupportedData),

            1005u64 => Some(WSStatusCode::NoCode), // reserved
            1006u64 => Some(WSStatusCode::Aborted), // reserved

            1007u64 => Some(WSStatusCode::InvalidData),
            1008u64 => Some(WSStatusCode::ClientError),
            1009u64 => Some(WSStatusCode::TooLargeData),
            1010u64 => Some(WSStatusCode::ExtensionMissing),
            1011u64 => Some(WSStatusCode::ServerError),

            1015u64 => Some(WSStatusCode::TlsError), // reserved

            code if 1000 <= code && code <= 2999 => Some(WSStatusCode::ProtocolCode(code as u16)),
            code if 3000 <= code && code <= 3999 => Some(WSStatusCode::ApplicationCode(code as u16)),
            code if 4000 <= code && code <= 4999 => Some(WSStatusCode::OtherCode(code as u16)),
            _ => None
        }
    }
    fn from_i64(n: i64) -> Option<WSStatusCode> {
        if n < 0i64 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }
}

#[derive(Show)]
pub struct WSMessage {
    pub header: WSHeader,
    pub data: Vec<u8>,
    pub status: Option<WSStatusCode>
}

impl WSMessage {
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data[]).into_owned()
    }

    pub fn push(&mut self, msg: WSMessage) {
        self.data.push_all(msg.data[]);
    }

    pub fn text(data: &str) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPTEXT,
            data: data.as_bytes().to_vec(),
            status: None
        }
    }

    pub fn binary(data: &[u8]) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPBIN,
            data: data.to_vec(),
            status: None
        }
    }

    pub fn masked(&mut self, enabled: bool) {
        if enabled {
            self.header.insert(WS_MASK);
        } else {
            self.header.remove(WS_MASK);
        }
    }

    pub fn is_masked(&self) -> bool {
        self.header.contains(WS_MASK)
    }

    pub fn close(status: WSStatusCode, data: &str) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPTERM,
            data: data.as_bytes().to_vec(),
            status: Some(status)
        }
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        self.to_string()[].parse::<Json>().unwrap()
    }
}

impl FromStr for WSMessage {
    #[inline] fn from_str(s: &str) -> Option<WSMessage> {
        Some(WSMessage::text(s))
    }
}
<commit_msg>richer chainable message builder<commit_after>use std::str::FromStr;
use std::num::{FromPrimitive, ToPrimitive};
use serialize::json::{Json, ToJson};

bitflags! {
    #[derive(Show)] flags WSHeader: u16 {
        // Main structure, mask with & to get header parts
        const WS_FIN     = 0b1000000000000000, // final flag
        const WS_RSV     = 0b0111000000000000, // reserved
        const WS_OPCODE  = 0b0000111100000000, // opcode
        const WS_MASK    = 0b0000000010000000, // mask flag
        const WS_LEN     = 0b0000000001111111, // length

        // Opcodes, check for equality after masking with WS_OPCODE
        const WS_OPCONT  = 0b0000000000000000,
        const WS_OPTEXT  = 0b0000000100000000,
        const WS_OPBIN   = 0b0000001000000000,
        const WS_OPTERM  = 0b0000100000000000,
        const WS_OPPING  = 0b0000100100000000,
        const WS_OPPONG  = 0b0000101000000000,

        // Helper masks
        const WS_OPCTRL  = 0b0000100000000000, // if matches with &, this is a control code
        const WS_LEN16   = 0b0000000001111110, // if &WS_LEN equals this, it has 16-bit length
        const WS_LEN64   = 0b0000000001111111, // if &WS_LEN equals this, it has 32-bit length
    }
}

// TODO: use this instead of u16
#[derive(Copy, Show)]
pub enum WSStatusCode {
    NoError, // = 1000,
    GoneAway, // = 1001,
    ProtocolError, // = 1002,
    UnsupportedData, // = 1003,

    // RESERVERD = 1004,
    NoCode, // = 1005, // reserved
    Aborted, // = 1006, // reserved

    InvalidData, // = 1007,
    ClientError, // = 1008,
    TooLargeData, // = 1009,
    ExtensionMissing, // = 1010,
    ServerError, // = 1011,

    TlsError, // = 1015 // reserved

    // Also:
    // 0-999 - cannot be used,
    // 1000-2999 - reserved for protocol,
    ProtocolCode(u16),
    // 3000-3999 - reserved for apps, issued by IANA,
    ApplicationCode(u16),
    // 4000-4999 - for private use
    OtherCode(u16)
}

impl ToPrimitive for WSStatusCode {
    fn to_u64(&self) -> Option<u64> {
        match *self {
            WSStatusCode::NoError => Some(1000u64),
            WSStatusCode::GoneAway => Some(1001u64),
            WSStatusCode::ProtocolError => Some(1002u64),
            WSStatusCode::UnsupportedData => Some(1003u64),

            WSStatusCode::NoCode => Some(1005u64), // reserved
            WSStatusCode::Aborted => Some(1006u64), // reserved

            WSStatusCode::InvalidData => Some(1007u64),
            WSStatusCode::ClientError => Some(1008u64),
            WSStatusCode::TooLargeData => Some(1009u64),
            WSStatusCode::ExtensionMissing => Some(1010u64),
            WSStatusCode::ServerError => Some(1011u64),

            WSStatusCode::TlsError => Some(1015u64), // reserved

            WSStatusCode::ProtocolCode(code) if 1000 <= code && code <= 2999 => Some(code as u64),
            WSStatusCode::ApplicationCode(code) if 3000 <= code && code <= 3999 => Some(code as u64),
            WSStatusCode::OtherCode(code) if 4000 <= code && code <= 4999 => Some(code as u64),
            _ => None
        }
    }
    fn to_i64(&self) -> Option<i64> {
        self.to_u64().map(|v| v as i64)
    }
}

impl FromPrimitive for WSStatusCode {
    fn from_u64(n: u64) -> Option<WSStatusCode> {
        match n {
            1000u64 => Some(WSStatusCode::NoError),
            1001u64 => Some(WSStatusCode::GoneAway),
            1002u64 => Some(WSStatusCode::ProtocolError),
            1003u64 => Some(WSStatusCode::UnsupportedData),

            1005u64 => Some(WSStatusCode::NoCode), // reserved
            1006u64 => Some(WSStatusCode::Aborted), // reserved

            1007u64 => Some(WSStatusCode::InvalidData),
            1008u64 => Some(WSStatusCode::ClientError),
            1009u64 => Some(WSStatusCode::TooLargeData),
            1010u64 => Some(WSStatusCode::ExtensionMissing),
            1011u64 => Some(WSStatusCode::ServerError),

            1015u64 => Some(WSStatusCode::TlsError), // reserved

            code if 1000 <= code && code <= 2999 => Some(WSStatusCode::ProtocolCode(code as u16)),
            code if 3000 <= code && code <= 3999 => Some(WSStatusCode::ApplicationCode(code as u16)),
            code if 4000 <= code && code <= 4999 => Some(WSStatusCode::OtherCode(code as u16)),
            _ => None
        }
    }
    fn from_i64(n: i64) -> Option<WSStatusCode> {
        if n < 0i64 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }
}

#[derive(Show)]
pub struct WSMessage {
    pub header: WSHeader,
    pub data: Vec<u8>,
    pub status: Option<WSStatusCode>
}

impl WSMessage {
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data[]).into_owned()
    }

    pub fn push(&mut self, msg: WSMessage) {
        self.data.push_all(msg.data[]);
    }

    #[inline] pub fn text(data: &str) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPTEXT,
            data: data.as_bytes().to_vec(),
            status: None
        }
    }

    #[inline] pub fn binary(data: &[u8]) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPBIN,
            data: data.to_vec(),
            status: None
        }
    }

    pub fn first(mut self) -> WSMessage {
        self.header.remove(WS_FIN);
        self
    }

    pub fn more(mut self) -> WSMessage {
        self.header.remove(WS_FIN | WS_OPCODE);
        self.header.insert(WS_OPCONT);
        self
    }

    pub fn last(mut self) -> WSMessage {
        self.header.remove(WS_OPCODE);
        self.header.insert(WS_FIN | WS_OPCONT);
        self
    }

    pub fn is_first(&self) -> bool {
        !self.is_final() && !self.is_cont()
    }

    pub fn is_last(&self) -> bool {
        self.is_final() && self.is_cont()
    }

    pub fn is_more(&self) -> bool {
        !self.is_final() && self.is_cont()
    }

    pub fn is_whole(&self) -> bool {
        self.is_final() && !self.is_cont()
    }

    #[inline] pub fn is_final(&self) -> bool {
        self.header.contains(WS_FIN)
    }

    #[inline] pub fn opcode(&self) -> WSHeader {
        self.header & WS_OPCODE
    }

    pub fn mask(mut self) -> WSMessage {
        self.header.insert(WS_MASK);
        self
    }

    pub fn unmask(mut self) -> WSMessage {
        self.header.remove(WS_MASK);
        self
    }

    pub fn is_masked(&self) -> bool {
        self.header.contains(WS_MASK)
    }

    #[inline] pub fn close(status: WSStatusCode, data: &[u8]) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPTERM,
            data: data.to_vec(),
            status: Some(status)
        }
    }

    #[inline] pub fn ping(data: &[u8]) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPPING,
            data: data.to_vec(),
            status: None
        }
    }

    #[inline] pub fn pong(data: &[u8]) -> WSMessage {
        WSMessage {
            header: WS_FIN | WS_OPPONG,
            data: data.to_vec(),
            status: None
        }
    }

    pub fn is_control(&self) -> bool {
        self.header.contains(WS_OPCTRL)
    }

    #[inline] pub fn is_text(&self) -> bool { self.opcode() == WS_OPTEXT }
    #[inline] pub fn is_binary(&self) -> bool { self.opcode() == WS_OPBIN }
    #[inline] pub fn is_ping(&self) -> bool { self.opcode() == WS_OPPING }
    #[inline] pub fn is_pong(&self) -> bool { self.opcode() == WS_OPPONG }
    #[inline] pub fn is_close(&self) -> bool { self.opcode() == WS_OPTERM }
    #[inline] pub fn is_cont(&self) -> bool { self.opcode() == WS_OPCONT }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        self.to_string()[].parse::<Json>().unwrap()
    }
}

impl FromStr for WSMessage {
    #[inline] fn from_str(s: &str) -> Option<WSMessage> {
        Some(WSMessage::text(s))
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate transliterator;
use transliterator::*;

fn main()
{
  println!("Hello, CUI world!")
}
<commit_msg>Mod instead of crate.<commit_after>#![feature(globs)]

mod transliterator;
use transliterator::*;

fn main()
{
  println!("Hello, CUI world!")
}
<|endoftext|>