Compare commits

..

7 Commits

Author SHA1 Message Date
yhirose 9452c0a4b6 Release v0.10.7 2022-04-28 10:21:14 -04:00
Yoshiki Matsuda 307b729549 Accept large data transfer over SSL (#1261)
* Add large data transfer test

* Replace `SSL_read` and `SSL_write` with `ex` functions

* Reflect review comment

* Fix return value of `SSLSocketStream::read/write`

* Fix return value in the case of `SSL_ERROR_ZERO_RETURN`

* Disable `LargeDataTransfer` test due to OoM in CI
2022-04-27 21:08:39 -04:00
mylogin 696239d6e1 Link Windows crypto libs only when CPPHTTPLIB_OPENSSL_SUPPORT is set (#1254) 2022-04-20 22:04:55 -04:00
Andrea Pappacoda 6929d90353 build(meson): allow using OpenSSL 3.0 (#1256)
Following 0857eba17b cpp-httplib is fully compatible with OpenSSL versions newer than 1.1.1
2022-04-20 21:39:52 -04:00
yhirose 348d032029 Updated README 2022-04-19 23:02:30 -04:00
Andrea Pappacoda d1d3fcdfd5 build(meson): mark *_encrypted_pem as test deps (#1255)
Meson only runs required targets. The key_encrypted_pem and
cert_encrypted_pem targets added in 020b0db090
and 8191fd8e6c weren't added to the list
of targets required by the test target, so the generation of the
encrypted certs was skipped, resulting in the failure of
BindServerTest.BindAndListenSeparatelySSLEncryptedKey.
2022-04-19 07:12:00 -04:00
Eli Schwartz abf3a67dd0 meson: fix regression that broke extracting version (#1253)
* meson: fix regression that broke extracting version

In commit 33f67386fe the code that
heuristically parsed the version broke due to the version being moved
around into a more easily accessible define.

While we are at it, pass the exact path of httplib.h to un-break usage
as a meson subproject. This was broken in commit
8ecdb11979 which checked the return code
of trying to get the version; it was always broken, but formerly failed
in silence and resulted in no version number.

* meson: use the compiler builtins to extract the version from the header

As a convenient string define, it is now possible to ask the
preprocessor what the version of cpp-httplib is. This can be used from
meson too, in order to avoid encoding C++ file structure into python
regexes.
2022-04-19 07:11:51 -04:00
5 changed files with 109 additions and 60 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ SSL Support
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
NOTE: cpp-httplib currently supports only version 1.1.1.
NOTE: cpp-httplib currently supports only version 1.1.1 and 3.0.
```c++
#define CPPHTTPLIB_OPENSSL_SUPPORT
+56 -52
View File
@@ -8,7 +8,7 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.10.6"
#define CPPHTTPLIB_VERSION "0.10.7"
/*
* Configuration
@@ -144,8 +144,6 @@ using ssize_t = int;
#include <io.h>
#include <winsock2.h>
#include <wincrypt.h>
#include <ws2tcpip.h>
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
@@ -154,8 +152,6 @@ using ssize_t = int;
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptui.lib")
#endif
#ifndef strcasecmp
@@ -220,14 +216,21 @@ using socket_t = int;
#include <thread>
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
#ifdef _WIN32
#include <wincrypt.h>
// these are defined in wincrypt.h and it breaks compilation if BoringSSL is
// used
#ifdef _WIN32
#undef X509_NAME
#undef X509_CERT_PAIR
#undef X509_EXTENSIONS
#undef PKCS7_SIGNER_INFO
#ifdef _MSC_VER
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptui.lib")
#endif
#endif //_WIN32
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -7219,62 +7222,63 @@ inline bool SSLSocketStream::is_writable() const {
}
inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
size_t readbytes = 0;
if (SSL_pending(ssl_) > 0) {
return SSL_read(ssl_, ptr, static_cast<int>(size));
} else if (is_readable()) {
auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
#ifdef _WIN32
while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
(err == SSL_ERROR_SYSCALL &&
WSAGetLastError() == WSAETIMEDOUT))) {
#else
while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
#endif
if (SSL_pending(ssl_) > 0) {
return SSL_read(ssl_, ptr, static_cast<int>(size));
} else if (is_readable()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_read(ssl_, ptr, static_cast<int>(size));
if (ret >= 0) { return ret; }
err = SSL_get_error(ssl_, ret);
} else {
return -1;
}
}
}
return ret;
auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
if (!is_readable()) { return -1; }
auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
#ifdef _WIN32
while (--n >= 0 &&
(err == SSL_ERROR_WANT_READ ||
(err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
#else
while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
#endif
if (SSL_pending(ssl_) > 0) {
ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
if (!is_readable()) { return -1; }
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
err = SSL_get_error(ssl_, ret);
}
if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
if (is_writable()) {
auto ret = SSL_write(ssl_, ptr, static_cast<int>(size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
if (!is_writable()) { return -1; }
size_t written = 0;
auto ret = SSL_write_ex(ssl_, ptr, size, &written);
if (ret == 1) { return static_cast<ssize_t>(written); }
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
#ifdef _WIN32
while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
(err == SSL_ERROR_SYSCALL &&
WSAGetLastError() == WSAETIMEDOUT))) {
while (--n >= 0 &&
(err == SSL_ERROR_WANT_WRITE ||
(err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
#else
while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
#endif
if (is_writable()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_write(ssl_, ptr, static_cast<int>(size));
if (ret >= 0) { return ret; }
err = SSL_get_error(ssl_, ret);
} else {
return -1;
}
}
}
return ret;
if (!is_writable()) { return -1; }
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_write_ex(ssl_, ptr, size, &written);
if (ret == 1) { return static_cast<ssize_t>(written); }
err = SSL_get_error(ssl_, ret);
}
if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
+6 -7
View File
@@ -21,12 +21,11 @@ project(
version = meson.project_version()
python3 = find_program('python3')
if version == 'undefined'
# Meson doesn't have regular expressions, but since it is implemented
# in python we can be sure we can use it to parse the file manually
version = run_command(
python3, '-c', 'import re; raw_version = re.search("User\-Agent.*cpp\-httplib/([0-9]+\.?)+", open("httplib.h").read()).group(0); print(re.search("([0-9]+\\.?)+", raw_version).group(0))',
check: true
).stdout().strip()
cxx = meson.get_compiler('cpp')
version = cxx.get_define('CPPHTTPLIB_VERSION',
prefix: '#include <httplib.h>',
include_directories: include_directories('.')).strip('"')
assert(version != '', 'failed to get version from httplib.h')
endif
message('cpp-httplib version ' + version)
@@ -34,7 +33,7 @@ message('cpp-httplib version ' + version)
deps = [dependency('threads')]
args = []
openssl_dep = dependency('openssl', version: ['>=1.1.1', '<1.1.2'], required: get_option('cpp-httplib_openssl'))
openssl_dep = dependency('openssl', version: '>=1.1.1', required: get_option('cpp-httplib_openssl'))
if openssl_dep.found()
deps += openssl_dep
args += '-DCPPHTTPLIB_OPENSSL_SUPPORT'
+2
View File
@@ -100,6 +100,8 @@ test(
key_pem,
cert_pem,
cert2_pem,
key_encrypted_pem,
cert_encrypted_pem,
rootca_key_pem,
rootca_cert_pem,
client_key_pem,
+44
View File
@@ -4660,6 +4660,50 @@ TEST(SSLClientServerTest, CustomizeServerSSLCtx) {
t.join();
}
// Disabled due to the out-of-memory problem on GitHub Actions Workflows
TEST(SSLClientServerTest, DISABLED_LargeDataTransfer) {
// prepare large data
std::random_device seed_gen;
std::mt19937 random(seed_gen());
constexpr auto large_size_byte = 2147483648UL + 1048576UL; // 2GiB + 1MiB
std::vector<std::uint32_t> binary(large_size_byte / sizeof(std::uint32_t));
std::generate(binary.begin(), binary.end(), [&random]() { return random(); });
// server
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(svr.is_valid());
svr.Post("/binary", [&](const Request &req, Response &res) {
EXPECT_EQ(large_size_byte, req.body.size());
EXPECT_EQ(0, std::memcmp(binary.data(), req.body.data(), large_size_byte));
res.set_content(req.body, "application/octet-stream");
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// client POST
SSLClient cli("localhost", PORT);
cli.enable_server_certificate_verification(false);
cli.set_read_timeout(std::chrono::seconds(100));
cli.set_write_timeout(std::chrono::seconds(100));
auto res = cli.Post("/binary", reinterpret_cast<char *>(binary.data()),
large_size_byte, "application/octet-stream");
// compare
EXPECT_EQ(200, res->status);
EXPECT_EQ(large_size_byte, res->body.size());
EXPECT_EQ(0, std::memcmp(binary.data(), res->body.data(), large_size_byte));
// cleanup
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
#ifdef _WIN32