Browse Source

only convert RFC2231 "extended values" if the parameter name ends with a "*"

afl-fuzzing
Roker 3 years ago
parent
commit
80ed56adc7
1 changed files with 20 additions and 17 deletions
  1. +20
    -17
      src/bodyparser.cc

+ 20
- 17
src/bodyparser.cc View File

@ -36,7 +36,7 @@ using qi::_1;
{
std::string name;
int count = -1;
bool with_charset = false;
bool ext_value = false; // extended value: charset'language'encoded_value
};
struct Rfc2231ParamValue
@ -96,16 +96,16 @@ 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] );
>> -(qi::lit('*')[ &(_val)->*&Rfc2231ParamName::ext_value = true] );
pEpMIME::TRule<Rfc2231ParamValue> param_value =
-(
-qi::hold[
(+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
] // 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)
@ -127,7 +127,7 @@ std::string convert(std::string& charset, const std::string& input)
void ContentType::unwrap()
{
std::vector<pEpMIME::NameValue> new_params;
std::string name, value;
std::string ml_name, ml_value; // multiline parameters
std::string charset = "UTF-8";
int old_count = -1;
for(auto& p:params)
@ -136,24 +136,25 @@ void ContentType::unwrap()
std::string::const_iterator begin = p.name.cbegin();
if(qi::parse(begin, p.name.cend(), param_name, pn))
{
const std::string& value = pn.ext_value ? convert(charset, p.value ) : p.value;
switch(pn.count)
{
case -1 : // has charset but no multi-line value
new_params.emplace_back( pn.name, convert(charset, p.value ) );
new_params.emplace_back( pn.name, value );
break;
case 0 : // start of a multi-line value
if(!name.empty())
if(!ml_name.empty())
{
new_params.emplace_back( name, value);
new_params.emplace_back( ml_name, ml_value);
}
name = pn.name;
value = convert( charset, p.value );
ml_name = pn.name;
ml_value = value;
old_count = 0;
break;
default:
if(pn.name == name && pn.count == old_count+1)
if(pn.name == ml_name && pn.count == old_count+1)
{
value += convert( charset, p.value );
ml_value += value;
old_count = pn.count;
}else{
// non-contiguous counter -> discard it.
@ -161,10 +162,10 @@ void ContentType::unwrap()
break;
}
}else{
if(!name.empty())
if(!ml_name.empty())
{
new_params.emplace_back( name, value);
name.clear(); value.clear();
new_params.emplace_back( ml_name, ml_value);
ml_name.clear(); ml_value.clear();
}
// "legacy" parameter:
new_params.emplace_back( std::move(p) );
@ -241,7 +242,7 @@ Decoder getDecoder(const sv transfer_encoding)
}
// Tokens from RFC 2045
Rule token = +( vchar - qi::char_("]()<>@,;:\\\"/?=["));
Rule token = +( vchar.alias() - qi::char_("]()<>@,;:\\\"/?=["));
TRule<NameValue> parameter = token >> '=' >> (token | quoted_string.alias());
TRule<ContentType> content_type = token >> '/' >> token >> *( qi::omit[*cfws] >> ';' >> qi::omit[*cfws] >> parameter);
@ -278,6 +279,7 @@ void parse_body(message* msg, const HeaderSection& headers, const BodyLines& bod
// TODO: for whatever reason "string_view cts" does not work with qi::parse(). WTF!
const std::string cts = header_value(headers, "Content-Type").to_string();
ContentType ct;
auto begin = cts.cbegin();
const bool okay = qi::parse(begin, cts.cend(), content_type, ct);
@ -285,8 +287,9 @@ void parse_body(message* msg, const HeaderSection& headers, const BodyLines& bod
{
throw std::runtime_error( "Cannot parse \"" + std::string{cts} + "\" as ContentType");
}
std::cerr << "<<< CT raw: " << ct << ">>>\n";
ct.sanitize();
std::cerr << ct << std::endl;
std::cerr << "<<< CT san: " << ct << ">>>\n";
if(ct.type == "text")
{
const sv charset = header_value( ct.params, "charset" );


Loading…
Cancel
Save