Skip to content
This repository was archived by the owner on Apr 30, 2025. It is now read-only.

Commit c202aa9

Browse files
authored
Read buffer support. (Fix yhirose#1023) (yhirose#1046)
1 parent e3e28c6 commit c202aa9

File tree

2 files changed

+87
-19
lines changed

2 files changed

+87
-19
lines changed

httplib.h

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,10 @@ bool parse_range_header(const std::string &s, Ranges &ranges);
16711671

16721672
int close_socket(socket_t sock);
16731673

1674+
ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);
1675+
1676+
ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);
1677+
16741678
enum class EncodingType { None = 0, Gzip, Brotli };
16751679

16761680
EncodingType encoding_type(const Request &req, const Response &res);
@@ -2189,6 +2193,34 @@ template <typename T> inline ssize_t handle_EINTR(T fn) {
21892193
return res;
21902194
}
21912195

2196+
inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
2197+
return handle_EINTR([&]() {
2198+
return recv(sock,
2199+
#ifdef _WIN32
2200+
static_cast<char *>(ptr),
2201+
static_cast<int>(size),
2202+
#else
2203+
ptr,
2204+
size,
2205+
#endif
2206+
flags);
2207+
});
2208+
}
2209+
2210+
inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags) {
2211+
return handle_EINTR([&]() {
2212+
return send(sock,
2213+
#ifdef _WIN32
2214+
static_cast<const char *>(ptr),
2215+
static_cast<int>(size),
2216+
#else
2217+
ptr,
2218+
size,
2219+
#endif
2220+
flags);
2221+
});
2222+
}
2223+
21922224
inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
21932225
#ifdef CPPHTTPLIB_USE_POLL
21942226
struct pollfd pfd_read;
@@ -2313,6 +2345,12 @@ class SocketStream : public Stream {
23132345
time_t read_timeout_usec_;
23142346
time_t write_timeout_sec_;
23152347
time_t write_timeout_usec_;
2348+
2349+
std::vector<char> read_buff_;
2350+
size_t read_buff_off_ = 0;
2351+
size_t read_buff_content_size_ = 0;
2352+
2353+
static const size_t read_buff_size_ = 1024 * 4;
23162354
};
23172355

23182356
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -4368,7 +4406,8 @@ inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
43684406
: sock_(sock), read_timeout_sec_(read_timeout_sec),
43694407
read_timeout_usec_(read_timeout_usec),
43704408
write_timeout_sec_(write_timeout_sec),
4371-
write_timeout_usec_(write_timeout_usec) {}
4409+
write_timeout_usec_(write_timeout_usec),
4410+
read_buff_(read_buff_size_, 0) {}
43724411

43734412
inline SocketStream::~SocketStream() {}
43744413

@@ -4381,31 +4420,56 @@ inline bool SocketStream::is_writable() const {
43814420
}
43824421

43834422
inline ssize_t SocketStream::read(char *ptr, size_t size) {
4384-
if (!is_readable()) { return -1; }
4385-
43864423
#ifdef _WIN32
4387-
if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) {
4388-
return -1;
4389-
}
4390-
return recv(sock_, ptr, static_cast<int>(size), CPPHTTPLIB_RECV_FLAGS);
4424+
size = std::min(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
43914425
#else
4392-
return handle_EINTR(
4393-
[&]() { return recv(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS); });
4426+
size = std::min(size, static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
43944427
#endif
4428+
4429+
if (read_buff_off_ < read_buff_content_size_) {
4430+
auto remaining_size = read_buff_content_size_ - read_buff_off_;
4431+
if (size <= remaining_size) {
4432+
memcpy(ptr, read_buff_.data() + read_buff_off_, size);
4433+
read_buff_off_ += size;
4434+
return static_cast<ssize_t>(size);
4435+
} else {
4436+
memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
4437+
read_buff_off_ += remaining_size;
4438+
return static_cast<ssize_t>(remaining_size);
4439+
}
4440+
}
4441+
4442+
if (!is_readable()) { return -1; }
4443+
4444+
read_buff_off_ = 0;
4445+
read_buff_content_size_ = 0;
4446+
4447+
if (size < read_buff_size_) {
4448+
auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, CPPHTTPLIB_RECV_FLAGS);
4449+
if (n <= 0) {
4450+
return n;
4451+
} else if (n <= static_cast<ssize_t>(size)) {
4452+
memcpy(ptr, read_buff_.data(), static_cast<size_t>(n));
4453+
return n;
4454+
} else {
4455+
memcpy(ptr, read_buff_.data(), size);
4456+
read_buff_off_ = size;
4457+
read_buff_content_size_ = static_cast<size_t>(n);
4458+
return static_cast<ssize_t>(size);
4459+
}
4460+
} else {
4461+
return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
4462+
}
43954463
}
43964464

43974465
inline ssize_t SocketStream::write(const char *ptr, size_t size) {
43984466
if (!is_writable()) { return -1; }
43994467

44004468
#ifdef _WIN32
4401-
if (size > static_cast<size_t>((std::numeric_limits<int>::max)())) {
4402-
return -1;
4403-
}
4404-
return send(sock_, ptr, static_cast<int>(size), CPPHTTPLIB_SEND_FLAGS);
4405-
#else
4406-
return handle_EINTR(
4407-
[&]() { return send(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); });
4469+
size = std::min(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
44084470
#endif
4471+
4472+
return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
44094473
}
44104474

44114475
inline void SocketStream::get_remote_ip_and_port(std::string &ip,

test/test.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,11 +1349,13 @@ class ServerTest : public ::testing::Test {
13491349
std::this_thread::sleep_for(std::chrono::seconds(2));
13501350
res.set_content("slow", "text/plain");
13511351
})
1352+
#if 0
13521353
.Post("/slowpost",
13531354
[&](const Request & /*req*/, Response &res) {
13541355
std::this_thread::sleep_for(std::chrono::seconds(2));
13551356
res.set_content("slow", "text/plain");
13561357
})
1358+
#endif
13571359
.Get("/remote_addr",
13581360
[&](const Request &req, Response &res) {
13591361
auto remote_addr = req.headers.find("REMOTE_ADDR")->second;
@@ -2623,6 +2625,7 @@ TEST_F(ServerTest, SlowRequest) {
26232625
std::thread([=]() { auto res = cli_.Get("/slow"); }));
26242626
}
26252627

2628+
#if 0
26262629
TEST_F(ServerTest, SlowPost) {
26272630
char buffer[64 * 1024];
26282631
memset(buffer, 0x42, sizeof(buffer));
@@ -2640,7 +2643,6 @@ TEST_F(ServerTest, SlowPost) {
26402643
EXPECT_EQ(200, res->status);
26412644
}
26422645

2643-
#if 0
26442646
TEST_F(ServerTest, SlowPostFail) {
26452647
char buffer[64 * 1024];
26462648
memset(buffer, 0x42, sizeof(buffer));
@@ -3564,10 +3566,12 @@ TEST(StreamingTest, NoContentLengthStreaming) {
35643566
Client client(HOST, PORT);
35653567

35663568
auto get_thread = std::thread([&client]() {
3567-
auto res = client.Get("/stream", [](const char *data, size_t len) -> bool {
3568-
EXPECT_EQ("aaabbb", std::string(data, len));
3569+
std::string s;
3570+
auto res = client.Get("/stream", [&s](const char *data, size_t len) -> bool {
3571+
s += std::string(data, len);
35693572
return true;
35703573
});
3574+
EXPECT_EQ("aaabbb", s);
35713575
});
35723576

35733577
// Give GET time to get a few messages.

0 commit comments

Comments
 (0)