Browse Source

add parsing of RFC2231-encoded parameter values… *sigh*

afl-fuzzing
Roker 3 years ago
parent
commit
0611742d40
3 changed files with 83 additions and 9 deletions
  1. +77
    -8
      src/bodyparser.cc
  2. +5
    -0
      src/pEpMIME_internal.hh
  3. +1
    -1
      src/rules.cc

+ 77
- 8
src/bodyparser.cc View File

@ -35,8 +35,15 @@ using qi::_1;
struct Rfc2231ParamName
{
std::string name;
unsigned count;
bool with_charset;
int count = -1;
bool with_charset = false;
};
struct Rfc2231ParamValue
{
std::string charset;
// language is ignored
std::string value;
};
BOOST_FUSION_ADAPT_STRUCT(
@ -81,28 +88,90 @@ void ContentType::tolower()
ascii_tolower(subtype);
}
qi::uint_parser<unsigned char, 16,2,2> hex_octet;
pEpMIME::TRule<char> ext_octet = qi::lit('%') >> hex_octet;
pEpMIME::TRule<char> attrib_char = qi::ascii::print - qi::char_("]*'%()<>@,:\\\"/?=[");
pEpMIME::TRule<Rfc2231ParamName> param_name =
(+(qi::char_ - '*')) [ &(_val)->*&Rfc2231ParamName::name <<= _1 ]
>> -(qi::lit('*') >> qi::uint_[ &(_val)->*&Rfc2231ParamName::count = _1] )
>> -(qi::lit('*')[ &(_val)->*&Rfc2231ParamName::with_charset = true] );
pEpMIME::TRule<Rfc2231ParamValue> param_value =
-(
(+qi::char_("A-Za-z0-9_./-"))[ &(_val)->*&Rfc2231ParamValue::charset <<= _1 ]
>> '\''
>> qi::omit[ *(qi::char_ - '\'') ] // language is ignored
>> '\''
) // charset & language is optional and normally only present in the 1st part
>> ( +(ext_octet | attrib_char))[ &(_val)->*&Rfc2231ParamValue::value <<= _1 ];
std::string convert(std::string& charset, const std::string& input)
{
Rfc2231ParamValue pv;
std::string::const_iterator begin = input.begin();
if(qi::parse(begin, input.end(), param_value, pv))
{
if(pv.charset.size())
{
charset = pv.charset;
}
return to_utf8(charset, pv.value);
}
return to_utf8(charset, input);
}
void ContentType::unwrap()
{
std::vector<pEpMIME::NameValue> params;
std::vector<pEpMIME::NameValue> new_params;
std::string name, value;
for(const auto& p:params)
std::string charset = "UTF-8";
int old_count = -1;
for(auto& p:params)
{
Rfc2231ParamName pn;
auto begin = p.name.begin();
if(qi::parse(begin, p.name.end(), param_name, pn))
std::string::const_iterator begin = p.name.cbegin();
if(qi::parse(begin, p.name.cend(), param_name, pn))
{
if(pn.name == name)
switch(pn.count)
{
case -1 : // has charset but no multi-line value
new_params.emplace_back( pn.name, convert(charset, p.value ) );
break;
case 0 : // start of a multi-line value
if(!name.empty())
{
new_params.emplace_back( name, value);
}
name = pn.name;
value = convert( charset, p.value );
old_count = 0;
break;
default:
if(pn.name == name && pn.count == old_count+1)
{
value += convert( charset, p.value );
old_count = pn.count;
}else{
// non-contiguous counter -> discard it.
}
break;
}
}else{
if(!name.empty())
{
value += p.value; // TODO: decode encoded values!
new_params.emplace_back( name, value);
name.clear(); value.clear();
}
// "legacy" parameter:
new_params.emplace_back( std::move(p) );
}
}
params.swap(new_params);
}
std::ostream& operator<<(std::ostream& o, const ContentType& ct)


+ 5
- 0
src/pEpMIME_internal.hh View File

@ -21,6 +21,11 @@ namespace pEpMIME
struct NameValue
{
NameValue() = default;
NameValue(const std::string& n, const std::string& v)
: name(n), value(v)
{}
std::string name, value;
};


+ 1
- 1
src/rules.cc View File

@ -43,7 +43,7 @@ Rule ocfws = (*(fws | comment))[ qi::_val += ' ']; // optional cfws, but al
// RFC 2047
TRule<std::string, std::string, std::string, std::string> encoded_word = ( qi::lit("=?")
>> ((+qi::char_("a-zA-Z0-9_+-"))[px::ref(qi::_a) <<= qi::_1] ) // charset -> _a
>> -( '*' >> *(qi::char_ - '?')) // optional "language" flag, according to RFC 2184
>> -( '*' >> *(qi::char_ - '?')) // optional "language" flag, according to RFC 2184 / 2231
>> (
( qi::lit("?B?") >> (*qi::char_("a-zA-Z0-9/=+")) [px::ref(qi::_b) <<= qi::_1][ qi::_c = px::bind(base64::decode, px::cref(qi::_b))] ) // "B" encoding
|


Loading…
Cancel
Save