From: Joel Rosdahl Date: Tue, 7 Jun 2022 18:11:29 +0000 (+0200) Subject: bump: Upgrade to cpp-httplib 0.10.8 X-Git-Tag: v4.7~201 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=65deaea00258b4b12ed82585b771a557eacd1356;p=thirdparty%2Fccache.git bump: Upgrade to cpp-httplib 0.10.8 --- diff --git a/LICENSE.adoc b/LICENSE.adoc index 2413c98e9..0829e328d 100644 --- a/LICENSE.adoc +++ b/LICENSE.adoc @@ -516,13 +516,13 @@ SUCH DAMAGE. === src/third_party/httplib.* cpp-httplib - A C++11 cross-platform HTTP/HTTPS library. Copied from cpp-httplib -v0.10.2 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The +v0.10.8 downloaded from https://github.com/yhirose/cpp-httplib[cpp-httplib]. The library has the following license: ---- The MIT License (MIT) -Copyright (c) 2021 yhirose +Copyright (c) 2022 yhirose Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/third_party/httplib.cpp b/src/third_party/httplib.cpp index 70c86f1a6..03c080622 100644 --- a/src/third_party/httplib.cpp +++ b/src/third_party/httplib.cpp @@ -469,7 +469,8 @@ ssize_t select_write(socket_t sock, time_t sec, time_t usec) { #endif } -Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { +Error wait_until_socket_is_ready(socket_t sock, time_t sec, + time_t usec) { #ifdef CPPHTTPLIB_USE_POLL struct pollfd pfd_read; pfd_read.fd = sock; @@ -479,9 +480,7 @@ Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); - if (poll_res == 0) { - return Error::ConnectionTimeout; - } + if (poll_res == 0) { return Error::ConnectionTimeout; } if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { int error = 0; @@ -513,9 +512,7 @@ Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { return select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv); }); - if (ret == 0) { - return Error::ConnectionTimeout; - } + if (ret == 0) { return Error::ConnectionTimeout; } if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { int error = 0; @@ -805,11 +802,14 @@ bool bind_ip_address(socket_t sock, const char *host) { #endif #ifdef USE_IF2IP -std::string if2ip(const std::string &ifn) { +std::string if2ip(int address_family, const std::string &ifn) { struct ifaddrs *ifap; getifaddrs(&ifap); + std::string addr_candidate; for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr && ifn == ifa->ifa_name) { + if (ifa->ifa_addr && ifn == ifa->ifa_name && + (AF_UNSPEC == address_family || + ifa->ifa_addr->sa_family == address_family)) { if (ifa->ifa_addr->sa_family == AF_INET) { auto sa = reinterpret_cast(ifa->ifa_addr); char buf[INET_ADDRSTRLEN]; @@ -817,11 +817,26 @@ std::string if2ip(const std::string &ifn) { freeifaddrs(ifap); return std::string(buf, INET_ADDRSTRLEN); } + } else if (ifa->ifa_addr->sa_family == AF_INET6) { + auto sa = reinterpret_cast(ifa->ifa_addr); + if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) { + char buf[INET6_ADDRSTRLEN] = {}; + if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) { + // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL + auto s6_addr_head = sa->sin6_addr.s6_addr[0]; + if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) { + addr_candidate = std::string(buf, INET6_ADDRSTRLEN); + } else { + freeifaddrs(ifap); + return std::string(buf, INET6_ADDRSTRLEN); + } + } + } } } } freeifaddrs(ifap); - return std::string(); + return addr_candidate; } #endif @@ -836,9 +851,9 @@ socket_t create_client_socket( [&](socket_t sock2, struct addrinfo &ai) -> bool { if (!intf.empty()) { #ifdef USE_IF2IP - auto ip = if2ip(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; } @@ -857,9 +872,7 @@ socket_t create_client_socket( } error = wait_until_socket_is_ready(sock2, connection_timeout_sec, connection_timeout_usec); - if (error != Error::Success) { - return false; - } + if (error != Error::Success) { return false; } } set_nonblocking(sock2, false); @@ -971,10 +984,12 @@ find_content_type(const std::string &path, default: return nullptr; case "css"_t: return "text/css"; case "csv"_t: return "text/csv"; - case "txt"_t: return "text/plain"; - case "vtt"_t: return "text/vtt"; case "htm"_t: case "html"_t: return "text/html"; + case "js"_t: + case "mjs"_t: return "text/javascript"; + case "txt"_t: return "text/plain"; + case "vtt"_t: return "text/vtt"; case "apng"_t: return "image/apng"; case "avif"_t: return "image/avif"; @@ -1006,8 +1021,6 @@ find_content_type(const std::string &path, case "7z"_t: return "application/x-7z-compressed"; case "atom"_t: return "application/atom+xml"; case "pdf"_t: return "application/pdf"; - case "js"_t: - case "mjs"_t: return "application/javascript"; case "json"_t: return "application/json"; case "rss"_t: return "application/rss+xml"; case "tar"_t: return "application/x-tar"; @@ -1092,14 +1105,21 @@ const char *status_message(int status) { } bool can_compress_content_type(const std::string &content_type) { - return (!content_type.rfind("text/", 0) && - content_type != "text/event-stream") || - content_type == "image/svg+xml" || - content_type == "application/javascript" || - content_type == "application/json" || - content_type == "application/xml" || - content_type == "application/protobuf" || - content_type == "application/xhtml+xml"; + using udl::operator""_t; + + auto tag = str2tag(content_type); + + switch (tag) { + case "image/svg+xml"_t: + case "application/javascript"_t: + case "application/json"_t: + case "application/xml"_t: + case "application/protobuf"_t: + case "application/xhtml+xml"_t: return true; + + default: + return !content_type.rfind("text/", 0) && tag != "text/event-stream"_t; + } } EncodingType encoding_type(const Request &req, const Response &res) { @@ -1178,7 +1198,6 @@ bool gzip_compressor::compress(const char *data, size_t data_length, assert((flush == Z_FINISH && ret == Z_STREAM_END) || (flush == Z_NO_FLUSH && ret == Z_OK)); assert(strm_.avail_in == 0); - } while (data_length > 0); return true; @@ -1590,7 +1609,7 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, if (!ret) { status = exceed_payload_max_length ? 413 : 400; } return ret; }); -} +} // namespace detail ssize_t write_headers(Stream &strm, const Headers &headers) { ssize_t write_len = 0; @@ -1904,10 +1923,11 @@ public: bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, const MultipartContentHeader &header_callback) { + // TODO: support 'filename*' static const std::regex re_content_disposition( - "^Content-Disposition:\\s*form-data;\\s*name=\"(.*?)\"(?:;\\s*filename=" - "\"(.*?)\")?\\s*$", + R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~", std::regex_constants::icase); + static const std::string dash_ = "--"; static const std::string crlf_ = "\r\n"; @@ -2297,36 +2317,36 @@ bool has_crlf(const char *s) { } #ifdef CPPHTTPLIB_OPENSSL_SUPPORT -template -std::string message_digest(const std::string &s, Init init, - Update update, Final final, - size_t digest_length) { - std::vector md(digest_length, 0); - CTX ctx; - init(&ctx); - update(&ctx, s.data(), s.size()); - final(md.data(), &ctx); +std::string message_digest(const std::string &s, const EVP_MD *algo) { + auto context = std::unique_ptr( + EVP_MD_CTX_new(), EVP_MD_CTX_free); + + unsigned int hash_length = 0; + unsigned char hash[EVP_MAX_MD_SIZE]; + + EVP_DigestInit_ex(context.get(), algo, nullptr); + EVP_DigestUpdate(context.get(), s.c_str(), s.size()); + EVP_DigestFinal_ex(context.get(), hash, &hash_length); std::stringstream ss; - for (auto c : md) { - ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)c; + for (auto i = 0u; i < hash_length; ++i) { + ss << std::hex << std::setw(2) << std::setfill('0') + << (unsigned int)hash[i]; } + return ss.str(); } std::string MD5(const std::string &s) { - return message_digest(s, MD5_Init, MD5_Update, MD5_Final, - MD5_DIGEST_LENGTH); + return message_digest(s, EVP_md5()); } std::string SHA_256(const std::string &s) { - return message_digest(s, SHA256_Init, SHA256_Update, SHA256_Final, - SHA256_DIGEST_LENGTH); + return message_digest(s, EVP_sha256()); } std::string SHA_512(const std::string &s) { - return message_digest(s, SHA512_Init, SHA512_Update, SHA512_Final, - SHA512_DIGEST_LENGTH); + return message_digest(s, EVP_sha512()); } #endif @@ -2363,10 +2383,14 @@ class WSInit { public: WSInit() { WSADATA wsaData; - WSAStartup(0x0002, &wsaData); + if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true; } - ~WSInit() { WSACleanup(); } + ~WSInit() { + if (is_valid_) WSACleanup(); + } + + bool is_valid_ = false; }; static WSInit wsinit_; @@ -2530,6 +2554,8 @@ void hosted_at(const char *hostname, std::vector &addrs) { addrs.push_back(ip); } } + + freeaddrinfo(result); } std::string append_query_params(const char *path, const Params ¶ms) { @@ -2810,7 +2836,7 @@ ssize_t SocketStream::read(char *ptr, size_t size) { 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((std::numeric_limits::max)())); #endif @@ -3117,6 +3143,14 @@ bool Server::parse_request_line(const char *s, Request &req) { if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } { + // Skip URL fragment + for (size_t i = 0; i < req.target.size(); i++) { + if (req.target[i] == '#') { + req.target.erase(i); + break; + } + } + size_t count = 0; detail::split(req.target.data(), req.target.data() + req.target.size(), '?', @@ -3304,7 +3338,7 @@ 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; } @@ -4312,9 +4346,12 @@ bool ClientImpl::write_request(Stream &strm, Request &req, if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); } +#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT if (!req.has_header("User-Agent")) { - req.headers.emplace("User-Agent", "cpp-httplib/0.10.1"); + auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION; + req.headers.emplace("User-Agent", agent); } +#endif if (req.body.empty()) { if (req.content_provider_) { @@ -4428,8 +4465,8 @@ std::unique_ptr 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; }); @@ -5090,8 +5127,8 @@ void ClientImpl::set_follow_location(bool on) { follow_location_ = on; } void ClientImpl::set_url_encode(bool on) { url_encode_ = on; } -void ClientImpl::set_hostname_addr_map( - const std::map addr_map) { +void +ClientImpl::set_hostname_addr_map(std::map addr_map) { addr_map_ = std::move(addr_map); } @@ -5334,62 +5371,63 @@ bool SSLSocketStream::is_writable() const { } 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(size)); - } else if (is_readable()) { - auto ret = SSL_read(ssl_, ptr, static_cast(size)); - if (ret < 0) { - auto err = SSL_get_error(ssl_, ret); - int n = 1000; + auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes); + if (ret == 1) { return static_cast(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(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))) { + while (--n >= 0 && + (err == SSL_ERROR_WANT_READ || + (err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) { #else - while (--n >= 0 && err == SSL_ERROR_WANT_READ) { + while (--n >= 0 && err == SSL_ERROR_WANT_READ) { #endif - if (SSL_pending(ssl_) > 0) { - return SSL_read(ssl_, ptr, static_cast(size)); - } else if (is_readable()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - ret = SSL_read(ssl_, ptr, static_cast(size)); - if (ret >= 0) { return ret; } - err = SSL_get_error(ssl_, ret); - } else { - return -1; - } - } + if (SSL_pending(ssl_) > 0) { + ret = SSL_read_ex(ssl_, ptr, size, &readbytes); + if (ret == 1) { return static_cast(readbytes); } + if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; } + return -1; } - return ret; + 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(readbytes); } + err = SSL_get_error(ssl_, ret); } + if (err == SSL_ERROR_ZERO_RETURN) { return 0; } return -1; } ssize_t SSLSocketStream::write(const char *ptr, size_t size) { - if (is_writable()) { - auto ret = SSL_write(ssl_, ptr, static_cast(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(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(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(written); } + err = SSL_get_error(ssl_, ret); } + if (err == SSL_ERROR_ZERO_RETURN) { return 0; } return -1; } @@ -5407,7 +5445,8 @@ static SSLInit sslinit_; // SSL HTTP server implementation SSLServer::SSLServer(const char *cert_path, const char *private_key_path, const char *client_ca_cert_file_path, - const char *client_ca_cert_dir_path) { + const char *client_ca_cert_dir_path, + const char *private_key_password) { ctx_ = SSL_CTX_new(TLS_server_method()); if (ctx_) { @@ -5417,6 +5456,12 @@ SSLServer::SSLServer(const char *cert_path, const char *private_key_path, SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); + // add default password callback before opening encrypted private key + if (private_key_password != nullptr && (private_key_password[0] != '\0')) { + SSL_CTX_set_default_passwd_cb_userdata(ctx_, + (char *)private_key_password); + } + if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != 1) { @@ -5478,11 +5523,11 @@ SSL_CTX *SSLServer::ssl_context() const { return ctx_; } 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) { @@ -5676,31 +5721,31 @@ bool SSLClient::load_certs() { 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; @@ -5717,8 +5762,8 @@ 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; }); @@ -6209,8 +6254,8 @@ size_t Client::is_socket_open() const { return cli_->is_socket_open(); } void Client::stop() { cli_->stop(); } -void Client::set_hostname_addr_map( - const std::map addr_map) { +void +Client::set_hostname_addr_map(std::map addr_map) { cli_->set_hostname_addr_map(std::move(addr_map)); } diff --git a/src/third_party/httplib.h b/src/third_party/httplib.h index 014d21653..ed165bcd4 100644 --- a/src/third_party/httplib.h +++ b/src/third_party/httplib.h @@ -1,13 +1,15 @@ // // httplib.h // -// Copyright (c) 2021 Yuji Hirose. All rights reserved. +// Copyright (c) 2022 Yuji Hirose. All rights reserved. // MIT License // #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H +#define CPPHTTPLIB_VERSION "0.10.7" + /* * Configuration */ @@ -72,6 +74,10 @@ #define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits::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 @@ -142,8 +148,6 @@ using ssize_t = int; #include #include - -#include #include #ifndef WSA_FLAG_NO_HANDLE_INHERIT @@ -152,8 +156,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 @@ -168,8 +170,8 @@ using socket_t = SOCKET; #else // not _WIN32 #include -#include #include +#include #include #include #ifdef __linux__ @@ -191,6 +193,7 @@ using socket_t = int; #endif #endif //_WIN32 +#include #include #include #include @@ -217,17 +220,24 @@ using socket_t = int; #include #ifdef CPPHTTPLIB_OPENSSL_SUPPORT +#ifdef _WIN32 +#include + // 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 -#include +#include #include #include @@ -973,7 +983,7 @@ public: void stop(); - void set_hostname_addr_map(const std::map addr_map); + void set_hostname_addr_map(std::map addr_map); void set_default_headers(Headers headers); @@ -1308,7 +1318,7 @@ public: void stop(); - void set_hostname_addr_map(const std::map addr_map); + void set_hostname_addr_map(std::map addr_map); void set_default_headers(Headers headers); @@ -1384,7 +1394,8 @@ class SSLServer : public Server { public: SSLServer(const char *cert_path, const char *private_key_path, const char *client_ca_cert_file_path = nullptr, - const char *client_ca_cert_dir_path = nullptr); + const char *client_ca_cert_dir_path = nullptr, + const char *private_key_password = nullptr); SSLServer(X509 *cert, EVP_PKEY *private_key, X509_STORE *client_ca_cert_store = nullptr);