Compare commits

..

No commits in common. "master" and "v0.20.0" have entirely different histories.

4 changed files with 25 additions and 95 deletions

View File

@ -18,7 +18,7 @@
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
After installation with Cmake, a find_package(httplib COMPONENTS OpenSSL ZLIB Brotli zstd) is available. After installation with Cmake, a find_package(httplib COMPONENTS OpenSSL ZLIB Brotli) is available.
This creates a httplib::httplib target (if found and if listed components are supported). This creates a httplib::httplib target (if found and if listed components are supported).
It can be linked like so: It can be linked like so:
@ -159,26 +159,10 @@ elseif(HTTPLIB_USE_BROTLI_IF_AVAILABLE)
endif() endif()
if(HTTPLIB_REQUIRE_ZSTD) if(HTTPLIB_REQUIRE_ZSTD)
find_package(zstd) find_package(zstd REQUIRED)
if(NOT zstd_FOUND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(zstd REQUIRED IMPORTED_TARGET libzstd)
add_library(zstd::libzstd ALIAS PkgConfig::zstd)
endif()
set(HTTPLIB_IS_USING_ZSTD TRUE) set(HTTPLIB_IS_USING_ZSTD TRUE)
elseif(HTTPLIB_USE_ZSTD_IF_AVAILABLE) elseif(HTTPLIB_USE_ZSTD_IF_AVAILABLE)
find_package(zstd QUIET) find_package(zstd QUIET)
if(NOT zstd_FOUND)
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(zstd QUIET IMPORTED_TARGET libzstd)
if(TARGET PkgConfig::zstd)
add_library(zstd::libzstd ALIAS PkgConfig::zstd)
endif()
endif()
endif()
# Both find_package and PkgConf set a XXX_FOUND var
set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND}) set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND})
endif() endif()

View File

@ -39,25 +39,7 @@ if(@HTTPLIB_IS_USING_BROTLI@)
endif() endif()
if(@HTTPLIB_IS_USING_ZSTD@) if(@HTTPLIB_IS_USING_ZSTD@)
set(httplib_fd_zstd_quiet_arg) find_dependency(zstd)
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
set(httplib_fd_zstd_quiet_arg QUIET)
endif()
set(httplib_fd_zstd_required_arg)
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
set(httplib_fd_zstd_required_arg REQUIRED)
endif()
find_package(zstd QUIET)
if(NOT zstd_FOUND)
find_package(PkgConfig ${httplib_fd_zstd_quiet_arg} ${httplib_fd_zstd_required_arg})
if(PKG_CONFIG_FOUND)
pkg_check_modules(zstd ${httplib_fd_zstd_quiet_arg} ${httplib_fd_zstd_required_arg} IMPORTED_TARGET libzstd)
if(TARGET PkgConfig::zstd)
add_library(zstd::libzstd ALIAS PkgConfig::zstd)
endif()
endif()
endif()
set(httplib_zstd_FOUND ${zstd_FOUND}) set(httplib_zstd_FOUND ${zstd_FOUND})
endif() endif()

View File

@ -8,7 +8,7 @@
#ifndef CPPHTTPLIB_HTTPLIB_H #ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.20.1" #define CPPHTTPLIB_VERSION "0.20.0"
/* /*
* Configuration * Configuration
@ -145,10 +145,6 @@
#define CPPHTTPLIB_LISTEN_BACKLOG 5 #define CPPHTTPLIB_LISTEN_BACKLOG 5
#endif #endif
#ifndef CPPHTTPLIB_MAX_LINE_LENGTH
#define CPPHTTPLIB_MAX_LINE_LENGTH 32768
#endif
/* /*
* Headers * Headers
*/ */
@ -192,9 +188,6 @@ using ssize_t = long;
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
// afunix.h uses types declared in winsock2.h, so has to be included after it.
#include <afunix.h>
#ifndef WSA_FLAG_NO_HANDLE_INHERIT #ifndef WSA_FLAG_NO_HANDLE_INHERIT
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 #define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif #endif
@ -1087,7 +1080,8 @@ private:
bool listen_internal(); bool listen_internal();
bool routing(Request &req, Response &res, Stream &strm); bool routing(Request &req, Response &res, Stream &strm);
bool handle_file_request(const Request &req, Response &res); bool handle_file_request(const Request &req, Response &res,
bool head = false);
bool dispatch_request(Request &req, Response &res, bool dispatch_request(Request &req, Response &res,
const Handlers &handlers) const; const Handlers &handlers) const;
bool dispatch_request_for_content_reader( bool dispatch_request_for_content_reader(
@ -2065,9 +2059,7 @@ template <size_t N> inline constexpr size_t str_len(const char (&)[N]) {
} }
inline bool is_numeric(const std::string &str) { inline bool is_numeric(const std::string &str) {
return !str.empty() && return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
std::all_of(str.cbegin(), str.cend(),
[](unsigned char c) { return std::isdigit(c); });
} }
inline uint64_t get_header_value_u64(const Headers &headers, inline uint64_t get_header_value_u64(const Headers &headers,
@ -3072,11 +3064,6 @@ inline bool stream_line_reader::getline() {
#endif #endif
for (size_t i = 0;; i++) { for (size_t i = 0;; i++) {
if (size() >= CPPHTTPLIB_MAX_LINE_LENGTH) {
// Treat exceptionally long lines as an error to
// prevent infinite loops/memory exhaustion
return false;
}
char byte; char byte;
auto n = strm_.read(&byte, 1); auto n = strm_.read(&byte, 1);
@ -3378,7 +3365,7 @@ private:
time_t write_timeout_sec_; time_t write_timeout_sec_;
time_t write_timeout_usec_; time_t write_timeout_usec_;
time_t max_timeout_msec_; time_t max_timeout_msec_;
const std::chrono::time_point<std::chrono::steady_clock> start_time_; const std::chrono::time_point<std::chrono::steady_clock> start_time;
std::vector<char> read_buff_; std::vector<char> read_buff_;
size_t read_buff_off_ = 0; size_t read_buff_off_ = 0;
@ -3416,7 +3403,7 @@ private:
time_t write_timeout_sec_; time_t write_timeout_sec_;
time_t write_timeout_usec_; time_t write_timeout_usec_;
time_t max_timeout_msec_; time_t max_timeout_msec_;
const std::chrono::time_point<std::chrono::steady_clock> start_time_; const std::chrono::time_point<std::chrono::steady_clock> start_time;
}; };
#endif #endif
@ -3551,6 +3538,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
hints.ai_flags = socket_flags; hints.ai_flags = socket_flags;
} }
#ifndef _WIN32
if (hints.ai_family == AF_UNIX) { if (hints.ai_family == AF_UNIX) {
const auto addrlen = host.length(); const auto addrlen = host.length();
if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; } if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; }
@ -3574,19 +3562,11 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
sizeof(addr) - sizeof(addr.sun_path) + addrlen); sizeof(addr) - sizeof(addr.sun_path) + addrlen);
#ifndef SOCK_CLOEXEC #ifndef SOCK_CLOEXEC
#ifndef _WIN32
fcntl(sock, F_SETFD, FD_CLOEXEC); fcntl(sock, F_SETFD, FD_CLOEXEC);
#endif
#endif #endif
if (socket_options) { socket_options(sock); } if (socket_options) { socket_options(sock); }
#ifdef _WIN32
// Setting SO_REUSEADDR seems not to work well with AF_UNIX on windows, so
// remove the option.
detail::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 0);
#endif
bool dummy; bool dummy;
if (!bind_or_connect(sock, hints, dummy)) { if (!bind_or_connect(sock, hints, dummy)) {
close_socket(sock); close_socket(sock);
@ -3595,6 +3575,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
} }
return sock; return sock;
} }
#endif
auto service = std::to_string(port); auto service = std::to_string(port);
@ -6065,8 +6046,6 @@ inline void calc_actual_timeout(time_t max_timeout_msec, time_t duration_msec,
auto actual_timeout_msec = auto actual_timeout_msec =
(std::min)(max_timeout_msec - duration_msec, timeout_msec); (std::min)(max_timeout_msec - duration_msec, timeout_msec);
if (actual_timeout_msec < 0) { actual_timeout_msec = 0; }
actual_timeout_sec = actual_timeout_msec / 1000; actual_timeout_sec = actual_timeout_msec / 1000;
actual_timeout_usec = (actual_timeout_msec % 1000) * 1000; actual_timeout_usec = (actual_timeout_msec % 1000) * 1000;
} }
@ -6081,7 +6060,7 @@ inline SocketStream::SocketStream(
read_timeout_usec_(read_timeout_usec), read_timeout_usec_(read_timeout_usec),
write_timeout_sec_(write_timeout_sec), write_timeout_sec_(write_timeout_sec),
write_timeout_usec_(write_timeout_usec), write_timeout_usec_(write_timeout_usec),
max_timeout_msec_(max_timeout_msec), start_time_(start_time), max_timeout_msec_(max_timeout_msec), start_time(start_time),
read_buff_(read_buff_size_, 0) {} read_buff_(read_buff_size_, 0) {}
inline SocketStream::~SocketStream() = default; inline SocketStream::~SocketStream() = default;
@ -6179,7 +6158,7 @@ inline socket_t SocketStream::socket() const { return sock_; }
inline time_t SocketStream::duration() const { inline time_t SocketStream::duration() const {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start_time_) std::chrono::steady_clock::now() - start_time)
.count(); .count();
} }
@ -6879,7 +6858,8 @@ Server::read_content_core(Stream &strm, Request &req, Response &res,
return true; return true;
} }
inline bool Server::handle_file_request(const Request &req, Response &res) { inline bool Server::handle_file_request(const Request &req, Response &res,
bool head) {
for (const auto &entry : base_dirs_) { for (const auto &entry : base_dirs_) {
// Prefix match // Prefix match
if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) { if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
@ -6912,7 +6892,7 @@ inline bool Server::handle_file_request(const Request &req, Response &res) {
return true; return true;
}); });
if (req.method != "HEAD" && file_request_handler_) { if (!head && file_request_handler_) {
file_request_handler_(req, res); file_request_handler_(req, res);
} }
@ -7046,8 +7026,9 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) {
} }
// File handler // File handler
if ((req.method == "GET" || req.method == "HEAD") && auto is_head_request = req.method == "HEAD";
handle_file_request(req, res)) { if ((req.method == "GET" || is_head_request) &&
handle_file_request(req, res, is_head_request)) {
return true; return true;
} }
@ -7337,9 +7318,8 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
} }
// Setup `is_connection_closed` method // Setup `is_connection_closed` method
auto sock = strm.socket(); req.is_connection_closed = [&]() {
req.is_connection_closed = [sock]() { return !detail::is_socket_alive(strm.socket());
return !detail::is_socket_alive(sock);
}; };
// Routing // Routing
@ -9220,7 +9200,7 @@ inline SSLSocketStream::SSLSocketStream(
read_timeout_usec_(read_timeout_usec), read_timeout_usec_(read_timeout_usec),
write_timeout_sec_(write_timeout_sec), write_timeout_sec_(write_timeout_sec),
write_timeout_usec_(write_timeout_usec), write_timeout_usec_(write_timeout_usec),
max_timeout_msec_(max_timeout_msec), start_time_(start_time) { max_timeout_msec_(max_timeout_msec), start_time(start_time) {
SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY); SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
} }
@ -9326,7 +9306,7 @@ inline socket_t SSLSocketStream::socket() const { return sock_; }
inline time_t SSLSocketStream::duration() const { inline time_t SSLSocketStream::duration() const {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start_time_) std::chrono::steady_clock::now() - start_time)
.count(); .count();
} }

View File

@ -43,10 +43,6 @@ const int PORT = 1234;
const string LONG_QUERY_VALUE = string(25000, '@'); const string LONG_QUERY_VALUE = string(25000, '@');
const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE; const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
const string TOO_LONG_QUERY_VALUE = string(35000, '@');
const string TOO_LONG_QUERY_URL =
"/too-long-query-value?key=" + TOO_LONG_QUERY_VALUE;
const std::string JSON_DATA = "{\"hello\":\"world\"}"; const std::string JSON_DATA = "{\"hello\":\"world\"}";
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
@ -74,6 +70,7 @@ static void read_file(const std::string &path, std::string &out) {
fs.read(&out[0], static_cast<std::streamsize>(size)); fs.read(&out[0], static_cast<std::streamsize>(size));
} }
#ifndef _WIN32
class UnixSocketTest : public ::testing::Test { class UnixSocketTest : public ::testing::Test {
protected: protected:
void TearDown() override { std::remove(pathname_.c_str()); } void TearDown() override { std::remove(pathname_.c_str()); }
@ -170,7 +167,6 @@ TEST_F(UnixSocketTest, abstract) {
} }
#endif #endif
#ifndef _WIN32
TEST(SocketStream, wait_writable_UNIX) { TEST(SocketStream, wait_writable_UNIX) {
int fds[2]; int fds[2];
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
@ -2871,11 +2867,6 @@ protected:
EXPECT_EQ(LONG_QUERY_URL, req.target); EXPECT_EQ(LONG_QUERY_URL, req.target);
EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key")); EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
}) })
.Get("/too-long-query-value",
[&](const Request &req, Response & /*res*/) {
EXPECT_EQ(TOO_LONG_QUERY_URL, req.target);
EXPECT_EQ(TOO_LONG_QUERY_VALUE, req.get_param_value("key"));
})
.Get("/array-param", .Get("/array-param",
[&](const Request &req, Response & /*res*/) { [&](const Request &req, Response & /*res*/) {
EXPECT_EQ(3u, req.get_param_value_count("array")); EXPECT_EQ(3u, req.get_param_value_count("array"));
@ -3664,13 +3655,6 @@ TEST_F(ServerTest, LongQueryValue) {
EXPECT_EQ(StatusCode::UriTooLong_414, res->status); EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
} }
TEST_F(ServerTest, TooLongQueryValue) {
auto res = cli_.Get(TOO_LONG_QUERY_URL.c_str());
ASSERT_FALSE(res);
EXPECT_EQ(Error::Read, res.error());
}
TEST_F(ServerTest, TooLongHeader) { TEST_F(ServerTest, TooLongHeader) {
Request req; Request req;
req.method = "GET"; req.method = "GET";
@ -8639,7 +8623,7 @@ TEST(MaxTimeoutTest, ContentStream) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(MaxTimeoutTest, ContentStreamSSL) { TEST(MaxTimeoutTest, ContentStreamSSL) {
time_t timeout = 2000; time_t timeout = 2000;
time_t threshold = 1200; // SSL_shutdown is slow on some operating systems. time_t threshold = 500; // SSL_shutdown is slow on some operating systems.
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);