@@ -1246,6 +1246,17 @@ class Result {
12461246 Headers &&request_headers = Headers{})
12471247 : res_(std::move(res)), err_(err),
12481248 request_headers_ (std::move(request_headers)) {}
1249+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1250+ Result (std::unique_ptr<Response> &&res, Error err, Headers &&request_headers,
1251+ int ssl_error)
1252+ : res_(std::move(res)), err_(err),
1253+ request_headers_(std::move(request_headers)), ssl_error_(ssl_error) {}
1254+ Result (std::unique_ptr<Response> &&res, Error err, Headers &&request_headers,
1255+ int ssl_error, unsigned long ssl_openssl_error)
1256+ : res_(std::move(res)), err_(err),
1257+ request_headers_(std::move(request_headers)), ssl_error_(ssl_error),
1258+ ssl_openssl_error_(ssl_openssl_error) {}
1259+ #endif
12491260 // Response
12501261 operator bool () const { return res_ != nullptr ; }
12511262 bool operator ==(std::nullptr_t ) const { return res_ == nullptr ; }
@@ -1260,6 +1271,13 @@ class Result {
12601271 // Error
12611272 Error error () const { return err_; }
12621273
1274+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1275+ // SSL Error
1276+ int ssl_error () const { return ssl_error_; }
1277+ // OpenSSL Error
1278+ unsigned long ssl_openssl_error () const { return ssl_openssl_error_; }
1279+ #endif
1280+
12631281 // Request Headers
12641282 bool has_request_header (const std::string &key) const ;
12651283 std::string get_request_header_value (const std::string &key,
@@ -1273,6 +1291,10 @@ class Result {
12731291 std::unique_ptr<Response> res_;
12741292 Error err_ = Error::Unknown;
12751293 Headers request_headers_;
1294+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1295+ int ssl_error_ = 0 ;
1296+ unsigned long ssl_openssl_error_ = 0 ;
1297+ #endif
12761298};
12771299
12781300class ClientImpl {
@@ -1570,6 +1592,11 @@ class ClientImpl {
15701592
15711593 Logger logger_;
15721594
1595+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1596+ int last_ssl_error_ = 0 ;
1597+ unsigned long last_openssl_error_ = 0 ;
1598+ #endif
1599+
15731600private:
15741601 bool send_ (Request &req, Response &res, Error &error);
15751602 Result send_ (Request &&req);
@@ -1840,6 +1867,9 @@ class SSLServer : public Server {
18401867
18411868 SSL_CTX *ctx_;
18421869 std::mutex ctx_mutex_;
1870+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1871+ int last_ssl_error_ = 0 ;
1872+ #endif
18431873};
18441874
18451875class SSLClient final : public ClientImpl {
@@ -8173,7 +8203,12 @@ inline Result ClientImpl::send_(Request &&req) {
81738203 auto res = detail::make_unique<Response>();
81748204 auto error = Error::Success;
81758205 auto ret = send (req, *res, error);
8206+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8207+ return Result{ret ? std::move (res) : nullptr , error, std::move (req.headers ),
8208+ last_ssl_error_, last_openssl_error_};
8209+ #else
81768210 return Result{ret ? std::move (res) : nullptr , error, std::move (req.headers )};
8211+ #endif
81778212}
81788213
81798214inline bool ClientImpl::handle_request (Stream &strm, Request &req,
@@ -8723,7 +8758,12 @@ inline Result ClientImpl::send_with_content_provider(
87238758 req, body, content_length, std::move (content_provider),
87248759 std::move (content_provider_without_length), content_type, error);
87258760
8761+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8762+ return Result{std::move (res), error, std::move (req.headers ), last_ssl_error_,
8763+ last_openssl_error_};
8764+ #else
87268765 return Result{std::move (res), error, std::move (req.headers )};
8766+ #endif
87278767}
87288768
87298769inline std::string
@@ -9790,8 +9830,8 @@ inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock,
97909830template <typename U>
97919831bool ssl_connect_or_accept_nonblocking (socket_t sock, SSL *ssl,
97929832 U ssl_connect_or_accept,
9793- time_t timeout_sec,
9794- time_t timeout_usec ) {
9833+ time_t timeout_sec, time_t timeout_usec,
9834+ int *ssl_error ) {
97959835 auto res = 0 ;
97969836 while ((res = ssl_connect_or_accept (ssl)) != 1 ) {
97979837 auto err = SSL_get_error (ssl, res);
@@ -9804,6 +9844,7 @@ bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl,
98049844 break ;
98059845 default : break ;
98069846 }
9847+ if (ssl_error) { *ssl_error = err; }
98079848 return false ;
98089849 }
98099850 return true ;
@@ -9897,9 +9938,10 @@ inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
98979938 if (ret >= 0 ) { return ret; }
98989939 err = SSL_get_error (ssl_, ret);
98999940 } else {
9900- return - 1 ;
9941+ break ;
99019942 }
99029943 }
9944+ assert (ret < 0 );
99039945 }
99049946 return ret;
99059947 } else {
@@ -9929,9 +9971,10 @@ inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
99299971 if (ret >= 0 ) { return ret; }
99309972 err = SSL_get_error (ssl_, ret);
99319973 } else {
9932- return - 1 ;
9974+ break ;
99339975 }
99349976 }
9977+ assert (ret < 0 );
99359978 }
99369979 return ret;
99379980 }
@@ -9982,6 +10025,7 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
998210025 SSL_CTX_use_PrivateKey_file (ctx_, private_key_path, SSL_FILETYPE_PEM) !=
998310026 1 ||
998410027 SSL_CTX_check_private_key (ctx_) != 1 ) {
10028+ last_ssl_error_ = static_cast <int >(ERR_get_error ());
998510029 SSL_CTX_free (ctx_);
998610030 ctx_ = nullptr ;
998710031 } else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
@@ -10055,7 +10099,8 @@ inline bool SSLServer::process_and_close_socket(socket_t sock) {
1005510099 sock, ctx_, ctx_mutex_,
1005610100 [&](SSL *ssl2) {
1005710101 return detail::ssl_connect_or_accept_nonblocking (
10058- sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_);
10102+ sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_,
10103+ &last_ssl_error_);
1005910104 },
1006010105 [](SSL * /* ssl2*/ ) { return true ; });
1006110106
@@ -10123,6 +10168,7 @@ inline SSLClient::SSLClient(const std::string &host, int port,
1012310168 SSL_FILETYPE_PEM) != 1 ||
1012410169 SSL_CTX_use_PrivateKey_file (ctx_, client_key_path.c_str (),
1012510170 SSL_FILETYPE_PEM) != 1 ) {
10171+ last_openssl_error_ = ERR_get_error ();
1012610172 SSL_CTX_free (ctx_);
1012710173 ctx_ = nullptr ;
1012810174 }
@@ -10149,6 +10195,7 @@ inline SSLClient::SSLClient(const std::string &host, int port,
1014910195
1015010196 if (SSL_CTX_use_certificate (ctx_, client_cert) != 1 ||
1015110197 SSL_CTX_use_PrivateKey (ctx_, client_key) != 1 ) {
10198+ last_openssl_error_ = ERR_get_error ();
1015210199 SSL_CTX_free (ctx_);
1015310200 ctx_ = nullptr ;
1015410201 }
@@ -10292,11 +10339,13 @@ inline bool SSLClient::load_certs() {
1029210339 if (!ca_cert_file_path_.empty ()) {
1029310340 if (!SSL_CTX_load_verify_locations (ctx_, ca_cert_file_path_.c_str (),
1029410341 nullptr )) {
10342+ last_openssl_error_ = ERR_get_error ();
1029510343 ret = false ;
1029610344 }
1029710345 } else if (!ca_cert_dir_path_.empty ()) {
1029810346 if (!SSL_CTX_load_verify_locations (ctx_, nullptr ,
1029910347 ca_cert_dir_path_.c_str ())) {
10348+ last_openssl_error_ = ERR_get_error ();
1030010349 ret = false ;
1030110350 }
1030210351 } else {
@@ -10329,7 +10378,7 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1032910378
1033010379 if (!detail::ssl_connect_or_accept_nonblocking (
1033110380 socket.sock , ssl2, SSL_connect, connection_timeout_sec_,
10332- connection_timeout_usec_)) {
10381+ connection_timeout_usec_, &last_ssl_error_ )) {
1033310382 error = Error::SSLConnection;
1033410383 return false ;
1033510384 }
@@ -10342,6 +10391,7 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1034210391 }
1034310392
1034410393 if (verification_status == SSLVerifierResponse::CertificateRejected) {
10394+ last_openssl_error_ = ERR_get_error ();
1034510395 error = Error::SSLServerVerification;
1034610396 return false ;
1034710397 }
@@ -10350,6 +10400,7 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1035010400 verify_result_ = SSL_get_verify_result (ssl2);
1035110401
1035210402 if (verify_result_ != X509_V_OK) {
10403+ last_openssl_error_ = static_cast <unsigned long >(verify_result_);
1035310404 error = Error::SSLServerVerification;
1035410405 return false ;
1035510406 }
@@ -10358,12 +10409,14 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1035810409 auto se = detail::scope_exit ([&] { X509_free (server_cert); });
1035910410
1036010411 if (server_cert == nullptr ) {
10412+ last_openssl_error_ = ERR_get_error ();
1036110413 error = Error::SSLServerVerification;
1036210414 return false ;
1036310415 }
1036410416
1036510417 if (server_hostname_verification_) {
1036610418 if (!verify_host (server_cert)) {
10419+ last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH;
1036710420 error = Error::SSLServerHostnameVerification;
1036810421 return false ;
1036910422 }
0 commit comments