<commit_before>use std::{cmp::Ordering, fmt, path::Path};

use async_trait::async_trait;
use language_tags::LanguageTag;
use regex::Regex;
use serde::{Deserialize, Serialize};

use crate::{build::BuildStep, bundle::KbdgenBundle};

const REPOSITORY: &str = "repo";
const HOSTING_APP: &str = "HostingApp";
const INFO_PLIST_STRINGS: &str = "InfoPlist.strings";

const KEYBOARD: &str = "Keyboard";
const NORTHERN_SAMI: &str = "northern-sami-keyboard";
const INFO_PLIST: &str = "Info.plist";

#[derive(Serialize, Deserialize, Debug)]
pub struct XcodeInfoPlist {
    #[serde(rename = "CFBundleName")]
    cf_bundle_name: String,
    #[serde(rename = "CFBundleDisplayName")]
    cf_bundle_display_name: String,
}

impl fmt::Display for XcodeInfoPlist {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(&format!(
            "\"CFBundleName\" = {:?};\n\"CFBundleDisplayName\" = {:?};",
            self.cf_bundle_name, self.cf_bundle_display_name
        ))
    }
}

// LAYOUT PLIST START

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlistExtensionAttributes {
    #[serde(rename = "IsASCIICapable")]
    is_ascii_capable: bool,
    #[serde(rename = "PrefersRightToLeft")]
    prefers_right_to_left: bool,
    #[serde(rename = "PrimaryLanguage")]
    primary_language: String,
    #[serde(rename = "RequestsOpenAccess")]
    requests_open_access: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlistExtension {
    #[serde(rename = "NSExtensionAttributes")]
    ns_extension_attributes: LayoutInfoPlistExtensionAttributes,
    #[serde(rename = "NSExtensionPointIdentifier")]
    ns_extension_point_identifier: String,
    #[serde(rename = "NSExtensionPrincipalClass")]
    ns_extension_principal_class: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlist {
    #[serde(rename = "DivvunSpellerPath")]
    divvun_speller_path: String,
    #[serde(rename = "DivvunSpellerPackageKey")]
    divvun_speller_package_key: String,
    #[serde(rename = "CFBundleDevelopmentRegion")]
    cf_bundle_development_region: String,
    #[serde(rename = "CFBundleDisplayName")]
    cf_bundle_display_name: String,
    #[serde(rename = "CFBundleExecutable")]
    cf_bundle_executable: String,
    #[serde(rename = "CFBundleIdentifier")]
    cf_bundle_identifier: String,
    #[serde(rename = "CFBundleInfoDictionaryVersion")]
    cf_bundle_info_dictionary_version: String,
    #[serde(rename = "CFBundleName")]
    cf_bundle_name: String,
    #[serde(rename = "CFBundlePackageType")]
    cf_bundle_package_type: String,
    #[serde(rename = "CFBundleShortVersionString")]
    cf_bundle_short_version_string: String,
    #[serde(rename = "CFBundleSignature")]
    cf_bundle_signature: String,
    #[serde(rename = "CFBundleVersion")]
    cf_bundle_version: String,
    #[serde(rename = "DivvunKeyboardIndex")]
    divvun_keyboard_index: usize,
    #[serde(rename = "ITSAppUsesNonExemptEncryption")]
    its_app_uses_non_exempt_encryption: bool,
    #[serde(rename = "LSApplicationQueriesSchemes")]
    ls_application_queries_schemes: Vec<String>,
    #[serde(rename = "NSExtension")]
    ns_extension: LayoutInfoPlistExtension,
}

// LAYOUT PLIST END

pub fn replace_all_occurances(input: String, character: char, replace_with: char) -> String {
    input
        .as_str()
        .chars()
        .map(|curr| {
            if curr.cmp(&character) != Ordering::Equal {
                curr
            } else {
                replace_with
            }
        })
        .into_iter()
        .collect::<String>()
}

pub struct GenerateXcode;

#[async_trait(?Send)]
impl BuildStep for GenerateXcode {
    async fn build(&self, bundle: &KbdgenBundle, output_path: &Path) {
        let repository_path = output_path.join(REPOSITORY);

        for (layout_index, (language_tag, layout)) in bundle.layouts.iter().enumerate() {
            if let Some(target) = &bundle.targets.ios {
                if let Some(_ios_layout) = &layout.i_os {
                    // GENERATE LOCALES
                    for (locale_name, locale_info) in &bundle.project.locales {
                        let hosting_app_path = repository_path.join(HOSTING_APP);
                        let locale_name = if locale_name == "en" {
                            "Base"
                        } else {
                            locale_name
                        };
                        let locale_path = hosting_app_path.join(&format!("{}.lproj", locale_name));
                        let info_path = locale_path.join(INFO_PLIST_STRINGS);
                        println!("{:?}", locale_path);

                        std::fs::create_dir_all(&locale_path).unwrap();

                        let info_plist = XcodeInfoPlist {
                            cf_bundle_name: locale_info.name.to_string(),
                            cf_bundle_display_name: locale_info.name.to_string(),
                        };
                        std::fs::write(info_path, info_plist.to_string()).unwrap();
                    }

                    // GENERATE LAYOUTS

                    let keyboard_name = replace_all_occurances(
                        bundle
                            .project
                            .locales
                            .get("en")
                            .unwrap()
                            .name
                            .to_lowercase(),
                        ' ',
                        '-',
                    );

                    let keyboard_path = repository_path.join(KEYBOARD);
                    let info_plist_template = keyboard_path.join(INFO_PLIST);

                    let layout_path = keyboard_path.join(keyboard_name);
                    let layout_info_plist_path = layout_path.join(INFO_PLIST);

                    std::fs::create_dir_all(&layout_path).unwrap();

                    let mut parsed_plist: LayoutInfoPlist =
                        plist::from_file(info_plist_template.clone()).expect("valid stuff");

                    parsed_plist.cf_bundle_display_name = layout.autonym().to_string();
                    parsed_plist.cf_bundle_short_version_string = target.version.clone();
                    parsed_plist.cf_bundle_version = target.build.clone();
                    parsed_plist.ls_application_queries_schemes[0] = target.package_id.clone();
                    parsed_plist
                        .ns_extension
                        .ns_extension_attributes
                        .primary_language = language_tag.to_string();
                    parsed_plist.divvun_keyboard_index = layout_index;

                    plist::to_file_xml(layout_info_plist_path.clone(), &parsed_plist).unwrap();
                }
            }
        }
    }
}
<commit_msg>now updates entitlements<commit_after>use std::{cmp::Ordering, fmt, path::Path};

use async_trait::async_trait;
use serde::{Deserialize, Serialize};

use crate::{build::BuildStep, bundle::KbdgenBundle};

const REPOSITORY: &str = "repo";
const HOSTING_APP: &str = "HostingApp";
const INFO_PLIST_STRINGS: &str = "InfoPlist.strings";

const KEYBOARD: &str = "Keyboard";
const INFO_PLIST: &str = "Info.plist";

const SETTINGS_BUNDLE: &str = "Settings.bundle";
const ROOT_PLIST: &str = "Root.plist";
const ENTITLEMENTS_EXTENSION: &str = ".entitlements";

#[derive(Serialize, Deserialize, Debug)]
pub struct XcodeInfoPlist {
    #[serde(rename = "CFBundleName")]
    cf_bundle_name: String,
    #[serde(rename = "CFBundleDisplayName")]
    cf_bundle_display_name: String,
}

impl fmt::Display for XcodeInfoPlist {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(&format!(
            "\"CFBundleName\" = {:?};\n\"CFBundleDisplayName\" = {:?};",
            self.cf_bundle_name, self.cf_bundle_display_name
        ))
    }
}

// LAYOUT PLIST START

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlistExtensionAttributes {
    #[serde(rename = "IsASCIICapable")]
    is_ascii_capable: bool,
    #[serde(rename = "PrefersRightToLeft")]
    prefers_right_to_left: bool,
    #[serde(rename = "PrimaryLanguage")]
    primary_language: String,
    #[serde(rename = "RequestsOpenAccess")]
    requests_open_access: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlistExtension {
    #[serde(rename = "NSExtensionAttributes")]
    ns_extension_attributes: LayoutInfoPlistExtensionAttributes,
    #[serde(rename = "NSExtensionPointIdentifier")]
    ns_extension_point_identifier: String,
    #[serde(rename = "NSExtensionPrincipalClass")]
    ns_extension_principal_class: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct LayoutInfoPlist {
    #[serde(rename = "DivvunSpellerPath")]
    divvun_speller_path: String,
    #[serde(rename = "DivvunSpellerPackageKey")]
    divvun_speller_package_key: String,
    #[serde(rename = "CFBundleDevelopmentRegion")]
    cf_bundle_development_region: String,
    #[serde(rename = "CFBundleDisplayName")]
    cf_bundle_display_name: String,
    #[serde(rename = "CFBundleExecutable")]
    cf_bundle_executable: String,
    #[serde(rename = "CFBundleIdentifier")]
    cf_bundle_identifier: String,
    #[serde(rename = "CFBundleInfoDictionaryVersion")]
    cf_bundle_info_dictionary_version: String,
    #[serde(rename = "CFBundleName")]
    cf_bundle_name: String,
    #[serde(rename = "CFBundlePackageType")]
    cf_bundle_package_type: String,
    #[serde(rename = "CFBundleShortVersionString")]
    cf_bundle_short_version_string: String,
    #[serde(rename = "CFBundleSignature")]
    cf_bundle_signature: String,
    #[serde(rename = "CFBundleVersion")]
    cf_bundle_version: String,
    #[serde(rename = "DivvunKeyboardIndex")]
    divvun_keyboard_index: usize,
    #[serde(rename = "ITSAppUsesNonExemptEncryption")]
    its_app_uses_non_exempt_encryption: bool,
    #[serde(rename = "LSApplicationQueriesSchemes")]
    ls_application_queries_schemes: Vec<String>,
    #[serde(rename = "NSExtension")]
    ns_extension: LayoutInfoPlistExtension,
}

// LAYOUT PLIST END

#[derive(Serialize, Deserialize, Debug)]
pub struct EntitlementsDict {
    #[serde(rename = "com.apple.security.application-groups")]
    com_apple_security_application_groups: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PreferenceSpecifier {
    #[serde(rename = "Type")]
    preference_type: String,
    #[serde(rename = "Title")]
    title: String,
    #[serde(rename = "Key")]
    key: String,
    #[serde(rename = "DefaultValue")]
    default_value: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SettingsRootDict {
    #[serde(rename = "StringsTable")]
    strings_table: String,
    #[serde(rename = "PreferenceSpecifiers")]
    preference_specifiers: Vec<PreferenceSpecifier>,
    #[serde(rename = "ApplicationGroupContainerIdentifier")]
    application_group_container_identifier: String,
}

pub fn replace_all_occurances(input: String, character: char, replace_with: char) -> String {
    input
        .as_str()
        .chars()
        .map(|curr| {
            if curr.cmp(&character) != Ordering::Equal {
                curr
            } else {
                replace_with
            }
        })
        .into_iter()
        .collect::<String>()
}

pub struct GenerateXcode;

#[async_trait(?Send)]
impl BuildStep for GenerateXcode {
    async fn build(&self, bundle: &KbdgenBundle, output_path: &Path) {
        let repository_path = output_path.join(REPOSITORY);
        let hosting_app_path = repository_path.join(HOSTING_APP);
        let keyboard_path = repository_path.join(KEYBOARD);

        for (layout_index, (language_tag, layout)) in bundle.layouts.iter().enumerate() {
            if let Some(target) = &bundle.targets.ios {
                if let Some(_ios_layout) = &layout.i_os {
                    // GENERATE LOCALES
                    for (locale_name, locale_info) in &bundle.project.locales {
                        let locale_name = if locale_name == "en" {
                            "Base"
                        } else {
                            locale_name
                        };
                        let locale_path = hosting_app_path.join(&format!("{}.lproj", locale_name));
                        let info_path = locale_path.join(INFO_PLIST_STRINGS);
                        println!("{:?}", locale_path);

                        std::fs::create_dir_all(&locale_path).unwrap();

                        let info_plist = XcodeInfoPlist {
                            cf_bundle_name: locale_info.name.to_string(),
                            cf_bundle_display_name: locale_info.name.to_string(),
                        };
                        std::fs::write(info_path, info_plist.to_string()).unwrap();
                    }

                    // GENERATE LAYOUTS

                    let keyboard_name = replace_all_occurances(
                        bundle
                            .project
                            .locales
                            .get("en")
                            .unwrap()
                            .name
                            .to_lowercase(),
                        ' ',
                        '-',
                    );

                    let info_plist_template = keyboard_path.join(INFO_PLIST);

                    let layout_path = keyboard_path.join(keyboard_name);
                    let layout_info_plist_path = layout_path.join(INFO_PLIST);

                    std::fs::create_dir_all(&layout_path).unwrap();

                    let mut parsed_plist: LayoutInfoPlist =
                        plist::from_file(info_plist_template.clone()).expect("valid stuff");

                    parsed_plist.cf_bundle_display_name = layout.autonym().to_string();
                    parsed_plist.cf_bundle_short_version_string = target.version.clone();
                    parsed_plist.cf_bundle_version = target.build.clone();
                    parsed_plist.ls_application_queries_schemes[0] = target.package_id.clone();
                    parsed_plist
                        .ns_extension
                        .ns_extension_attributes
                        .primary_language = language_tag.to_string();
                    parsed_plist.divvun_keyboard_index = layout_index;

                    plist::to_file_xml(layout_info_plist_path.clone(), &parsed_plist).unwrap();

                    // UPDATE ENTITLEMENTS
                    let new_entitlements = format!("{}.{}", "group", target.package_id);

                    // KEYBOARD
                    let keyboard_entitlements_path =
                        keyboard_path.join(format!("{}{}", KEYBOARD, ENTITLEMENTS_EXTENSION));
                    let mut keyboard_entitlements: EntitlementsDict =
                        plist::from_file(keyboard_entitlements_path.clone()).expect("valid stuff");
                    keyboard_entitlements.com_apple_security_application_groups =
                        vec![new_entitlements.clone()];
                    plist::to_file_xml(keyboard_entitlements_path.clone(), &keyboard_entitlements)
                        .unwrap();

                    // HOSTING APP
                    let hosting_app_entitlements_path =
                        hosting_app_path.join(format!("{}{}", HOSTING_APP, ENTITLEMENTS_EXTENSION));
                    let mut hosting_app_entitlements: EntitlementsDict =
                        plist::from_file(hosting_app_entitlements_path.clone())
                            .expect("valid stuff");
                    hosting_app_entitlements.com_apple_security_application_groups =
                        vec![new_entitlements.clone()];
                    plist::to_file_xml(
                        hosting_app_entitlements_path.clone(),
                        &hosting_app_entitlements,
                    )
                    .unwrap();

                    // ROOT PLIST
                    let root_plist_path = hosting_app_path.join(SETTINGS_BUNDLE).join(ROOT_PLIST);
                    let mut root_plist: SettingsRootDict =
                        plist::from_file(root_plist_path.clone()).expect("valid stuff");
                    root_plist.application_group_container_identifier = new_entitlements.clone();
                    plist::to_file_xml(root_plist_path.clone(), &root_plist).unwrap();
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use LalafellBot;
use commands::*;
use tasks::AutoTagTask;

use discord::builders::EmbedBuilder;
use discord::model::PublicChannel;

use std::sync::Arc;

pub struct UpdateTagsCommand {
  bot: Arc<LalafellBot>
}

impl UpdateTagsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> UpdateTagsCommand {
    UpdateTagsCommand {
      bot: bot
    }
  }
}

impl HasBot for UpdateTagsCommand {
  fn bot(&self) -> Arc<LalafellBot> {
    self.bot.clone()
  }
}

impl<'a> PublicChannelCommand<'a> for UpdateTagsCommand {
  fn run(&self, message: &Message, channel: &PublicChannel, _: &[&str]) -> CommandResult<'a> {
    let server_id = channel.server_id;
    let state_option = self.bot.state.read().unwrap();
    let state = state_option.as_ref().unwrap();
    let server = match state.servers().iter().find(|x| x.id == server_id) {
      Some(s) => s,
      None => {
        let err: error::Error = "could not find server for channel".into();
        return Err(err.into());
      }
    };
    if server.owner_id != message.author.id {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }
    let thread_bot = self.bot.clone();
    let mut task = AutoTagTask::new();
    task.next_sleep = 0;
    {
      let mut database = self.bot.database.write().unwrap();
      database.autotags.last_updated = 0;
    }
    ::std::thread::spawn(move || task.run_once(thread_bot));
    Ok(CommandSuccess::default()
      .message(|e: EmbedBuilder| e.description("Task started.")))
  }
}
<commit_msg>fix: allow updatetags outside of a channel<commit_after>use LalafellBot;
use commands::*;
use tasks::AutoTagTask;

use discord::builders::EmbedBuilder;

use std::sync::Arc;

pub struct UpdateTagsCommand {
  bot: Arc<LalafellBot>
}

impl UpdateTagsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> UpdateTagsCommand {
    UpdateTagsCommand {
      bot: bot
    }
  }
}

impl<'a> Command<'a> for UpdateTagsCommand {
  fn run(&self, message: &Message, _: &[&str]) -> CommandResult<'a> {
    if !self.bot.config.bot.administrators.contains(&message.author.id.0) {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }
    let thread_bot = self.bot.clone();
    let mut task = AutoTagTask::new();
    task.next_sleep = 0;
    {
      let mut database = self.bot.database.write().unwrap();
      database.autotags.last_updated = 0;
    }
    ::std::thread::spawn(move || task.run_once(thread_bot));
    Ok(CommandSuccess::default()
      .message(|e: EmbedBuilder| e.description("Task started.")))
  }
}
<|endoftext|>


<commit_before>#![allow(dead_code)] // not used on all platforms

use crate::fs;
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;

pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
    if !from.is_file() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "the source path is not an existing regular file",
        ));
    }

    let mut reader = fs::File::open(from)?;
    let mut writer = fs::File::create(to)?;
    let perm = reader.metadata()?.permissions();

    let ret = io::copy(&mut reader, &mut writer)?;
    fs::set_permissions(to, perm)?;
    Ok(ret)
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
    let filetype = fs::symlink_metadata(path)?.file_type();
    if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
    for child in fs::read_dir(path)? {
        let child = child?;
        if child.file_type()?.is_dir() {
            remove_dir_all_recursive(&child.path())?;
        } else {
            fs::remove_file(&child.path())?;
        }
    }
    fs::remove_dir(path)
}
<commit_msg>Auto merge of #80755 - sunfishcode:path-cleanup/copy, r=nagisa<commit_after>#![allow(dead_code)] // not used on all platforms

use crate::fs;
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;

pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
    let mut reader = fs::File::open(from)?;
    let metadata = reader.metadata()?;

    if !metadata.is_file() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "the source path is not an existing regular file",
        ));
    }

    let mut writer = fs::File::create(to)?;
    let perm = metadata.permissions();

    let ret = io::copy(&mut reader, &mut writer)?;
    writer.set_permissions(perm)?;
    Ok(ret)
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
    let filetype = fs::symlink_metadata(path)?.file_type();
    if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
    for child in fs::read_dir(path)? {
        let child = child?;
        if child.file_type()?.is_dir() {
            remove_dir_all_recursive(&child.path())?;
        } else {
            fs::remove_file(&child.path())?;
        }
    }
    fs::remove_dir(path)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::path::PathBuf;
use std::io::{BufReader, Error as IoError};
use std::fs::{File};

use glob::{Pattern, PatternError};

use core::settings::{Settings, ParseSettings, SettingsError, read_json};

use self::ParseProjectError::*;

#[derive(Debug)]
pub struct Project {
    path: Option<PathBuf>,
    folders: Vec<ProjectFolder>,
    settings: Option<Settings>,
    // todo: add buils system here
}

#[derive(Debug)]
struct ProjectFolder {
    name: Option<String>,
    path: String,
    folder: Option<Folder>,
    settings: ProjectFolderSettings
}

#[derive(Debug, Default)]
struct ExcludePatterns {
    patterns: Vec<Pattern>
}

#[derive(Debug)]
struct ProjectFolderSettings {
    folder_exclude_patterns: ExcludePatterns,
    file_exclude_patterns: ExcludePatterns,
    follow_symlinks: bool
}

#[derive(Debug)]
struct Folder {
    folders: BTreeMap<String, Folder>,
    files: Vec<String>
}

#[derive(Debug)]
pub enum ProjectError {
    Settings(SettingsError),
    Parse(ParseProjectError),
    Io(IoError)
}

#[derive(Debug)]
pub enum ParseProjectError {
    ProjectIsNotObject,
    ProjectFoldersIsNotArray,
    ProjectFolderIsNotObject,
    FolderNameIsNotString,
    FolderPathIsNotString,
    FollowSymlinksIsNotBoolean,
    ExcludePatternsIsNotArray,
    PatternIsNotString,
    IncorrectPattern(PatternError)
}

impl From<PatternError> for ParseProjectError {
    fn from(error: PatternError) -> ParseProjectError {
        IncorrectPattern(error)
    }
}

impl From<ParseProjectError> for ProjectError {
    fn from(error: ParseProjectError) -> ProjectError {
        ProjectError::Parse(error)
    }
}

impl From<SettingsError> for ProjectError {
    fn from(error: SettingsError) -> ProjectError {
        ProjectError::Settings(error)
    }
}

impl From<IoError> for ProjectError {
    fn from(error: IoError) -> ProjectError {
        ProjectError::Io(error)
    }
}

impl ParseSettings for ExcludePatterns {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<ExcludePatterns, ParseProjectError> {
        let arr = match settings {
            Settings::Array(arr) => arr,
            _ => return Err(ExcludePatternsIsNotArray)
        };

        let mut patterns = Vec::new();

        for pattern in arr {
            match pattern {
                Settings::String(s) => match Pattern::new(&s) {
                    Ok(pattern) => patterns.push(pattern),
                    Err(err) => return Err(IncorrectPattern(err))
                },
                _ => return Err(PatternIsNotString)
            }
        }

        Ok(ExcludePatterns {
            patterns: patterns
        })
    }
}

impl ParseSettings for ProjectFolder {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<ProjectFolder, ParseProjectError> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ProjectFolderIsNotObject)
        };

        let name = match obj.remove("name") {
            Some(Settings::String(s)) => Some(s),
            None => None,
            Some(_) => return Err(FolderNameIsNotString)
        };

        let path = match obj.remove("name") {
            Some(Settings::String(s)) => s,
            _ => return Err(FolderPathIsNotString)
        };

        let folder_exclude_patterns = match obj.remove("folder_exclude_patterns") {
            Some(obj) => try!(ExcludePatterns::parse_settings(obj)),
            None => ExcludePatterns::default()
        };

        let file_exclude_patterns = match obj.remove("file_exclude_patterns") {
            Some(obj) => try!(ExcludePatterns::parse_settings(obj)),
            None => ExcludePatterns::default()
        };

        let follow_symlinks = match obj.remove("follow_symlinks") {
            Some(Settings::Boolean(v)) => v,
            None => false,
            Some(..) => return Err(FollowSymlinksIsNotBoolean),
        };

        Ok(ProjectFolder {
            name: name,
            path: path,
            folder: None,
            settings: ProjectFolderSettings {
                follow_symlinks: follow_symlinks,
                file_exclude_patterns: file_exclude_patterns,
                folder_exclude_patterns: folder_exclude_patterns
            }
        })
    }
}

impl ParseSettings for Project {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<Project, ParseProjectError> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ProjectIsNotObject)
        };

        let folders_arr = match obj.remove("folders") {
            Some(Settings::Array(arr)) => arr,
            _ => return Err(ProjectFoldersIsNotArray),
        };

        let mut folders = Vec::new();

        for folder_settings in folders_arr {
            folders.push(try!(ProjectFolder::parse_settings(folder_settings)))
        }

        let settings = obj.remove("settings");

        Ok(Project {
            path: None,
            folders: folders,
            settings: settings
        })
    }
}

impl Project {
    pub fn new() -> Project {
        Project {
            path: None,
            folders: Vec::new(),
            settings: None,
        }
    }

    pub fn open(path: PathBuf) -> Result<Project, ProjectError> {
        let file = try!(File::open(&path));
        let reader = BufReader::new(file);
        let settings = try!(read_json(reader));
        let mut project = try!(Project::parse_settings(settings));
        project.path = Some(path);
        Ok(project)
    }
}
<commit_msg>project tree walking<commit_after>use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{BufReader, Error as IoError};
use std::fs::{File, Metadata, read_dir, metadata, symlink_metadata};

use glob::{Pattern, PatternError};

use core::settings::{Settings, ParseSettings, SettingsError, read_json};

use self::ParseProjectError::*;

#[derive(Debug)]
pub struct Project {
    path: Option<PathBuf>,
    folders: Vec<ProjectFolder>,
    settings: Option<Settings>,
    // todo: add buils system here
}

#[derive(Debug)]
struct ProjectFolder {
    name: Option<String>,
    path: PathBuf,
    folder: Folder,
    settings: ProjectFolderSettings
}

#[derive(Debug, Default)]
struct ExcludePatterns {
    patterns: Vec<Pattern>
}

#[derive(Debug)]
struct ProjectFolderSettings {
    folder_exclude_patterns: ExcludePatterns,
    file_exclude_patterns: ExcludePatterns,
    follow_symlinks: bool
}

#[derive(Debug, Default)]
struct Folder {
    folders: BTreeMap<String, Folder>,
    files: Vec<String>
}

#[derive(Debug)]
pub enum ProjectError {
    Settings(SettingsError),
    Parse(ParseProjectError),
    Io(IoError)
}

#[derive(Debug)]
pub enum ParseProjectError {
    ProjectIsNotObject,
    ProjectFoldersIsNotArray,
    ProjectFolderIsNotObject,
    FolderNameIsNotString,
    FolderPathIsNotString,
    FollowSymlinksIsNotBoolean,
    ExcludePatternsIsNotArray,
    PatternIsNotString,
    IncorrectPattern(PatternError)
}

impl From<PatternError> for ParseProjectError {
    fn from(error: PatternError) -> ParseProjectError {
        IncorrectPattern(error)
    }
}

impl From<ParseProjectError> for ProjectError {
    fn from(error: ParseProjectError) -> ProjectError {
        ProjectError::Parse(error)
    }
}

impl From<SettingsError> for ProjectError {
    fn from(error: SettingsError) -> ProjectError {
        ProjectError::Settings(error)
    }
}

impl From<IoError> for ProjectError {
    fn from(error: IoError) -> ProjectError {
        ProjectError::Io(error)
    }
}

impl ParseSettings for ExcludePatterns {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<ExcludePatterns, ParseProjectError> {
        let arr = match settings {
            Settings::Array(arr) => arr,
            _ => return Err(ExcludePatternsIsNotArray)
        };

        let mut patterns = Vec::new();

        for pattern in arr {
            match pattern {
                Settings::String(s) => patterns.push(try!(Pattern::new(&s))),
                _ => return Err(PatternIsNotString)
            }
        }

        Ok(ExcludePatterns {
            patterns: patterns
        })
    }
}

impl ParseSettings for ProjectFolder {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<ProjectFolder, ParseProjectError> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ProjectFolderIsNotObject)
        };

        let name = match obj.remove("name") {
            Some(Settings::String(s)) => Some(s),
            None => None,
            Some(_) => return Err(FolderNameIsNotString)
        };

        let path = match obj.remove("name") {
            Some(Settings::String(s)) => PathBuf::from(s),
            _ => return Err(FolderPathIsNotString)
        };

        let folder_exclude_patterns = match obj.remove("folder_exclude_patterns") {
            Some(obj) => try!(ExcludePatterns::parse_settings(obj)),
            None => ExcludePatterns::default()
        };

        let file_exclude_patterns = match obj.remove("file_exclude_patterns") {
            Some(obj) => try!(ExcludePatterns::parse_settings(obj)),
            None => ExcludePatterns::default()
        };

        let follow_symlinks = match obj.remove("follow_symlinks") {
            Some(Settings::Boolean(v)) => v,
            None => false,
            Some(..) => return Err(FollowSymlinksIsNotBoolean),
        };

        let settings = ProjectFolderSettings {
            follow_symlinks: follow_symlinks,
            file_exclude_patterns: file_exclude_patterns,
            folder_exclude_patterns: folder_exclude_patterns
        };

        Ok(ProjectFolder {
            name: name,
            path: path,
            folder: Folder::default(),
            settings: settings
        })
    }
}

impl ParseSettings for Project {
    type Error = ParseProjectError;

    fn parse_settings(settings: Settings) -> Result<Project, ParseProjectError> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ProjectIsNotObject)
        };

        let folders_arr = match obj.remove("folders") {
            Some(Settings::Array(arr)) => arr,
            _ => return Err(ProjectFoldersIsNotArray),
        };

        let folders = try!(folders_arr.into_iter().map(ProjectFolder::parse_settings).collect());
        let settings = obj.remove("settings");

        Ok(Project {
            path: None,
            folders: folders,
            settings: settings
        })
    }
}

impl ProjectFolderSettings {
    fn metadata(&self, path: &Path) -> Result<Metadata, IoError> {
        if self.follow_symlinks {
            metadata(path)
        } else {
            symlink_metadata(path)
        }
    }

    fn file_matched(&self, path: &Path) -> bool {
        !self.file_exclude_patterns.patterns.iter().any(|p| p.matches_path(path))
    }

    fn folder_matched(&self, path: &Path) -> bool {
        !self.folder_exclude_patterns.patterns.iter().any(|p| p.matches_path(path))
    }
}

impl Folder {
    fn walk(path: &Path, settings: &ProjectFolderSettings) -> Result<Folder, IoError> {
        let mut files = Vec::new();
        let mut folders = BTreeMap::new();
        for entry in try!(read_dir(path)) {
            let entry = try!(entry);
            let path = entry.path();
            let metadata = try!(settings.metadata(&path));
            let name = entry.file_name().to_string_lossy().into_owned();
            if metadata.is_file() {
                if settings.file_matched(&path) {
                    files.push(name);
                }
            } else if metadata.is_dir() {
                if settings.folder_matched(&path) {
                    let folder = try!(Folder::walk(&path, settings));
                    folders.insert(name, folder);
                }
            }
        }
        Ok(Folder {
            files: files,
            folders: folders
        })
    }
}

impl Project {
    pub fn new() -> Project {
        Project {
            path: None,
            folders: Vec::new(),
            settings: None,
        }
    }

    pub fn open(path: PathBuf) -> Result<Project, ProjectError> {
        let file = try!(File::open(&path));
        let reader = BufReader::new(file);
        let settings = try!(read_json(reader));
        let mut project = try!(Project::parse_settings(settings));
        project.path = Some(path);
        try!(project.walk());
        Ok(project)
    }

    pub fn walk(&mut self) -> Result<(), ProjectError> {
        for pf in self.folders.iter_mut() {
            pf.folder = try!(Folder::walk(&pf.path, &pf.settings));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// rust
// http://rosettacode.org/wiki/foo
// Accepts two command line arguments
// cargo run --name agm arg1 arg2

use std::os;
use std::num;

fn main () {
    let args = os::args();
    let args = args.as_slice();

    let x = from_str::<f32>(args[1].as_slice()).unwrap() ;
    let y = from_str::<f32>(args[2].as_slice()).unwrap() ;

    let result = agm(x,y);
    println!("The arithmetic-geometric mean is {}", result);
}

fn agm (x: f32, y: f32) -> (f32) {
    let e: f32 = 0.000001;
    let mut a = x;
    let mut g = y;
    let mut a1: f32;
    let mut g1: f32;

    loop {
            a1 = (a + g) / 2f32;
            g1 = (a * g).sqrt();
            a = a1;
            g = g1;
            if num::abs( a - g) < e {  return a; }
        }

}

#[test]
fn test_agm_12_6() {
    assert! ( agm(12f32,6f32) == 8.740746f32 );
}
<commit_msg>Thanks Adolfo for the style corrects & added [cnfg(not(test))] to main.<commit_after>// http://rosettacode.org/wiki/Arithmetric-geometric_mean
// Accepts two command line arguments
// cargo run --name agm arg1 arg2

use std::{num, os};

#[cfg(not(test))]
fn main () {
    let args = os::args();
    let args = args.as_slice();

    let x = from_str::<f32>(args[1].as_slice()).unwrap() ;
    let y = from_str::<f32>(args[2].as_slice()).unwrap() ;

    let result = agm(x,y);
    println!("The arithmetic-geometric mean is {}", result);
}

fn agm (x: f32, y: f32) -> f32 {
    let e: f32 = 0.000001;
    let mut a = x;
    let mut g = y;
    let mut a1: f32;
    let mut g1: f32;

    loop {
        a1 = (a + g) / 2f32;
        g1 = (a * g).sqrt();
        a = a1;
        g = g1;
        if num::abs( a - g) < e {  return a; }
    }

}

#[test]
fn test_agm_12_6() {
    assert! ( agm(12f32,6f32) == 8.740746f32 );
}
<|endoftext|>


<commit_before>use std::mem;

#[cfg(feature = "unstable-debug")]
use std::intrinsics;

pub struct Any {
    ptr: *mut (),
    drop: fn(*mut ()),
    fingerprint: Fingerprint,

    /// For panic messages only. Not used for comparison.
    #[cfg(feature = "unstable-debug")]
    type_name: &'static str,
}

// These functions are all unsafe. They are not exposed to the user. Declaring
// them as `unsafe fn` would not make the rest of erased-serde any safer or more
// readable.
impl Any {
    // This is unsafe -- caller must not hold on to the Any beyond the lifetime
    // of T.
    //
    // Example of bad code:
    //
    //    let s = "bad".to_owned();
    //    let a = Any::new(&s);
    //    drop(s);
    //
    // Now `a.view()` and `a.take()` return references to a dead String.
    pub(crate) fn new<T>(t: T) -> Self {
        let ptr = Box::into_raw(Box::new(t));
        Any {
            ptr: ptr as *mut (),
            drop: |ptr| drop(unsafe { Box::from_raw(ptr as *mut T) }),
            fingerprint: Fingerprint::of::<T>(),
            #[cfg(feature = "unstable-debug")]
            type_name: unsafe { intrinsics::type_name::<T>() },
        }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn view<T>(&mut self) -> &mut T {
        if self.fingerprint != Fingerprint::of::<T>() {
            self.invalid_cast_to::<T>();
        }
        let ptr = self.ptr as *mut T;
        unsafe { &mut *ptr }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn take<T>(self) -> T {
        if self.fingerprint != Fingerprint::of::<T>() {
            self.invalid_cast_to::<T>();
        }
        let ptr = self.ptr as *mut T;
        let box_t = unsafe { Box::from_raw(ptr) };
        mem::forget(self);
        *box_t
    }

    #[cfg(not(feature = "unstable-debug"))]
    fn invalid_cast_to<T>(&self) -> ! {
        panic!("invalid cast; enable `unstable-debug` feature to debug");
    }

    #[cfg(feature = "unstable-debug")]
    fn invalid_cast_to<T>(&self) -> ! {
        let from = self.type_name;
        let to = unsafe { intrinsics::type_name::<T>() };
        panic!("invalid cast: {} to {}", from, to);
    }
}

impl Drop for Any {
    fn drop(&mut self) {
        (self.drop)(self.ptr);
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Fingerprint {
    size: usize,
    align: usize,
    id: usize,
}

impl Fingerprint {
    fn of<T>() -> Fingerprint {
        Fingerprint {
            size: mem::size_of::<T>(),
            align: mem::align_of::<T>(),
            // This is not foolproof -- theoretically Rust or LLVM could
            // deduplicate some or all of these methods. But in practice it's
            // great and I am comfortable relying on this in debug mode to catch
            // bugs early.
            id: Fingerprint::of::<T> as usize,
        }
    }
}

#[test]
fn test_fingerprint() {
    assert_eq!(Fingerprint::of::<usize>(), Fingerprint::of::<usize>());
    assert_eq!(Fingerprint::of::<&str>(), Fingerprint::of::<&'static str>());

    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<isize>());
    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&mut usize>());

    struct A;
    struct B;
    assert_ne!(Fingerprint::of::<A>(), Fingerprint::of::<B>());
}
<commit_msg>Support stable compiler without struct field attributes<commit_after>use std::mem;

#[cfg(feature = "unstable-debug")]
use std::intrinsics;

pub struct Any {
    ptr: *mut (),
    drop: fn(*mut ()),
    fingerprint: Fingerprint,

    /// For panic messages only. Not used for comparison.
    #[cfg(feature = "unstable-debug")]
    type_name: &'static str,
}

// These functions are all unsafe. They are not exposed to the user. Declaring
// them as `unsafe fn` would not make the rest of erased-serde any safer or more
// readable.
impl Any {
    // This is unsafe -- caller must not hold on to the Any beyond the lifetime
    // of T.
    //
    // Example of bad code:
    //
    //    let s = "bad".to_owned();
    //    let a = Any::new(&s);
    //    drop(s);
    //
    // Now `a.view()` and `a.take()` return references to a dead String.
    pub(crate) fn new<T>(t: T) -> Self {
        let ptr = Box::into_raw(Box::new(t)) as *mut ();
        let drop = |ptr| drop(unsafe { Box::from_raw(ptr as *mut T) });
        let fingerprint = Fingerprint::of::<T>();

        // Once attributes on struct literal fields are stable, do that instead.
        // https://github.com/rust-lang/rust/issues/41681
        #[cfg(not(feature = "unstable-debug"))]
        {
            Any { ptr, drop, fingerprint }
        }

        #[cfg(feature = "unstable-debug")]
        {
            let type_name = unsafe { intrinsics::type_name::<T>() };
            Any { ptr, drop, fingerprint, type_name }
        }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn view<T>(&mut self) -> &mut T {
        if self.fingerprint != Fingerprint::of::<T>() {
            self.invalid_cast_to::<T>();
        }
        let ptr = self.ptr as *mut T;
        unsafe { &mut *ptr }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn take<T>(self) -> T {
        if self.fingerprint != Fingerprint::of::<T>() {
            self.invalid_cast_to::<T>();
        }
        let ptr = self.ptr as *mut T;
        let box_t = unsafe { Box::from_raw(ptr) };
        mem::forget(self);
        *box_t
    }

    #[cfg(not(feature = "unstable-debug"))]
    fn invalid_cast_to<T>(&self) -> ! {
        panic!("invalid cast; enable `unstable-debug` feature to debug");
    }

    #[cfg(feature = "unstable-debug")]
    fn invalid_cast_to<T>(&self) -> ! {
        let from = self.type_name;
        let to = unsafe { intrinsics::type_name::<T>() };
        panic!("invalid cast: {} to {}", from, to);
    }
}

impl Drop for Any {
    fn drop(&mut self) {
        (self.drop)(self.ptr);
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Fingerprint {
    size: usize,
    align: usize,
    id: usize,
}

impl Fingerprint {
    fn of<T>() -> Fingerprint {
        Fingerprint {
            size: mem::size_of::<T>(),
            align: mem::align_of::<T>(),
            // This is not foolproof -- theoretically Rust or LLVM could
            // deduplicate some or all of these methods. But in practice it's
            // great and I am comfortable relying on this in debug mode to catch
            // bugs early.
            id: Fingerprint::of::<T> as usize,
        }
    }
}

#[test]
fn test_fingerprint() {
    assert_eq!(Fingerprint::of::<usize>(), Fingerprint::of::<usize>());
    assert_eq!(Fingerprint::of::<&str>(), Fingerprint::of::<&'static str>());

    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<isize>());
    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&mut usize>());

    struct A;
    struct B;
    assert_ne!(Fingerprint::of::<A>(), Fingerprint::of::<B>());
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::OpenOptions;
use async_std::io::{self, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_TIMEOUT")
                .long("dns-lookup-timeout")
                .takes_value(true)
                .default_value("5")
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value("15")
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value("10")
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("timeout")
                .takes_value(true)
                .default_value("30")
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    let dns_timeout = u64::from_str_radix(matches.value_of("DNS_TIMEOUT").unwrap(), 10)
        .expect("DNS_TIMEOUT must be an integer")
        * 1_000;
    let connect_timeout = u64::from_str_radix(matches.value_of("CONNECT_TIMEOUT").unwrap(), 10)
        .expect("CONNECT_TIMEOUT must be an integer")
        * 1_000;
    let read_timeout = u64::from_str_radix(matches.value_of("READ_TIMEOUT").unwrap(), 10)
        .expect("READ_TIMEOUT must be an integer")
        * 1_000;
    let request_timeout = u64::from_str_radix(matches.value_of("REQUEST_TIMEOUT").unwrap(), 10)
        .expect("REQUEST_TIMEOUT must be an integer")
        * 1_000;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut f, verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
        )
        .await?
    } else {
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut io::stdout(), verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
        )
        .await?
    };
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            Pin::new(&mut self_.out).poll_write(cx, buf)
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<commit_msg>Rename the dns-lookup-timeout parameter to dns-timeout<commit_after>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::OpenOptions;
use async_std::io::{self, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_LOOKUP_TIMEOUT")
                .long("dns-timeout")
                .takes_value(true)
                .default_value("5")
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value("15")
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value("10")
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("timeout")
                .takes_value(true)
                .default_value("30")
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    let dns_timeout = u64::from_str_radix(matches.value_of("DNS_LOOKUP_TIMEOUT").unwrap(), 10)
        .expect("DNS_LOOKUP_TIMEOUT must be an integer")
        * 1_000;
    let connect_timeout = u64::from_str_radix(matches.value_of("CONNECT_TIMEOUT").unwrap(), 10)
        .expect("CONNECT_TIMEOUT must be an integer")
        * 1_000;
    let read_timeout = u64::from_str_radix(matches.value_of("READ_TIMEOUT").unwrap(), 10)
        .expect("READ_TIMEOUT must be an integer")
        * 1_000;
    let request_timeout = u64::from_str_radix(matches.value_of("REQUEST_TIMEOUT").unwrap(), 10)
        .expect("REQUEST_TIMEOUT must be an integer")
        * 1_000;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut f, verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
        )
        .await?
    } else {
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut io::stdout(), verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
        )
        .await?
    };
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            Pin::new(&mut self_.out).poll_write(cx, buf)
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate tokio_process;

use self::futures::future::Future;
use self::futures::Stream;
use self::hyper::header::ContentEncoding;
use self::hyper::header::ContentLength;
use self::hyper::header::ContentType;
use self::hyper::server::{Request, Response};
use cgi::tokio_process::CommandExt;
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

pub fn do_cgi(
    req: Request,
    cmd: Command,
    handle: tokio_core::reactor::Handle,
) -> Box<Future<Item = Response, Error = hyper::Error>> {
    let mut cmd = cmd;
    cmd.stdout(Stdio::piped());
    cmd.stderr(Stdio::inherit());
    cmd.stdin(Stdio::piped());
    println!("REQUEST_METHOD {:?}", req.method());
    cmd.env("SERVER_SOFTWARE", "hyper")
        .env("SERVER_NAME", "localhost") // TODO
        .env("GATEWAY_INTERFACE", "CGI/1.1")
        .env("SERVER_PROTOCOL", "HTTP/1.1") // TODO
        .env("SERVER_PORT", "80") // TODO
        .env("REQUEST_METHOD", format!("{}", req.method()))
        .env("SCRIPT_NAME", "") // TODO
        .env("QUERY_STRING", req.query().unwrap_or(""))
        .env("REMOTE_ADDR", "") // TODO
        .env("AUTH_TYPE", "") // TODO
        .env("REMOTE_USER", "") // TODO
        .env(
            "CONTENT_TYPE",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentType::plaintext())
            ),
        )
        .env(
            "HTTP_CONTENT_ENCODING",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentEncoding(vec![]))
            ),
        )
        .env(
            "CONTENT_LENGTH",
            &format!("{}", req.headers().get().unwrap_or(&ContentLength(0))),
        );

    let mut child = cmd.spawn_async(&handle).expect("can't spawn CGI command");

    Box::new(req.body().concat2().and_then(move |body| {
        child
            .stdin()
            .take()
            .unwrap()
            .write_all(&body)
            .expect("can't write command output (body)");

        Box::new(
            child
                .wait_with_output()
                .map(|command_result| {
                    let mut stdout = io::BufReader::new(command_result.stdout.as_slice());

                    let mut data = vec![];
                    let mut response = Response::new();

                    for line in stdout.by_ref().lines() {
                        println!("STDOUT line: {:?}", line);
                        if line.as_ref().unwrap().is_empty() {
                            break;
                        }
                        let l: Vec<&str> =
                            line.as_ref().unwrap().as_str().splitn(2, ": ").collect();
                        if l[0] == "Status" {
                            response.set_status(hyper::StatusCode::Unregistered(
                                u16::from_str(l[1].split(" ").next().unwrap()).unwrap(),
                            ));
                        } else {
                            response
                                .headers_mut()
                                .set_raw(l[0].to_string(), l[1].to_string());
                        }
                    }
                    stdout
                        .read_to_end(&mut data)
                        .expect("can't read command output");
                    response.set_body(hyper::Chunk::from(data));
                    response
                })
                .map_err(|e| e.into()),
        )
    }))
}
<commit_msg>Extract function<commit_after>extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate tokio_process;

use self::futures::future::Future;
use self::futures::Stream;
use self::hyper::header::ContentEncoding;
use self::hyper::header::ContentLength;
use self::hyper::header::ContentType;
use self::hyper::server::{Request, Response};
use cgi::tokio_process::CommandExt;
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

pub fn do_cgi(
    req: Request,
    cmd: Command,
    handle: tokio_core::reactor::Handle,
) -> Box<Future<Item = Response, Error = hyper::Error>> {
    let mut cmd = cmd;
    cmd.stdout(Stdio::piped());
    cmd.stderr(Stdio::inherit());
    cmd.stdin(Stdio::piped());
    println!("REQUEST_METHOD {:?}", req.method());
    cmd.env("SERVER_SOFTWARE", "hyper")
        .env("SERVER_NAME", "localhost") // TODO
        .env("GATEWAY_INTERFACE", "CGI/1.1")
        .env("SERVER_PROTOCOL", "HTTP/1.1") // TODO
        .env("SERVER_PORT", "80") // TODO
        .env("REQUEST_METHOD", format!("{}", req.method()))
        .env("SCRIPT_NAME", "") // TODO
        .env("QUERY_STRING", req.query().unwrap_or(""))
        .env("REMOTE_ADDR", "") // TODO
        .env("AUTH_TYPE", "") // TODO
        .env("REMOTE_USER", "") // TODO
        .env(
            "CONTENT_TYPE",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentType::plaintext())
            ),
        )
        .env(
            "HTTP_CONTENT_ENCODING",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentEncoding(vec![]))
            ),
        )
        .env(
            "CONTENT_LENGTH",
            &format!("{}", req.headers().get().unwrap_or(&ContentLength(0))),
        );

    let mut child = cmd.spawn_async(&handle).expect("can't spawn CGI command");

    Box::new(req.body().concat2().and_then(move |body| {
        child
            .stdin()
            .take()
            .unwrap()
            .write_all(&body)
            .expect("can't write command output (body)");

        Box::new(
            child
                .wait_with_output()
                .map(build_response)
                .map_err(|e| e.into()),
        )
    }))
}

fn build_response(command_result: std::process::Output) -> Response {
    let mut stdout = io::BufReader::new(command_result.stdout.as_slice());

    let mut data = vec![];
    let mut response = Response::new();

    for line in stdout.by_ref().lines() {
        println!("STDOUT line: {:?}", line);
        if line.as_ref().unwrap().is_empty() {
            break;
        }
        let l: Vec<&str> =
            line.as_ref().unwrap().as_str().splitn(2, ": ").collect();
        if l[0] == "Status" {
            response.set_status(hyper::StatusCode::Unregistered(
                u16::from_str(l[1].split(" ").next().unwrap()).unwrap(),
            ));
        } else {
            response
                .headers_mut()
                .set_raw(l[0].to_string(), l[1].to_string());
        }
    }
    stdout
        .read_to_end(&mut data)
        .expect("can't read command output");
    response.set_body(hyper::Chunk::from(data));
    response
}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }

    fn make_response(&self, mut response: Response) {
        response.headers_mut().set(self.content_type());
        response.headers_mut().set(self.content_length());
        response.start().unwrap().write(self.content()).unwrap();
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request).make_response(response),
            path == "/ip" => origin(&request).make_response(response),
            path.starts_with("/status/") => status(path).make_response(response),
            path.starts_with("/test") => test(&request).make_response(response),
            true => notfound404().make_response(response),
        ];
    }
}

fn notfound404() -> String {
    String::from("<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ")
}

fn index(request: &Request) -> String {
    String::from("<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ")
}

fn status(path: &str) -> StatusCode {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    }
}

fn origin(request: &Request) -> String {
    String::from("Remote address decoding is not implemented yet")
}

fn test(request: &Request) -> String {
    format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
            request.remote_addr,
            request.method,
            request.version,
            request.headers,
            request.uri)
}
<commit_msg>simple /ip decoding<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }

    fn make_response(&self, mut response: Response) {
        response.headers_mut().set(self.content_type());
        response.headers_mut().set(self.content_length());
        response.start().unwrap().write(self.content()).unwrap();
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request).make_response(response),
            path == "/ip" => origin(&request).make_response(response),
            path.starts_with("/status/") => status(path).make_response(response),
            path.starts_with("/test") => test(&request).make_response(response),
            true => notfound404().make_response(response),
        ];
    }
}

fn notfound404() -> String {
    String::from("<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ")
}

fn index(request: &Request) -> String {
    String::from("<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ")
}

fn status(path: &str) -> StatusCode {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    }
}

fn origin(request: &Request) -> String {
    format!("origin: {}", request.remote_addr)
}

fn test(request: &Request) -> String {
    format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
            request.remote_addr,
            request.method,
            request.version,
            request.headers,
            request.uri)
}
<|endoftext|>


<commit_before>use std::mem;

pub struct Encoder<'a> {
    chunks: Vec<Chunk<'a>>,
    capacity: usize,
}

enum Chunk<'a> {
    Uint8(u8),
    Uint16(u16),
    Uint32(u32),
    Blob(&'a [u8]),
}

static MAX_SIZE: usize = 0x3FFFFFFF;

impl<'a> Encoder<'a> {
    pub fn new() -> Encoder<'a> {
        Encoder {
            chunks: Vec::new(),
            capacity: 0,
        }
    }

    pub fn uint8(&'a mut self, uint8: u8) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint8(uint8));
        self.capacity += 1;
        return self;
    }

    pub fn uint16(&'a mut self, uint16: u16) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint16(uint16));
        self.capacity += 2;
        return self;
    }

    pub fn uint32(&'a mut self, uint32: u32) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint32(uint32));
        self.capacity += 4;
        return self;
    }

    pub fn int8(&'a mut self, int8: i8) -> &'a mut Encoder {
        self.uint8(unsafe { mem::transmute_copy(&int8) })
    }

    pub fn int16(&'a mut self, int16: i16) -> &'a mut Encoder {
        self.uint16(unsafe { mem::transmute_copy(&int16) })
    }

    pub fn int32(&'a mut self, int32: i32) -> &'a mut Encoder {
        self.uint32(unsafe { mem::transmute_copy(&int32) })
    }

    pub fn float32(&'a mut self, float32: f32) -> &'a mut Encoder {
        self.uint32(unsafe { mem::transmute_copy(&float32) })
    }

    pub fn float64(&'a mut self, float64: f64) -> &'a mut Encoder {
        let uint64: u64 = unsafe { mem::transmute_copy(&float64) };
        return self
            .uint32((uint64 >> 32) as u32)
            .uint32((uint64 & 0xFFFFFFFF) as u32);
    }

    pub fn size(&'a mut self, size: usize) -> &'a mut Encoder {
        if size > MAX_SIZE {
            return self.uint32(0xFFFFFFFF);
        }

        // can fit on 7 bits
        if size < 0x80 {
            return self.uint8(size as u8);
        }

        // can fit on 14 bits
        if size < 0x4000 {
            return self.uint16((size as u16) | 0x8000);
        }

        // use up to 30 bits
        return self.uint32((size as u32) | 0xC0000000);
    }

    pub fn blob(&'a mut self, blob: &'a [u8]) -> &'a mut Encoder {
        let size = blob.len();
        let borrow = self.size(size);
        borrow.capacity += size;
        borrow.chunks.push(Chunk::Blob(blob));
        return borrow;
    }

    pub fn string(&'a mut self, string: &'a str) -> &'a mut Encoder {
        self.blob(string.as_bytes())
    }

    pub fn encode(&'a mut self) -> Result<Vec<u8>, ()> {
        let mut data: Vec<u8> = Vec::with_capacity(self.capacity);

        for chunk in self.chunks.iter() {
            match chunk {
                &Chunk::Uint8(uint8) => data.push(uint8),
                &Chunk::Uint16(uint16) => {
                    data.push((uint16 >> 8) as u8);
                    data.push((uint16 & 0xFF) as u8);
                },
                &Chunk::Uint32(uint32) => {
                    data.push(((uint32) >> 24) as u8);
                    data.push((((uint32) >> 16) & 0xFF) as u8);
                    data.push((((uint32) >> 8) & 0xFF) as u8);
                    data.push(((uint32) & 0xFF) as u8);
                },
                &Chunk::Blob(blob) => {
                    if blob.len() > MAX_SIZE {
                        return Err(());
                    }
                    data.extend_from_slice(blob);
                }
            }
        }

        Ok(data)
    }
}

pub struct Decoder<'a> {
    index: usize,
    length: usize,
    data: &'a[u8],
}

impl<'a> Decoder<'a> {
    pub fn new(data: &[u8]) -> Decoder {
        Decoder {
            index: 0,
            length: data.len(),
            data: data,
        }
    }

    pub fn uint8(&mut self) -> Result<u8, ()> {
        if self.index >= self.length {
            return Err(());
        }
        let uint8 = self.data[self.index];
        self.index += 1;
        return Ok(uint8);
    }

    pub fn uint16(&mut self) -> Result<u16, ()> {
        Ok(
            (try!(self.uint8()) as u16) << 8 |
            (try!(self.uint8()) as u16)
        )
    }

    pub fn uint32(&mut self) -> Result<u32, ()> {
        Ok(
            (try!(self.uint8()) as u32) << 24 |
            (try!(self.uint8()) as u32) << 16 |
            (try!(self.uint8()) as u32) << 8  |
            (try!(self.uint8()) as u32)
        )
    }

    pub fn int8(&mut self) -> Result<i8, ()> {
        let uint8 = try!(self.uint8());
        Ok(unsafe { mem::transmute_copy(&uint8) })
    }

    pub fn int16(&mut self) -> Result<i16, ()> {
        let uint16 = try!(self.uint16());
        Ok(unsafe { mem::transmute_copy(&uint16) })
    }

    pub fn int32(&mut self) -> Result<i32, ()> {
        let uint32 = try!(self.uint32());
        Ok(unsafe { mem::transmute_copy(&uint32) })
    }

    pub fn float32(&mut self) -> Result<f32, ()> {
        let uint32 = try!(self.uint32());
        Ok(unsafe { mem::transmute_copy(&uint32) })
    }

    pub fn float64(&mut self) -> Result<f64, ()> {
        let uint64 = (try!(self.uint32()) as u64) << 32 |
                     (try!(self.uint32()) as u64);
        Ok(unsafe { mem::transmute_copy(&uint64) })
    }

    pub fn size(&mut self) -> Result<usize, ()> {
        let mut size: usize = try!(self.uint8()) as usize;

        // 1 byte (no signature)
        if (size & 128) == 0 {
            return Ok(size);
        }

        let sig: u8 = (size as u8) >> 6;
        // remove signature from the first byte
        size = size & 63 /* 00111111 */;

        // 2 bytes (signature is 10)
        if sig == 2 {
            return Ok(size << 8 | try!(self.uint8()) as usize);
        }

        Ok(
            size << 24                          |
            (try!(self.uint8()) as usize) << 16 |
            (try!(self.uint8()) as usize) << 8  |
            (try!(self.uint8()) as usize)
        )
    }

    pub fn blob(&mut self) -> Result<Vec<u8>, ()> {
        let size = try!(self.size());
        if self.index + size >= self.length {
            return Err(());
        }

        let blob = self.data[self.index .. self.index + size].to_vec();

        self.index += size;

        return Ok(blob);
    }

    pub fn string(&mut self) -> Result<String, ()> {
        let blob = try!(self.blob());
        return match String::from_utf8(blob) {
            Ok(string) => Ok(string),
            Err(_) => Err(()),
        }
    }
}
<commit_msg>minor cleanup<commit_after>use std::mem;

pub struct Encoder<'a> {
    chunks: Vec<Chunk<'a>>,
    capacity: usize,
}

enum Chunk<'a> {
    Uint8(u8),
    Uint16(u16),
    Uint32(u32),
    Blob(&'a [u8]),
}

static MAX_SIZE: usize = 0x3FFFFFFF;

impl<'a> Encoder<'a> {
    pub fn new() -> Encoder<'a> {
        Encoder {
            chunks: Vec::new(),
            capacity: 0,
        }
    }

    pub fn uint8(&'a mut self, uint8: u8) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint8(uint8));
        self.capacity += 1;
        return self;
    }

    pub fn uint16(&'a mut self, uint16: u16) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint16(uint16));
        self.capacity += 2;
        return self;
    }

    pub fn uint32(&'a mut self, uint32: u32) -> &'a mut Encoder {
        self.chunks.push(Chunk::Uint32(uint32));
        self.capacity += 4;
        return self;
    }

    pub fn int8(&'a mut self, int8: i8) -> &'a mut Encoder {
        self.uint8(unsafe { mem::transmute_copy(&int8) })
    }

    pub fn int16(&'a mut self, int16: i16) -> &'a mut Encoder {
        self.uint16(unsafe { mem::transmute_copy(&int16) })
    }

    pub fn int32(&'a mut self, int32: i32) -> &'a mut Encoder {
        self.uint32(unsafe { mem::transmute_copy(&int32) })
    }

    pub fn float32(&'a mut self, float32: f32) -> &'a mut Encoder {
        self.uint32(unsafe { mem::transmute_copy(&float32) })
    }

    pub fn float64(&'a mut self, float64: f64) -> &'a mut Encoder {
        let uint64: u64 = unsafe { mem::transmute_copy(&float64) };
        return self
            .uint32((uint64 >> 32) as u32)
            .uint32((uint64 & 0xFFFFFFFF) as u32);
    }

    pub fn size(&'a mut self, size: usize) -> &'a mut Encoder {
        if size > MAX_SIZE {
            return self.uint32(0xFFFFFFFF);
        }

        // can fit on 7 bits
        if size < 0x80 {
            return self.uint8(size as u8);
        }

        // can fit on 14 bits
        if size < 0x4000 {
            return self.uint16((size as u16) | 0x8000);
        }

        // use up to 30 bits
        return self.uint32((size as u32) | 0xC0000000);
    }

    pub fn blob(&'a mut self, blob: &'a [u8]) -> &'a mut Encoder {
        let size = blob.len();
        let borrow = self.size(size);
        borrow.capacity += size;
        borrow.chunks.push(Chunk::Blob(blob));
        return borrow;
    }

    pub fn string(&'a mut self, string: &'a str) -> &'a mut Encoder {
        self.blob(string.as_bytes())
    }

    pub fn encode(&'a self) -> Result<Vec<u8>, ()> {
        let mut data: Vec<u8> = Vec::with_capacity(self.capacity);

        for chunk in self.chunks.iter() {
            match chunk {
                &Chunk::Uint8(uint8) => data.push(uint8),
                &Chunk::Uint16(uint16) => {
                    data.push((uint16 >> 8) as u8);
                    data.push((uint16 & 0xFF) as u8);
                },
                &Chunk::Uint32(uint32) => {
                    data.push(((uint32) >> 24) as u8);
                    data.push((((uint32) >> 16) & 0xFF) as u8);
                    data.push((((uint32) >> 8) & 0xFF) as u8);
                    data.push(((uint32) & 0xFF) as u8);
                },
                &Chunk::Blob(blob) => {
                    if blob.len() > MAX_SIZE {
                        return Err(());
                    }
                    data.extend_from_slice(blob);
                }
            }
        }

        Ok(data)
    }
}

pub struct Decoder<'a> {
    index: usize,
    length: usize,
    data: &'a[u8],
}

impl<'a> Decoder<'a> {
    pub fn new(data: &[u8]) -> Decoder {
        Decoder {
            index: 0,
            length: data.len(),
            data: data,
        }
    }

    pub fn uint8(&mut self) -> Result<u8, ()> {
        if self.index >= self.length {
            return Err(());
        }
        let uint8 = self.data[self.index];
        self.index += 1;
        return Ok(uint8);
    }

    pub fn uint16(&mut self) -> Result<u16, ()> {
        Ok(
            (try!(self.uint8()) as u16) << 8 |
            (try!(self.uint8()) as u16)
        )
    }

    pub fn uint32(&mut self) -> Result<u32, ()> {
        Ok(
            (try!(self.uint8()) as u32) << 24 |
            (try!(self.uint8()) as u32) << 16 |
            (try!(self.uint8()) as u32) << 8  |
            (try!(self.uint8()) as u32)
        )
    }

    pub fn int8(&mut self) -> Result<i8, ()> {
        let uint8 = try!(self.uint8());
        Ok(unsafe { mem::transmute_copy(&uint8) })
    }

    pub fn int16(&mut self) -> Result<i16, ()> {
        let uint16 = try!(self.uint16());
        Ok(unsafe { mem::transmute_copy(&uint16) })
    }

    pub fn int32(&mut self) -> Result<i32, ()> {
        let uint32 = try!(self.uint32());
        Ok(unsafe { mem::transmute_copy(&uint32) })
    }

    pub fn float32(&mut self) -> Result<f32, ()> {
        let uint32 = try!(self.uint32());
        Ok(unsafe { mem::transmute_copy(&uint32) })
    }

    pub fn float64(&mut self) -> Result<f64, ()> {
        let uint64 = (try!(self.uint32()) as u64) << 32 |
                     (try!(self.uint32()) as u64);
        Ok(unsafe { mem::transmute_copy(&uint64) })
    }

    pub fn size(&mut self) -> Result<usize, ()> {
        let mut size: usize = try!(self.uint8()) as usize;

        // 1 byte (no signature)
        if (size & 128) == 0 {
            return Ok(size);
        }

        let sig: u8 = (size as u8) >> 6;
        // remove signature from the first byte
        size = size & 63 /* 00111111 */;

        // 2 bytes (signature is 10)
        if sig == 2 {
            return Ok(size << 8 | try!(self.uint8()) as usize);
        }

        Ok(
            size << 24                          |
            (try!(self.uint8()) as usize) << 16 |
            (try!(self.uint8()) as usize) << 8  |
            (try!(self.uint8()) as usize)
        )
    }

    pub fn blob(&mut self) -> Result<Vec<u8>, ()> {
        let size = try!(self.size());
        if self.index + size >= self.length {
            return Err(());
        }

        let blob = self.data[self.index .. self.index + size].to_vec();

        self.index += size;

        return Ok(blob);
    }

    pub fn string(&mut self) -> Result<String, ()> {
        let blob = try!(self.blob());
        return match String::from_utf8(blob) {
            Ok(string) => Ok(string),
            Err(_) => Err(()),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id = "iron"]
#![comment = "Rapid Web Development in Rust"]
#![license = "MIT"]

#![deny(missing_doc)]
#![deny(unused_result)]
#![deny(unnecessary_qualification)]
#![deny(non_camel_case_types)]
#![deny(unused_variable)]
#![deny(unnecessary_typecast)]

#![feature(macro_rules, phase)]
//! The main crate for the Iron library.

extern crate regex;
#[phase(plugin)] extern crate regex_macros;

extern crate http;
extern crate anymap;

pub use request::Request;
pub use response::Response;

pub use iron::{Iron, ServerT};
pub use middleware::Middleware;

pub use furnace::Furnace;
pub use furnace::stackfurnace::StackFurnace;

pub use alloy::Alloy;

pub mod request;
pub mod response;
pub mod mixin;
pub mod middleware;
pub mod alloy;
pub mod furnace;
pub mod iron;

<commit_msg>(feat) Changed exports to work with Chain.<commit_after>#![crate_id = "iron"]
#![comment = "Rapid Web Development in Rust"]
#![license = "MIT"]

#![deny(missing_doc)]
#![deny(unused_result)]
#![deny(unnecessary_qualification)]
#![deny(non_camel_case_types)]
#![deny(unused_variable)]
#![deny(unnecessary_typecast)]

#![feature(macro_rules, phase)]
//! The main crate for the Iron library.

extern crate regex;
#[phase(plugin)] extern crate regex_macros;

extern crate http;
extern crate anymap;

pub use request::Request;
pub use response::Response;

pub use iron::{Iron, ServerT};
pub use middleware::Middleware;

pub use chain::Chain;
pub use chain::stackchain::StackChain;

pub use alloy::Alloy;

pub mod request;
pub mod response;
pub mod mixin;
pub mod middleware;
pub mod alloy;
pub mod chain;
pub mod iron;

<|endoftext|>


<commit_before>//! Crate **ruma_identifiers** contains types for [Matrix](https://matrix.org/) identifiers
//! for events, rooms, room aliases, room versions, and users.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs,
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]

#[cfg(feature = "diesel")]
#[cfg_attr(feature = "diesel", macro_use)]
extern crate diesel;

use std::fmt::{Formatter, Result as FmtResult};

use rand::{distributions::Alphanumeric, thread_rng, Rng};
use url::Url;

pub use url::Host;

#[doc(inline)]
pub use crate::device_id::DeviceId;
pub use crate::{
    error::Error, event_id::EventId, room_alias_id::RoomAliasId, room_id::RoomId,
    room_id_or_room_alias_id::RoomIdOrAliasId, room_version_id::RoomVersionId, user_id::UserId,
};

pub mod device_id;
#[cfg(feature = "diesel")]
mod diesel_integration;
mod error;
mod event_id;
mod room_alias_id;
mod room_id;
mod room_id_or_room_alias_id;
mod room_version_id;
mod user_id;

/// All identifiers must be 255 bytes or less.
const MAX_BYTES: usize = 255;
/// The minimum number of characters an ID can be.
///
/// This is an optimization and not required by the spec. The shortest possible valid ID is a sigil
/// + a single character local ID + a colon + a single character hostname.
const MIN_CHARS: usize = 4;
/// The number of bytes in a valid sigil.
const SIGIL_BYTES: usize = 1;

/// `Display` implementation shared by identifier types.
fn display(
    f: &mut Formatter<'_>,
    sigil: char,
    localpart: &str,
    hostname: &Host,
    port: u16,
) -> FmtResult {
    if port == 443 {
        write!(f, "{}{}:{}", sigil, localpart, hostname)
    } else {
        write!(f, "{}{}:{}:{}", sigil, localpart, hostname, port)
    }
}

/// Generates a random identifier localpart.
fn generate_localpart(length: usize) -> String {
    thread_rng()
        .sample_iter(&Alphanumeric)
        .take(length)
        .collect()
}

/// Checks if an identifier is within the acceptable byte lengths.
fn validate_id(id: &str) -> Result<(), Error> {
    if id.len() > MAX_BYTES {
        return Err(Error::MaximumLengthExceeded);
    }

    if id.len() < MIN_CHARS {
        return Err(Error::MinimumLengthNotSatisfied);
    }

    Ok(())
}

/// Parses the localpart, host, and port from a string identifier.
fn parse_id(required_sigil: char, id: &str) -> Result<(&str, Host, u16), Error> {
    validate_id(id)?;

    if !id.starts_with(required_sigil) {
        return Err(Error::MissingSigil);
    }

    let delimiter_index = match id.find(':') {
        Some(index) => index,
        None => return Err(Error::MissingDelimiter),
    };

    let localpart = &id[1..delimiter_index];
    let raw_host = &id[delimiter_index + SIGIL_BYTES..];
    let url_string = format!("https://{}", raw_host);
    let url = Url::parse(&url_string)?;

    let host = match url.host() {
        Some(host) => host.to_owned(),
        None => return Err(Error::InvalidHost),
    };

    let port = url.port().unwrap_or(443);

    Ok((localpart, host, port))
}
<commit_msg>Remove #![deny(warnings)], #![warn(clippy::…)]<commit_after>//! Crate **ruma_identifiers** contains types for [Matrix](https://matrix.org/) identifiers
//! for events, rooms, room aliases, room versions, and users.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs
)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]

#[cfg(feature = "diesel")]
#[cfg_attr(feature = "diesel", macro_use)]
extern crate diesel;

use std::fmt::{Formatter, Result as FmtResult};

use rand::{distributions::Alphanumeric, thread_rng, Rng};
use url::Url;

pub use url::Host;

#[doc(inline)]
pub use crate::device_id::DeviceId;
pub use crate::{
    error::Error, event_id::EventId, room_alias_id::RoomAliasId, room_id::RoomId,
    room_id_or_room_alias_id::RoomIdOrAliasId, room_version_id::RoomVersionId, user_id::UserId,
};

pub mod device_id;
#[cfg(feature = "diesel")]
mod diesel_integration;
mod error;
mod event_id;
mod room_alias_id;
mod room_id;
mod room_id_or_room_alias_id;
mod room_version_id;
mod user_id;

/// All identifiers must be 255 bytes or less.
const MAX_BYTES: usize = 255;
/// The minimum number of characters an ID can be.
///
/// This is an optimization and not required by the spec. The shortest possible valid ID is a sigil
/// + a single character local ID + a colon + a single character hostname.
const MIN_CHARS: usize = 4;
/// The number of bytes in a valid sigil.
const SIGIL_BYTES: usize = 1;

/// `Display` implementation shared by identifier types.
fn display(
    f: &mut Formatter<'_>,
    sigil: char,
    localpart: &str,
    hostname: &Host,
    port: u16,
) -> FmtResult {
    if port == 443 {
        write!(f, "{}{}:{}", sigil, localpart, hostname)
    } else {
        write!(f, "{}{}:{}:{}", sigil, localpart, hostname, port)
    }
}

/// Generates a random identifier localpart.
fn generate_localpart(length: usize) -> String {
    thread_rng()
        .sample_iter(&Alphanumeric)
        .take(length)
        .collect()
}

/// Checks if an identifier is within the acceptable byte lengths.
fn validate_id(id: &str) -> Result<(), Error> {
    if id.len() > MAX_BYTES {
        return Err(Error::MaximumLengthExceeded);
    }

    if id.len() < MIN_CHARS {
        return Err(Error::MinimumLengthNotSatisfied);
    }

    Ok(())
}

/// Parses the localpart, host, and port from a string identifier.
fn parse_id(required_sigil: char, id: &str) -> Result<(&str, Host, u16), Error> {
    validate_id(id)?;

    if !id.starts_with(required_sigil) {
        return Err(Error::MissingSigil);
    }

    let delimiter_index = match id.find(':') {
        Some(index) => index,
        None => return Err(Error::MissingDelimiter),
    };

    let localpart = &id[1..delimiter_index];
    let raw_host = &id[delimiter_index + SIGIL_BYTES..];
    let url_string = format!("https://{}", raw_host);
    let url = Url::parse(&url_string)?;

    let host = match url.host() {
        Some(host) => host.to_owned(),
        None => return Err(Error::InvalidHost),
    };

    let port = url.port().unwrap_or(443);

    Ok((localpart, host, port))
}
<|endoftext|>