Skip to content

Commit caa31aa

Browse files
committed
Accept large data transfer over SSL (Fix #1261, Close #1312)
1 parent dae3184 commit caa31aa

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

httplib.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,14 @@ using socket_t = int;
193193
#endif
194194
#endif //_WIN32
195195

196-
#include <cstring>
197196
#include <algorithm>
198197
#include <array>
199198
#include <atomic>
200199
#include <cassert>
201200
#include <cctype>
202201
#include <climits>
203202
#include <condition_variable>
203+
#include <cstring>
204204
#include <errno.h>
205205
#include <fcntl.h>
206206
#include <fstream>
@@ -5098,14 +5098,16 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
50985098

50995099
// Flush buffer
51005100
auto &data = bstrm.get_buffer();
5101-
strm.write(data.data(), data.size());
5101+
detail::write_data(strm, data.data(), data.size());
51025102
}
51035103

51045104
// Body
51055105
auto ret = true;
51065106
if (req.method != "HEAD") {
51075107
if (!res.body.empty()) {
5108-
if (!strm.write(res.body)) { ret = false; }
5108+
if (!detail::write_data(strm, res.body.data(), res.body.size())) {
5109+
ret = false;
5110+
}
51095111
} else if (res.content_provider_) {
51105112
if (write_content_with_provider(strm, req, res, boundary, content_type)) {
51115113
res.content_provider_success_ = true;
@@ -6322,7 +6324,8 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
63226324
auto last = offset + data_len == content_length;
63236325

63246326
auto ret = compressor.compress(
6325-
data, data_len, last, [&](const char *compressed_data, size_t compressed_data_len) {
6327+
data, data_len, last,
6328+
[&](const char *compressed_data, size_t compressed_data_len) {
63266329
req.body.append(compressed_data, compressed_data_len);
63276330
return true;
63286331
});
@@ -7261,7 +7264,10 @@ inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
72617264

72627265
inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
72637266
if (is_writable()) {
7264-
auto ret = SSL_write(ssl_, ptr, static_cast<int>(size));
7267+
auto handle_size = static_cast<int>(
7268+
std::min<size_t>(size, std::numeric_limits<int>::max()));
7269+
7270+
auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
72657271
if (ret < 0) {
72667272
auto err = SSL_get_error(ssl_, ret);
72677273
int n = 1000;
@@ -7274,7 +7280,7 @@ inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
72747280
#endif
72757281
if (is_writable()) {
72767282
std::this_thread::sleep_for(std::chrono::milliseconds(1));
7277-
ret = SSL_write(ssl_, ptr, static_cast<int>(size));
7283+
ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
72787284
if (ret >= 0) { return ret; }
72797285
err = SSL_get_error(ssl_, ret);
72807286
} else {

test/test.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4660,6 +4660,50 @@ TEST(SSLClientServerTest, CustomizeServerSSLCtx) {
46604660

46614661
t.join();
46624662
}
4663+
4664+
// Disabled due to the out-of-memory problem on GitHub Actions Workflows
4665+
TEST(SSLClientServerTest, DISABLED_LargeDataTransfer) {
4666+
4667+
// prepare large data
4668+
std::random_device seed_gen;
4669+
std::mt19937 random(seed_gen());
4670+
constexpr auto large_size_byte = 2147483648UL + 1048576UL; // 2GiB + 1MiB
4671+
std::vector<std::uint32_t> binary(large_size_byte / sizeof(std::uint32_t));
4672+
std::generate(binary.begin(), binary.end(), [&random]() { return random(); });
4673+
4674+
// server
4675+
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
4676+
ASSERT_TRUE(svr.is_valid());
4677+
4678+
svr.Post("/binary", [&](const Request &req, Response &res) {
4679+
EXPECT_EQ(large_size_byte, req.body.size());
4680+
EXPECT_EQ(0, std::memcmp(binary.data(), req.body.data(), large_size_byte));
4681+
res.set_content(req.body, "application/octet-stream");
4682+
});
4683+
4684+
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
4685+
while (!svr.is_running()) {
4686+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
4687+
}
4688+
4689+
// client POST
4690+
SSLClient cli("localhost", PORT);
4691+
cli.enable_server_certificate_verification(false);
4692+
cli.set_read_timeout(std::chrono::seconds(100));
4693+
cli.set_write_timeout(std::chrono::seconds(100));
4694+
auto res = cli.Post("/binary", reinterpret_cast<char *>(binary.data()),
4695+
large_size_byte, "application/octet-stream");
4696+
4697+
// compare
4698+
EXPECT_EQ(200, res->status);
4699+
EXPECT_EQ(large_size_byte, res->body.size());
4700+
EXPECT_EQ(0, std::memcmp(binary.data(), res->body.data(), large_size_byte));
4701+
4702+
// cleanup
4703+
svr.stop();
4704+
listen_thread.join();
4705+
ASSERT_FALSE(svr.is_running());
4706+
}
46634707
#endif
46644708

46654709
#ifdef _WIN32

0 commit comments

Comments
 (0)