mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-11-06 15:51:46 +00:00
Cap a send() or wolfSSL_read() length at INT_MAX (#2655)
* Cap a send() or wolfSSL_read() length at INT_MAX On 64-bit Windows SocketStream::write() handed size to send(), whose length is an int, so a single write of 4 GiB or more went out as its low 32 bits: a 4 GiB + 1 byte write sent one byte, and write_data() then retried the remaining 4 GiB as zero-byte sends forever. The INT_MAX cap that read() has was limited to 32-bit Windows indf20c27(#1294), when the body was still written with one unchecked write(); write_data() now sends the rest, so the cap applies to every Windows build again. The wolfSSL tls::read() had the same cast, so a read into a buffer over INT_MAX failed. Cap it as the OpenSSL backend has done sincef80864c. * Drop the 4 GiB write test and shorten comments The Windows-only test allocated 4 GiB and took about 5 s, which is too heavy for CI. --------- Co-authored-by: yhirose <yuji.hirose.bug@gmail.com>
This commit is contained in:
1 parent
453b1b8613
commit
a1ba73a256
2 files changed
+48
-1
No files matched your search
@@ -12876,7 +12876,8 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
|
|||||||
inline ssize_t SocketStream::write(const char *ptr, size_t size) {
|
inline ssize_t SocketStream::write(const char *ptr, size_t size) {
|
||||||
if (!wait_writable()) { return -1; }
|
if (!wait_writable()) { return -1; }
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_WIN64)
|
// Winsock's send() takes an int length, even on 64-bit Windows
|
||||||
|
#ifdef _WIN32
|
||||||
size =
|
size =
|
||||||
(std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
|
(std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||||
#endif
|
#endif
|
||||||
@@ -23054,6 +23055,9 @@ inline ssize_t read(session_t session, void *buf, size_t len, TlsError &err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto wsession = static_cast<impl::WolfSSLSession *>(session);
|
auto wsession = static_cast<impl::WolfSSLSession *>(session);
|
||||||
|
constexpr auto max_len =
|
||||||
|
static_cast<size_t>((std::numeric_limits<int>::max)());
|
||||||
|
if (len > max_len) { len = max_len; }
|
||||||
int ret = wolfSSL_read(wsession->ssl, buf, static_cast<int>(len));
|
int ret = wolfSSL_read(wsession->ssl, buf, static_cast<int>(len));
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
|||||||
@@ -25056,6 +25056,49 @@ TEST(SSLTest, ResponseBodyTerminatedByConnectionClose) {
|
|||||||
EXPECT_EQ(StatusCode::OK_200, res->status);
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
EXPECT_EQ(expected_body, res->body);
|
EXPECT_EQ(expected_body, res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Without Content-Length, the full buffer size reaches tls::read().
|
||||||
|
TEST(SSLTest, ReadIntoBufferOverIntMax) {
|
||||||
|
if (sizeof(size_t) <= sizeof(int)) {
|
||||||
|
GTEST_SKIP() << "size_t cannot exceed INT_MAX here";
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||||
|
ASSERT_TRUE(svr.is_valid());
|
||||||
|
|
||||||
|
svr.Get("/no-content-length", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_content_provider("text/plain",
|
||||||
|
[&](size_t offset, DataSink &sink) -> bool {
|
||||||
|
if (offset == 0) { sink.write("Hello", 5); }
|
||||||
|
sink.done();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
auto port = svr.bind_to_any_port(HOST);
|
||||||
|
auto listen_thread = std::thread([&svr] { svr.listen_after_bind(); });
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
listen_thread.join();
|
||||||
|
});
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
SSLClient cli(HOST, port);
|
||||||
|
cli.enable_server_certificate_verification(false);
|
||||||
|
|
||||||
|
auto handle = cli.open_stream("GET", "/no-content-length");
|
||||||
|
ASSERT_TRUE(handle.is_valid()) << to_string(handle.error);
|
||||||
|
|
||||||
|
const auto len = static_cast<size_t>((std::numeric_limits<int>::max)()) + 1;
|
||||||
|
std::unique_ptr<char[]> buf(new char[len]);
|
||||||
|
std::string body;
|
||||||
|
ssize_t n;
|
||||||
|
while ((n = handle.read(buf.get(), len)) > 0) {
|
||||||
|
body.append(buf.get(), static_cast<size_t>(n));
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, n);
|
||||||
|
EXPECT_EQ("Hello", body);
|
||||||
|
}
|
||||||
#endif // CPPHTTPLIB_SSL_ENABLED
|
#endif // CPPHTTPLIB_SSL_ENABLED
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
Reference in new issue
Block a user