fix(http): Send multipart body for PUT (#6746)

This commit is contained in:
Nerixyz
2026-01-18 12:47:44 +01:00
committed by GitHub
parent 00c6905a46
commit 282a96660f
3 changed files with 123 additions and 3 deletions
+1
View File
@@ -89,6 +89,7 @@
- Dev: Refactored types used for emoji parsing. (#6714)
- Dev: `LinkParser` now parses `QStringView`s. (#6715)
- Dev: Cleaned up `AccountController` connections. (#6735)
- Dev: Send multipart body for HTTP `PUT` requests. (#6746)
- Dev: Removed unused variables. (#6748)
## 2.5.4
+20 -3
View File
@@ -87,12 +87,24 @@ QNetworkReply *NetworkTask::createReply()
case NetworkRequestType::Get:
return accessManager->get(request);
case NetworkRequestType::Put:
return accessManager->put(request, data->payload);
case NetworkRequestType::Delete:
return accessManager->deleteResource(data->request);
case NetworkRequestType::Put:
if (data->multiPartPayload)
{
assert(data->payload.isNull());
return accessManager->put(request,
data->multiPartPayload.get());
}
else
{
assert(data->multiPartPayload == nullptr);
return accessManager->put(request, data->payload);
}
case NetworkRequestType::Post:
if (data->multiPartPayload)
{
@@ -103,8 +115,11 @@ QNetworkReply *NetworkTask::createReply()
}
else
{
assert(data->multiPartPayload == nullptr);
return accessManager->post(request, data->payload);
}
case NetworkRequestType::Patch:
if (data->multiPartPayload)
{
@@ -115,6 +130,8 @@ QNetworkReply *NetworkTask::createReply()
}
else
{
assert(data->multiPartPayload == nullptr);
return NetworkManager::accessManager->sendCustomRequest(
request, "PATCH", data->payload);
}
+102
View File
@@ -8,6 +8,7 @@
#include "common/network/NetworkResult.hpp"
#include "NetworkHelpers.hpp"
#include "Test.hpp"
#include "util/QMagicEnum.hpp"
#include <QCoreApplication>
@@ -25,6 +26,24 @@ QString getDelayURL(int delay)
return QString("%1/delay/%2").arg(HTTPBIN_BASE_URL).arg(delay);
}
QString getHttpbinUrl(QStringView path)
{
return QString("%1/%2").arg(HTTPBIN_BASE_URL, path);
}
QHttpMultiPart *makeMultipart()
{
auto *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart part;
part.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"text\""));
part.setBody("my text");
multipart->append(part);
return multipart;
}
} // namespace
TEST(NetworkRequest, Success)
@@ -281,3 +300,86 @@ TEST(NetworkRequest, BatchedTimeouts)
}
#endif
}
TEST(NetworkRequest, HttpGetHeaders)
{
EXPECT_TRUE(NetworkManager::workerThread->isRunning());
RequestWaiter waiter;
NetworkRequest(getHttpbinUrl(u"headers"), NetworkRequestType::Get)
.timeout(1000)
.onSuccess([&](const NetworkResult &result) {
// make sure we don't attempt to send a body
auto body = QString::fromUtf8(result.getData());
EXPECT_FALSE(body.contains("content-length", Qt::CaseInsensitive));
waiter.requestDone();
})
.execute();
waiter.waitForRequest();
}
TEST(NetworkRequest, HttpBody)
{
EXPECT_TRUE(NetworkManager::workerThread->isRunning());
for (auto ty : std::array{
NetworkRequestType::Post,
NetworkRequestType::Put,
NetworkRequestType::Patch,
})
{
auto path = qmagicenum::enumNameString(ty).toLower();
RequestWaiter waiter;
bool success = false;
NetworkRequest(getHttpbinUrl(path), ty)
.timeout(1000)
.payload("foobar")
.header("Content-Type", "text/plain")
.onSuccess([&](const NetworkResult &result) {
EXPECT_EQ(result.getData(), "foobar") << path;
success = true;
})
.finally([&] {
waiter.requestDone();
})
.execute();
waiter.waitForRequest();
ASSERT_TRUE(success) << path;
}
}
TEST(NetworkRequest, HttpBodyMultipart)
{
EXPECT_TRUE(NetworkManager::workerThread->isRunning());
for (auto ty : std::array{
NetworkRequestType::Post,
NetworkRequestType::Put,
NetworkRequestType::Patch,
})
{
auto path = qmagicenum::enumNameString(ty).toLower();
RequestWaiter waiter;
bool success = false;
NetworkRequest(getHttpbinUrl(path), ty)
.timeout(1000)
.multiPart(makeMultipart())
.onSuccess([&](const NetworkResult &result) {
auto body = QString::fromUtf8(result.getData());
EXPECT_TRUE(body.contains("Content-Disposition: form-data; "
"name=\"text\"\r\n\r\nmy text",
Qt::CaseInsensitive))
<< "Path:" << path << "Body:" << body;
success = true;
})
.finally([&] {
waiter.requestDone();
})
.execute();
waiter.waitForRequest();
ASSERT_TRUE(success) << path;
}
}