Compare commits

...

9 Commits

Author SHA1 Message Date
yhirose 219d13b718 Fix #1303 2022-06-07 09:52:08 -04:00
conghuawang df20c27696 resolve http server can't send file large than 2GB (Fix #1290) (#1294)
* resolve problem: http server can't send file large than 2GB.
add unit test for http server send large file.
add /bigobj compile option to msvc x64.

* disable unit test "ServerLargeContentTest" due to out-of-memory on GitHub Actions.
2022-05-27 11:56:20 -04:00
yhirose a5a62768c0 Fix #1292 (#1296) 2022-05-27 11:54:43 -04:00
yhirose 4001637beb Added CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 2022-05-26 10:16:32 -04:00
Martín Córdova 47044c05a8 Fix compile error with MINGW-64 GCC-12.1.0 (#1283) 2022-05-24 07:16:54 -04:00
Andrea Pappacoda a449d82723 build(cmake): minor tweaks (#1274)
- Enable THREADS_PREFER_PTHREAD_FLAG to use -pthread where supported
- Remove low-level compile features (closes #1272)
- Remove unneeded DESTINATION options where possible
2022-05-17 07:02:44 -04:00
yhirose fee8e97b4e Rename fuzzing test corpus for #1264 2022-05-03 14:53:59 -04:00
yhirose 72d9ed4056 Added fuzzing corpus for #1264 2022-05-02 18:06:14 -04:00
Andrea Pappacoda 1be1b3a86d build(meson): don't require python3 (#1267)
Thanks to abf3a67dd0 the use of python3
isn't required anymore to configure the build, so I moved the
find_program('python3') inside the "if compile" block.

This makes it possible to configure cpp-httplib on systems where python
isn't available with tools like muon: https://sr.ht/~lattis/muon/
2022-04-30 17:40:47 -04:00
8 changed files with 94 additions and 45 deletions
+4 -15
View File
@@ -100,6 +100,7 @@ if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
endif()
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
set(THREADS_PREFER_PTHREAD_FLAG true)
find_package(Threads REQUIRED)
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
if(HTTPLIB_REQUIRE_OPENSSL)
@@ -160,7 +161,7 @@ if(HTTPLIB_COMPILE)
ERROR_VARIABLE _httplib_split_error
)
if(_httplib_split_error)
message(FATAL_ERROR "Failed when trying to split Cpp-httplib with the Python script.\n${_httplib_split_error}")
message(FATAL_ERROR "Failed when trying to split cpp-httplib with the Python script.\n${_httplib_split_error}")
endif()
# split.py puts output in "out"
@@ -187,19 +188,9 @@ endif()
# Only useful if building in-tree, versus using it from an installation.
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
# Might be missing some, but this list is somewhat comprehensive
# Require C++11
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
cxx_std_11
cxx_nullptr
cxx_lambdas
cxx_override
cxx_defaulted_functions
cxx_attribute_deprecated
cxx_auto_type
cxx_decltype
cxx_deleted_functions
cxx_range_for
cxx_sizeof_member
)
target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
@@ -274,11 +265,9 @@ endif()
# and linkage information (doesn't find deps though).
install(TARGETS ${PROJECT_NAME}
EXPORT httplibTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES "${_httplib_build_includedir}/httplib.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${_httplib_build_includedir}/httplib.h" TYPE INCLUDE)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+24 -18
View File
@@ -74,6 +74,10 @@
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())
#endif
#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
#endif
#ifndef CPPHTTPLIB_TCP_NODELAY
#define CPPHTTPLIB_TCP_NODELAY false
#endif
@@ -166,7 +170,6 @@ using socket_t = SOCKET;
#else // not _WIN32
#include <arpa/inet.h>
#include <cstring>
#include <ifaddrs.h>
#include <net/if.h>
#include <netdb.h>
@@ -190,6 +193,7 @@ using socket_t = int;
#endif
#endif //_WIN32
#include <cstring>
#include <algorithm>
#include <array>
#include <atomic>
@@ -2704,9 +2708,9 @@ inline socket_t create_client_socket(
[&](socket_t sock2, struct addrinfo &ai) -> bool {
if (!intf.empty()) {
#ifdef USE_IF2IP
auto ip = if2ip(address_family, intf);
if (ip.empty()) { ip = intf; }
if (!bind_ip_address(sock2, ip.c_str())) {
auto ip_from_if = if2ip(address_family, intf);
if (ip_from_if.empty()) { ip_from_if = intf; }
if (!bind_ip_address(sock2, ip_from_if.c_str())) {
error = Error::BindIPAddress;
return false;
}
@@ -4407,6 +4411,8 @@ inline void hosted_at(const char *hostname, std::vector<std::string> &addrs) {
addrs.push_back(ip);
}
}
freeaddrinfo(result);
}
inline std::string append_query_params(const char *path, const Params &params) {
@@ -4687,7 +4693,7 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
inline ssize_t SocketStream::write(const char *ptr, size_t size) {
if (!is_writable()) { return -1; }
#ifdef _WIN32
#if defined(_WIN32) && !defined(_WIN64)
size =
(std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
#endif
@@ -5189,7 +5195,7 @@ inline bool Server::read_content(Stream &strm, Request &req, Response &res) {
})) {
const auto &content_type = req.get_header_value("Content-Type");
if (!content_type.find("application/x-www-form-urlencoded")) {
if (req.body.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
res.status = 413; // NOTE: should be 414?
return false;
}
@@ -6316,8 +6322,8 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
auto last = offset + data_len == content_length;
auto ret = compressor.compress(
data, data_len, last, [&](const char *data, size_t data_len) {
req.body.append(data, data_len);
data, data_len, last, [&](const char *compressed_data, size_t compressed_data_len) {
req.body.append(compressed_data, compressed_data_len);
return true;
});
@@ -7374,11 +7380,11 @@ inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
inline bool SSLServer::process_and_close_socket(socket_t sock) {
auto ssl = detail::ssl_new(
sock, ctx_, ctx_mutex_,
[&](SSL *ssl) {
[&](SSL *ssl2) {
return detail::ssl_connect_or_accept_nonblocking(
sock, ssl, SSL_accept, read_timeout_sec_, read_timeout_usec_);
sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_);
},
[](SSL * /*ssl*/) { return true; });
[](SSL * /*ssl2*/) { return true; });
bool ret = false;
if (ssl) {
@@ -7572,31 +7578,31 @@ inline bool SSLClient::load_certs() {
inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
auto ssl = detail::ssl_new(
socket.sock, ctx_, ctx_mutex_,
[&](SSL *ssl) {
[&](SSL *ssl2) {
if (server_certificate_verification_) {
if (!load_certs()) {
error = Error::SSLLoadingCerts;
return false;
}
SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr);
}
if (!detail::ssl_connect_or_accept_nonblocking(
socket.sock, ssl, SSL_connect, connection_timeout_sec_,
socket.sock, ssl2, SSL_connect, connection_timeout_sec_,
connection_timeout_usec_)) {
error = Error::SSLConnection;
return false;
}
if (server_certificate_verification_) {
verify_result_ = SSL_get_verify_result(ssl);
verify_result_ = SSL_get_verify_result(ssl2);
if (verify_result_ != X509_V_OK) {
error = Error::SSLServerVerification;
return false;
}
auto server_cert = SSL_get_peer_certificate(ssl);
auto server_cert = SSL_get_peer_certificate(ssl2);
if (server_cert == nullptr) {
error = Error::SSLServerVerification;
@@ -7613,8 +7619,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
return true;
},
[&](SSL *ssl) {
SSL_set_tlsext_host_name(ssl, host_.c_str());
[&](SSL *ssl2) {
SSL_set_tlsext_host_name(ssl2, host_.c_str());
return true;
});
+2 -3
View File
@@ -19,7 +19,6 @@ project(
# Check just in case downstream decides to edit the source
# and add a project version
version = meson.project_version()
python3 = find_program('python3')
if version == 'undefined'
cxx = meson.get_compiler('cpp')
version = cxx.get_define('CPPHTTPLIB_VERSION',
@@ -28,8 +27,6 @@ if version == 'undefined'
assert(version != '', 'failed to get version from httplib.h')
endif
message('cpp-httplib version ' + version)
deps = [dependency('threads')]
args = []
@@ -64,6 +61,8 @@ endif
cpp_httplib_dep = dependency('', required: false)
if get_option('cpp-httplib_compile')
python3 = find_program('python3')
httplib_ch = custom_target(
'split',
input: 'httplib.h',
+1 -1
View File
@@ -5,5 +5,5 @@
option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
option('cpp-httplib_zlib', type: 'feature', value: 'auto', description: 'Enable zlib support')
option('cpp-httplib_brotli', type: 'feature', value: 'auto', description: 'Enable Brotli support')
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file')
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file (requires python3)')
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
+1 -1
View File
@@ -1,5 +1,5 @@
CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion -Wshadow # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
PREFIX = /usr/local
#PREFIX = $(shell brew --prefix)
File diff suppressed because one or more lines are too long
+41 -7
View File
@@ -109,11 +109,11 @@ TEST(SplitTest, ParseQueryString) {
detail::split(s.c_str(), s.c_str() + s.size(), '&',
[&](const char *b, const char *e) {
string key, val;
detail::split(b, e, '=', [&](const char *b, const char *e) {
detail::split(b, e, '=', [&](const char *b2, const char *e2) {
if (key.empty()) {
key.assign(b, e);
key.assign(b2, e2);
} else {
val.assign(b, e);
val.assign(b2, e2);
}
});
dic.emplace(key, val);
@@ -3015,8 +3015,8 @@ TEST(GzipDecompressor, ChunkedDecompression) {
httplib::detail::gzip_compressor compressor;
bool result = compressor.compress(
data.data(), data.size(),
/*last=*/true, [&](const char *data, size_t size) {
compressed_data.insert(compressed_data.size(), data, size);
/*last=*/true, [&](const char *compressed_data_chunk, size_t compressed_data_size) {
compressed_data.insert(compressed_data.size(), compressed_data_chunk, compressed_data_size);
return true;
});
ASSERT_TRUE(result);
@@ -3035,8 +3035,8 @@ TEST(GzipDecompressor, ChunkedDecompression) {
std::min(compressed_data.size() - chunk_begin, chunk_size);
bool result = decompressor.decompress(
compressed_data.data() + chunk_begin, current_chunk_size,
[&](const char *data, size_t size) {
decompressed_data.insert(decompressed_data.size(), data, size);
[&](const char *decompressed_data_chunk, size_t decompressed_data_chunk_size) {
decompressed_data.insert(decompressed_data.size(), decompressed_data_chunk, decompressed_data_chunk_size);
return true;
});
ASSERT_TRUE(result);
@@ -4742,6 +4742,40 @@ TEST(SendAPI, SimpleInterface_Online) {
EXPECT_EQ(301, res->status);
}
// Disabled due to out-of-memory problem on GitHub Actions
#ifdef _WIN64
TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
// allocate content size larger than 2GB in memory
const size_t content_size = 2LL * 1024LL * 1024LL * 1024LL + 1LL;
char *content = (char *)malloc(content_size);
ASSERT_TRUE(content);
Server svr;
svr.Get("/foo", [=](const httplib::Request &req, httplib::Response &resp) {
resp.set_content(content, content_size, "application/octet-stream");
});
auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli(HOST, PORT);
auto res = cli.Get("/foo");
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ(content_size, res->body.length());
free(content);
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(YahooRedirectTest2, SimpleInterface_Online) {
Client cli("http://yahoo.com");
+2
View File
@@ -116,6 +116,7 @@
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -158,6 +159,7 @@
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
<SDLCheck>true</SDLCheck>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>