mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2025-05-10 09:43:51 +00:00
parent
887def9490
commit
c4f3f9529b
84
httplib.h
84
httplib.h
@ -152,6 +152,8 @@ using ssize_t = int;
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#pragma comment(lib, "crypt32.lib")
|
||||||
|
#pragma comment(lib, "cryptui.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef strcasecmp
|
#ifndef strcasecmp
|
||||||
@ -1062,6 +1064,8 @@ private:
|
|||||||
bool connect_with_proxy(Socket &sock, Response &res, bool &success);
|
bool connect_with_proxy(Socket &sock, Response &res, bool &success);
|
||||||
bool initialize_ssl(Socket &socket);
|
bool initialize_ssl(Socket &socket);
|
||||||
|
|
||||||
|
bool load_certs();
|
||||||
|
|
||||||
bool verify_host(X509 *server_cert) const;
|
bool verify_host(X509 *server_cert) const;
|
||||||
bool verify_host_with_subject_alt_name(X509 *server_cert) const;
|
bool verify_host_with_subject_alt_name(X509 *server_cert) const;
|
||||||
bool verify_host_with_common_name(X509 *server_cert) const;
|
bool verify_host_with_common_name(X509 *server_cert) const;
|
||||||
@ -1069,12 +1073,14 @@ private:
|
|||||||
|
|
||||||
SSL_CTX *ctx_;
|
SSL_CTX *ctx_;
|
||||||
std::mutex ctx_mutex_;
|
std::mutex ctx_mutex_;
|
||||||
|
std::once_flag initialize_cert_;
|
||||||
|
|
||||||
std::vector<std::string> host_components_;
|
std::vector<std::string> host_components_;
|
||||||
|
|
||||||
std::string ca_cert_file_path_;
|
std::string ca_cert_file_path_;
|
||||||
std::string ca_cert_dir_path_;
|
std::string ca_cert_dir_path_;
|
||||||
X509_STORE *ca_cert_store_ = nullptr;
|
X509_STORE *ca_cert_store_ = nullptr;
|
||||||
bool server_certificate_verification_ = false;
|
bool server_certificate_verification_ = true;
|
||||||
long verify_result_ = 0;
|
long verify_result_ = 0;
|
||||||
|
|
||||||
friend class Client;
|
friend class Client;
|
||||||
@ -1313,9 +1319,7 @@ public:
|
|||||||
|
|
||||||
void stop() { cli_->stop(); }
|
void stop() { cli_->stop(); }
|
||||||
|
|
||||||
void set_tcp_nodelay(bool on) {
|
void set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
|
||||||
cli_->set_tcp_nodelay(on);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_socket_options(SocketOptions socket_options) {
|
void set_socket_options(SocketOptions socket_options) {
|
||||||
cli_->set_socket_options(socket_options);
|
cli_->set_socket_options(socket_options);
|
||||||
@ -2776,7 +2780,7 @@ inline std::string params_to_query_str(const Params ¶ms) {
|
|||||||
if (it != params.begin()) { query += "&"; }
|
if (it != params.begin()) { query += "&"; }
|
||||||
query += it->first;
|
query += it->first;
|
||||||
query += "=";
|
query += "=";
|
||||||
query += detail::encode_url(it->second);
|
query += encode_url(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
@ -3223,6 +3227,33 @@ inline std::string SHA_512(const std::string &s) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
// NOTE: This code came up with the following stackoverflow post:
|
||||||
|
// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
|
||||||
|
inline bool load_system_certs_on_windows(X509_STORE *store) {
|
||||||
|
auto hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, L"ROOT");
|
||||||
|
|
||||||
|
if (!hStore) { return false; }
|
||||||
|
|
||||||
|
PCCERT_CONTEXT pContext = NULL;
|
||||||
|
while (pContext = CertEnumCertificatesInStore(hStore, pContext)) {
|
||||||
|
auto encoded_cert =
|
||||||
|
static_cast<const unsigned char *>(pContext->pbCertEncoded);
|
||||||
|
|
||||||
|
auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
|
||||||
|
if (x509) {
|
||||||
|
X509_STORE_add_cert(store, x509);
|
||||||
|
X509_free(x509);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CertFreeCertificateContext(pContext);
|
||||||
|
CertCloseStore(hStore, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class WSInit {
|
class WSInit {
|
||||||
public:
|
public:
|
||||||
WSInit() {
|
WSInit() {
|
||||||
@ -5544,23 +5575,44 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool SSLClient::initialize_ssl(Socket &socket) {
|
inline bool SSLClient::load_certs() {
|
||||||
auto ssl = detail::ssl_new(
|
bool ret = true;
|
||||||
socket.sock, ctx_, ctx_mutex_,
|
|
||||||
[&](SSL *ssl) {
|
std::call_once(initialize_cert_, [&]() {
|
||||||
if (ca_cert_file_path_.empty() && ca_cert_store_ == nullptr) {
|
std::lock_guard<std::mutex> guard(ctx_mutex_);
|
||||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr);
|
if (!ca_cert_file_path_.empty()) {
|
||||||
} else if (!ca_cert_file_path_.empty()) {
|
|
||||||
if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
|
if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
|
||||||
nullptr)) {
|
nullptr)) {
|
||||||
return false;
|
ret = false;
|
||||||
|
}
|
||||||
|
} else if (!ca_cert_dir_path_.empty()) {
|
||||||
|
if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
|
||||||
|
ca_cert_dir_path_.c_str())) {
|
||||||
|
ret = false;
|
||||||
}
|
}
|
||||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
|
|
||||||
} else if (ca_cert_store_ != nullptr) {
|
} else if (ca_cert_store_ != nullptr) {
|
||||||
if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store_) {
|
if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store_) {
|
||||||
SSL_CTX_set_cert_store(ctx_, ca_cert_store_);
|
SSL_CTX_set_cert_store(ctx_, ca_cert_store_);
|
||||||
}
|
}
|
||||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
|
||||||
|
#else
|
||||||
|
SSL_CTX_set_default_verify_paths(ctx_);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SSLClient::initialize_ssl(Socket &socket) {
|
||||||
|
auto ssl = detail::ssl_new(
|
||||||
|
socket.sock, ctx_, ctx_mutex_,
|
||||||
|
[&](SSL *ssl) {
|
||||||
|
if (server_certificate_verification_) {
|
||||||
|
if (!load_certs()) { return false; }
|
||||||
|
SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSL_connect(ssl) != 1) { return false; }
|
if (SSL_connect(ssl) != 1) { return false; }
|
||||||
@ -5750,3 +5802,5 @@ inline bool SSLClient::check_host_name(const char *pattern,
|
|||||||
} // namespace httplib
|
} // namespace httplib
|
||||||
|
|
||||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
|
|
||||||
|
22
test/test.cc
22
test/test.cc
@ -765,6 +765,9 @@ protected:
|
|||||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
cli_.enable_server_certificate_verification(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@ -2627,6 +2630,9 @@ protected:
|
|||||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
cli_.enable_server_certificate_verification(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@ -2704,6 +2710,9 @@ protected:
|
|||||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
cli_.enable_server_certificate_verification(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@ -2763,6 +2772,7 @@ TEST(SSLClientTest, ServerCertificateVerification1) {
|
|||||||
TEST(SSLClientTest, ServerCertificateVerification2) {
|
TEST(SSLClientTest, ServerCertificateVerification2) {
|
||||||
SSLClient cli("google.com");
|
SSLClient cli("google.com");
|
||||||
cli.enable_server_certificate_verification(true);
|
cli.enable_server_certificate_verification(true);
|
||||||
|
cli.set_ca_cert_path("hello");
|
||||||
auto res = cli.Get("/");
|
auto res = cli.Get("/");
|
||||||
ASSERT_TRUE(res == nullptr);
|
ASSERT_TRUE(res == nullptr);
|
||||||
}
|
}
|
||||||
@ -2819,8 +2829,10 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
|
||||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||||
auto res = cli.Get("/test");
|
cli.enable_server_certificate_verification(false);
|
||||||
cli.set_connection_timeout(30);
|
cli.set_connection_timeout(30);
|
||||||
|
|
||||||
|
auto res = cli.Get("/test");
|
||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
ASSERT_EQ(200, res->status);
|
ASSERT_EQ(200, res->status);
|
||||||
|
|
||||||
@ -2888,8 +2900,10 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
|
||||||
httplib::SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
httplib::SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||||
auto res = cli.Get("/test");
|
cli.enable_server_certificate_verification(false);
|
||||||
cli.set_connection_timeout(30);
|
cli.set_connection_timeout(30);
|
||||||
|
|
||||||
|
auto res = cli.Get("/test");
|
||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
ASSERT_EQ(200, res->status);
|
ASSERT_EQ(200, res->status);
|
||||||
|
|
||||||
@ -2934,8 +2948,10 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
|
||||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||||
auto res = cli.Get("/test");
|
cli.enable_server_certificate_verification(false);
|
||||||
cli.set_connection_timeout(30);
|
cli.set_connection_timeout(30);
|
||||||
|
|
||||||
|
auto res = cli.Get("/test");
|
||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
ASSERT_EQ(200, res->status);
|
ASSERT_EQ(200, res->status);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user