<commit_before>use std::ascii::OwnedAsciiExt;
use std::collections::HashMap;
use std::io::File;

use command::command::{
    Attribute,
    Envelope,
    Flags,
    InternalDate,
    RFC822,
    Body,
    BodyPeek,
    BodyStructure,
    UID
};
use command::command::{
    AllRFC822,
    HeaderRFC822,
    SizeRFC822,
    TextRFC822
};
use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    size: uint,
    raw_contents: String,
    raw_header: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();
        let size = raw_contents.as_slice().len();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let path_flags = path.next();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let flags = match path_flags {
            None => Vec::new(),
            Some(flags) => {
                let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
                let mut vec_flags: Vec<Flag> = Vec::new();
                for flag in unparsed_flags.chars() {
                    let parsed_flag = match flag {
                        'D' => Some(Draft),
                        'F' => Some(Flagged),
                        'R' => Some(Answered),
                        'S' => Some(Seen),
                        _ => None
                    };
                    match parsed_flag {
                        Some(enum_flag) => vec_flags.push(enum_flag),
                        None => { }
                    }
                }
                vec_flags
            }
        };

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].to_string().into_ascii_upper().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"RECEIVED".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["CONTENT-TYPE".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            size: size,
            raw_contents: raw_contents.clone(),
            raw_header: raw_header.to_string()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }

    pub fn fetch(&self, attributes: &Vec<Attribute>) -> String {
        let mut res = String::new();
        for attr in attributes.iter() {
            let attr_str = match attr {
                &Envelope => { format!("ENVELOPE {}", self.get_envelope()) },
                &Flags => { "".to_string() },
                &InternalDate => { "".to_string() },
                &RFC822(ref attr) => {
                    let rfc_attr = match attr {
                        &AllRFC822 => { "".to_string() },
                        &HeaderRFC822 => { format!(".HEADER {{{}}}\n{}", self.raw_header.len(), self.raw_header) },
                        &SizeRFC822 => { format!(".SIZE {}", self.size) },
                        &TextRFC822 => { "".to_string() }
                    };
                    format!("RFC822{}", rfc_attr)
                },
                &Body(ref section, ref octets) => { "".to_string() },
                &BodyPeek(ref section, ref octets) => { "".to_string() },
                &BodyStructure => { "".to_string() },
                &UID => { "".to_string() }
            };
            res = format!("{} {}", res, attr_str);
        }
        res
    }

    /**
     * RFC3501 - 7.4.2 - P.76-77
     *
     * Returns a parenthesized list that described the envelope structure of a
     * message.
     * Computed by parsing the [RFC-2822] header into the component parts,
     * defaulting various fields as necessary.
     *
     * Requires (in the following order): date, subject, from, sender, reply-to,
     * to, cc, bcc, in-reply-to, and message-id.
     * The date, subject, in-reply-to, and message-id fields are strings.
     * The from, sender, reply-to, to, cc, and bcc fields are parenthesized
     * lists of address structures.
     */
    fn get_envelope(&self) -> String {
        let date = self.get_quoted_field_or_nil("DATE".to_string());
        let subject = self.get_quoted_field_or_nil("SUBJECT".to_string());
        let from = self.get_parenthesized_addresses("FROM".to_string());
        let sender = self.get_parenthesized_addresses("SENDER".to_string());
        let reply_to = self.get_parenthesized_addresses("REPLY-TO".to_string());
        let to = self.get_parenthesized_addresses("TO".to_string());
        let cc = self.get_parenthesized_addresses("CC".to_string());
        let bcc = self.get_parenthesized_addresses("BCC".to_string());
        let in_reply_to = self.get_quoted_field_or_nil("IN-REPLY-TO".to_string());
        let message_id = self.get_quoted_field_or_nil("MESSAGE-ID".to_string());

        format!(
            "({} {} {} {} {} {} {} {} {} {})",
            date,
            subject,
            from,
            sender,
            reply_to,
            to,
            cc,
            bcc,
            in_reply_to,
            message_id)
    }

    fn get_quoted_field_or_nil(&self, key: String) -> String {
        match self.headers.find(&key) {
            Some(v) => format!("\"{}\"", v),
            None => "NIL".to_string()
        }
    }

    fn get_parenthesized_addresses(&self, key: String) -> String {
        let addresses = match self.headers.find(&key) {
            Some(v) => v,
            None => return "NIL".to_string()
        };

        "NIL".to_string()
    }
}
<commit_msg>Suspend work on FETCH ENVELOPE<commit_after>use std::ascii::OwnedAsciiExt;
use std::collections::HashMap;
use std::io::File;

use command::command::{
    Attribute,
    Envelope,
    Flags,
    InternalDate,
    RFC822,
    Body,
    BodyPeek,
    BodyStructure,
    UID
};
use command::command::{
    AllRFC822,
    HeaderRFC822,
    SizeRFC822,
    TextRFC822
};
use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    size: uint,
    raw_contents: String,
    raw_header: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();
        let size = raw_contents.as_slice().len();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let path_flags = path.next();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let flags = match path_flags {
            None => Vec::new(),
            Some(flags) => {
                let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
                let mut vec_flags: Vec<Flag> = Vec::new();
                for flag in unparsed_flags.chars() {
                    let parsed_flag = match flag {
                        'D' => Some(Draft),
                        'F' => Some(Flagged),
                        'R' => Some(Answered),
                        'S' => Some(Seen),
                        _ => None
                    };
                    match parsed_flag {
                        Some(enum_flag) => vec_flags.push(enum_flag),
                        None => { }
                    }
                }
                vec_flags
            }
        };

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].to_string().into_ascii_upper().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"RECEIVED".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["CONTENT-TYPE".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            size: size,
            raw_contents: raw_contents.clone(),
            raw_header: raw_header.to_string()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }

    pub fn fetch(&self, attributes: &Vec<Attribute>) -> String {
        let mut res = String::new();
        for attr in attributes.iter() {
            let attr_str = match attr {
                &Envelope => { format!("ENVELOPE {}", self.get_envelope()) }, // TODO: Finish implementing this.
                &Flags => { "".to_string() },
                &InternalDate => { "".to_string() },
                &RFC822(ref attr) => {
                    let rfc_attr = match attr {
                        &AllRFC822 => { "".to_string() },
                        &HeaderRFC822 => { format!(".HEADER {{{}}}\n{}", self.raw_header.len(), self.raw_header) },
                        &SizeRFC822 => { format!(".SIZE {}", self.size) },
                        &TextRFC822 => { "".to_string() }
                    };
                    format!("RFC822{}", rfc_attr)
                },
                &Body(ref section, ref octets) => { "".to_string() },
                &BodyPeek(ref section, ref octets) => { "".to_string() },
                &BodyStructure => { "".to_string() },
                &UID => { "".to_string() }
            };
            res = format!("{} {}", res, attr_str);
        }
        res
    }

    /**
     * RFC3501 - 7.4.2 - P.76-77
     *
     * Returns a parenthesized list that described the envelope structure of a
     * message.
     * Computed by parsing the [RFC-2822] header into the component parts,
     * defaulting various fields as necessary.
     *
     * Requires (in the following order): date, subject, from, sender, reply-to,
     * to, cc, bcc, in-reply-to, and message-id.
     * The date, subject, in-reply-to, and message-id fields are strings.
     * The from, sender, reply-to, to, cc, and bcc fields are parenthesized
     * lists of address structures.
     */
    // TODO: Finish implementing this.
    fn get_envelope(&self) -> String {
        let date = self.get_quoted_field_or_nil("DATE".to_string());
        let subject = self.get_quoted_field_or_nil("SUBJECT".to_string());
        let from = self.get_parenthesized_addresses("FROM".to_string());
        let sender = self.get_parenthesized_addresses("SENDER".to_string());
        let reply_to = self.get_parenthesized_addresses("REPLY-TO".to_string());
        let to = self.get_parenthesized_addresses("TO".to_string());
        let cc = self.get_parenthesized_addresses("CC".to_string());
        let bcc = self.get_parenthesized_addresses("BCC".to_string());
        let in_reply_to = self.get_quoted_field_or_nil("IN-REPLY-TO".to_string());
        let message_id = self.get_quoted_field_or_nil("MESSAGE-ID".to_string());

        format!(
            "({} {} {} {} {} {} {} {} {} {})",
            date,
            subject,
            from,
            sender,
            reply_to,
            to,
            cc,
            bcc,
            in_reply_to,
            message_id)
    }

    fn get_quoted_field_or_nil(&self, key: String) -> String {
        match self.headers.find(&key) {
            Some(v) => format!("\"{}\"", v),
            None => "NIL".to_string()
        }
    }

    /**
     * RFC3501 - 7.4.2 - P.76
     */
    // TODO: Finish implementing this.
    fn get_parenthesized_addresses(&self, key: String) -> String {
        let addresses = match self.headers.find(&key) {
            Some(v) => v, // TODO: this is not parenthesized.
            None => return "NIL".to_string()
        };

        addresses.clone()
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::fmt;
use common::escape_string;

/// Represents a comment concerning the location/translation of a message
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Comment {
    /// File and line
    Source(String, usize)
}

/// Represents a message, with a string and a list of comments
/// corresponding to position in source file
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Message {
    pub comments: Vec<Comment>,
    pub msg: String,
}

impl Message {
    /// Creates a new message
    pub fn new<S:Into<String>>(msg: S) -> Message {
        Message {
            msg: msg.into(),
            comments: vec!(),
        }
    }

    /// Add a source location to a comment
    pub fn add_source<S:Into<String>>(&mut self, file: S, line: usize) -> &mut Self {
        self.comments.push(Comment::Source(file.into(), line));
        self
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "#:"));
        for comment in &self.comments {
            match *comment {
                Comment::Source(ref file, line) => try!(write!(f, " {}:{}", file, line)),
            }
        }
        writeln!(f, "
msgid \"{}\"
msgstr \"\"\n",
                 escape_string(self.msg.as_str()))
    }
}
<commit_msg>Use ? instead of try! in message.rs<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::fmt;
use common::escape_string;

/// Represents a comment concerning the location/translation of a message
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Comment {
    /// File and line
    Source(String, usize)
}

/// Represents a message, with a string and a list of comments
/// corresponding to position in source file
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Message {
    pub comments: Vec<Comment>,
    pub msg: String,
}

impl Message {
    /// Creates a new message
    pub fn new<S:Into<String>>(msg: S) -> Message {
        Message {
            msg: msg.into(),
            comments: vec!(),
        }
    }

    /// Add a source location to a comment
    pub fn add_source<S:Into<String>>(&mut self, file: S, line: usize) -> &mut Self {
        self.comments.push(Comment::Source(file.into(), line));
        self
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "#:")?;
        for comment in &self.comments {
            match *comment {
                Comment::Source(ref file, line) => write!(f, " {}:{}", file, line)?,
            }
        }
        writeln!(f, "
msgid \"{}\"
msgstr \"\"\n",
                 escape_string(self.msg.as_str()))
    }
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        Self { cipher: aes::AES::new(key) }
    }

    pub fn auth_encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let counter = self.get_counter(nonce);
        let ciphertext = self.counter_mode(&message, &counter);
        let tag = self.tag(&ciphertext, data, &counter);
        (ciphertext, tag)
    }

    pub fn auth_decrypt(
        &self,
        ciphertext: &[u8],
        tag: &[u8],
        data: &[u8],
        nonce: &[u8],
    ) -> Result<Vec<u8>, ()> {
        assert_eq!(16, tag.len());
        let counter = self.get_counter(nonce);
        let expected_tag = self.tag(ciphertext, data, &counter);
        self.check_tag(&expected_tag, tag)?;
        let message = self.counter_mode(&ciphertext, &counter);
        Ok(message)
    }

    fn get_counter(&self, nonce: &[u8]) -> [u8; 16] {
        if nonce.len() == 12 {
            let mut counter = [0; 16];
            counter[..12].copy_from_slice(nonce);
            counter[15] = 1;
            counter
        } else {
            self.ghash(&[], nonce)
        }
    }

    fn counter_mode(&self, input: &[u8], counter: &[u8; 16]) -> Vec<u8> {
        let mut output = vec![];
        let x0 = (&counter[..12], BigEndian::read_u32(&counter[12..]));
        for (i, mi) in (1..).zip(input.chunks(16)) {
            let xi = Self::incr(x0, i);
            output.extend(mi.iter().zip(&self.cipher.cipher(&xi)).map(|(x, y)| x ^ y));
        }
        output.truncate(input.len());
        output
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], counter: &[u8; 16]) -> [u8; 16] {
        let mut tag = self.ghash(data, ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(counter)) {
            *t ^= x;
        }
        tag
    }

    /// This is meant to check the tag without early returns, but the compiler ruins it
    fn check_tag(&self, expected: &[u8], tag: &[u8]) -> Result<(), ()> {
        let diff = expected.iter().zip(tag).fold(0, |acc, (x, y)| acc | x ^ y);
        if diff == 0 { Ok(()) } else { Err(()) }
    }

    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }

    fn ghash(&self, a: &[u8], c: &[u8]) -> [u8; 16] {
        ghash::ghash(&self.cipher.cipher(&[0; 16]), a, c)
    }
}

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

    fn check(k: &[u8], m: &Vec<u8>, a: &[u8], n: &[u8], c: &Vec<u8>, t: &[u8]) {
        let gcm = GCM::new(&k);
        let actual = gcm.auth_encrypt(&m, &a, &n);
        assert_eq!(c, &actual.0);
        assert_eq!(t, actual.1);
        assert_eq!(m, &gcm.auth_decrypt(&c, &t, &a, &n).unwrap());
    }

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        check(&key, &vec![], &[], &nonce, &vec![], &tag);

        let message = vec![0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);
    }
}
<commit_msg>gcm: small api changes<commit_after>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        Self { cipher: aes::AES::new(key) }
    }

    pub fn encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let counter = self.get_counter(nonce);
        let ciphertext = self.counter_mode(&message, &counter);
        let tag = self.tag(&ciphertext, data, &counter);
        (ciphertext, tag)
    }

    pub fn decrypt(
        &self,
        ciphertext: &[u8],
        data: &[u8],
        tag: &[u8],
        nonce: &[u8],
    ) -> Result<Vec<u8>, ()> {
        assert_eq!(16, tag.len());
        let counter = self.get_counter(nonce);
        let expected_tag = self.tag(ciphertext, data, &counter);
        self.check_tag(&expected_tag, tag)?;
        let message = self.counter_mode(&ciphertext, &counter);
        Ok(message)
    }

    fn get_counter(&self, nonce: &[u8]) -> [u8; 16] {
        if nonce.len() == 12 {
            let mut counter = [0; 16];
            counter[..12].copy_from_slice(nonce);
            counter[15] = 1;
            counter
        } else {
            self.ghash(&[], nonce)
        }
    }

    fn counter_mode(&self, input: &[u8], counter: &[u8; 16]) -> Vec<u8> {
        let mut output = vec![];
        let x0 = (&counter[..12], BigEndian::read_u32(&counter[12..]));
        for (i, mi) in (1..).zip(input.chunks(16)) {
            let xi = Self::incr(x0, i);
            output.extend(mi.iter().zip(&self.cipher.cipher(&xi)).map(|(x, y)| x ^ y));
        }
        output.truncate(input.len());
        output
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], counter: &[u8; 16]) -> [u8; 16] {
        let mut tag = self.ghash(data, ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(counter)) {
            *t ^= x;
        }
        tag
    }

    /// This is meant to check the tag without early returns, but the compiler ruins it
    fn check_tag(&self, expected: &[u8], tag: &[u8]) -> Result<(), ()> {
        let diff = expected.iter().zip(tag).fold(0, |acc, (x, y)| acc | x ^ y);
        if diff == 0 { Ok(()) } else { Err(()) }
    }

    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }

    fn ghash(&self, a: &[u8], c: &[u8]) -> [u8; 16] {
        ghash::ghash(&self.cipher.cipher(&[0; 16]), a, c)
    }
}

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

    fn check(k: &[u8], m: &Vec<u8>, a: &[u8], n: &[u8], c: &Vec<u8>, t: &[u8]) {
        let gcm = GCM::new(&k);
        let actual = gcm.encrypt(&m, &a, &n);
        assert_eq!(c, &actual.0);
        assert_eq!(t, actual.1);
        assert_eq!(m, &gcm.decrypt(&c, &a, &t, &n).unwrap());
    }

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        check(&key, &vec![], &[], &nonce, &vec![], &tag);

        let message = vec![0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);
    }
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate gip;
#[macro_use]
extern crate structopt;

use gip::{Provider, ProviderAny, ProviderType};
use std::env::home_dir;
use std::fs::File;
use std::io::Read;
use structopt::StructOpt;

// -------------------------------------------------------------------------------------------------
// Usage
// -------------------------------------------------------------------------------------------------

#[derive(Debug, StructOpt)]
#[structopt(name = "gip")]
#[structopt(raw(long_version = "option_env!(\"LONG_VERSION\").unwrap_or(env!(\"CARGO_PKG_VERSION\"))"))]
#[structopt(raw(setting = "clap::AppSettings::ColoredHelp"))]
#[structopt(raw(setting = "clap::AppSettings::DeriveDisplayOrder"))]
pub struct Opt {
    /// IPv4 address ( default )
    #[structopt(short = "4", long = "v4", conflicts_with = "v6")]
    pub v4: bool,

    /// IPv6 address
    #[structopt(short = "6", long = "v6", conflicts_with = "v4")]
    pub v6: bool,

    /// Show by plane text ( default )
    #[structopt(short = "p", long = "plane")]
    pub show_plane: bool,

    /// Show by plane text without line break
    #[structopt(short = "s", long = "string")]
    pub show_string: bool,

    /// Show by JSON
    #[structopt(short = "j", long = "json")]
    pub show_json: bool,

    /// Timeout per each provider by milliseconds
    #[structopt(long = "timeout", default_value = "1000")]
    pub timeout: usize,

    /// Key string of JSON format
    #[structopt(long = "json-key", default_value = "ip")]
    pub json_key: String,

    /// Proxy for HTTP access ( "host:port" )
    #[structopt(long = "proxy")]
    pub proxy: Option<String>,

    /// Show provider list
    #[structopt(short = "l", long = "list")]
    pub show_list: bool,

    /// Show verbose message
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

// -------------------------------------------------------------------------------------------------
// Error
// -------------------------------------------------------------------------------------------------

error_chain! {
    links {
        Gip(::gip::Error, ::gip::ErrorKind);
    }
    foreign_links {
        Io(::std::io::Error);
        ParseInt(::std::num::ParseIntError);
    }
}

// -------------------------------------------------------------------------------------------------
// Main
// -------------------------------------------------------------------------------------------------

quick_main!(run);

pub fn run() -> Result<()> {
    let opt = Opt::from_args();
    run_opt(&opt)
}

pub fn run_opt(opt: &Opt) -> Result<()> {
    let giprc = match home_dir() {
        Some(mut p) => {
            p.push(".gip.toml");
            if p.exists() {
                Some(p)
            } else {
                None
            }
        }
        None => None,
    };

    let mut client = match giprc {
        Some(p) => {
            let mut f =
                File::open(&p).chain_err(|| format!("failed to open {}", p.to_string_lossy()))?;
            let mut s = String::new();
            let _ = f.read_to_string(&mut s);
            ProviderAny::from_toml(&s)?
        }
        None => ProviderAny::from_toml(&gip::DEFAULT_TOML)?,
    };

    if opt.v6 {
        client.ptype = ProviderType::IPv6;
    }

    if opt.show_list {
        for p in &client.providers {
            println!("{:?}: {}", p.get_type(), p.get_name());
        }
        return Ok(());
    }

    client.set_timeout(opt.timeout);

    if opt.proxy.is_some() {
        let proxy_str = opt.proxy.clone().unwrap();
        let (host, port) = proxy_str.split_at(proxy_str.find(':').unwrap_or(0));
        let port = port.trim_matches(':')
            .parse::<u16>()
            .chain_err(|| format!("failed to parse proxy: {}", proxy_str))?;
        client.set_proxy(host, port);
    }

    let addr = client.get_addr()?;
    let addr_str = if opt.v6 {
        format!("{:?}", addr.v6addr.unwrap())
    } else {
        format!("{:?}", addr.v4addr.unwrap())
    };

    if opt.verbose {
        println!("IP Address: {}", addr_str);
        println!("Provider  : {}", addr.provider);
        println!("Check Time: {}", addr.time.rfc822());
    } else {
        if opt.show_string {
            print!("{}", addr_str);
        } else if opt.show_json {
            println!("{{\"{}\": \"{}\"}}", opt.json_key, addr_str);
        } else {
            println!("{}", addr_str);
        }
    }

    return Ok(());
}

// -------------------------------------------------------------------------------------------------
// Test
// -------------------------------------------------------------------------------------------------

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

    #[test]
    fn test_run() {
        let args = vec!["gip"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_verbose() {
        let args = vec!["gip", "-V"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_string() {
        let args = vec!["gip", "-s"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_json() {
        let args = vec!["gip", "-j"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_list() {
        let args = vec!["gip", "-l"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }
}
<commit_msg>Add option conflict<commit_after>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate gip;
#[macro_use]
extern crate structopt;

use gip::{Provider, ProviderAny, ProviderType};
use std::env::home_dir;
use std::fs::File;
use std::io::Read;
use structopt::StructOpt;

// -------------------------------------------------------------------------------------------------
// Usage
// -------------------------------------------------------------------------------------------------

#[derive(Debug, StructOpt)]
#[structopt(name = "gip")]
#[structopt(raw(long_version = "option_env!(\"LONG_VERSION\").unwrap_or(env!(\"CARGO_PKG_VERSION\"))"))]
#[structopt(raw(setting = "clap::AppSettings::ColoredHelp"))]
#[structopt(raw(setting = "clap::AppSettings::DeriveDisplayOrder"))]
pub struct Opt {
    /// IPv4 address ( default )
    #[structopt(short = "4", long = "v4", conflicts_with = "v6")]
    pub v4: bool,

    /// IPv6 address
    #[structopt(short = "6", long = "v6", conflicts_with = "v4")]
    pub v6: bool,

    /// Show by plane text ( default )
    #[structopt(short = "p", long = "plane", conflicts_with = "string", conflicts_with = "json")]
    pub show_plane: bool,

    /// Show by plane text without line break
    #[structopt(short = "s", long = "string", conflicts_with = "plane", conflicts_with = "json")]
    pub show_string: bool,

    /// Show by JSON
    #[structopt(short = "j", long = "json", conflicts_with = "plane", conflicts_with = "string")]
    pub show_json: bool,

    /// Timeout per each provider by milliseconds
    #[structopt(long = "timeout", default_value = "1000")]
    pub timeout: usize,

    /// Key string of JSON format
    #[structopt(long = "json-key", default_value = "ip")]
    pub json_key: String,

    /// Proxy for HTTP access ( "host:port" )
    #[structopt(long = "proxy")]
    pub proxy: Option<String>,

    /// Show provider list
    #[structopt(short = "l", long = "list")]
    pub show_list: bool,

    /// Show verbose message
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

// -------------------------------------------------------------------------------------------------
// Error
// -------------------------------------------------------------------------------------------------

error_chain! {
    links {
        Gip(::gip::Error, ::gip::ErrorKind);
    }
    foreign_links {
        Io(::std::io::Error);
        ParseInt(::std::num::ParseIntError);
    }
}

// -------------------------------------------------------------------------------------------------
// Main
// -------------------------------------------------------------------------------------------------

quick_main!(run);

pub fn run() -> Result<()> {
    let opt = Opt::from_args();
    run_opt(&opt)
}

pub fn run_opt(opt: &Opt) -> Result<()> {
    let giprc = match home_dir() {
        Some(mut p) => {
            p.push(".gip.toml");
            if p.exists() {
                Some(p)
            } else {
                None
            }
        }
        None => None,
    };

    let mut client = match giprc {
        Some(p) => {
            let mut f =
                File::open(&p).chain_err(|| format!("failed to open {}", p.to_string_lossy()))?;
            let mut s = String::new();
            let _ = f.read_to_string(&mut s);
            ProviderAny::from_toml(&s)?
        }
        None => ProviderAny::from_toml(&gip::DEFAULT_TOML)?,
    };

    if opt.v6 {
        client.ptype = ProviderType::IPv6;
    }

    if opt.show_list {
        for p in &client.providers {
            println!("{:?}: {}", p.get_type(), p.get_name());
        }
        return Ok(());
    }

    client.set_timeout(opt.timeout);

    if opt.proxy.is_some() {
        let proxy_str = opt.proxy.clone().unwrap();
        let (host, port) = proxy_str.split_at(proxy_str.find(':').unwrap_or(0));
        let port = port.trim_matches(':')
            .parse::<u16>()
            .chain_err(|| format!("failed to parse proxy: {}", proxy_str))?;
        client.set_proxy(host, port);
    }

    let addr = client.get_addr()?;
    let addr_str = if opt.v6 {
        format!("{:?}", addr.v6addr.unwrap())
    } else {
        format!("{:?}", addr.v4addr.unwrap())
    };

    if opt.verbose {
        println!("IP Address: {}", addr_str);
        println!("Provider  : {}", addr.provider);
        println!("Check Time: {}", addr.time.rfc822());
    } else {
        if opt.show_string {
            print!("{}", addr_str);
        } else if opt.show_json {
            println!("{{\"{}\": \"{}\"}}", opt.json_key, addr_str);
        } else {
            println!("{}", addr_str);
        }
    }

    return Ok(());
}

// -------------------------------------------------------------------------------------------------
// Test
// -------------------------------------------------------------------------------------------------

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

    #[test]
    fn test_run() {
        let args = vec!["gip"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_verbose() {
        let args = vec!["gip", "-V"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_string() {
        let args = vec!["gip", "-s"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_json() {
        let args = vec!["gip", "-j"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_list() {
        let args = vec!["gip", "-l"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }
}
<|endoftext|>


<commit_before>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc::{c_uint, if_nametoindex};
use std::ffi::{CString, NulError};
use std::io;

/// Error that can occur during interface name resolution.
#[derive(Debug)]
pub enum NameToIndexError {
    /// Failed to allocate a C-style string to for the syscall
    NulError,
    IOError(io::Error),
}

impl From<NulError> for NameToIndexError {
    fn from(_: NulError) -> NameToIndexError {
        NameToIndexError::NulError
    }
}

impl From<io::Error> for NameToIndexError {
    fn from(e: io::Error) -> NameToIndexError {
        NameToIndexError::IOError(e)
    }
}

/// Resolve an interface into a interface number.
pub fn name_to_index(name: &str) -> Result<c_uint, NameToIndexError> {
    let name = try!(CString::new(name));

    let if_index;
    unsafe {
        if_index = if_nametoindex(name.as_ptr());
    }

    if if_index == 0 {
        return Err(NameToIndexError::from(io::Error::last_os_error()));
    }

    Ok(if_index)
}
<commit_msg>Changed Error type to nix::Error.<commit_after>//! Network interface name resolution.
//!
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.

use libc::{c_uint, if_nametoindex};
use std::ffi::{CString, NulError};
use ::Error;

/// Resolve an interface into a interface number.
pub fn name_to_index(name: &str) -> Result<c_uint, Error> {
    let name = match CString::new(name) {
        Err(e) => match e { NulError(..) => {
            // A NulError indicates that a '\0' was found inside the string,
            // making it impossible to create valid C-String. To avoid having
            // to create a new error type for this rather rare case,
            // nix::Error's invalid_argument() constructor is used.
            //
            // We match the NulError individually here to ensure to avoid
            // accidentally returning invalid_argument() for errors other than
            // NulError (which currently don't exist).
            return Err(Error::invalid_argument());
        }},
        Ok(s) => s
    };

    let if_index;
    unsafe {
        if_index = if_nametoindex(name.as_ptr());
    }

    if if_index == 0 { Err(Error::last()) } else { Ok(if_index) }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fmt;
use std::iter::FromIterator;
use std::result;
use std::str;
use std::str::FromStr;

use headers_place::HeadersPlace;
use req_resp::RequestOrResponse;

use error::Error;
use result::Result;

use assert_types::*;

use bytes::Bytes;

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum PseudoHeaderName {
    // 8.1.2.3 Request Pseudo-Header Fields
    Method,
    Scheme,
    Authority,
    Path,

    // 8.1.2.4 Response Pseudo-Header Fields
    Status,
}

impl PseudoHeaderName {
    pub fn name(&self) -> &'static str {
        match *self {
            PseudoHeaderName::Method => ":method",
            PseudoHeaderName::Scheme => ":scheme",
            PseudoHeaderName::Authority => ":authority",
            PseudoHeaderName::Path => ":path",
            PseudoHeaderName::Status => ":status",
        }
    }

    pub fn parse(value: &[u8]) -> Result<PseudoHeaderName> {
        match value {
            b":method" => Ok(PseudoHeaderName::Method),
            b":scheme" => Ok(PseudoHeaderName::Scheme),
            b":authority" => Ok(PseudoHeaderName::Authority),
            b":path" => Ok(PseudoHeaderName::Path),
            b":status" => Ok(PseudoHeaderName::Status),
            _ => Err(Error::Other("invalid pseudo header")),
        }
    }

    pub fn req_or_resp(&self) -> RequestOrResponse {
        match *self {
            PseudoHeaderName::Method => RequestOrResponse::Request,
            PseudoHeaderName::Scheme => RequestOrResponse::Request,
            PseudoHeaderName::Authority => RequestOrResponse::Request,
            PseudoHeaderName::Path => RequestOrResponse::Request,
            PseudoHeaderName::Status => RequestOrResponse::Response,
        }
    }

    pub fn name_bytes(&self) -> Bytes {
        Bytes::from_static(self.name().as_bytes())
    }

    pub fn names(request_or_response: RequestOrResponse) -> &'static [PseudoHeaderName] {
        static REQUEST_HEADERS: &[PseudoHeaderName] = &[
            PseudoHeaderName::Method,
            PseudoHeaderName::Scheme,
            PseudoHeaderName::Authority,
            PseudoHeaderName::Path,
        ];
        static RESPONSE_HEADERS: &[PseudoHeaderName] = &[PseudoHeaderName::Status];
        match request_or_response {
            RequestOrResponse::Request => REQUEST_HEADERS,
            RequestOrResponse::Response => RESPONSE_HEADERS,
        }
    }

    pub fn all_names() -> &'static [PseudoHeaderName] {
        static ALL_HEADERS: &[PseudoHeaderName] = &[
            PseudoHeaderName::Method,
            PseudoHeaderName::Scheme,
            PseudoHeaderName::Authority,
            PseudoHeaderName::Path,
            PseudoHeaderName::Status,
        ];
        ALL_HEADERS
    }
}

#[allow(dead_code)]
pub struct HeaderName(Bytes);

impl<'a> From<&'a str> for HeaderName {
    fn from(_name: &'a str) -> HeaderName {
        unimplemented!()
    }
}

/// A convenience struct representing a part of a header (either the name or the value).
pub struct HeaderPart(Bytes);

impl fmt::Debug for HeaderPart {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<Vec<u8>> for HeaderPart {
    fn from(vec: Vec<u8>) -> HeaderPart {
        HeaderPart(Bytes::from(vec))
    }
}

impl From<Bytes> for HeaderPart {
    fn from(bytes: Bytes) -> HeaderPart {
        HeaderPart(bytes)
    }
}

impl<'a> From<&'a [u8]> for HeaderPart {
    fn from(buf: &'a [u8]) -> HeaderPart {
        HeaderPart(Bytes::from(buf))
    }
}

macro_rules! from_static_size_array {
    ($N:expr) => {
        impl<'a> From<&'a [u8; $N]> for HeaderPart {
            fn from(buf: &'a [u8; $N]) -> HeaderPart {
                buf[..].into()
            }
        }
    };
}

macro_rules! impl_from_static_size_array {
    ($($N:expr,)+) => {
        $(
            from_static_size_array!($N);
        )+
    }
}

impl_from_static_size_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
);

impl From<String> for HeaderPart {
    fn from(s: String) -> HeaderPart {
        From::from(s.into_bytes())
    }
}

impl<'a> From<&'a str> for HeaderPart {
    fn from(s: &'a str) -> HeaderPart {
        From::from(s.as_bytes())
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Header {
    pub name: Bytes,
    pub value: Bytes,
}

fn _assert_header_sync_send() {
    assert_sync::<Header>();
    assert_send::<Header>();
}

#[derive(Debug)]
pub enum HeaderError {
    UnknownPseudoHeader,
    EmptyName,
    EmptyValue(PseudoHeaderName),
    IncorrectCharInName,
    UnexpectedPseudoHeader(PseudoHeaderName),
    PseudoHeadersInTrailers,
    PseudoHeadersAfterRegularHeaders,
    MoreThanOnePseudoHeader(PseudoHeaderName),
    MissingPseudoHeader(PseudoHeaderName),
    ConnectionSpecificHeader(&'static str),
    TeCanOnlyContainTrailer,
}

pub type HeaderResult<T> = result::Result<T, HeaderError>;

impl Header {
    /// Creates a new `Header` with the given name and value.
    ///
    /// The name and value need to be convertible into a `HeaderPart`.
    pub fn new<N: Into<HeaderPart>, V: Into<HeaderPart>>(name: N, value: V) -> Header {
        Header {
            name: name.into().0,
            value: value.into().0,
        }
    }

    /// Return a borrowed representation of the `Header` name.
    pub fn name(&self) -> &[u8] {
        &self.name
    }
    /// Return a borrowed representation of the `Header` value.
    pub fn value(&self) -> &[u8] {
        &self.value
    }

    /// name: value
    pub fn format(&self) -> String {
        format!(
            "{}: {}",
            String::from_utf8_lossy(&self.name),
            String::from_utf8_lossy(&self.value)
        )
    }

    pub fn is_preudo_header(&self) -> bool {
        self.name.len() != 0 && self.name[0] == b':'
    }

    pub fn pseudo_header_name(&self) -> HeaderResult<Option<PseudoHeaderName>> {
        if self.is_preudo_header() {
            for &h in PseudoHeaderName::all_names() {
                if self.name.as_ref() == h.name().as_bytes() {
                    return Ok(Some(h));
                }
            }
            Err(HeaderError::UnknownPseudoHeader)
        } else {
            Ok(None)
        }
    }

    fn validate_header_name_char(b: u8) -> HeaderResult<()> {
        // TODO: restrict more
        if b >= b'A' && b <= b'Z' {
            return Err(HeaderError::IncorrectCharInName);
        }
        Ok(())
    }

    pub fn validate(&self, req_or_resp: RequestOrResponse) -> HeaderResult<()> {
        if self.name.len() == 0 {
            return Err(HeaderError::EmptyName);
        }

        if let Some(h) = self.pseudo_header_name()? {
            if h.req_or_resp() != req_or_resp {
                return Err(HeaderError::UnexpectedPseudoHeader(h));
            }
        }

        for c in &self.name {
            Header::validate_header_name_char(c)?;
        }

        // HTTP/2 does not use the Connection header field to indicate
        // connection-specific header fields; in this protocol, connection-
        // specific metadata is conveyed by other means.  An endpoint MUST NOT
        // generate an HTTP/2 message containing connection-specific header
        // fields; any message containing connection-specific header fields MUST
        // be treated as malformed (Section 8.1.2.6).
        let connection_specific_headers = [
            "connection",
            "keep-alive",
            "proxy-connection",
            "transfer-encoding",
            "upgrade",
        ];
        for s in &connection_specific_headers {
            if self.name == s.as_bytes() {
                return Err(HeaderError::ConnectionSpecificHeader(s));
            }
        }

        if self.name.as_ref() == b"te" {
            // The only exception to this is the TE header field, which MAY be
            // present in an HTTP/2 request; when it is, it MUST NOT contain any
            // value other than "trailers".
            if self.value.as_ref() != b"trailers" {
                return Err(HeaderError::TeCanOnlyContainTrailer);
            }
        }

        Ok(())
    }
}

impl<N: Into<HeaderPart>, V: Into<HeaderPart>> From<(N, V)> for Header {
    fn from(p: (N, V)) -> Header {
        Header::new(p.0, p.1)
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct Headers(pub Vec<Header>);

impl Headers {
    pub fn new() -> Headers {
        Default::default()
    }

    /// Multiline string
    pub fn dump(&self) -> String {
        let mut r = String::new();
        for h in &self.0 {
            r.push_str(&h.format());
            r.push_str("\n");
        }
        r
    }

    pub fn new_get(path: &str) -> Headers {
        Headers(vec![
            Header::new(":method", "GET"),
            Header::new(":path", path),
        ])
    }

    pub fn new_post(path: &str) -> Headers {
        Headers(vec![
            Header::new(":method", "POST"),
            Header::new(":path", path),
        ])
    }

    pub fn from_status(code: u32) -> Headers {
        Headers(vec![Header::new(":status", format!("{}", code))])
    }

    pub fn ok_200() -> Headers {
        Headers::from_status(200)
    }

    pub fn not_found_404() -> Headers {
        Headers::from_status(404)
    }

    pub fn internal_error_500() -> Headers {
        Headers::from_status(500)
    }

    pub fn contains_preudo_headers(&self) -> bool {
        self.0.iter().any(|h| h.is_preudo_header())
    }

    pub fn validate(
        &self,
        req_or_resp: RequestOrResponse,
        headers_place: HeadersPlace,
    ) -> HeaderResult<()> {
        let mut saw_regular_header = false;

        // TODO: array is enough
        let mut pseudo_headers_met = HashSet::new();

        for header in &self.0 {
            header.validate(req_or_resp)?;

            // 8.1.2.1.  Pseudo-Header Fields
            // All pseudo-header fields MUST appear in the header block before
            // regular header fields.  Any request or response that contains a
            // pseudo-header field that appears in a header block after a regular
            // header field MUST be treated as malformed (Section 8.1.2.6).
            if let Some(header_name) = header.pseudo_header_name()? {
                if headers_place == HeadersPlace::Trailing {
                    return Err(HeaderError::PseudoHeadersInTrailers);
                }

                if saw_regular_header {
                    return Err(HeaderError::PseudoHeadersAfterRegularHeaders);
                }

                if !pseudo_headers_met.insert(header_name) {
                    return Err(HeaderError::MoreThanOnePseudoHeader(header_name));
                }

                if header_name == PseudoHeaderName::Path {
                    if header.value.is_empty() {
                        return Err(HeaderError::EmptyValue(header_name));
                    }
                }
            } else {
                saw_regular_header = true;
            }
        }

        if headers_place == HeadersPlace::Initial {
            match req_or_resp {
                // All HTTP/2 requests MUST include exactly one valid value for the
                // ":method", ":scheme", and ":path" pseudo-header fields, unless it is
                // a CONNECT request (Section 8.3).  An HTTP request that omits
                // mandatory pseudo-header fields is malformed (Section 8.1.2.6).
                RequestOrResponse::Request => {
                    let required_headers = [
                        PseudoHeaderName::Method,
                        PseudoHeaderName::Scheme,
                        PseudoHeaderName::Path,
                    ];
                    for required in &required_headers {
                        if pseudo_headers_met.get(required).is_none() {
                            return Err(HeaderError::MissingPseudoHeader(*required));
                        }
                    }
                }
                // For HTTP/2 responses, a single ":status" pseudo-header field is
                // defined that carries the HTTP status code field (see [RFC7231],
                // Section 6).  This pseudo-header field MUST be included in all
                // responses; otherwise, the response is malformed (Section 8.1.2.6).
                RequestOrResponse::Response => {
                    let required = PseudoHeaderName::Status;
                    if pseudo_headers_met.get(&required).is_none() {
                        return Err(HeaderError::MissingPseudoHeader(required));
                    }
                }
            }
        }

        Ok(())
    }

    pub fn get_opt<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.0
            .iter()
            .find(|h| h.name() == name.as_bytes())
            .and_then(|h| str::from_utf8(h.value()).ok())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.get_opt(name).unwrap()
    }

    pub fn get_opt_parse<I: FromStr>(&self, name: &str) -> Option<I> {
        self.get_opt(name).and_then(|h| h.parse().ok())
    }

    pub fn status(&self) -> u32 {
        self.get_opt_parse(":status").unwrap()
    }

    pub fn path(&self) -> &str {
        self.get(":path")
    }

    pub fn method(&self) -> &str {
        self.get(":method")
    }

    pub fn content_length(&self) -> Option<u64> {
        match self.get_opt("content-length") {
            Some(v) => v.parse().ok(),
            None => None,
        }
    }

    pub fn add(&mut self, name: &str, value: &str) {
        self.0.push(Header::new(name, value));
    }

    pub fn extend(&mut self, headers: Headers) {
        self.0.extend(headers.0);
    }
}

impl FromIterator<Header> for Headers {
    fn from_iter<T: IntoIterator<Item = Header>>(iter: T) -> Headers {
        Headers(iter.into_iter().collect())
    }
}

#[cfg(test)]
mod test {
    use solicit::header::Header;

    #[test]
    fn test_partial_eq_of_headers() {
        let fully_static = Header::new(b":method", b"GET");
        let static_name = Header::new(b":method", b"GET".to_vec());
        let other = Header::new(b":path", b"/");

        assert!(fully_static == static_name);
        assert!(fully_static != other);
        assert!(static_name != other);
    }

    #[test]
    fn test_debug() {
        assert_eq!(
            "Header { name: b\":method\", value: b\"GET\" }",
            format!("{:?}", Header::new(b":method", b"GET"))
        );
        assert_eq!(
            "Header { name: b\":method\", value: b\"\\xcd\" }",
            format!("{:?}", Header::new(b":method", b"\xcd"))
        );
    }
}
<commit_msg>Remove macro specializations in header construction<commit_after>use std::collections::HashSet;
use std::fmt;
use std::iter::FromIterator;
use std::result;
use std::str;
use std::str::FromStr;

use headers_place::HeadersPlace;
use req_resp::RequestOrResponse;

use error::Error;
use result::Result;

use assert_types::*;

use bytes::Bytes;

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum PseudoHeaderName {
    // 8.1.2.3 Request Pseudo-Header Fields
    Method,
    Scheme,
    Authority,
    Path,

    // 8.1.2.4 Response Pseudo-Header Fields
    Status,
}

impl PseudoHeaderName {
    pub fn name(&self) -> &'static str {
        match *self {
            PseudoHeaderName::Method => ":method",
            PseudoHeaderName::Scheme => ":scheme",
            PseudoHeaderName::Authority => ":authority",
            PseudoHeaderName::Path => ":path",
            PseudoHeaderName::Status => ":status",
        }
    }

    pub fn parse(value: &[u8]) -> Result<PseudoHeaderName> {
        match value {
            b":method" => Ok(PseudoHeaderName::Method),
            b":scheme" => Ok(PseudoHeaderName::Scheme),
            b":authority" => Ok(PseudoHeaderName::Authority),
            b":path" => Ok(PseudoHeaderName::Path),
            b":status" => Ok(PseudoHeaderName::Status),
            _ => Err(Error::Other("invalid pseudo header")),
        }
    }

    pub fn req_or_resp(&self) -> RequestOrResponse {
        match *self {
            PseudoHeaderName::Method => RequestOrResponse::Request,
            PseudoHeaderName::Scheme => RequestOrResponse::Request,
            PseudoHeaderName::Authority => RequestOrResponse::Request,
            PseudoHeaderName::Path => RequestOrResponse::Request,
            PseudoHeaderName::Status => RequestOrResponse::Response,
        }
    }

    pub fn name_bytes(&self) -> Bytes {
        Bytes::from_static(self.name().as_bytes())
    }

    pub fn names(request_or_response: RequestOrResponse) -> &'static [PseudoHeaderName] {
        static REQUEST_HEADERS: &[PseudoHeaderName] = &[
            PseudoHeaderName::Method,
            PseudoHeaderName::Scheme,
            PseudoHeaderName::Authority,
            PseudoHeaderName::Path,
        ];
        static RESPONSE_HEADERS: &[PseudoHeaderName] = &[PseudoHeaderName::Status];
        match request_or_response {
            RequestOrResponse::Request => REQUEST_HEADERS,
            RequestOrResponse::Response => RESPONSE_HEADERS,
        }
    }

    pub fn all_names() -> &'static [PseudoHeaderName] {
        static ALL_HEADERS: &[PseudoHeaderName] = &[
            PseudoHeaderName::Method,
            PseudoHeaderName::Scheme,
            PseudoHeaderName::Authority,
            PseudoHeaderName::Path,
            PseudoHeaderName::Status,
        ];
        ALL_HEADERS
    }
}

#[allow(dead_code)]
pub struct HeaderName(Bytes);

impl<'a> From<&'a str> for HeaderName {
    fn from(_name: &'a str) -> HeaderName {
        unimplemented!()
    }
}

/// A convenience struct representing a part of a header (either the name or the value).
pub struct HeaderPart(Bytes);

impl fmt::Debug for HeaderPart {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<Vec<u8>> for HeaderPart {
    fn from(vec: Vec<u8>) -> HeaderPart {
        HeaderPart(Bytes::from(vec))
    }
}

impl From<Bytes> for HeaderPart {
    fn from(bytes: Bytes) -> HeaderPart {
        HeaderPart(bytes)
    }
}

impl<'a> From<&'a [u8]> for HeaderPart {
    fn from(buf: &'a [u8]) -> HeaderPart {
        HeaderPart(Bytes::from(buf))
    }
}

impl From<String> for HeaderPart {
    fn from(s: String) -> HeaderPart {
        From::from(s.into_bytes())
    }
}

impl<'a> From<&'a str> for HeaderPart {
    fn from(s: &'a str) -> HeaderPart {
        From::from(s.as_bytes())
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Header {
    pub name: Bytes,
    pub value: Bytes,
}

fn _assert_header_sync_send() {
    assert_sync::<Header>();
    assert_send::<Header>();
}

#[derive(Debug)]
pub enum HeaderError {
    UnknownPseudoHeader,
    EmptyName,
    EmptyValue(PseudoHeaderName),
    IncorrectCharInName,
    UnexpectedPseudoHeader(PseudoHeaderName),
    PseudoHeadersInTrailers,
    PseudoHeadersAfterRegularHeaders,
    MoreThanOnePseudoHeader(PseudoHeaderName),
    MissingPseudoHeader(PseudoHeaderName),
    ConnectionSpecificHeader(&'static str),
    TeCanOnlyContainTrailer,
}

pub type HeaderResult<T> = result::Result<T, HeaderError>;

impl Header {
    /// Creates a new `Header` with the given name and value.
    ///
    /// The name and value need to be convertible into a `HeaderPart`.
    pub fn new<N: Into<HeaderPart>, V: Into<HeaderPart>>(name: N, value: V) -> Header {
        Header {
            name: name.into().0,
            value: value.into().0,
        }
    }

    /// Return a borrowed representation of the `Header` name.
    pub fn name(&self) -> &[u8] {
        &self.name
    }
    /// Return a borrowed representation of the `Header` value.
    pub fn value(&self) -> &[u8] {
        &self.value
    }

    /// name: value
    pub fn format(&self) -> String {
        format!(
            "{}: {}",
            String::from_utf8_lossy(&self.name),
            String::from_utf8_lossy(&self.value)
        )
    }

    pub fn is_preudo_header(&self) -> bool {
        self.name.len() != 0 && self.name[0] == b':'
    }

    pub fn pseudo_header_name(&self) -> HeaderResult<Option<PseudoHeaderName>> {
        if self.is_preudo_header() {
            for &h in PseudoHeaderName::all_names() {
                if self.name.as_ref() == h.name().as_bytes() {
                    return Ok(Some(h));
                }
            }
            Err(HeaderError::UnknownPseudoHeader)
        } else {
            Ok(None)
        }
    }

    fn validate_header_name_char(b: u8) -> HeaderResult<()> {
        // TODO: restrict more
        if b >= b'A' && b <= b'Z' {
            return Err(HeaderError::IncorrectCharInName);
        }
        Ok(())
    }

    pub fn validate(&self, req_or_resp: RequestOrResponse) -> HeaderResult<()> {
        if self.name.len() == 0 {
            return Err(HeaderError::EmptyName);
        }

        if let Some(h) = self.pseudo_header_name()? {
            if h.req_or_resp() != req_or_resp {
                return Err(HeaderError::UnexpectedPseudoHeader(h));
            }
        }

        for c in &self.name {
            Header::validate_header_name_char(c)?;
        }

        // HTTP/2 does not use the Connection header field to indicate
        // connection-specific header fields; in this protocol, connection-
        // specific metadata is conveyed by other means.  An endpoint MUST NOT
        // generate an HTTP/2 message containing connection-specific header
        // fields; any message containing connection-specific header fields MUST
        // be treated as malformed (Section 8.1.2.6).
        let connection_specific_headers = [
            "connection",
            "keep-alive",
            "proxy-connection",
            "transfer-encoding",
            "upgrade",
        ];
        for s in &connection_specific_headers {
            if self.name == s.as_bytes() {
                return Err(HeaderError::ConnectionSpecificHeader(s));
            }
        }

        if self.name.as_ref() == b"te" {
            // The only exception to this is the TE header field, which MAY be
            // present in an HTTP/2 request; when it is, it MUST NOT contain any
            // value other than "trailers".
            if self.value.as_ref() != b"trailers" {
                return Err(HeaderError::TeCanOnlyContainTrailer);
            }
        }

        Ok(())
    }
}

impl<N: Into<HeaderPart>, V: Into<HeaderPart>> From<(N, V)> for Header {
    fn from(p: (N, V)) -> Header {
        Header::new(p.0, p.1)
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct Headers(pub Vec<Header>);

impl Headers {
    pub fn new() -> Headers {
        Default::default()
    }

    /// Multiline string
    pub fn dump(&self) -> String {
        let mut r = String::new();
        for h in &self.0 {
            r.push_str(&h.format());
            r.push_str("\n");
        }
        r
    }

    pub fn new_get(path: &str) -> Headers {
        Headers(vec![
            Header::new(":method", "GET"),
            Header::new(":path", path),
        ])
    }

    pub fn new_post(path: &str) -> Headers {
        Headers(vec![
            Header::new(":method", "POST"),
            Header::new(":path", path),
        ])
    }

    pub fn from_status(code: u32) -> Headers {
        Headers(vec![Header::new(":status", format!("{}", code))])
    }

    pub fn ok_200() -> Headers {
        Headers::from_status(200)
    }

    pub fn not_found_404() -> Headers {
        Headers::from_status(404)
    }

    pub fn internal_error_500() -> Headers {
        Headers::from_status(500)
    }

    pub fn contains_preudo_headers(&self) -> bool {
        self.0.iter().any(|h| h.is_preudo_header())
    }

    pub fn validate(
        &self,
        req_or_resp: RequestOrResponse,
        headers_place: HeadersPlace,
    ) -> HeaderResult<()> {
        let mut saw_regular_header = false;

        // TODO: array is enough
        let mut pseudo_headers_met = HashSet::new();

        for header in &self.0 {
            header.validate(req_or_resp)?;

            // 8.1.2.1.  Pseudo-Header Fields
            // All pseudo-header fields MUST appear in the header block before
            // regular header fields.  Any request or response that contains a
            // pseudo-header field that appears in a header block after a regular
            // header field MUST be treated as malformed (Section 8.1.2.6).
            if let Some(header_name) = header.pseudo_header_name()? {
                if headers_place == HeadersPlace::Trailing {
                    return Err(HeaderError::PseudoHeadersInTrailers);
                }

                if saw_regular_header {
                    return Err(HeaderError::PseudoHeadersAfterRegularHeaders);
                }

                if !pseudo_headers_met.insert(header_name) {
                    return Err(HeaderError::MoreThanOnePseudoHeader(header_name));
                }

                if header_name == PseudoHeaderName::Path {
                    if header.value.is_empty() {
                        return Err(HeaderError::EmptyValue(header_name));
                    }
                }
            } else {
                saw_regular_header = true;
            }
        }

        if headers_place == HeadersPlace::Initial {
            match req_or_resp {
                // All HTTP/2 requests MUST include exactly one valid value for the
                // ":method", ":scheme", and ":path" pseudo-header fields, unless it is
                // a CONNECT request (Section 8.3).  An HTTP request that omits
                // mandatory pseudo-header fields is malformed (Section 8.1.2.6).
                RequestOrResponse::Request => {
                    let required_headers = [
                        PseudoHeaderName::Method,
                        PseudoHeaderName::Scheme,
                        PseudoHeaderName::Path,
                    ];
                    for required in &required_headers {
                        if pseudo_headers_met.get(required).is_none() {
                            return Err(HeaderError::MissingPseudoHeader(*required));
                        }
                    }
                }
                // For HTTP/2 responses, a single ":status" pseudo-header field is
                // defined that carries the HTTP status code field (see [RFC7231],
                // Section 6).  This pseudo-header field MUST be included in all
                // responses; otherwise, the response is malformed (Section 8.1.2.6).
                RequestOrResponse::Response => {
                    let required = PseudoHeaderName::Status;
                    if pseudo_headers_met.get(&required).is_none() {
                        return Err(HeaderError::MissingPseudoHeader(required));
                    }
                }
            }
        }

        Ok(())
    }

    pub fn get_opt<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.0
            .iter()
            .find(|h| h.name() == name.as_bytes())
            .and_then(|h| str::from_utf8(h.value()).ok())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.get_opt(name).unwrap()
    }

    pub fn get_opt_parse<I: FromStr>(&self, name: &str) -> Option<I> {
        self.get_opt(name).and_then(|h| h.parse().ok())
    }

    pub fn status(&self) -> u32 {
        self.get_opt_parse(":status").unwrap()
    }

    pub fn path(&self) -> &str {
        self.get(":path")
    }

    pub fn method(&self) -> &str {
        self.get(":method")
    }

    pub fn content_length(&self) -> Option<u64> {
        match self.get_opt("content-length") {
            Some(v) => v.parse().ok(),
            None => None,
        }
    }

    pub fn add(&mut self, name: &str, value: &str) {
        self.0.push(Header::new(name, value));
    }

    pub fn extend(&mut self, headers: Headers) {
        self.0.extend(headers.0);
    }
}

impl FromIterator<Header> for Headers {
    fn from_iter<T: IntoIterator<Item = Header>>(iter: T) -> Headers {
        Headers(iter.into_iter().collect())
    }
}

#[cfg(test)]
mod test {
    use solicit::header::Header;

    #[test]
    fn test_partial_eq_of_headers() {
        let fully_static = Header::new(&b":method"[..], &b"GET"[..]);
        let static_name = Header::new(&b":method"[..], b"GET".to_vec());
        let other = Header::new(&b":path"[..], &b"/"[..]);

        assert!(fully_static == static_name);
        assert!(fully_static != other);
        assert!(static_name != other);
    }

    #[test]
    fn test_debug() {
        assert_eq!(
            "Header { name: b\":method\", value: b\"GET\" }",
            format!("{:?}", Header::new(&b":method"[..], &b"GET"[..]))
        );
        assert_eq!(
            "Header { name: b\":method\", value: b\"\\xcd\" }",
            format!("{:?}", Header::new(&b":method"[..], &b"\xcd"[..]))
        );
    }
}
<|endoftext|>