mail_internals/bind/
mime.rs

1use std::borrow::Cow;
2
3use soft_ascii_string::{ SoftAsciiStr, SoftAsciiString};
4use grammar::is_token_char;
5use percent_encoding::{
6    EncodeSet,
7    percent_encode
8};
9
10#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
11struct MimeParamEncodingSet;
12impl EncodeSet for MimeParamEncodingSet {
13    fn contains(&self, byte: u8) -> bool {
14        //if it is in the encoding set we need to encode it
15        //which we need to to if it is _not_ a token char
16        !is_token_char(byte as char)
17    }
18}
19
20
21/// percent encodes a byte sequence so that it can be used
22/// in a RFC 2231 conform encoded mime header parameter
23pub fn percent_encode_param_value<'a, R>(input: &'a R) -> Cow<'a, SoftAsciiStr>
24    where R: ?Sized+AsRef<[u8]>
25{
26    let cow: Cow<'a, str> = percent_encode(input.as_ref(), MimeParamEncodingSet).into();
27    match cow {
28        Cow::Owned(o) =>
29            //SAFE: MimeParamEncodingSet makes all non-us-ascii bytes encoded AND
30            // percent_encoding::percent_encode always only produces ascii anyway
31            Cow::Owned(SoftAsciiString::from_unchecked(o)),
32        Cow::Borrowed(b) =>
33            Cow::Borrowed(SoftAsciiStr::from_unchecked(b))
34    }
35}
36
37
38#[cfg(test)]
39mod test {
40    use std::borrow::Cow;
41    use super::*;
42
43    #[test]
44    fn encode_simple() {
45        let input = "this is tüxt";
46        let res = percent_encode_param_value(input);
47        assert_eq!("this%20is%20t%C3%BCxt", res.as_str());
48    }
49
50    #[test]
51    fn no_encode_no_alloc() {
52        let input = "full_valid";
53        let res = percent_encode_param_value(input);
54        assert_eq!(res, Cow::Borrowed(input));
55    }
56}