summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuha Vuolle <[email protected]>2024-06-07 11:46:55 +0300
committerMarc Mutz <[email protected]>2024-06-18 13:56:12 +0000
commit6b23a3c5e4316c5f889ea5e9bbfd785b78716268 (patch)
tree5f30e89cd3d0be47d6597eab75dd8d56e310dd75
parent8c8a0c06d4f77ba8a707ec0a101b423543bf30f0 (diff)
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 <[email protected]>
-rw-r--r--src/network/access/qformdatabuilder.cpp30
-rw-r--r--src/network/access/qformdatabuilder.h4
-rw-r--r--tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp32
3 files changed, 61 insertions, 5 deletions
diff --git a/src/network/access/qformdatabuilder.cpp b/src/network/access/qformdatabuilder.cpp
index 2cb5cc1f0e8..986286a1213 100644
--- a/src/network/access/qformdatabuilder.cpp
+++ b/src/network/access/qformdatabuilder.cpp
@@ -28,17 +28,37 @@ QT_BEGIN_NAMESPACE
\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
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_assignable_v<decltype(m_body)>);
+ const auto enc = name.visit([](auto name) { return nameToByteArray(name); });
+
m_headerValue += "form-data; name=\"";
- for (auto c : name) {
+ for (auto c : enc) {
if (c == '"' || c == '\\')
m_headerValue += '\\';
m_headerValue += c;
@@ -292,10 +312,14 @@ QFormDataBuilder::~QFormDataBuilder()
\a name as the name parameter of the form-data. The returned reference is
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
*/
-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_assignable_v<decltype(m_parts)>);
diff --git a/src/network/access/qformdatabuilder.h b/src/network/access/qformdatabuilder.h
index 68f9f3742c3..332a5e43166 100644
--- a/src/network/access/qformdatabuilder.h
+++ b/src/network/access/qformdatabuilder.h
@@ -32,7 +32,7 @@ class QFormDataPartBuilder
{
struct PrivateConstructor { explicit PrivateConstructor() = default; };
public:
- Q_NETWORK_EXPORT explicit QFormDataPartBuilder(QLatin1StringView name, PrivateConstructor);
+ Q_NETWORK_EXPORT explicit QFormDataPartBuilder(QAnyStringView name, PrivateConstructor);
QFormDataPartBuilder(QFormDataPartBuilder &&other) noexcept
: m_headerValue(std::move(other.m_headerValue)),
@@ -109,7 +109,7 @@ public:
}
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();
private:
std::vector<QFormDataPartBuilder> m_parts;
diff --git a/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp
index 2dd86e7be58..154edc806c1 100644
--- a/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp
+++ b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp
@@ -29,6 +29,9 @@ private Q_SLOTS:
void specifyMimeType_data();
void specifyMimeType();
+
+ void picksUtf8NameEncodingIfAsciiDoesNotSuffice_data();
+ void picksUtf8NameEncodingIfAsciiDoesNotSuffice();
};
void tst_QFormDataBuilder::generateQHttpPartWithDevice_data()
@@ -325,6 +328,35 @@ void tst_QFormDataBuilder::specifyMimeType()
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)
#include "tst_qformdatabuilder.moc"