Throw exception when an invalid value type is set in a header field.
This commit is contained in:
parent
d2c2f52a23
commit
8378b350df
@ -360,6 +360,7 @@ libvmimetest_sources = [
|
||||
'tests/parser/dispositionTest.cpp',
|
||||
'tests/parser/emailAddressTest.cpp',
|
||||
'tests/parser/headerTest.cpp',
|
||||
'tests/parser/headerFieldTest.cpp',
|
||||
'tests/parser/htmlTextPartTest.cpp',
|
||||
'tests/parser/mailboxTest.cpp',
|
||||
'tests/parser/mediaTypeTest.cpp',
|
||||
|
@ -94,15 +94,15 @@ namespace exceptions
|
||||
|
||||
|
||||
//
|
||||
// bad_field_type
|
||||
// bad_field_value_type
|
||||
//
|
||||
|
||||
bad_field_type::~bad_field_type() throw() {}
|
||||
bad_field_type::bad_field_type(const exception& other)
|
||||
: exception("Bad field type.", other) {}
|
||||
bad_field_value_type::~bad_field_value_type() throw() {}
|
||||
bad_field_value_type::bad_field_value_type(const string& fieldName, const exception& other)
|
||||
: exception("Bad value type for field '" + fieldName + "'.", other) {}
|
||||
|
||||
exception* bad_field_type::clone() const { return new bad_field_type(*this); }
|
||||
const char* bad_field_type::name() const throw() { return "bad_field_type"; }
|
||||
exception* bad_field_value_type::clone() const { return new bad_field_value_type(*this); }
|
||||
const char* bad_field_value_type::name() const throw() { return "bad_field_value_type"; }
|
||||
|
||||
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#include "vmime/parserHelpers.hpp"
|
||||
|
||||
#include "vmime/exception.hpp"
|
||||
|
||||
|
||||
namespace vmime
|
||||
{
|
||||
@ -324,6 +326,9 @@ ref <headerFieldValue> headerField::getValue()
|
||||
|
||||
void headerField::setValue(ref <headerFieldValue> value)
|
||||
{
|
||||
if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value))
|
||||
throw exceptions::bad_field_value_type(getName());
|
||||
|
||||
if (value != NULL)
|
||||
m_value = value;
|
||||
}
|
||||
@ -331,12 +336,18 @@ void headerField::setValue(ref <headerFieldValue> value)
|
||||
|
||||
void headerField::setValueConst(ref <const headerFieldValue> value)
|
||||
{
|
||||
if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value))
|
||||
throw exceptions::bad_field_value_type(getName());
|
||||
|
||||
m_value = value->clone().dynamicCast <headerFieldValue>();
|
||||
}
|
||||
|
||||
|
||||
void headerField::setValue(const headerFieldValue& value)
|
||||
{
|
||||
if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, value))
|
||||
throw exceptions::bad_field_value_type(getName());
|
||||
|
||||
m_value = value.clone().dynamicCast <headerFieldValue>();
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ ref <headerFieldValue> headerFieldFactory::createValue(const string& fieldName)
|
||||
ref <headerFieldValue> value = NULL;
|
||||
|
||||
if (pos != m_valueMap.end())
|
||||
value = ((*pos).second)();
|
||||
value = ((*pos).second.allocFunc)();
|
||||
else
|
||||
value = registerer <headerFieldValue, text>::creator();
|
||||
|
||||
@ -134,5 +134,18 @@ ref <headerFieldValue> headerFieldFactory::createValue(const string& fieldName)
|
||||
}
|
||||
|
||||
|
||||
bool headerFieldFactory::isValueTypeValid
|
||||
(const headerField& field, const headerFieldValue& value) const
|
||||
{
|
||||
ValueMap::const_iterator pos = m_valueMap.find
|
||||
(utility::stringUtils::toLower(field.getName()));
|
||||
|
||||
if (pos != m_valueMap.end())
|
||||
return ((*pos).second.checkTypeFunc)(value);
|
||||
|
||||
return true; // No info on this field
|
||||
}
|
||||
|
||||
|
||||
} // vmime
|
||||
|
||||
|
56
tests/parser/headerFieldTest.cpp
Normal file
56
tests/parser/headerFieldTest.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Linking this library statically or dynamically with other modules is making
|
||||
// a combined work based on this library. Thus, the terms and conditions of
|
||||
// the GNU General Public License cover the whole combination.
|
||||
//
|
||||
|
||||
#include "tests/testUtils.hpp"
|
||||
|
||||
|
||||
#define VMIME_TEST_SUITE headerFieldTest
|
||||
#define VMIME_TEST_SUITE_MODULE "Parser"
|
||||
|
||||
|
||||
VMIME_TEST_SUITE_BEGIN
|
||||
|
||||
VMIME_TEST_LIST_BEGIN
|
||||
VMIME_TEST(testBadValueType)
|
||||
VMIME_TEST_LIST_END
|
||||
|
||||
|
||||
void testBadValueType()
|
||||
{
|
||||
vmime::headerFieldFactory *hfactory = vmime::headerFieldFactory::getInstance();
|
||||
|
||||
// "To" header field accepts values of type "addressList"
|
||||
vmime::ref <vmime::headerField> to = hfactory->create(vmime::fields::TO);
|
||||
VASSERT_THROW("to",
|
||||
to->setValue(vmime::mailbox("email@vmime.org")),
|
||||
vmime::exceptions::bad_field_value_type);
|
||||
|
||||
// Unregistered header field accepts any value type
|
||||
vmime::ref <vmime::headerField> custom = hfactory->create("X-MyCustomHeader");
|
||||
VASSERT_NO_THROW("custom/1",
|
||||
custom->setValue(vmime::mailbox("email@vmime.org")));
|
||||
VASSERT_NO_THROW("custom/2",
|
||||
custom->setValue(vmime::text("field value text")));
|
||||
}
|
||||
|
||||
VMIME_TEST_SUITE_END
|
@ -98,12 +98,12 @@ namespace exceptions
|
||||
{
|
||||
|
||||
|
||||
class bad_field_type : public vmime::exception
|
||||
class bad_field_value_type : public vmime::exception
|
||||
{
|
||||
public:
|
||||
|
||||
bad_field_type(const exception& other = NO_EXCEPTION);
|
||||
~bad_field_type() throw();
|
||||
bad_field_value_type(const string& fieldName, const exception& other = NO_EXCEPTION);
|
||||
~bad_field_value_type() throw();
|
||||
|
||||
exception* clone() const;
|
||||
const char* name() const throw();
|
||||
|
@ -94,12 +94,16 @@ public:
|
||||
|
||||
/** Set the value of this field.
|
||||
*
|
||||
* @throw exceptions::bad_field_value_type if the value type is not
|
||||
* valid for this header field
|
||||
* @param value new value
|
||||
*/
|
||||
virtual void setValue(ref <headerFieldValue> value);
|
||||
|
||||
/** Set the value of this field by cloning the specified value.
|
||||
*
|
||||
* @throw exceptions::bad_field_value_type if the value type is not
|
||||
* valid for this header field
|
||||
* @param value new value
|
||||
*/
|
||||
virtual void setValueConst(ref <const headerFieldValue> value);
|
||||
@ -107,6 +111,8 @@ public:
|
||||
/** Set the value of this field (reference version).
|
||||
* The value will be cloned.
|
||||
*
|
||||
* @throw exceptions::bad_field_value_type if the value type is not
|
||||
* valid for this header field
|
||||
* @param value new value
|
||||
*/
|
||||
virtual void setValue(const headerFieldValue& value);
|
||||
|
@ -48,8 +48,17 @@ protected:
|
||||
|
||||
NameMap m_nameMap;
|
||||
|
||||
|
||||
struct ValueInfo
|
||||
{
|
||||
typedef ref <headerFieldValue> (*ValueAllocFunc)(void);
|
||||
typedef std::map <string, ValueAllocFunc> ValueMap;
|
||||
typedef bool (*ValueTypeCheckFunc)(const object&);
|
||||
|
||||
ValueAllocFunc allocFunc;
|
||||
ValueTypeCheckFunc checkTypeFunc;
|
||||
};
|
||||
|
||||
typedef std::map <string, ValueInfo> ValueMap;
|
||||
|
||||
ValueMap m_valueMap;
|
||||
|
||||
@ -64,6 +73,12 @@ public:
|
||||
{
|
||||
public:
|
||||
|
||||
static bool checkType(const object& obj)
|
||||
{
|
||||
const TYPE* typedObj = dynamic_cast <const TYPE*>(&obj);
|
||||
return typedObj != NULL;
|
||||
}
|
||||
|
||||
static ref <BASE_TYPE> creator()
|
||||
{
|
||||
// Allocate a new object
|
||||
@ -94,9 +109,12 @@ public:
|
||||
template <class T>
|
||||
void registerFieldValue(const string& name)
|
||||
{
|
||||
ValueInfo vi;
|
||||
vi.allocFunc = ®isterer <headerFieldValue, T>::creator;
|
||||
vi.checkTypeFunc = ®isterer <headerField, T>::checkType;
|
||||
|
||||
m_valueMap.insert(ValueMap::value_type
|
||||
(utility::stringUtils::toLower(name),
|
||||
®isterer <headerFieldValue, T>::creator));
|
||||
(utility::stringUtils::toLower(name), vi));
|
||||
}
|
||||
|
||||
/** Create a new field object for the specified field name.
|
||||
@ -116,6 +134,15 @@ public:
|
||||
* @return a new value object for the field
|
||||
*/
|
||||
ref <headerFieldValue> createValue(const string& fieldName);
|
||||
|
||||
/** Returns whether the specified value type is valid for the specified field.
|
||||
*
|
||||
* @param field header field
|
||||
* @param value value for this header field
|
||||
* @return true if the value type is compatible with the header field, or
|
||||
* false otherwise
|
||||
*/
|
||||
bool isValueTypeValid(const headerField& field, const headerFieldValue& value) const;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user