mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f14accb7b6 | |||
| c5c704cb3b | |||
| 115a786581 | |||
| 5ef4cfd263 | |||
| 03fecb2f78 | |||
| 7fc8682a0a | |||
| f1431311a4 | |||
| 1d14e051a5 | |||
| 97ae6733ed | |||
| 1d6b22b5f0 | |||
| 1a49076b5b | |||
| d0e4cb3f07 | |||
| e2813d9d4d | |||
| 20a7f088ce | |||
| f63ba7d013 | |||
| 0a629d7391 |
@@ -219,7 +219,6 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
# Needed for Windows libs on Mingw, as the pragma comment(lib, "xyz") aren't triggered.
|
||||
$<$<PLATFORM_ID:Windows>:ws2_32>
|
||||
$<$<PLATFORM_ID:Windows>:crypt32>
|
||||
$<$<PLATFORM_ID:Windows>:cryptui>
|
||||
# Needed for API from MacOS Security framework
|
||||
"$<$<AND:$<PLATFORM_ID:Darwin>,$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>,$<BOOL:${HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN}>>:-framework CoreFoundation -framework Security>"
|
||||
# Can't put multiple targets in a single generator expression or it bugs out.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||
#define CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
#define CPPHTTPLIB_VERSION "0.14.0"
|
||||
#define CPPHTTPLIB_VERSION "0.14.2"
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
@@ -247,7 +247,6 @@ using socket_t = int;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
#pragma comment(lib, "cryptui.lib")
|
||||
#endif
|
||||
#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
@@ -331,7 +330,7 @@ struct scope_exit {
|
||||
explicit scope_exit(std::function<void(void)> &&f)
|
||||
: exit_function(std::move(f)), execute_on_destruction{true} {}
|
||||
|
||||
scope_exit(scope_exit &&rhs)
|
||||
scope_exit(scope_exit &&rhs) noexcept
|
||||
: exit_function(std::move(rhs.exit_function)),
|
||||
execute_on_destruction{rhs.execute_on_destruction} {
|
||||
rhs.release();
|
||||
@@ -383,6 +382,7 @@ public:
|
||||
DataSink &operator=(DataSink &&) = delete;
|
||||
|
||||
std::function<bool(const char *data, size_t data_len)> write;
|
||||
std::function<bool()> is_writable;
|
||||
std::function<void()> done;
|
||||
std::function<void(const Headers &trailer)> done_with_trailer;
|
||||
std::ostream os;
|
||||
@@ -393,7 +393,7 @@ private:
|
||||
explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
|
||||
|
||||
protected:
|
||||
std::streamsize xsputn(const char *s, std::streamsize n) {
|
||||
std::streamsize xsputn(const char *s, std::streamsize n) override {
|
||||
sink_.write(s, static_cast<size_t>(n));
|
||||
return n;
|
||||
}
|
||||
@@ -869,15 +869,15 @@ private:
|
||||
bool routing(Request &req, Response &res, Stream &strm);
|
||||
bool handle_file_request(const Request &req, Response &res,
|
||||
bool head = false);
|
||||
bool dispatch_request(Request &req, Response &res, const Handlers &handlers);
|
||||
bool
|
||||
dispatch_request_for_content_reader(Request &req, Response &res,
|
||||
ContentReader content_reader,
|
||||
const HandlersForContentReader &handlers);
|
||||
bool dispatch_request(Request &req, Response &res,
|
||||
const Handlers &handlers) const;
|
||||
bool dispatch_request_for_content_reader(
|
||||
Request &req, Response &res, ContentReader content_reader,
|
||||
const HandlersForContentReader &handlers) const;
|
||||
|
||||
bool parse_request_line(const char *s, Request &req);
|
||||
bool parse_request_line(const char *s, Request &req) const;
|
||||
void apply_ranges(const Request &req, Response &res,
|
||||
std::string &content_type, std::string &boundary);
|
||||
std::string &content_type, std::string &boundary) const;
|
||||
bool write_response(Stream &strm, bool close_connection, const Request &req,
|
||||
Response &res);
|
||||
bool write_response_with_content(Stream &strm, bool close_connection,
|
||||
@@ -897,7 +897,7 @@ private:
|
||||
bool read_content_core(Stream &strm, Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader multipart_header,
|
||||
ContentReceiver multipart_receiver);
|
||||
ContentReceiver multipart_receiver) const;
|
||||
|
||||
virtual bool process_and_close_socket(socket_t sock);
|
||||
|
||||
@@ -963,7 +963,7 @@ enum class Error {
|
||||
SSLPeerCouldBeClosed_,
|
||||
};
|
||||
|
||||
std::string to_string(const Error error);
|
||||
std::string to_string(Error error);
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Error &obj);
|
||||
|
||||
@@ -1221,7 +1221,7 @@ public:
|
||||
void set_ca_cert_path(const std::string &ca_cert_file_path,
|
||||
const std::string &ca_cert_dir_path = std::string());
|
||||
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
||||
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size);
|
||||
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const;
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -1250,14 +1250,14 @@ protected:
|
||||
// Also, shutdown_ssl and close_socket should also NOT be called concurrently
|
||||
// with a DIFFERENT thread sending requests using that socket.
|
||||
virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
|
||||
void shutdown_socket(Socket &socket);
|
||||
void shutdown_socket(Socket &socket) const;
|
||||
void close_socket(Socket &socket);
|
||||
|
||||
bool process_request(Stream &strm, Request &req, Response &res,
|
||||
bool close_connection, Error &error);
|
||||
|
||||
bool write_content_with_provider(Stream &strm, const Request &req,
|
||||
Error &error);
|
||||
Error &error) const;
|
||||
|
||||
void copy_settings(const ClientImpl &rhs);
|
||||
|
||||
@@ -1348,7 +1348,8 @@ private:
|
||||
Result send_(Request &&req);
|
||||
|
||||
socket_t create_client_socket(Error &error) const;
|
||||
bool read_response_line(Stream &strm, const Request &req, Response &res);
|
||||
bool read_response_line(Stream &strm, const Request &req,
|
||||
Response &res) const;
|
||||
bool write_request(Stream &strm, Request &req, bool close_connection,
|
||||
Error &error);
|
||||
bool redirect(Request &req, Response &res, Error &error);
|
||||
@@ -1367,7 +1368,7 @@ private:
|
||||
const std::string &content_type);
|
||||
ContentProviderWithoutLength get_multipart_content_provider(
|
||||
const std::string &boundary, const MultipartFormDataItems &items,
|
||||
const MultipartFormDataProviderItems &provider_items);
|
||||
const MultipartFormDataProviderItems &provider_items) const;
|
||||
|
||||
std::string adjust_host_string(const std::string &host) const;
|
||||
|
||||
@@ -1680,7 +1681,7 @@ public:
|
||||
private:
|
||||
bool create_and_connect_socket(Socket &socket, Error &error) override;
|
||||
void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
|
||||
void shutdown_ssl_impl(Socket &socket, bool shutdown_socket);
|
||||
void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully);
|
||||
|
||||
bool process_socket(const Socket &socket,
|
||||
std::function<bool(Stream &strm)> callback) override;
|
||||
@@ -2066,7 +2067,7 @@ public:
|
||||
|
||||
class nocompressor : public compressor {
|
||||
public:
|
||||
virtual ~nocompressor() = default;
|
||||
~nocompressor() override = default;
|
||||
|
||||
bool compress(const char *data, size_t data_length, bool /*last*/,
|
||||
Callback callback) override;
|
||||
@@ -2076,7 +2077,7 @@ public:
|
||||
class gzip_compressor : public compressor {
|
||||
public:
|
||||
gzip_compressor();
|
||||
~gzip_compressor();
|
||||
~gzip_compressor() override;
|
||||
|
||||
bool compress(const char *data, size_t data_length, bool last,
|
||||
Callback callback) override;
|
||||
@@ -2089,7 +2090,7 @@ private:
|
||||
class gzip_decompressor : public decompressor {
|
||||
public:
|
||||
gzip_decompressor();
|
||||
~gzip_decompressor();
|
||||
~gzip_decompressor() override;
|
||||
|
||||
bool is_valid() const override;
|
||||
|
||||
@@ -2228,7 +2229,7 @@ inline std::string from_i_to_hex(size_t n) {
|
||||
|
||||
inline size_t to_utf8(int code, char *buff) {
|
||||
if (code < 0x0080) {
|
||||
buff[0] = (code & 0x7F);
|
||||
buff[0] = static_cast<char>(code & 0x7F);
|
||||
return 1;
|
||||
} else if (code < 0x0800) {
|
||||
buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
|
||||
@@ -2563,7 +2564,7 @@ inline mmap::mmap(const char *path)
|
||||
#endif
|
||||
,
|
||||
size_(0), addr_(nullptr) {
|
||||
if (!open(path)) { std::runtime_error(""); }
|
||||
open(path);
|
||||
}
|
||||
|
||||
inline mmap::~mmap() { close(); }
|
||||
@@ -2836,7 +2837,7 @@ private:
|
||||
size_t read_buff_off_ = 0;
|
||||
size_t read_buff_content_size_ = 0;
|
||||
|
||||
static const size_t read_buff_size_ = 1024 * 4;
|
||||
static const size_t read_buff_size_ = 1024l * 4;
|
||||
};
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -2965,7 +2966,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
|
||||
#ifndef _WIN32
|
||||
if (hints.ai_family == AF_UNIX) {
|
||||
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; }
|
||||
|
||||
auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
|
||||
if (sock != INVALID_SOCKET) {
|
||||
@@ -3169,7 +3170,7 @@ inline socket_t create_client_socket(
|
||||
#ifdef USE_IF2IP
|
||||
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())) {
|
||||
if (!bind_ip_address(sock2, ip_from_if)) {
|
||||
error = Error::BindIPAddress;
|
||||
return false;
|
||||
}
|
||||
@@ -3326,7 +3327,7 @@ find_content_type(const std::string &path,
|
||||
auto ext = file_extension(path);
|
||||
|
||||
auto it = user_data.find(ext);
|
||||
if (it != user_data.end()) { return it->second.c_str(); }
|
||||
if (it != user_data.end()) { return it->second; }
|
||||
|
||||
using udl::operator""_t;
|
||||
|
||||
@@ -3537,7 +3538,7 @@ inline bool gzip_decompressor::decompress(const char *data, size_t data_length,
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) return false;
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) { return false; }
|
||||
|
||||
} while (data_length > 0);
|
||||
|
||||
@@ -3805,7 +3806,7 @@ inline bool read_content_chunked(Stream &strm, T &x,
|
||||
|
||||
if (!line_reader.getline()) { return false; }
|
||||
|
||||
if (strcmp(line_reader.ptr(), "\r\n")) { return false; }
|
||||
if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; }
|
||||
|
||||
if (!line_reader.getline()) { return false; }
|
||||
}
|
||||
@@ -3815,7 +3816,7 @@ inline bool read_content_chunked(Stream &strm, T &x,
|
||||
// Trailer
|
||||
if (!line_reader.getline()) { return false; }
|
||||
|
||||
while (strcmp(line_reader.ptr(), "\r\n")) {
|
||||
while (strcmp(line_reader.ptr(), "\r\n") != 0) {
|
||||
if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
|
||||
|
||||
// Exclude line terminator
|
||||
@@ -3959,6 +3960,8 @@ inline bool write_content(Stream &strm, const ContentProvider &content_provider,
|
||||
return ok;
|
||||
};
|
||||
|
||||
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
|
||||
|
||||
while (offset < end_offset && !is_shutting_down()) {
|
||||
if (!strm.is_writable()) {
|
||||
error = Error::Write;
|
||||
@@ -4003,6 +4006,8 @@ write_content_without_length(Stream &strm,
|
||||
return ok;
|
||||
};
|
||||
|
||||
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
|
||||
|
||||
data_sink.done = [&](void) { data_available = false; };
|
||||
|
||||
while (data_available && !is_shutting_down()) {
|
||||
@@ -4053,6 +4058,8 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider,
|
||||
return ok;
|
||||
};
|
||||
|
||||
data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
|
||||
|
||||
auto done_with_trailer = [&](const Headers *trailer) {
|
||||
if (!ok) { return; }
|
||||
|
||||
@@ -4150,7 +4157,7 @@ inline bool redirect(T &cli, Request &req, Response &res,
|
||||
req = new_req;
|
||||
res = new_res;
|
||||
|
||||
if (res.location.empty()) res.location = location;
|
||||
if (res.location.empty()) { res.location = location; }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -4237,7 +4244,7 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
|
||||
auto len = static_cast<size_t>(m.length(1));
|
||||
auto all_valid_ranges = true;
|
||||
split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
|
||||
if (!all_valid_ranges) return;
|
||||
if (!all_valid_ranges) { return; }
|
||||
static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))");
|
||||
std::cmatch cm;
|
||||
if (std::regex_match(b, e, cm, re_another_range)) {
|
||||
@@ -4588,7 +4595,7 @@ serialize_multipart_formdata(const MultipartFormDataItems &items,
|
||||
body += item.content + serialize_multipart_formdata_item_end();
|
||||
}
|
||||
|
||||
if (finish) body += serialize_multipart_formdata_finish(boundary);
|
||||
if (finish) { body += serialize_multipart_formdata_finish(boundary); }
|
||||
|
||||
return body;
|
||||
}
|
||||
@@ -5296,7 +5303,7 @@ inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
|
||||
write_timeout_sec_(write_timeout_sec),
|
||||
write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
|
||||
|
||||
inline SocketStream::~SocketStream() {}
|
||||
inline SocketStream::~SocketStream() = default;
|
||||
|
||||
inline bool SocketStream::is_readable() const {
|
||||
return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
|
||||
@@ -5510,7 +5517,7 @@ inline Server::Server()
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Server::~Server() {}
|
||||
inline Server::~Server() = default;
|
||||
|
||||
inline std::unique_ptr<detail::MatcherBase>
|
||||
Server::make_matcher(const std::string &pattern) {
|
||||
@@ -5522,66 +5529,60 @@ Server::make_matcher(const std::string &pattern) {
|
||||
}
|
||||
|
||||
inline Server &Server::Get(const std::string &pattern, Handler handler) {
|
||||
get_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Post(const std::string &pattern, Handler handler) {
|
||||
post_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Post(const std::string &pattern,
|
||||
HandlerWithContentReader handler) {
|
||||
post_handlers_for_content_reader_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
|
||||
std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Put(const std::string &pattern, Handler handler) {
|
||||
put_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Put(const std::string &pattern,
|
||||
HandlerWithContentReader handler) {
|
||||
put_handlers_for_content_reader_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
|
||||
std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Patch(const std::string &pattern, Handler handler) {
|
||||
patch_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Patch(const std::string &pattern,
|
||||
HandlerWithContentReader handler) {
|
||||
patch_handlers_for_content_reader_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
|
||||
std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Delete(const std::string &pattern, Handler handler) {
|
||||
delete_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Delete(const std::string &pattern,
|
||||
HandlerWithContentReader handler) {
|
||||
delete_handlers_for_content_reader_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
|
||||
std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::Options(const std::string &pattern, Handler handler) {
|
||||
options_handlers_.push_back(
|
||||
std::make_pair(make_matcher(pattern), std::move(handler)));
|
||||
options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -5729,8 +5730,7 @@ inline Server &Server::set_payload_max_length(size_t length) {
|
||||
|
||||
inline bool Server::bind_to_port(const std::string &host, int port,
|
||||
int socket_flags) {
|
||||
if (bind_internal(host, port, socket_flags) < 0) return false;
|
||||
return true;
|
||||
return bind_internal(host, port, socket_flags) >= 0;
|
||||
}
|
||||
inline int Server::bind_to_any_port(const std::string &host, int socket_flags) {
|
||||
return bind_internal(host, 0, socket_flags);
|
||||
@@ -5764,7 +5764,7 @@ inline void Server::stop() {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Server::parse_request_line(const char *s, Request &req) {
|
||||
inline bool Server::parse_request_line(const char *s, Request &req) const {
|
||||
auto len = strlen(s);
|
||||
if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
|
||||
len -= 2;
|
||||
@@ -6015,10 +6015,11 @@ inline bool Server::read_content_with_content_receiver(
|
||||
std::move(multipart_receiver));
|
||||
}
|
||||
|
||||
inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader multipart_header,
|
||||
ContentReceiver multipart_receiver) {
|
||||
inline bool
|
||||
Server::read_content_core(Stream &strm, Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader multipart_header,
|
||||
ContentReceiver multipart_receiver) const {
|
||||
detail::MultipartFormDataParser multipart_form_data_parser;
|
||||
ContentReceiverWithProgress out;
|
||||
|
||||
@@ -6082,7 +6083,7 @@ inline bool Server::handle_file_request(const Request &req, Response &res,
|
||||
|
||||
if (detail::is_file(path)) {
|
||||
for (const auto &kv : entry.headers) {
|
||||
res.set_header(kv.first.c_str(), kv.second);
|
||||
res.set_header(kv.first, kv.second);
|
||||
}
|
||||
|
||||
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
||||
@@ -6309,7 +6310,7 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) {
|
||||
}
|
||||
|
||||
inline bool Server::dispatch_request(Request &req, Response &res,
|
||||
const Handlers &handlers) {
|
||||
const Handlers &handlers) const {
|
||||
for (const auto &x : handlers) {
|
||||
const auto &matcher = x.first;
|
||||
const auto &handler = x.second;
|
||||
@@ -6324,7 +6325,7 @@ inline bool Server::dispatch_request(Request &req, Response &res,
|
||||
|
||||
inline void Server::apply_ranges(const Request &req, Response &res,
|
||||
std::string &content_type,
|
||||
std::string &boundary) {
|
||||
std::string &boundary) const {
|
||||
if (req.ranges.size() > 1) {
|
||||
boundary = detail::make_multipart_data_boundary();
|
||||
|
||||
@@ -6436,7 +6437,7 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||
|
||||
inline bool Server::dispatch_request_for_content_reader(
|
||||
Request &req, Response &res, ContentReader content_reader,
|
||||
const HandlersForContentReader &handlers) {
|
||||
const HandlersForContentReader &handlers) const {
|
||||
for (const auto &x : handlers) {
|
||||
const auto &matcher = x.first;
|
||||
const auto &handler = x.second;
|
||||
@@ -6678,7 +6679,7 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
|
||||
// Check is custom IP specified for host_
|
||||
std::string ip;
|
||||
auto it = addr_map_.find(host_);
|
||||
if (it != addr_map_.end()) ip = it->second;
|
||||
if (it != addr_map_.end()) { ip = it->second; }
|
||||
|
||||
return detail::create_client_socket(
|
||||
host_, ip, port_, address_family_, tcp_nodelay_, socket_options_,
|
||||
@@ -6703,7 +6704,7 @@ inline void ClientImpl::shutdown_ssl(Socket & /*socket*/,
|
||||
socket_requests_are_from_thread_ == std::this_thread::get_id());
|
||||
}
|
||||
|
||||
inline void ClientImpl::shutdown_socket(Socket &socket) {
|
||||
inline void ClientImpl::shutdown_socket(Socket &socket) const {
|
||||
if (socket.sock == INVALID_SOCKET) { return; }
|
||||
detail::shutdown_socket(socket.sock);
|
||||
}
|
||||
@@ -6728,7 +6729,7 @@ inline void ClientImpl::close_socket(Socket &socket) {
|
||||
}
|
||||
|
||||
inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
|
||||
Response &res) {
|
||||
Response &res) const {
|
||||
std::array<char, 2048> buf{};
|
||||
|
||||
detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
|
||||
@@ -6992,7 +6993,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
||||
} else {
|
||||
if (next_scheme == "https") {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLClient cli(next_host.c_str(), next_port);
|
||||
SSLClient cli(next_host, next_port);
|
||||
cli.copy_settings(*this);
|
||||
if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
|
||||
return detail::redirect(cli, req, res, path, location, error);
|
||||
@@ -7000,7 +7001,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
ClientImpl cli(next_host.c_str(), next_port);
|
||||
ClientImpl cli(next_host, next_port);
|
||||
cli.copy_settings(*this);
|
||||
return detail::redirect(cli, req, res, path, location, error);
|
||||
}
|
||||
@@ -7009,7 +7010,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
||||
|
||||
inline bool ClientImpl::write_content_with_provider(Stream &strm,
|
||||
const Request &req,
|
||||
Error &error) {
|
||||
Error &error) const {
|
||||
auto is_shutting_down = []() { return false; };
|
||||
|
||||
if (req.is_chunked_content_provider_) {
|
||||
@@ -7335,13 +7336,14 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
||||
|
||||
inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
|
||||
const std::string &boundary, const MultipartFormDataItems &items,
|
||||
const MultipartFormDataProviderItems &provider_items) {
|
||||
size_t cur_item = 0, cur_start = 0;
|
||||
const MultipartFormDataProviderItems &provider_items) const {
|
||||
size_t cur_item = 0;
|
||||
size_t cur_start = 0;
|
||||
// cur_item and cur_start are copied to within the std::function and maintain
|
||||
// state between successive calls
|
||||
return [&, cur_item, cur_start](size_t offset,
|
||||
DataSink &sink) mutable -> bool {
|
||||
if (!offset && items.size()) {
|
||||
if (!offset && !items.empty()) {
|
||||
sink.os << detail::serialize_multipart_formdata(items, boundary, false);
|
||||
return true;
|
||||
} else if (cur_item < provider_items.size()) {
|
||||
@@ -7358,8 +7360,9 @@ inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
|
||||
cur_sink.write = sink.write;
|
||||
cur_sink.done = [&]() { has_data = false; };
|
||||
|
||||
if (!provider_items[cur_item].provider(offset - cur_start, cur_sink))
|
||||
if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!has_data) {
|
||||
sink.os << detail::serialize_multipart_formdata_item_end();
|
||||
@@ -7478,7 +7481,7 @@ inline Result ClientImpl::Get(const std::string &path, const Params ¶ms,
|
||||
if (params.empty()) { return Get(path, headers); }
|
||||
|
||||
std::string path_with_query = append_query_params(path, params);
|
||||
return Get(path_with_query.c_str(), headers, progress);
|
||||
return Get(path_with_query, headers, progress);
|
||||
}
|
||||
|
||||
inline Result ClientImpl::Get(const std::string &path, const Params ¶ms,
|
||||
@@ -7498,8 +7501,8 @@ inline Result ClientImpl::Get(const std::string &path, const Params ¶ms,
|
||||
}
|
||||
|
||||
std::string path_with_query = append_query_params(path, params);
|
||||
return Get(path_with_query.c_str(), headers, response_handler,
|
||||
content_receiver, progress);
|
||||
return Get(path_with_query, headers, response_handler, content_receiver,
|
||||
progress);
|
||||
}
|
||||
|
||||
inline Result ClientImpl::Head(const std::string &path) {
|
||||
@@ -7601,7 +7604,7 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
||||
const auto &content_type =
|
||||
detail::serialize_multipart_formdata_get_content_type(boundary);
|
||||
const auto &body = detail::serialize_multipart_formdata(items, boundary);
|
||||
return Post(path, headers, body, content_type.c_str());
|
||||
return Post(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
||||
@@ -7614,7 +7617,7 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
|
||||
const auto &content_type =
|
||||
detail::serialize_multipart_formdata_get_content_type(boundary);
|
||||
const auto &body = detail::serialize_multipart_formdata(items, boundary);
|
||||
return Post(path, headers, body, content_type.c_str());
|
||||
return Post(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
inline Result
|
||||
@@ -7996,9 +7999,9 @@ inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
|
||||
}
|
||||
|
||||
inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
|
||||
std::size_t size) {
|
||||
std::size_t size) const {
|
||||
auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
|
||||
if (!mem) return nullptr;
|
||||
if (!mem) { return nullptr; }
|
||||
|
||||
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
|
||||
if (!inf) {
|
||||
@@ -8148,7 +8151,7 @@ inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
|
||||
SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
}
|
||||
|
||||
inline SSLSocketStream::~SSLSocketStream() {}
|
||||
inline SSLSocketStream::~SSLSocketStream() = default;
|
||||
|
||||
inline bool SSLSocketStream::is_readable() const {
|
||||
return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
|
||||
@@ -8364,7 +8367,7 @@ inline SSLClient::SSLClient(const std::string &host, int port,
|
||||
|
||||
detail::split(&host_[0], &host_[host_.size()], '.',
|
||||
[&](const char *b, const char *e) {
|
||||
host_components_.emplace_back(std::string(b, e));
|
||||
host_components_.emplace_back(b, e);
|
||||
});
|
||||
|
||||
if (!client_cert_path.empty() && !client_key_path.empty()) {
|
||||
@@ -8385,7 +8388,7 @@ inline SSLClient::SSLClient(const std::string &host, int port,
|
||||
|
||||
detail::split(&host_[0], &host_[host_.size()], '.',
|
||||
[&](const char *b, const char *e) {
|
||||
host_components_.emplace_back(std::string(b, e));
|
||||
host_components_.emplace_back(b, e);
|
||||
});
|
||||
|
||||
if (client_cert != nullptr && client_key != nullptr) {
|
||||
@@ -8659,8 +8662,8 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
|
||||
|
||||
auto type = GEN_DNS;
|
||||
|
||||
struct in6_addr addr6;
|
||||
struct in_addr addr;
|
||||
struct in6_addr addr6 {};
|
||||
struct in_addr addr {};
|
||||
size_t addr_len = 0;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
@@ -8735,7 +8738,7 @@ inline bool SSLClient::check_host_name(const char *pattern,
|
||||
std::vector<std::string> pattern_components;
|
||||
detail::split(&pattern[0], &pattern[pattern_len], '.',
|
||||
[&](const char *b, const char *e) {
|
||||
pattern_components.emplace_back(std::string(b, e));
|
||||
pattern_components.emplace_back(b, e);
|
||||
});
|
||||
|
||||
if (host_components_.size() != pattern_components.size()) { return false; }
|
||||
@@ -8814,7 +8817,7 @@ inline Client::Client(const std::string &host, int port,
|
||||
: cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
|
||||
client_key_path)) {}
|
||||
|
||||
inline Client::~Client() {}
|
||||
inline Client::~Client() = default;
|
||||
|
||||
inline bool Client::is_valid() const {
|
||||
return cli_ != nullptr && cli_->is_valid();
|
||||
|
||||
@@ -102,3 +102,5 @@ if(HTTPLIB_IS_USING_OPENSSL)
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(fuzzing)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
file(GLOB HTTPLIB_CORPUS corpus/*)
|
||||
add_executable(httplib-test-fuzz
|
||||
server_fuzzer.cc
|
||||
standalone_fuzz_target_runner.cpp
|
||||
)
|
||||
target_link_libraries(httplib-test-fuzz PRIVATE httplib)
|
||||
add_test(
|
||||
NAME httplib-test-fuzz
|
||||
COMMAND httplib-test-fuzz ${HTTPLIB_CORPUS}
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include <httplib.h>
|
||||
#include <memory>
|
||||
|
||||
class FuzzedStream : public httplib::Stream {
|
||||
public:
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
// on the test corpus or on a single file,
|
||||
// e.g. the one that comes from a bug report.
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Forward declare the "fuzz target" interface.
|
||||
@@ -21,7 +21,7 @@ int main(int argc, char **argv) {
|
||||
std::ifstream in(argv[i]);
|
||||
in.seekg(0, in.end);
|
||||
size_t length = static_cast<size_t>(in.tellg());
|
||||
in.seekg (0, in.beg);
|
||||
in.seekg(0, in.beg);
|
||||
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
|
||||
// Allocate exactly length bytes so that we reliably catch buffer overflows.
|
||||
std::vector<char> bytes(length);
|
||||
|
||||
+72
-93
@@ -1088,12 +1088,8 @@ TEST(RedirectToDifferentPort, Redirect) {
|
||||
ASSERT_FALSE(svr1.is_running());
|
||||
});
|
||||
|
||||
while (!svr1.is_running() || !svr2.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));
|
||||
svr1.wait_until_ready();
|
||||
svr2.wait_until_ready();
|
||||
|
||||
Client cli("localhost", svr2_port);
|
||||
cli.set_follow_location(true);
|
||||
@@ -1125,9 +1121,6 @@ TEST(RedirectFromPageWithContent, Redirect) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli("localhost", PORT);
|
||||
cli.set_follow_location(true);
|
||||
@@ -1193,9 +1186,6 @@ TEST(RedirectFromPageWithContentIP6, Redirect) {
|
||||
ASSERT_LT(milliseconds, 5000U);
|
||||
}
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli("http://[::1]:1234");
|
||||
cli.set_follow_location(true);
|
||||
@@ -1246,8 +1236,7 @@ TEST(PathUrlEncodeTest, PathUrlEncode) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1277,8 +1266,7 @@ TEST(BindServerTest, DISABLED_BindDualStack) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli("127.0.0.1", PORT);
|
||||
@@ -1349,8 +1337,7 @@ TEST(ErrorHandlerTest, ContentLength) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1391,8 +1378,7 @@ TEST(ExceptionHandlerTest, ContentLength) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1432,8 +1418,7 @@ TEST(NoContentTest, ContentLength) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1483,8 +1468,7 @@ TEST(RoutingHandlerTest, PreRoutingHandler) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -1552,8 +1536,7 @@ TEST(InvalidFormatTest, StatusCode) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1577,7 +1560,7 @@ TEST(URLFragmentTest, WithFragment) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -1613,7 +1596,7 @@ TEST(HeaderWriter, SetHeaderWriter) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -2205,9 +2188,7 @@ protected:
|
||||
|
||||
t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
|
||||
|
||||
while (!svr_.is_running()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
svr_.wait_until_ready();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
@@ -4222,9 +4203,6 @@ TEST(MountTest, Unmount) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
svr.set_mount_point("/mount2", "./www2");
|
||||
@@ -4275,9 +4253,6 @@ TEST(ExceptionTest, ThrowExceptionInHandler) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
{
|
||||
@@ -4319,9 +4294,6 @@ TEST(KeepAliveTest, ReadTimeout) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
cli.set_keep_alive(true);
|
||||
cli.set_read_timeout(std::chrono::seconds(1));
|
||||
@@ -4351,7 +4323,7 @@ TEST(KeepAliveTest, Issue1041) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
svr.wait_until_ready();
|
||||
|
||||
Client cli(HOST, PORT);
|
||||
cli.set_keep_alive(true);
|
||||
@@ -4384,7 +4356,7 @@ TEST(KeepAliveTest, SSLClientReconnection) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -4447,9 +4419,6 @@ TEST(ClientProblemDetectionTest, ContentProvider) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
{
|
||||
@@ -4487,9 +4456,6 @@ TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
auto res = cli.Get("/");
|
||||
@@ -4498,6 +4464,43 @@ TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
|
||||
EXPECT_EQ("helloworld", res->body);
|
||||
}
|
||||
|
||||
TEST(LongPollingTest, ClientCloseDetection) {
|
||||
Server svr;
|
||||
|
||||
svr.Get("/events", [&](const Request & /*req*/, Response &res) {
|
||||
res.set_chunked_content_provider(
|
||||
"text/plain", [](std::size_t const, DataSink &sink) -> bool {
|
||||
EXPECT_TRUE(sink.is_writable()); // the socket is alive
|
||||
sink.os << "hello";
|
||||
|
||||
auto count = 10;
|
||||
while (count > 0 && sink.is_writable()) {
|
||||
this_thread::sleep_for(chrono::milliseconds(10));
|
||||
}
|
||||
EXPECT_FALSE(sink.is_writable()); // the socket is closed
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
svr.stop();
|
||||
listen_thread.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
auto res = cli.Get("/events", [&](const char *data, size_t data_length) {
|
||||
EXPECT_EQ("hello", string(data, data_length));
|
||||
return false; // close the socket immediately.
|
||||
});
|
||||
|
||||
ASSERT_FALSE(res);
|
||||
}
|
||||
|
||||
TEST(GetWithParametersTest, GetWithParameters) {
|
||||
Server svr;
|
||||
|
||||
@@ -4533,7 +4536,6 @@ TEST(GetWithParametersTest, GetWithParameters) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -4592,7 +4594,6 @@ TEST(GetWithParametersTest, GetWithParameters2) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
@@ -4660,7 +4661,6 @@ TEST(ServerDefaultHeadersTest, DefaultHeaders) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
Client cli("localhost", PORT);
|
||||
|
||||
@@ -4695,9 +4695,6 @@ TEST(KeepAliveTest, ReadTimeoutSSL) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
SSLClient cli("localhost", PORT);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_keep_alive(true);
|
||||
@@ -4736,9 +4733,7 @@ protected:
|
||||
t_ = thread(
|
||||
[&]() { ASSERT_TRUE(svr_.listen(std::string(), PORT, AI_PASSIVE)); });
|
||||
|
||||
while (!svr_.is_running()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
svr_.wait_until_ready();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
@@ -4775,9 +4770,7 @@ protected:
|
||||
ASSERT_TRUE(svr_.listen_after_bind());
|
||||
});
|
||||
|
||||
while (!svr_.is_running()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
svr_.wait_until_ready();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
@@ -4818,9 +4811,7 @@ protected:
|
||||
|
||||
t_ = thread([&]() { ASSERT_TRUE(svr_.listen(HOST, PORT)); });
|
||||
|
||||
while (!svr_.is_running()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
svr_.wait_until_ready();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
@@ -4937,7 +4928,7 @@ TEST(SSLClientTest, ServerCertificateVerification4) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli("127.0.0.1", PORT);
|
||||
cli.set_ca_cert_path(SERVER_CERT2_FILE);
|
||||
@@ -5053,7 +5044,7 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -5128,7 +5119,7 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -5159,7 +5150,7 @@ TEST(SSLClientServerTest, ClientCertMissing) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT);
|
||||
auto res = cli.Get("/test");
|
||||
@@ -5183,7 +5174,7 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -5204,12 +5195,12 @@ TEST(SSLClientServerTest, SSLConnectTimeout) {
|
||||
client_ca_cert_dir_path),
|
||||
stop_(false) {}
|
||||
|
||||
bool stop_;
|
||||
std::atomic_bool stop_;
|
||||
|
||||
private:
|
||||
bool process_and_close_socket(socket_t /*sock*/) override {
|
||||
// Don't create SSL context
|
||||
while (!stop_) {
|
||||
while (!stop_.load()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
return true;
|
||||
@@ -5231,7 +5222,7 @@ TEST(SSLClientServerTest, SSLConnectTimeout) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -5303,7 +5294,7 @@ TEST(SSLClientServerTest, CustomizeServerSSLCtx) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -5439,9 +5430,10 @@ TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
|
||||
ASSERT_TRUE(content);
|
||||
|
||||
Server svr;
|
||||
svr.Get("/foo", [=](const httplib::Request &req, httplib::Response &resp) {
|
||||
resp.set_content(content, content_size, "application/octet-stream");
|
||||
});
|
||||
svr.Get("/foo",
|
||||
[=](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content(content, content_size, "application/octet-stream");
|
||||
});
|
||||
|
||||
auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
@@ -5453,9 +5445,6 @@ TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
// 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);
|
||||
@@ -5590,7 +5579,8 @@ TEST(HttpToHttpsRedirectTest, CertFile) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
svr.wait_until_ready();
|
||||
ssl_svr.wait_until_ready();
|
||||
|
||||
Client cli("127.0.0.1", PORT);
|
||||
cli.set_ca_cert_path(SERVER_CERT2_FILE);
|
||||
@@ -5646,7 +5636,6 @@ TEST(MultipartFormDataTest, LargeData) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
std::string data(1024 * 1024 * 2, '.');
|
||||
@@ -5794,7 +5783,6 @@ TEST(MultipartFormDataTest, DataProviderItems) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli("https://localhost:8080");
|
||||
@@ -5996,7 +5984,6 @@ TEST(MultipartFormDataTest, PostCustomBoundary) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
std::string data(1024 * 1024 * 2, '.');
|
||||
@@ -6018,9 +6005,6 @@ TEST(MultipartFormDataTest, PostCustomBoundary) {
|
||||
}
|
||||
|
||||
TEST(MultipartFormDataTest, PostInvalidBoundaryChars) {
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
std::string data(1024 * 1024 * 2, '&');
|
||||
std::stringstream buffer;
|
||||
buffer << data;
|
||||
@@ -6083,7 +6067,6 @@ TEST(MultipartFormDataTest, PutFormData) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
std::string data(1024 * 1024 * 2, '&');
|
||||
@@ -6148,7 +6131,6 @@ TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
std::string data(1024 * 1024 * 2, '&');
|
||||
@@ -6170,9 +6152,6 @@ TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
|
||||
}
|
||||
|
||||
TEST(MultipartFormDataTest, PutInvalidBoundaryChars) {
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
std::string data(1024 * 1024 * 2, '&');
|
||||
std::stringstream buffer;
|
||||
buffer << data;
|
||||
@@ -6242,7 +6221,7 @@ TEST(MultipartFormDataTest, AlternateFilename) {
|
||||
"\r\n"
|
||||
"text default\r\n"
|
||||
"----------\r\n"
|
||||
"Content-Disposition: form-data; filename*=\"UTF-8''\%41.txt\"; "
|
||||
"Content-Disposition: form-data; filename*=\"UTF-8''%41.txt\"; "
|
||||
"filename=\"a.txt\"; name=\"file1\"\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"\r\n"
|
||||
@@ -6501,7 +6480,7 @@ TEST(RedirectTest, RedirectToUrlWithQueryParameters) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
@@ -6547,7 +6526,7 @@ TEST(VulnerabilityTest, CRLFInjection) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
svr.wait_until_ready();
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||
configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
|
||||
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||
configure_file(input: '1MB.txt', output: '1MB.txt', copy: true)
|
||||
|
||||
Reference in New Issue
Block a user