Skip to content

Commit cfb56c0

Browse files
committed
Fix #1818
1 parent 083fe43 commit cfb56c0

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

httplib.h

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,7 @@ class ClientImpl {
13191319
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
13201320
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
13211321
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1322+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
13221323

13231324
Result Put(const std::string &path);
13241325
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1336,6 +1337,7 @@ class ClientImpl {
13361337
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
13371338
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
13381339
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1340+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
13391341

13401342
Result Patch(const std::string &path);
13411343
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1353,6 +1355,7 @@ class ClientImpl {
13531355
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
13541356
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
13551357
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1358+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
13561359

13571360
Result Delete(const std::string &path, DownloadProgress progress = nullptr);
13581361
Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
@@ -1662,6 +1665,7 @@ class Client {
16621665
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
16631666
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
16641667
Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1668+
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
16651669

16661670
Result Put(const std::string &path);
16671671
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1679,6 +1683,7 @@ class Client {
16791683
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
16801684
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
16811685
Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1686+
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
16821687

16831688
Result Patch(const std::string &path);
16841689
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1696,6 +1701,7 @@ class Client {
16961701
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
16971702
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
16981703
Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
1704+
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
16991705

17001706
Result Delete(const std::string &path, DownloadProgress progress = nullptr);
17011707
Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
@@ -9115,6 +9121,32 @@ ClientImpl::Post(const std::string &path, const Headers &headers,
91159121
content_type, progress);
91169122
}
91179123

9124+
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
9125+
const std::string &body,
9126+
const std::string &content_type,
9127+
ContentReceiver content_receiver,
9128+
DownloadProgress progress) {
9129+
Request req;
9130+
req.method = "POST";
9131+
req.path = path;
9132+
req.headers = headers;
9133+
req.body = body;
9134+
req.content_receiver =
9135+
[content_receiver](const char *data, size_t data_length,
9136+
uint64_t /*offset*/, uint64_t /*total_length*/) {
9137+
return content_receiver(data, data_length);
9138+
};
9139+
req.download_progress = std::move(progress);
9140+
9141+
if (max_timeout_msec_ > 0) {
9142+
req.start_time_ = std::chrono::steady_clock::now();
9143+
}
9144+
9145+
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
9146+
9147+
return send_(std::move(req));
9148+
}
9149+
91189150
inline Result ClientImpl::Put(const std::string &path) {
91199151
return Put(path, std::string(), std::string());
91209152
}
@@ -9242,6 +9274,32 @@ ClientImpl::Put(const std::string &path, const Headers &headers,
92429274
content_type, progress);
92439275
}
92449276

9277+
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
9278+
const std::string &body,
9279+
const std::string &content_type,
9280+
ContentReceiver content_receiver,
9281+
DownloadProgress progress) {
9282+
Request req;
9283+
req.method = "PUT";
9284+
req.path = path;
9285+
req.headers = headers;
9286+
req.body = body;
9287+
req.content_receiver =
9288+
[content_receiver](const char *data, size_t data_length,
9289+
uint64_t /*offset*/, uint64_t /*total_length*/) {
9290+
return content_receiver(data, data_length);
9291+
};
9292+
req.download_progress = std::move(progress);
9293+
9294+
if (max_timeout_msec_ > 0) {
9295+
req.start_time_ = std::chrono::steady_clock::now();
9296+
}
9297+
9298+
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
9299+
9300+
return send_(std::move(req));
9301+
}
9302+
92459303
inline Result ClientImpl::Patch(const std::string &path) {
92469304
return Patch(path, std::string(), std::string());
92479305
}
@@ -9374,6 +9432,32 @@ ClientImpl::Patch(const std::string &path, const Headers &headers,
93749432
content_type, progress);
93759433
}
93769434

9435+
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
9436+
const std::string &body,
9437+
const std::string &content_type,
9438+
ContentReceiver content_receiver,
9439+
DownloadProgress progress) {
9440+
Request req;
9441+
req.method = "PATCH";
9442+
req.path = path;
9443+
req.headers = headers;
9444+
req.body = body;
9445+
req.content_receiver =
9446+
[content_receiver](const char *data, size_t data_length,
9447+
uint64_t /*offset*/, uint64_t /*total_length*/) {
9448+
return content_receiver(data, data_length);
9449+
};
9450+
req.download_progress = std::move(progress);
9451+
9452+
if (max_timeout_msec_ > 0) {
9453+
req.start_time_ = std::chrono::steady_clock::now();
9454+
}
9455+
9456+
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
9457+
9458+
return send_(std::move(req));
9459+
}
9460+
93779461
inline Result ClientImpl::Delete(const std::string &path,
93789462
DownloadProgress progress) {
93799463
return Delete(path, Headers(), std::string(), std::string(), progress);
@@ -10679,6 +10763,14 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
1067910763
UploadProgress progress) {
1068010764
return cli_->Post(path, headers, items, provider_items, progress);
1068110765
}
10766+
inline Result Client::Post(const std::string &path, const Headers &headers,
10767+
const std::string &body,
10768+
const std::string &content_type,
10769+
ContentReceiver content_receiver,
10770+
DownloadProgress progress) {
10771+
return cli_->Post(path, headers, body, content_type, content_receiver,
10772+
progress);
10773+
}
1068210774

1068310775
inline Result Client::Put(const std::string &path) { return cli_->Put(path); }
1068410776
inline Result Client::Put(const std::string &path, const Headers &headers) {
@@ -10764,6 +10856,14 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
1076410856
UploadProgress progress) {
1076510857
return cli_->Put(path, headers, items, provider_items, progress);
1076610858
}
10859+
inline Result Client::Put(const std::string &path, const Headers &headers,
10860+
const std::string &body,
10861+
const std::string &content_type,
10862+
ContentReceiver content_receiver,
10863+
DownloadProgress progress) {
10864+
return cli_->Put(path, headers, body, content_type, content_receiver,
10865+
progress);
10866+
}
1076710867

1076810868
inline Result Client::Patch(const std::string &path) {
1076910869
return cli_->Patch(path);
@@ -10853,6 +10953,14 @@ Client::Patch(const std::string &path, const Headers &headers,
1085310953
UploadProgress progress) {
1085410954
return cli_->Patch(path, headers, items, provider_items, progress);
1085510955
}
10956+
inline Result Client::Patch(const std::string &path, const Headers &headers,
10957+
const std::string &body,
10958+
const std::string &content_type,
10959+
ContentReceiver content_receiver,
10960+
DownloadProgress progress) {
10961+
return cli_->Patch(path, headers, body, content_type, content_receiver,
10962+
progress);
10963+
}
1085610964

1085710965
inline Result Client::Delete(const std::string &path,
1085810966
DownloadProgress progress) {

test/test.cc

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5302,6 +5302,195 @@ TEST_F(ServerTest, PatchContentReceiver) {
53025302
ASSERT_EQ("content", res->body);
53035303
}
53045304

5305+
template<typename ClientType>
5306+
void TestWithHeadersAndContentReceiver(
5307+
ClientType& cli,
5308+
std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
5309+
ContentReceiver, DownloadProgress)> request_func) {
5310+
Headers headers;
5311+
headers.emplace("X-Custom-Header", "test-value");
5312+
5313+
std::string received_body;
5314+
auto res = request_func(
5315+
cli, "/content_receiver", headers, "content", "application/json",
5316+
[&](const char *data, size_t data_length) {
5317+
received_body.append(data, data_length);
5318+
return true;
5319+
}, nullptr);
5320+
5321+
ASSERT_TRUE(res);
5322+
EXPECT_EQ(StatusCode::OK_200, res->status);
5323+
EXPECT_EQ("content", received_body);
5324+
}
5325+
5326+
TEST_F(ServerTest, PostWithHeadersAndContentReceiver) {
5327+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5328+
using ClientT = SSLClient;
5329+
#else
5330+
using ClientT = Client;
5331+
#endif
5332+
TestWithHeadersAndContentReceiver<ClientT>(cli_,
5333+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5334+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5335+
return cli.Post(path, headers, body, content_type, receiver, progress);
5336+
});
5337+
}
5338+
5339+
TEST_F(ServerTest, PutWithHeadersAndContentReceiver) {
5340+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5341+
using ClientT = SSLClient;
5342+
#else
5343+
using ClientT = Client;
5344+
#endif
5345+
TestWithHeadersAndContentReceiver<ClientT>(cli_,
5346+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5347+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5348+
return cli.Put(path, headers, body, content_type, receiver, progress);
5349+
});
5350+
}
5351+
5352+
TEST_F(ServerTest, PatchWithHeadersAndContentReceiver) {
5353+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5354+
using ClientT = SSLClient;
5355+
#else
5356+
using ClientT = Client;
5357+
#endif
5358+
TestWithHeadersAndContentReceiver<ClientT>(cli_,
5359+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5360+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5361+
return cli.Patch(path, headers, body, content_type, receiver, progress);
5362+
});
5363+
}
5364+
5365+
template<typename ClientType>
5366+
void TestWithHeadersAndContentReceiverWithProgress(
5367+
ClientType& cli,
5368+
std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
5369+
ContentReceiver, DownloadProgress)> request_func) {
5370+
Headers headers;
5371+
headers.emplace("X-Test-Header", "progress-test");
5372+
5373+
std::string received_body;
5374+
auto progress_called = false;
5375+
5376+
auto res = request_func(
5377+
cli, "/content_receiver", headers, "content", "text/plain",
5378+
[&](const char *data, size_t data_length) {
5379+
received_body.append(data, data_length);
5380+
return true;
5381+
},
5382+
[&](uint64_t /*current*/, uint64_t /*total*/) {
5383+
progress_called = true;
5384+
return true;
5385+
});
5386+
5387+
ASSERT_TRUE(res);
5388+
EXPECT_EQ(StatusCode::OK_200, res->status);
5389+
EXPECT_EQ("content", received_body);
5390+
EXPECT_TRUE(progress_called);
5391+
}
5392+
5393+
TEST_F(ServerTest, PostWithHeadersAndContentReceiverWithProgress) {
5394+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5395+
using ClientT = SSLClient;
5396+
#else
5397+
using ClientT = Client;
5398+
#endif
5399+
TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_,
5400+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5401+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5402+
return cli.Post(path, headers, body, content_type, receiver, progress);
5403+
});
5404+
}
5405+
5406+
TEST_F(ServerTest, PutWithHeadersAndContentReceiverWithProgress) {
5407+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5408+
using ClientT = SSLClient;
5409+
#else
5410+
using ClientT = Client;
5411+
#endif
5412+
TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_,
5413+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5414+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5415+
return cli.Put(path, headers, body, content_type, receiver, progress);
5416+
});
5417+
}
5418+
5419+
TEST_F(ServerTest, PatchWithHeadersAndContentReceiverWithProgress) {
5420+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5421+
using ClientT = SSLClient;
5422+
#else
5423+
using ClientT = Client;
5424+
#endif
5425+
TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_,
5426+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5427+
const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
5428+
return cli.Patch(path, headers, body, content_type, receiver, progress);
5429+
});
5430+
}
5431+
5432+
template<typename ClientType>
5433+
void TestWithHeadersAndContentReceiverError(
5434+
ClientType& cli,
5435+
std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
5436+
ContentReceiver)> request_func) {
5437+
Headers headers;
5438+
headers.emplace("X-Error-Test", "true");
5439+
5440+
std::string received_body;
5441+
auto receiver_failed = false;
5442+
5443+
auto res = request_func(
5444+
cli, "/content_receiver", headers, "content", "text/plain",
5445+
[&](const char *data, size_t data_length) {
5446+
received_body.append(data, data_length);
5447+
receiver_failed = true;
5448+
return false;
5449+
});
5450+
5451+
ASSERT_FALSE(res);
5452+
EXPECT_TRUE(receiver_failed);
5453+
}
5454+
5455+
TEST_F(ServerTest, PostWithHeadersAndContentReceiverError) {
5456+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5457+
using ClientT = SSLClient;
5458+
#else
5459+
using ClientT = Client;
5460+
#endif
5461+
TestWithHeadersAndContentReceiverError<ClientT>(cli_,
5462+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5463+
const std::string& content_type, ContentReceiver receiver) {
5464+
return cli.Post(path, headers, body, content_type, receiver);
5465+
});
5466+
}
5467+
5468+
TEST_F(ServerTest, PuttWithHeadersAndContentReceiverError) {
5469+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5470+
using ClientT = SSLClient;
5471+
#else
5472+
using ClientT = Client;
5473+
#endif
5474+
TestWithHeadersAndContentReceiverError<ClientT>(cli_,
5475+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5476+
const std::string& content_type, ContentReceiver receiver) {
5477+
return cli.Put(path, headers, body, content_type, receiver);
5478+
});
5479+
}
5480+
5481+
TEST_F(ServerTest, PatchWithHeadersAndContentReceiverError) {
5482+
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
5483+
using ClientT = SSLClient;
5484+
#else
5485+
using ClientT = Client;
5486+
#endif
5487+
TestWithHeadersAndContentReceiverError<ClientT>(cli_,
5488+
[](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body,
5489+
const std::string& content_type, ContentReceiver receiver) {
5490+
return cli.Patch(path, headers, body, content_type, receiver);
5491+
});
5492+
}
5493+
53055494
TEST_F(ServerTest, PostQueryStringAndBody) {
53065495
auto res =
53075496
cli_.Post("/query-string-and-body?key=value", "content", "text/plain");

0 commit comments

Comments
 (0)