Skip to content

Commit 2c0f892

Browse files
committed
toCurlCommand method has been added
1 parent bf3c431 commit 2c0f892

File tree

5 files changed

+143
-11
lines changed

5 files changed

+143
-11
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Modern, non-blocking and exception free HTTP Client library for C++ (17+)
2828
* [How to set timeout?](#how-to-set-timeout)
2929
* [Setting the User Agent](#setting-the-user-agent)
3030
* [How can I limit download and upload bandwidth?](#how-can-i-limit-download-and-upload-bandwidth)
31+
* [How do I get the request as a curl command?](#how-do-i-get-the-request-as-a-curl-command)
3132
* [Semantic Versioning](#semantic-versioning)
3233
* [Full function list](#full-function-list)
3334
* [License](#license)
@@ -488,6 +489,35 @@ int main() {
488489
```
489490

490491

492+
## How do I get the request as a curl command?
493+
494+
If you want to receive the request as a curl command, you can call the toCurlCommand method after making the necessary preparations.
495+
496+
```cpp
497+
#include <fstream>
498+
#include "libcpp-http-client.hpp"
499+
500+
using namespace lklibs;
501+
502+
int main() {
503+
HttpRequest httpRequest("https://api.myproject.com");
504+
505+
auto response = httpRequest
506+
.setMethod(HttpMethod::POST)
507+
.setPayload(R"({"param1": 7, "param2": "test"})")
508+
.addHeader("Content-Type", "application/json")
509+
.setTimeout(3)
510+
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0")
511+
.setDownloadBandwidthLimit(10240)
512+
.setUploadBandwidthLimit(20480);
513+
514+
std::string curlCommand = response.toCurlCommand();
515+
516+
return 0;
517+
}
518+
```
519+
520+
491521
## Semantic Versioning
492522

493523
Versioning of the library is done using conventional semantic versioning. Accordingly,

examples/main.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,22 @@ void setDownloadAndUploadBandwidthLimit()
248248
std::cout << "Data: " << response.textData << std::endl;
249249
}
250250

251+
void getCurlCommand()
252+
{
253+
HttpRequest httpRequest("https://httpbun.com/post");
254+
255+
auto response = httpRequest
256+
.setMethod(HttpMethod::POST)
257+
.setPayload(R"({"param1": 7, "param2": "test"})")
258+
.addHeader("Content-Type", "application/json")
259+
.setTimeout(3)
260+
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0")
261+
.setDownloadBandwidthLimit(10240)
262+
.setUploadBandwidthLimit(20480);
263+
264+
// You can convert the request to a cURL command string with toCurlCommand method
265+
std::cout << "Curl Command: " << response.toCurlCommand() << std::endl;
266+
}
251267

252268
int main()
253269
{
@@ -281,5 +297,7 @@ int main()
281297

282298
setDownloadAndUploadBandwidthLimit();
283299

300+
getCurlCommand();
301+
284302
return 0;
285303
}

src/libcpp-http-client.hpp

Lines changed: 71 additions & 3 deletions
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.3.1
4+
version 1.4.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,7 +38,7 @@ SOFTWARE.
3838
#include <map>
3939
#include <memory>
4040
#include <mutex>
41-
#include <cstdlib>
41+
#include <sstream>
4242
#include <curl/curl.h>
4343

4444
namespace lklibs
@@ -76,7 +76,7 @@ namespace lklibs
7676

7777
HttpResult() = default;
7878

79-
HttpResult(bool succeed, std::string textData, std::vector<unsigned char> binaryData, int statusCode, std::string errorMessage)
79+
HttpResult(const bool succeed, std::string textData, std::vector<unsigned char> binaryData, const int statusCode, std::string errorMessage)
8080
: succeed(succeed), textData(std::move(textData)), binaryData(std::move(binaryData)), statusCode(statusCode), errorMessage(std::move(errorMessage))
8181
{
8282
}
@@ -303,6 +303,55 @@ namespace lklibs
303303
return *this;
304304
}
305305

306+
/**
307+
* @brief Convert the request to a cURL command string
308+
* This can be useful for debugging or logging purposes
309+
*
310+
* @return cURL command string representing the request
311+
*/
312+
[[nodiscard]] std::string toCurlCommand() const noexcept
313+
{
314+
std::ostringstream cmd;
315+
316+
cmd << "curl";
317+
318+
cmd << " -X " << method;
319+
320+
for (const auto& header : headers)
321+
{
322+
cmd << " -H \"" << header.first << ": " << header.second << "\"";
323+
}
324+
325+
if (!userAgent.empty())
326+
{
327+
cmd << " -A \"" << userAgent << "\"";
328+
}
329+
330+
if (timeout > 0)
331+
{
332+
cmd << " --max-time " << timeout;
333+
}
334+
335+
if (sslErrorsWillBeIgnored)
336+
{
337+
cmd << " -k";
338+
}
339+
340+
if (downloadBandwidthLimit > 0)
341+
{
342+
cmd << " --limit-rate " << downloadBandwidthLimit;
343+
}
344+
345+
if (!payload.empty())
346+
{
347+
cmd << " --data '" << escapeSingleQuotes(payload) << "'";
348+
}
349+
350+
cmd << " \"" << url << "\"";
351+
352+
return cmd.str();
353+
}
354+
306355
/**
307356
* @brief Send the HTTP request and return the result as a future
308357
* The result can be obtained by calling the get() method of the future
@@ -458,6 +507,25 @@ namespace lklibs
458507

459508
return size * nmemb;
460509
}
510+
511+
static std::string escapeSingleQuotes(const std::string& input)
512+
{
513+
std::string output;
514+
515+
for (const char c : input)
516+
{
517+
if (c == '\'')
518+
{
519+
output += "'\\''";
520+
}
521+
else
522+
{
523+
output += c;
524+
}
525+
}
526+
527+
return output;
528+
}
461529
};
462530
}
463531

test/test.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ TEST(HttpGetTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpGetRequestMade
105105

106106
TEST(HttpGetTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpGetRequestForAnotherError)
107107
{
108-
HttpRequest httpRequest("https://httpbun.com/bearer");
108+
HttpRequest httpRequest("https://httpbun.com/bearer/123");
109109

110110
auto response = httpRequest.send().get();
111111

@@ -246,7 +246,7 @@ TEST(HttpPostTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPostRequestMa
246246

247247
TEST(HttpPostTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPostRequestForAnotherError)
248248
{
249-
HttpRequest httpRequest("https://httpbun.com/bearer");
249+
HttpRequest httpRequest("https://httpbun.com/bearer/123");
250250

251251
auto response = httpRequest
252252
.setMethod(HttpMethod::POST)
@@ -393,7 +393,7 @@ TEST(HttpPutTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPutRequestMade
393393

394394
TEST(HttpPutTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPutRequestForAnotherError)
395395
{
396-
HttpRequest httpRequest("https://httpbun.com/bearer");
396+
HttpRequest httpRequest("https://httpbun.com/bearer/123");
397397

398398
auto response = httpRequest
399399
.setMethod(HttpMethod::PUT)
@@ -540,7 +540,7 @@ TEST(HttpDeleteTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpDeleteReque
540540

541541
TEST(HttpDeleteTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpDeleteRequestForAnotherError)
542542
{
543-
HttpRequest httpRequest("https://httpbun.com/bearer");
543+
HttpRequest httpRequest("https://httpbun.com/bearer/123");
544544

545545
auto response = httpRequest
546546
.setMethod(HttpMethod::DELETE_)
@@ -685,7 +685,7 @@ TEST(HttpPatchTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPatchRequest
685685

686686
TEST(HttpPatchTest, AnErrorMessageShouldBeReturnedInResponseToAnHttpPatchRequestForAnotherError)
687687
{
688-
HttpRequest httpRequest("https://httpbun.com/bearer");
688+
HttpRequest httpRequest("https://httpbun.com/bearer/123");
689689

690690
auto response = httpRequest.setMethod(HttpMethod::PATCH).send().get();
691691

@@ -825,6 +825,22 @@ TEST(BandwidthLimitTest, UploadBandwidthLimitCanBeSet)
825825
ASSERT_TRUE(response.errorMessage.empty()) << "HTTP Error Message is not empty";
826826
}
827827

828+
TEST(CurlCommandTest, CurlCommandCanBeGet)
829+
{
830+
HttpRequest httpRequest("https://httpbun.com/post");
831+
832+
auto response = httpRequest
833+
.setMethod(HttpMethod::POST)
834+
.setPayload(R"({"param1": 7, "param2": "test"})")
835+
.addHeader("Content-Type", "application/json")
836+
.setTimeout(3)
837+
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0")
838+
.setDownloadBandwidthLimit(10240)
839+
.setUploadBandwidthLimit(20480);
840+
841+
ASSERT_EQ(response.toCurlCommand(), "curl -X POST -H \"Content-Type: application/json\" -A \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0\" --max-time 3 --limit-rate 10240 --data '{\"param1\": 7, \"param2\": \"test\"}' \"https://httpbun.com/post\"") << "Curl command is invalid";
842+
}
843+
828844
int main(int argc, char** argv)
829845
{
830846
testing::InitGoogleTest(&argc, argv);

vcpkg.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
"builtin-baseline" : "0719a71389654b88d827501d88e37e58ea8cbd70",
55
"dependencies" : [ {
66
"name" : "gtest",
7-
"version>=" : "1.14.0"
7+
"version>=" : "1.17.0#1"
88
}, {
99
"name" : "nlohmann-json",
10-
"version>=" : "3.11.3"
10+
"version>=" : "3.12.0"
1111
}, {
1212
"name" : "curl",
13-
"version>=" : "8.7.1#3"
13+
"version>=" : "8.15.0"
1414
} ]
1515
}

0 commit comments

Comments
 (0)