Accept QASV for multipart 'name' field
And adjust the encoding of 'name' parameter to always use UTF-8 / ASCII. This aligns with how other frameworks behave. Also amended docs to recommend ASCII for 'name'. Found in API review. Pick-to: 6.8 Change-Id: I54d1148bf95dece54b75c76914c49985da05e0b2 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
8c8a0c06d4
commit
6b23a3c5e4
@ -28,17 +28,37 @@ QT_BEGIN_NAMESPACE
|
|||||||
\sa QHttpPart, QHttpMultiPart, QFormDataBuilder
|
\sa QHttpPart, QHttpMultiPart, QFormDataBuilder
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static QByteArray nameToByteArray(QStringView view)
|
||||||
|
{
|
||||||
|
return view.toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QByteArray nameToByteArray(QLatin1StringView view)
|
||||||
|
{
|
||||||
|
if (!QtPrivate::isAscii(view))
|
||||||
|
return view.toString().toUtf8(); // ### optimize
|
||||||
|
|
||||||
|
return QByteArray::fromRawData(view.data(), view.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static QByteArray nameToByteArray(QUtf8StringView view)
|
||||||
|
{
|
||||||
|
return QByteArray::fromRawData(view.data(), view.size());
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a QFormDataPartBuilder object and sets \a name as the name
|
Constructs a QFormDataPartBuilder object and sets \a name as the name
|
||||||
parameter of the form-data.
|
parameter of the form-data.
|
||||||
*/
|
*/
|
||||||
QFormDataPartBuilder::QFormDataPartBuilder(QLatin1StringView name, PrivateConstructor /*unused*/)
|
QFormDataPartBuilder::QFormDataPartBuilder(QAnyStringView name, PrivateConstructor /*unused*/)
|
||||||
{
|
{
|
||||||
static_assert(std::is_nothrow_move_constructible_v<decltype(m_body)>);
|
static_assert(std::is_nothrow_move_constructible_v<decltype(m_body)>);
|
||||||
static_assert(std::is_nothrow_move_assignable_v<decltype(m_body)>);
|
static_assert(std::is_nothrow_move_assignable_v<decltype(m_body)>);
|
||||||
|
|
||||||
|
const auto enc = name.visit([](auto name) { return nameToByteArray(name); });
|
||||||
|
|
||||||
m_headerValue += "form-data; name=\"";
|
m_headerValue += "form-data; name=\"";
|
||||||
for (auto c : name) {
|
for (auto c : enc) {
|
||||||
if (c == '"' || c == '\\')
|
if (c == '"' || c == '\\')
|
||||||
m_headerValue += '\\';
|
m_headerValue += '\\';
|
||||||
m_headerValue += c;
|
m_headerValue += c;
|
||||||
@ -292,10 +312,14 @@ QFormDataBuilder::~QFormDataBuilder()
|
|||||||
\a name as the name parameter of the form-data. The returned reference is
|
\a name as the name parameter of the form-data. The returned reference is
|
||||||
valid until the next call to this function.
|
valid until the next call to this function.
|
||||||
|
|
||||||
|
Limiting \a name characters to US-ASCII is
|
||||||
|
\l {https://datatracker.ietf.org/doc/html/rfc7578#section-5.1.1}{strongly recommended}
|
||||||
|
for interoperability reasons.
|
||||||
|
|
||||||
\sa QFormDataPartBuilder, QHttpPart
|
\sa QFormDataPartBuilder, QHttpPart
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QFormDataPartBuilder &QFormDataBuilder::part(QLatin1StringView name)
|
QFormDataPartBuilder &QFormDataBuilder::part(QAnyStringView name)
|
||||||
{
|
{
|
||||||
static_assert(std::is_nothrow_move_constructible_v<decltype(m_parts)>);
|
static_assert(std::is_nothrow_move_constructible_v<decltype(m_parts)>);
|
||||||
static_assert(std::is_nothrow_move_assignable_v<decltype(m_parts)>);
|
static_assert(std::is_nothrow_move_assignable_v<decltype(m_parts)>);
|
||||||
|
@ -32,7 +32,7 @@ class QFormDataPartBuilder
|
|||||||
{
|
{
|
||||||
struct PrivateConstructor { explicit PrivateConstructor() = default; };
|
struct PrivateConstructor { explicit PrivateConstructor() = default; };
|
||||||
public:
|
public:
|
||||||
Q_NETWORK_EXPORT explicit QFormDataPartBuilder(QLatin1StringView name, PrivateConstructor);
|
Q_NETWORK_EXPORT explicit QFormDataPartBuilder(QAnyStringView name, PrivateConstructor);
|
||||||
|
|
||||||
QFormDataPartBuilder(QFormDataPartBuilder &&other) noexcept
|
QFormDataPartBuilder(QFormDataPartBuilder &&other) noexcept
|
||||||
: m_headerValue(std::move(other.m_headerValue)),
|
: m_headerValue(std::move(other.m_headerValue)),
|
||||||
@ -109,7 +109,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Q_NETWORK_EXPORT ~QFormDataBuilder();
|
Q_NETWORK_EXPORT ~QFormDataBuilder();
|
||||||
Q_NETWORK_EXPORT QFormDataPartBuilder &part(QLatin1StringView name);
|
Q_NETWORK_EXPORT QFormDataPartBuilder &part(QAnyStringView name);
|
||||||
Q_NETWORK_EXPORT std::unique_ptr<QHttpMultiPart> buildMultiPart();
|
Q_NETWORK_EXPORT std::unique_ptr<QHttpMultiPart> buildMultiPart();
|
||||||
private:
|
private:
|
||||||
std::vector<QFormDataPartBuilder> m_parts;
|
std::vector<QFormDataPartBuilder> m_parts;
|
||||||
|
@ -29,6 +29,9 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void specifyMimeType_data();
|
void specifyMimeType_data();
|
||||||
void specifyMimeType();
|
void specifyMimeType();
|
||||||
|
|
||||||
|
void picksUtf8NameEncodingIfAsciiDoesNotSuffice_data();
|
||||||
|
void picksUtf8NameEncodingIfAsciiDoesNotSuffice();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QFormDataBuilder::generateQHttpPartWithDevice_data()
|
void tst_QFormDataBuilder::generateQHttpPartWithDevice_data()
|
||||||
@ -325,6 +328,35 @@ void tst_QFormDataBuilder::specifyMimeType()
|
|||||||
QVERIFY(msg.contains(expected_content_type_data));
|
QVERIFY(msg.contains(expected_content_type_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QFormDataBuilder::picksUtf8NameEncodingIfAsciiDoesNotSuffice_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QAnyStringView>("name_data");
|
||||||
|
QTest::addColumn<QString>("expected_content_disposition_data");
|
||||||
|
|
||||||
|
QTest::newRow("latin1-ascii") << QAnyStringView("text"_L1) << uR"(form-data; name="text")"_s;
|
||||||
|
QTest::newRow("u8-ascii") << QAnyStringView(u8"text") << uR"(form-data; name="text")"_s;
|
||||||
|
QTest::newRow("u-ascii") << QAnyStringView(u"text") << uR"(form-data; name="text")"_s;
|
||||||
|
|
||||||
|
// 0xF6 is 'ö', use hex value with Latin-1 to avoid interpretation as UTF-8
|
||||||
|
QTest::newRow("latin1-latin") << QAnyStringView("t\xF6xt"_L1) << uR"(form-data; name="töxt")"_s;
|
||||||
|
QTest::newRow("u8-latin") << QAnyStringView(u8"töxt") << uR"(form-data; name="töxt")"_s;
|
||||||
|
QTest::newRow("u-latin") << QAnyStringView(u"töxt") << uR"(form-data; name="töxt")"_s;
|
||||||
|
|
||||||
|
QTest::newRow("u8-u8") << QAnyStringView(u8"テキスト") << uR"(form-data; name="テキスト")"_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QFormDataBuilder::picksUtf8NameEncodingIfAsciiDoesNotSuffice()
|
||||||
|
{
|
||||||
|
QFETCH(const QAnyStringView, name_data);
|
||||||
|
QFETCH(const QString, expected_content_disposition_data);
|
||||||
|
|
||||||
|
QFormDataBuilder qfdb;
|
||||||
|
QFormDataPartBuilder &qfdpb = qfdb.part(name_data).setBody("some"_ba);
|
||||||
|
auto msg = QDebug::toString(qfdpb.build());
|
||||||
|
|
||||||
|
QVERIFY2(msg.contains(expected_content_disposition_data),
|
||||||
|
qPrintable(u"content-disposition not found : "_s + expected_content_disposition_data));
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QFormDataBuilder)
|
QTEST_MAIN(tst_QFormDataBuilder)
|
||||||
#include "tst_qformdatabuilder.moc"
|
#include "tst_qformdatabuilder.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user