Skip to content

Commit 46265d4

Browse files
author
Levent KARAGÖL
committed
addMultipartFormData method has been added
1 parent 994bc43 commit 46265d4

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ HttpRequest& setQueryString(const std::string& queryString) noexcept;
583583

584584
HttpRequest& setPayload(const std::string& payload) noexcept;
585585

586+
HttpRequest& addMultipartFormData(const std::string& name, const std::string& data, const std::optional<std::string>& mimeType = std::nullopt) noexcept;
587+
586588
HttpRequest& returnAsBinary() noexcept;
587589

588590
HttpRequest& addHeader(const std::string& key, const std::string& value) noexcept;

src/libcpp-http-client.hpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
33
Modern, non-blocking and exception free HTTP Client library for C++ (17+)
4-
version 1.6.0
4+
version 1.7.0
55
https://github.com/leventkaragol/libcpp-http-client
66
77
If you encounter any issues, please submit a ticket at https://github.com/leventkaragol/libcpp-http-client/issues
@@ -38,6 +38,7 @@ SOFTWARE.
3838
#include <map>
3939
#include <memory>
4040
#include <mutex>
41+
#include <optional>
4142
#include <sstream>
4243
#include <curl/curl.h>
4344

@@ -234,6 +235,20 @@ namespace lklibs
234235
return *this;
235236
}
236237

238+
/**
239+
* @brief Set the file data to be sent with the request as multipart/form-data
240+
*
241+
* @param name: Name of the form field
242+
* @param data: Path to the file to be sent
243+
* @param mimeType: Optional MIME type of the file
244+
*/
245+
HttpRequest& addMultipartFormData(const std::string& name, const std::string& data, const std::optional<std::string>& mimeType = std::nullopt) noexcept
246+
{
247+
this->formData[name] = FormData{data, mimeType};
248+
249+
return *this;
250+
}
251+
237252
/**
238253
* @brief Set the timeout for the request
239254
*
@@ -393,9 +408,16 @@ namespace lklibs
393408
"PATCH"
394409
};
395410

411+
struct FormData
412+
{
413+
std::string data;
414+
std::optional<std::string> mimeType;
415+
};
416+
396417
std::string url;
397418
std::string method = "GET";
398419
std::string payload;
420+
std::map<std::string, FormData> formData;
399421
std::string userAgent;
400422
bool sslErrorsWillBeIgnored = false;
401423
ReturnFormat returnFormat = ReturnFormat::TEXT;
@@ -479,6 +501,31 @@ namespace lklibs
479501
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, this->payload.c_str());
480502
}
481503

504+
const std::unique_ptr<curl_mime, decltype(&curl_mime_free)> mime(curl_mime_init(curl.get()), &curl_mime_free);
505+
506+
if (!this->formData.empty())
507+
{
508+
for (const auto& [field, content] : this->formData)
509+
{
510+
std::unique_ptr<curl_mimepart, std::function<void(curl_mimepart*)>> part(
511+
curl_mime_addpart(mime.get()),
512+
[](curl_mimepart*) {});
513+
514+
curl_mime_name(part.get(), field.c_str());
515+
if (content.mimeType.has_value())
516+
{
517+
curl_mime_filedata(part.get(), content.data.c_str());
518+
curl_mime_type(part.get(), content.mimeType->c_str());
519+
}
520+
else
521+
{
522+
curl_mime_data(part.get(), content.data.c_str(), CURL_ZERO_TERMINATED);
523+
}
524+
}
525+
526+
curl_easy_setopt(curl.get(), CURLOPT_MIMEPOST, mime.get());
527+
}
528+
482529
if (dataCallback)
483530
{
484531
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, streamingWriteCallback);

test/test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@ TEST(HttpPostTest, HttpPostRequestMustBeCompletedSuccessfullyInItsSimplestForm)
164164
ASSERT_EQ(data["form"]["param2"], "test") << "Payload is invalid";
165165
}
166166

167+
TEST(HttpPostTest, HttpPostRequestMustBeCompletedSuccessfullyInItsFormData)
168+
{
169+
HttpRequest httpRequest("https://httpbun.com/post");
170+
171+
auto response = httpRequest
172+
.setMethod(HttpMethod::POST)
173+
.addMultipartFormData("param1", "7")
174+
.addMultipartFormData("param2", "test")
175+
.send()
176+
.get();
177+
178+
ASSERT_TRUE(response.succeed) << "HTTP Request failed";
179+
ASSERT_EQ(response.statusCode, 200) << "HTTP Status Code is not 200";
180+
ASSERT_FALSE(response.textData.empty()) << "HTTP Response is empty";
181+
ASSERT_TRUE(response.binaryData.empty()) << "Binary data is not empty";
182+
ASSERT_TRUE(response.errorMessage.empty()) << "HTTP Error Message is not empty";
183+
184+
auto data = json::parse(response.textData);
185+
186+
ASSERT_EQ(data["method"], "POST") << "HTTP Method is invalid";
187+
ASSERT_EQ(data["form"]["param1"], "7") << "Payload is invalid";
188+
ASSERT_EQ(data["form"]["param2"], "test") << "Payload is invalid";
189+
}
190+
167191
TEST(HttpPostTest, MultipleHttpPostRequestMustBeCompletedSuccessfullyInNonBlockingForm)
168192
{
169193
HttpRequest httpRequest1("https://httpbun.com/post");

0 commit comments

Comments
 (0)