Commit Graph

18 Commits (bb10)

Author SHA1 Message Date
Marc Mutz 678c839575 QFormDataBuilder: add options
There are (at least) three RFCs, all non-obsolete, purporting to guard
the formatting of multipart/form-data filename parameters, and they
all disagree: RFC 6266, RFC 7578 and RFC 8187. There is also
considerable implementation divergence.

So, to not have to hard-code any one of the different strategies, add
Options controlling the formatting.

Found to be required in implementation review.

Task-number: QTBUG-125985
Change-Id: Ibc82ff8a3460580ee70eafcaf9b88de36751940d
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Mate Barany <mate.barany@qt.io>
(cherry picked from commit 49ab4f156b7d1a0593f25680d0b841d2dc4c348e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-07-12 11:45:55 +00:00
Mate Barany 04787eef80 Apply the PIMPL idiom to QFormDataPartBuilder
Change QFormDataBuilderPrivate to store a vector of
QFormDataPartBuilderPrivates and pimplify QFormDataPartBuilder such that
it stores a pointer to the QFormDataBuilderPrivate and an index into the
vector. This makes it robust against QFDP::m_parts reallocations and we
can make QFDBP copyable which has the benefit that if the user wants to
"go back" to an earlier part, she can do so by storing the result of the
original part() call by value.

Found in API review.

Task-number: QTBUG-125985
Change-Id: I56e9018e539457e9494751bdb62509f84a680889
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit aca8235c753d673abe7442cdf8b628fe4e05c471)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-07-05 15:55:31 +00:00
Marc Mutz e2ffa8ddf6 Port tst_QFormDataBuilder to new style [6/6]: picksUtf8NameEncodingIfAsciiDoesNotSuffice()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for picksUtf8NameEncodingIfAsciiDoesNotSuffice(), too.

Requires to revert the needles from QString back to QByteArray.

This completes the port away from QFormDataPartBuilder::build() use in
the tests, allowing us to remove the tst_QFormDataBuilder friend
declaration and unexport build().

Task-number: QTBUG-125985
Change-Id: Icae84f54c6f768e097b36b4c4f964eeb6d676809
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit d0b0fe76663a4c7fe007cb66afa936ea7fe3d918)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:11:01 +00:00
Marc Mutz 53d9f99a08 Port tst_QFormDataBuilder to new style [5/6]: specifyMimeType()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for specifyMimeType(), too.

Requires to actually open the QBuffer and to revert the needles from
QString back to QByteArray.

Also anchor the needle between two CRLFs, because they each represent
one full header field. This is like anchoring a regex with ^~~~$.

As a drive-by, use QVERIFY2().

Task-number: QTBUG-125985
Change-Id: I8f7830e49d05044ef7388338498c96334a489c90
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 9bcf320fc1d3b484a39d692fd2c69c96f05e63e4)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:55 +00:00
Marc Mutz 1fc54987d4 Port tst_QFormDataBuilder to new style [4/6]: setHeadersDoesNotAffectHeaderFieldsManagedByBuilder()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for setHeadersDoesNotAffectHeaderFieldsManagedByBuilder(), too.

Requires to actually open the QBuffer and to revert the needles from
QString back to QByteArray.

Also anchor the needles with a CRLF on each side, because they each
represent one full header field. This is like anchoring a regex using
^~~~$.

As a drive-by, fix indentation and brace placement of initializer_list
QList consruction and rely on CTAD to deduce QByteArrayList from QList{}.

Task-number: QTBUG-125985
Change-Id: I405b5d67212e906a3b914d9e5b815835bdee5bc6
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit ab859d5f96855eeec50f3b39c925203ba7def73f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:47 +00:00
Marc Mutz a8f7a59b07 tst_QFormDataBuilder: give \r\n a symbolic name
... CRLF, what else?

Change-Id: Ibefb83495c34034a6727a0eaa42d8b312e0594ac
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit aeb1b9b48746395fc6680aa3fdda3469826b7ae8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:41 +00:00
Marc Mutz df6a26d9f0 Port tst_QFormDataBuilder to new style [3/6]: picksUtf8FilenameEncodingIfAsciiDontSuffice()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for picksUtf8FilenameEncodingIfAsciiDontSuffice(), too.

Requires to actually open the QBuffer and to revert the needles from
QString back to QByteArray.

Task-number: QTBUG-125985
Change-Id: I13c41e8df86296ae8652c460039798eb529d4628
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 2541f1945d2a64de7b2c13465a178ef70d96da89)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:35 +00:00
Marc Mutz 95590adb55 Port tst_QFormDataBuilder to new style [2/6]: escapesBackslashAndQuotesInFilenameAndName()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for escapesBackslashAndQuotesInFilenameAndName(), too.

Requires to actually open dummy_file (so make it a QBuffer, because
there's no file of that name in the filesystem) and to revert the
needles from QString back to QByteArray.

Task-number: QTBUG-125985
Change-Id: I888b3cac45ed24b2e877dc1642a95e3f1d64f2ff
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 14f68c9d44472966a66b5cf3b16f4fc7f60068ca)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:28 +00:00
Marc Mutz 7c9e8b1613 Port tst_QFormDataBuilder to new style [1/6]: generateQHttpPartWithDevice()
We don't want to have to rely on QDebug:toString() and the private
QFormDataPartBuilder::build() function for checks, so use the
framework originally introduced by Máté for the the moveSemantics()
test for generateQHttpPartWithDevice(), too.

Requires to actually open data_file and to revert the needles from
QString back to QByteArray.

Task-number: QTBUG-125985
Change-Id: Ie4518fedb58530ae98b44f1ba9e000e6f088ba86
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 4b21146ded83badfeb9f2c905f6602ff460adc63)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:22 +00:00
Marc Mutz ac1e88f58a tst_QFormDataBuilder: DRY the moveSemantics() test
Packages everything needed to build the actual serialization into a
helper function that's parametrized with a function_ref. Said helper
provides the function_ref with a default-constructed QFormDataBuilder
as an argument to the function, but since we're checking move
semantics here, it also expects to receive, via the return type, the
builder object to eventually use for building. This need not be the
same as the one it originally supplied.

If this looks a bit complicated, it's a necessary evil for
conveniently rolling out this way of performing the test to the rest
of the test functions, to eventually, finally get rid of using QDebug
to introspect individual QHttpParts when, in reality, we're only
interested in the QHttpMultiPart's wire serialization (iow: the
observable behavior).

Centralize the QSKIP in the helper function. This increases compile
coverage of the rest of the code, but requires QTEST_THROW_ON_SKIP,
so add a check for that alongside the QTEST_THROW_ON_FAIL one.

Task-number: QTBUG-125985
Change-Id: Ib6217a02159c79f48f0036e90d7bbbf43e69d0ba
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 9fcafa715ecb1c6e45fc51d599178bbde3cc1b12)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:15 +00:00
Marc Mutz 511e7fc9e8 tst_QFormDataBuilder: QVERIFY that QIODevice::open() succeeded
... so we don't have to guess around when the follow-up
checkBodyPartsAreEquivalent() fails.

Task-number: QTBUG-125985
Change-Id: I008eb7a1fa1c5457a5405838730d9e98b1cc20b4
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 4da130838ba0a0f4f7c659f8c58f7bb4304b032c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 23:10:08 +00:00
Mate Barany 4ca0c6db5e Add move semantics autotest for QFormDataBuilder
Change-Id: If9df38f0afd09218c15587b2864edb957cbbdaac
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit 12d2ba9c913d03d637ffb9d123949a5f45e69e5e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-20 19:30:13 +00:00
Juha Vuolle 78784065a8 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.

Change-Id: I54d1148bf95dece54b75c76914c49985da05e0b2
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit 6b23a3c5e4316c5f889ea5e9bbfd785b78716268)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-18 17:08:34 +00:00
Juha Vuolle b5dde79bc4 Adjust multipart 'filename' parameter encoding
The RFCs around these encodings are loose and allow
several ways for dealing with non-ASCII characters.
The encoding introduced in this commit should be
interoperable and aligns with other frameworks
(checked Curl, JS FormData, Postman, and Python
requests).

This consists of several adjustments:

1. Enclose the filename attribute in double quotes
2. If filename contains only ASCII characters, use them as-is
3. If filename contains characters beyond ASCII:
3.1. Encode them directly as raw UTF-8 to filename=
3.2. Set an additional filename*= parameter with
     percent encoded UTF-8. This is a legacy encoding
     for compatibility.

Task-number: QTBUG-125985
Change-Id: I5a6ad5388e4bb69e142caa7f6de7127526f441ad
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 8c8a0c06d4f77ba8a707ec0a101b423543bf30f0)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-18 17:08:31 +00:00
Mate Barany 0a57b0e542 Refactor test cases in tst_qformdatabuilder
Hide the construction details of QFormDataPartBuilder, change
the verification to be QString based instead of QByteArray based,
and use raw string literals (where useful) for readability.

Task-number: QTBUG-114647
Change-Id: I16fb6c943cf6fd7385e78bbffe3b2780ab0a6ac8
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit cb8abb718da4e18232de525ef1bb611f3a5dd929)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-18 17:08:21 +00:00
Mate Barany 885a49548d Add some missing tests for QFormDataBuilder
Test the setHeaders method and the option of manually setting the mime
type.

Task-number: QTBUG-114647
Change-Id: I86644b243830259156e60239adf370e5894450dc
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 132498a69a626be6feaf1855cf63dd79d1ac9445)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2024-06-13 20:34:42 +00:00
Marc Mutz 5677c111cb QFormData(Part)Builder: simplify filename formatting
We don't need the bodyName member, because it's the same as
originalBodyName, just encoded, and we can delay the encoding to
build() time.

This is not worse than the old code, since we anyway toString() the
QAnyStringView unconditionally.

So we don't need to visit the QASV and implement RFC2232 encoding for
all three view types, we can just use the QString version, after
toString().

This not only has the advantage of less code and not storing duplicate
data, but we now also encode u8"ä.txt" the same as "ä.txt"_L1 and
u"ä.txt", ie. using latin1, as required by Postel's Law, and not as
UTF-8, as the old code did.

Change-Id: If82a33a1cd09b859b3a4450a60083b1d3aedf7bc
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2024-05-30 20:52:42 +02:00
Mate Barany 32610561e3 Add convenience classes to generate QHttpMultipart messages
Constructing and composing a QHttpMultipart contains some aspects that
are possible candidates for automating, such as setting the headers
manually for each included part. As a reference, when issuing a default
multipart with CURL, one does not need to manually set the headers.

Add the class QFormDataPartBuilder to simplify the construction of
QHttpPart objects.

Add the class QFormDataBuilder to simplify the construction of
QHttpMultiPart objects.

[ChangeLog][QtNetwork][QFormDataBuilder] New class to help constructing
multipart/form-data QHttpMultiParts.

Fixes: QTBUG-114647
Change-Id: Ie035dabc01a9818d65a67c239807b50001fd984a
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
2024-05-30 18:52:42 +00:00