fix #606: HTMLForm constructor read application/x-www-form-urlencoded UTF-8 request body first parameter with BOM in name

This commit is contained in:
Guenter Obiltschnig 2014-11-12 10:33:57 +01:00
Родитель b2276e7f7e
Коммит eb8dce47fe
5 изменённых файлов: 64 добавлений и 10 удалений

Просмотреть файл

@ -35,6 +35,9 @@ struct Foundation_API UTF8
/// ///
/// toUpper(), toUpperInPlace(), toLower() and toLowerInPlace() provide /// toUpper(), toUpperInPlace(), toLower() and toLowerInPlace() provide
/// Unicode-based character case transformation for UTF-8 encoded strings. /// Unicode-based character case transformation for UTF-8 encoded strings.
///
/// removeBOM() removes the UTF-8 Byte Order Mark sequence (0xEF, 0xBB, 0xBF)
/// from the beginning of the given string, if it's there.
{ {
static int icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, std::string::const_iterator it2, std::string::const_iterator end2); static int icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, std::string::const_iterator it2, std::string::const_iterator end2);
static int icompare(const std::string& str1, const std::string& str2); static int icompare(const std::string& str1, const std::string& str2);
@ -51,6 +54,10 @@ struct Foundation_API UTF8
static std::string& toUpperInPlace(std::string& str); static std::string& toUpperInPlace(std::string& str);
static std::string toLower(const std::string& str); static std::string toLower(const std::string& str);
static std::string& toLowerInPlace(std::string& str); static std::string& toLowerInPlace(std::string& str);
static void removeBOM(std::string& str);
/// Remove the UTF-8 Byte Order Mark sequence (0xEF, 0xBB, 0xBF)
/// from the beginning of the string, if it's there.
}; };

Просмотреть файл

@ -160,4 +160,16 @@ std::string& UTF8::toLowerInPlace(std::string& str)
} }
void UTF8::removeBOM(std::string& str)
{
if (str.size() >= 3
&& static_cast<unsigned char>(str[0]) == 0xEF
&& static_cast<unsigned char>(str[1]) == 0xBB
&& static_cast<unsigned char>(str[2]) == 0xBF)
{
str.erase(0, 3);
}
}
} // namespace Poco } // namespace Poco

Просмотреть файл

@ -28,6 +28,7 @@
#include "Poco/URI.h" #include "Poco/URI.h"
#include "Poco/String.h" #include "Poco/String.h"
#include "Poco/CountingStream.h" #include "Poco/CountingStream.h"
#include "Poco/UTF8String.h"
#include <sstream> #include <sstream>
@ -42,20 +43,31 @@ namespace Poco {
namespace Net { namespace Net {
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded"; const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data"; const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1; const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1;
class HTMLFormCountingOutputStream : public CountingOutputStream class HTMLFormCountingOutputStream: public CountingOutputStream
{ {
public: public:
HTMLFormCountingOutputStream() : _isvalid(true) {} HTMLFormCountingOutputStream():
_valid(true)
{
}
bool isValid() const
{
return _valid;
}
void setValid(bool v)
{
_valid = v;
}
bool getIsValid() const { return _isvalid; }
void setIsValid(bool v) { _isvalid = v; }
private: private:
bool _isvalid; bool _valid;
}; };
@ -238,7 +250,7 @@ std::streamsize HTMLForm::calculateContentLength()
HTMLFormCountingOutputStream c; HTMLFormCountingOutputStream c;
write(c); write(c);
if (c.getIsValid()) if (c.isValid())
return c.chars(); return c.chars();
else else
return UNKNOWN_CONTENT_LENGTH; return UNKNOWN_CONTENT_LENGTH;
@ -274,6 +286,7 @@ void HTMLForm::readUrl(std::istream& istr)
int fields = 0; int fields = 0;
int ch = istr.get(); int ch = istr.get();
bool isFirst = true;
while (ch != eof) while (ch != eof)
{ {
if (_fieldLimit > 0 && fields == _fieldLimit) if (_fieldLimit > 0 && fields == _fieldLimit)
@ -296,6 +309,11 @@ void HTMLForm::readUrl(std::istream& istr)
ch = istr.get(); ch = istr.get();
} }
} }
// remove UTF-8 byte order mark from first name, if present
if (isFirst)
{
UTF8::removeBOM(name);
}
std::string decodedName; std::string decodedName;
std::string decodedValue; std::string decodedValue;
URI::decode(name, decodedName); URI::decode(name, decodedName);
@ -303,6 +321,7 @@ void HTMLForm::readUrl(std::istream& istr)
add(decodedName, decodedValue); add(decodedName, decodedValue);
++fields; ++fields;
if (ch == '&') ch = istr.get(); if (ch == '&') ch = istr.get();
isFirst = false;
} }
} }
@ -402,7 +421,7 @@ void HTMLForm::writeMultipart(std::ostream& ostr)
if (partlen != PartSource::UNKNOWN_CONTENT_LENGTH) if (partlen != PartSource::UNKNOWN_CONTENT_LENGTH)
costr->addChars(static_cast<int>(partlen)); costr->addChars(static_cast<int>(partlen));
else else
costr->setIsValid(false); costr->setValid(false);
} }
else else
StreamCopier::copyStream(ita->pSource->stream(), ostr); StreamCopier::copyStream(ita->pSource->stream(), ostr);

Просмотреть файл

@ -191,6 +191,20 @@ void HTMLFormTest::testReadUrlPUT()
} }
void HTMLFormTest::testReadUrlBOM()
{
HTTPRequest req("PUT", "/form.cgi?field0=value0");
std::istringstream istr("\357\273\277field1=value1&field2=value%202&field3=value%3D3&field4=value%264");
HTMLForm form(req, istr);
assert (form.size() == 5);
assert (form["field0"] == "value0");
assert (form["field1"] == "value1");
assert (form["field2"] == "value 2");
assert (form["field3"] == "value=3");
assert (form["field4"] == "value&4");
}
void HTMLFormTest::testReadMultipart() void HTMLFormTest::testReadMultipart()
{ {
std::istringstream istr( std::istringstream istr(
@ -359,6 +373,7 @@ CppUnit::Test* HTMLFormTest::suite()
CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlGET); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlGET);
CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPOST); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPOST);
CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPUT); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPUT);
CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlBOM);
CppUnit_addTest(pSuite, HTMLFormTest, testReadMultipart); CppUnit_addTest(pSuite, HTMLFormTest, testReadMultipart);
CppUnit_addTest(pSuite, HTMLFormTest, testSubmit1); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit1);
CppUnit_addTest(pSuite, HTMLFormTest, testSubmit2); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit2);

Просмотреть файл

@ -31,6 +31,7 @@ public:
void testReadUrlGET(); void testReadUrlGET();
void testReadUrlPOST(); void testReadUrlPOST();
void testReadUrlPUT(); void testReadUrlPUT();
void testReadUrlBOM();
void testReadMultipart(); void testReadMultipart();
void testSubmit1(); void testSubmit1();
void testSubmit2(); void testSubmit2();