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:
Родитель
b2276e7f7e
Коммит
eb8dce47fe
|
@ -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();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче