You've already forked cpp-httplib
							
							Removed std::atomic<Error> error_
				
					
				
			This commit is contained in:
		
							
								
								
									
										281
									
								
								httplib.h
									
									
									
									
									
								
							
							
						
						
									
										281
									
								
								httplib.h
									
									
									
									
									
								
							| @@ -753,7 +753,8 @@ enum Error { | |||||||
|   SSLConnection, |   SSLConnection, | ||||||
|   SSLLoadingCerts, |   SSLLoadingCerts, | ||||||
|   SSLServerVerification, |   SSLServerVerification, | ||||||
|   UnsupportedMultipartBoundaryChars |   UnsupportedMultipartBoundaryChars, | ||||||
|  |   Compression, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class Result { | class Result { | ||||||
| @@ -878,7 +879,8 @@ public: | |||||||
|   Result Options(const char *path); |   Result Options(const char *path); | ||||||
|   Result Options(const char *path, const Headers &headers); |   Result Options(const char *path, const Headers &headers); | ||||||
|  |  | ||||||
|   bool send(const Request &req, Response &res); |   bool send(const Request &req, Response &res, Error &error); | ||||||
|  |   Result send(const Request &req); | ||||||
|  |  | ||||||
|   size_t is_socket_open() const; |   size_t is_socket_open() const; | ||||||
|  |  | ||||||
| @@ -931,7 +933,7 @@ protected: | |||||||
|     bool is_open() const { return sock != INVALID_SOCKET; } |     bool is_open() const { return sock != INVALID_SOCKET; } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   virtual bool create_and_connect_socket(Socket &socket); |   virtual bool create_and_connect_socket(Socket &socket, Error &error); | ||||||
|  |  | ||||||
|   // All of: |   // All of: | ||||||
|   //   shutdown_ssl |   //   shutdown_ssl | ||||||
| @@ -949,16 +951,13 @@ protected: | |||||||
|   void lock_socket_and_shutdown_and_close(); |   void lock_socket_and_shutdown_and_close(); | ||||||
|  |  | ||||||
|   bool process_request(Stream &strm, const Request &req, Response &res, |   bool process_request(Stream &strm, const Request &req, Response &res, | ||||||
|                        bool close_connection); |                        bool close_connection, Error &error); | ||||||
|  |  | ||||||
|   bool write_content_with_provider(Stream &strm, const Request &req); |   bool write_content_with_provider(Stream &strm, const Request &req, | ||||||
|   Error get_last_error() const; |                                    Error &error); | ||||||
|  |  | ||||||
|   void copy_settings(const ClientImpl &rhs); |   void copy_settings(const ClientImpl &rhs); | ||||||
|  |  | ||||||
|   // Error state |  | ||||||
|   mutable std::atomic<Error> error_; |  | ||||||
|  |  | ||||||
|   // Socket endoint information |   // Socket endoint information | ||||||
|   const std::string host_; |   const std::string host_; | ||||||
|   const int port_; |   const int port_; | ||||||
| @@ -970,7 +969,7 @@ protected: | |||||||
|   std::recursive_mutex request_mutex_; |   std::recursive_mutex request_mutex_; | ||||||
|  |  | ||||||
|   // These are all protected under socket_mutex |   // These are all protected under socket_mutex | ||||||
|   int socket_requests_in_flight_ = 0; |   size_t socket_requests_in_flight_ = 0; | ||||||
|   std::thread::id socket_requests_are_from_thread_ = std::thread::id(); |   std::thread::id socket_requests_are_from_thread_ = std::thread::id(); | ||||||
|   bool socket_should_be_closed_when_request_is_done_ = false; |   bool socket_should_be_closed_when_request_is_done_ = false; | ||||||
|  |  | ||||||
| @@ -1025,13 +1024,20 @@ protected: | |||||||
|   Logger logger_; |   Logger logger_; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   socket_t create_client_socket() const; |   socket_t create_client_socket(Error &error) const; | ||||||
|   bool read_response_line(Stream &strm, Response &res); |   bool read_response_line(Stream &strm, Response &res); | ||||||
|   bool write_request(Stream &strm, const Request &req, bool close_connection); |   bool write_request(Stream &strm, const Request &req, bool close_connection, | ||||||
|   bool redirect(const Request &req, Response &res); |                      Error &error); | ||||||
|  |   bool redirect(const Request &req, Response &res, Error &error); | ||||||
|   bool handle_request(Stream &strm, const Request &req, Response &res, |   bool handle_request(Stream &strm, const Request &req, Response &res, | ||||||
|                       bool close_connection); |                       bool close_connection, Error &error); | ||||||
|   std::unique_ptr<Response> send_with_content_provider( |   std::unique_ptr<Response> send_with_content_provider( | ||||||
|  |       const char *method, const char *path, const Headers &headers, | ||||||
|  |       const std::string &body, size_t content_length, | ||||||
|  |       ContentProvider content_provider, | ||||||
|  |       ContentProviderWithoutLength content_provider_without_length, | ||||||
|  |       const char *content_type, Error &error); | ||||||
|  |   Result send_with_content_provider( | ||||||
|       const char *method, const char *path, const Headers &headers, |       const char *method, const char *path, const Headers &headers, | ||||||
|       const std::string &body, size_t content_length, |       const std::string &body, size_t content_length, | ||||||
|       ContentProvider content_provider, |       ContentProvider content_provider, | ||||||
| @@ -1149,7 +1155,8 @@ public: | |||||||
|   Result Options(const char *path); |   Result Options(const char *path); | ||||||
|   Result Options(const char *path, const Headers &headers); |   Result Options(const char *path, const Headers &headers); | ||||||
|  |  | ||||||
|   bool send(const Request &req, Response &res); |   bool send(const Request &req, Response &res, Error &error); | ||||||
|  |   Result send(const Request &req); | ||||||
|  |  | ||||||
|   size_t is_socket_open() const; |   size_t is_socket_open() const; | ||||||
|  |  | ||||||
| @@ -1260,15 +1267,16 @@ public: | |||||||
|   SSL_CTX *ssl_context() const; |   SSL_CTX *ssl_context() const; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   bool create_and_connect_socket(Socket &socket) override; |   bool create_and_connect_socket(Socket &socket, Error &error) override; | ||||||
|   void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override; |   void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override; | ||||||
|  |  | ||||||
|   bool process_socket(const Socket &socket, |   bool process_socket(const Socket &socket, | ||||||
|                       std::function<bool(Stream &strm)> callback) override; |                       std::function<bool(Stream &strm)> callback) override; | ||||||
|   bool is_ssl() const override; |   bool is_ssl() const override; | ||||||
|  |  | ||||||
|   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); |                           Error &error); | ||||||
|  |   bool initialize_ssl(Socket &socket, Error &error); | ||||||
|  |  | ||||||
|   bool load_certs(); |   bool load_certs(); | ||||||
|  |  | ||||||
| @@ -2056,8 +2064,7 @@ inline socket_t create_client_socket(const char *host, int port, | |||||||
|                                      bool tcp_nodelay, |                                      bool tcp_nodelay, | ||||||
|                                      SocketOptions socket_options, |                                      SocketOptions socket_options, | ||||||
|                                      time_t timeout_sec, time_t timeout_usec, |                                      time_t timeout_sec, time_t timeout_usec, | ||||||
|                                      const std::string &intf, |                                      const std::string &intf, Error &error) { | ||||||
|                                      std::atomic<Error> &error) { |  | ||||||
|   auto sock = create_socket( |   auto sock = create_socket( | ||||||
|       host, port, 0, tcp_nodelay, std::move(socket_options), |       host, port, 0, tcp_nodelay, std::move(socket_options), | ||||||
|       [&](socket_t sock, struct addrinfo &ai) -> bool { |       [&](socket_t sock, struct addrinfo &ai) -> bool { | ||||||
| @@ -2804,7 +2811,7 @@ inline bool write_data(Stream &strm, const char *d, size_t l) { | |||||||
| template <typename T> | template <typename T> | ||||||
| inline bool write_content(Stream &strm, const ContentProvider &content_provider, | inline bool write_content(Stream &strm, const ContentProvider &content_provider, | ||||||
|                           size_t offset, size_t length, T is_shutting_down, |                           size_t offset, size_t length, T is_shutting_down, | ||||||
|                           std::atomic<Error> &error) { |                           Error &error) { | ||||||
|   size_t end_offset = offset + length; |   size_t end_offset = offset + length; | ||||||
|   auto ok = true; |   auto ok = true; | ||||||
|   DataSink data_sink; |   DataSink data_sink; | ||||||
| @@ -2840,7 +2847,7 @@ template <typename T> | |||||||
| inline bool write_content(Stream &strm, const ContentProvider &content_provider, | inline bool write_content(Stream &strm, const ContentProvider &content_provider, | ||||||
|                           size_t offset, size_t length, |                           size_t offset, size_t length, | ||||||
|                           const T &is_shutting_down) { |                           const T &is_shutting_down) { | ||||||
|   std::atomic<Error> error; |   auto error = Error::Success; | ||||||
|   return write_content(strm, content_provider, offset, length, is_shutting_down, |   return write_content(strm, content_provider, offset, length, is_shutting_down, | ||||||
|                        error); |                        error); | ||||||
| } | } | ||||||
| @@ -2874,10 +2881,9 @@ write_content_without_length(Stream &strm, | |||||||
| } | } | ||||||
|  |  | ||||||
| template <typename T, typename U> | template <typename T, typename U> | ||||||
| inline bool write_content_chunked(Stream &strm, | inline bool | ||||||
|                                   const ContentProvider &content_provider, | write_content_chunked(Stream &strm, const ContentProvider &content_provider, | ||||||
|                                   const T &is_shutting_down, U &compressor, |                       const T &is_shutting_down, U &compressor, Error &error) { | ||||||
|                                   std::atomic<Error> &error) { |  | ||||||
|   size_t offset = 0; |   size_t offset = 0; | ||||||
|   auto data_available = true; |   auto data_available = true; | ||||||
|   auto ok = true; |   auto ok = true; | ||||||
| @@ -2960,14 +2966,15 @@ template <typename T, typename U> | |||||||
| inline bool write_content_chunked(Stream &strm, | inline bool write_content_chunked(Stream &strm, | ||||||
|                                   const ContentProvider &content_provider, |                                   const ContentProvider &content_provider, | ||||||
|                                   const T &is_shutting_down, U &compressor) { |                                   const T &is_shutting_down, U &compressor) { | ||||||
|   std::atomic<Error> error; |   auto error = Error::Success; | ||||||
|   return write_content_chunked(strm, content_provider, is_shutting_down, |   return write_content_chunked(strm, content_provider, is_shutting_down, | ||||||
|                                compressor, error); |                                compressor, error); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename T> | template <typename T> | ||||||
| inline bool redirect(T &cli, const Request &req, Response &res, | inline bool redirect(T &cli, const Request &req, Response &res, | ||||||
|                      const std::string &path, const std::string &location) { |                      const std::string &path, const std::string &location, | ||||||
|  |                      Error &error) { | ||||||
|   Request new_req = req; |   Request new_req = req; | ||||||
|   new_req.path = path; |   new_req.path = path; | ||||||
|   new_req.redirect_count_ -= 1; |   new_req.redirect_count_ -= 1; | ||||||
| @@ -2980,7 +2987,7 @@ inline bool redirect(T &cli, const Request &req, Response &res, | |||||||
|  |  | ||||||
|   Response new_res; |   Response new_res; | ||||||
|  |  | ||||||
|   auto ret = cli.send(new_req, new_res); |   auto ret = cli.send(new_req, new_res, error); | ||||||
|   if (ret) { |   if (ret) { | ||||||
|     new_res.location = location; |     new_res.location = location; | ||||||
|     res = new_res; |     res = new_res; | ||||||
| @@ -4832,7 +4839,8 @@ inline ClientImpl::ClientImpl(const std::string &host, int port) | |||||||
| inline ClientImpl::ClientImpl(const std::string &host, int port, | inline ClientImpl::ClientImpl(const std::string &host, int port, | ||||||
|                               const std::string &client_cert_path, |                               const std::string &client_cert_path, | ||||||
|                               const std::string &client_key_path) |                               const std::string &client_key_path) | ||||||
|     : error_(Error::Success), host_(host), port_(port), |     // : (Error::Success), host_(host), port_(port), | ||||||
|  |     : host_(host), port_(port), | ||||||
|       host_and_port_(host_ + ":" + std::to_string(port_)), |       host_and_port_(host_ + ":" + std::to_string(port_)), | ||||||
|       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} |       client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} | ||||||
|  |  | ||||||
| @@ -4840,8 +4848,6 @@ inline ClientImpl::~ClientImpl() { lock_socket_and_shutdown_and_close(); } | |||||||
|  |  | ||||||
| inline bool ClientImpl::is_valid() const { return true; } | inline bool ClientImpl::is_valid() const { return true; } | ||||||
|  |  | ||||||
| inline Error ClientImpl::get_last_error() const { return error_; } |  | ||||||
|  |  | ||||||
| inline void ClientImpl::copy_settings(const ClientImpl &rhs) { | inline void ClientImpl::copy_settings(const ClientImpl &rhs) { | ||||||
|   client_cert_path_ = rhs.client_cert_path_; |   client_cert_path_ = rhs.client_cert_path_; | ||||||
|   client_key_path_ = rhs.client_key_path_; |   client_key_path_ = rhs.client_key_path_; | ||||||
| @@ -4879,19 +4885,20 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) { | |||||||
|   logger_ = rhs.logger_; |   logger_ = rhs.logger_; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline socket_t ClientImpl::create_client_socket() const { | inline socket_t ClientImpl::create_client_socket(Error &error) const { | ||||||
|   if (!proxy_host_.empty() && proxy_port_ != -1) { |   if (!proxy_host_.empty() && proxy_port_ != -1) { | ||||||
|     return detail::create_client_socket( |     return detail::create_client_socket( | ||||||
|         proxy_host_.c_str(), proxy_port_, tcp_nodelay_, socket_options_, |         proxy_host_.c_str(), proxy_port_, tcp_nodelay_, socket_options_, | ||||||
|         connection_timeout_sec_, connection_timeout_usec_, interface_, error_); |         connection_timeout_sec_, connection_timeout_usec_, interface_, error); | ||||||
|   } |   } | ||||||
|   return detail::create_client_socket( |   return detail::create_client_socket( | ||||||
|       host_.c_str(), port_, tcp_nodelay_, socket_options_, |       host_.c_str(), port_, tcp_nodelay_, socket_options_, | ||||||
|       connection_timeout_sec_, connection_timeout_usec_, interface_, error_); |       connection_timeout_sec_, connection_timeout_usec_, interface_, error); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::create_and_connect_socket(Socket &socket) { | inline bool ClientImpl::create_and_connect_socket(Socket &socket, | ||||||
|   auto sock = create_client_socket(); |                                                   Error &error) { | ||||||
|  |   auto sock = create_client_socket(error); | ||||||
|   if (sock == INVALID_SOCKET) { return false; } |   if (sock == INVALID_SOCKET) { return false; } | ||||||
|   socket.sock = sock; |   socket.sock = sock; | ||||||
|   return true; |   return true; | ||||||
| @@ -4919,6 +4926,7 @@ inline void ClientImpl::close_socket(Socket &socket) { | |||||||
|   // than the one they intended! |   // than the one they intended! | ||||||
|   assert(socket_requests_in_flight_ == 0 || |   assert(socket_requests_in_flight_ == 0 || | ||||||
|          socket_requests_are_from_thread_ == std::this_thread::get_id()); |          socket_requests_are_from_thread_ == std::this_thread::get_id()); | ||||||
|  |  | ||||||
|   // It is also a bug if this happens while SSL is still active |   // It is also a bug if this happens while SSL is still active | ||||||
| #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | ||||||
|   assert(socket.ssl == nullptr); |   assert(socket.ssl == nullptr); | ||||||
| @@ -4964,7 +4972,7 @@ inline bool ClientImpl::read_response_line(Stream &strm, Response &res) { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::send(const Request &req, Response &res) { | inline bool ClientImpl::send(const Request &req, Response &res, Error &error) { | ||||||
|   std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_); |   std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_); | ||||||
|  |  | ||||||
|   { |   { | ||||||
| @@ -4989,7 +4997,7 @@ inline bool ClientImpl::send(const Request &req, Response &res) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!is_alive) { |     if (!is_alive) { | ||||||
|       if (!create_and_connect_socket(socket_)) { return false; } |       if (!create_and_connect_socket(socket_, error)) { return false; } | ||||||
|  |  | ||||||
| #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | ||||||
|       // TODO: refactoring |       // TODO: refactoring | ||||||
| @@ -4997,12 +5005,12 @@ inline bool ClientImpl::send(const Request &req, Response &res) { | |||||||
|         auto &scli = static_cast<SSLClient &>(*this); |         auto &scli = static_cast<SSLClient &>(*this); | ||||||
|         if (!proxy_host_.empty() && proxy_port_ != -1) { |         if (!proxy_host_.empty() && proxy_port_ != -1) { | ||||||
|           bool success = false; |           bool success = false; | ||||||
|           if (!scli.connect_with_proxy(socket_, res, success)) { |           if (!scli.connect_with_proxy(socket_, res, success, error)) { | ||||||
|             return success; |             return success; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!scli.initialize_ssl(socket_)) { return false; } |         if (!scli.initialize_ssl(socket_, error)) { return false; } | ||||||
|       } |       } | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
| @@ -5019,7 +5027,7 @@ inline bool ClientImpl::send(const Request &req, Response &res) { | |||||||
|  |  | ||||||
|   auto close_connection = !keep_alive_; |   auto close_connection = !keep_alive_; | ||||||
|   auto ret = process_socket(socket_, [&](Stream &strm) { |   auto ret = process_socket(socket_, [&](Stream &strm) { | ||||||
|     return handle_request(strm, req, res, close_connection); |     return handle_request(strm, req, res, close_connection, error); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // Briefly lock mutex in order to mark that a request is no longer ongoing |   // Briefly lock mutex in order to mark that a request is no longer ongoing | ||||||
| @@ -5040,16 +5048,24 @@ inline bool ClientImpl::send(const Request &req, Response &res) { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!ret) { |   if (!ret) { | ||||||
|     if (error_ == Error::Success) { error_ = Error::Unknown; } |     if (error == Error::Success) { error = Error::Unknown; } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | inline Result ClientImpl::send(const Request &req) { | ||||||
|  |   auto res = detail::make_unique<Response>(); | ||||||
|  |   auto error = Error::Success; | ||||||
|  |   auto ret = send(req, *res, error); | ||||||
|  |   return Result{ret ? std::move(res) : nullptr, error}; | ||||||
|  | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::handle_request(Stream &strm, const Request &req, | inline bool ClientImpl::handle_request(Stream &strm, const Request &req, | ||||||
|                                        Response &res, bool close_connection) { |                                        Response &res, bool close_connection, | ||||||
|  |                                        Error &error) { | ||||||
|   if (req.path.empty()) { |   if (req.path.empty()) { | ||||||
|     error_ = Error::Connection; |     error = Error::Connection; | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -5058,15 +5074,15 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req, | |||||||
|   if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) { |   if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) { | ||||||
|     auto req2 = req; |     auto req2 = req; | ||||||
|     req2.path = "http://" + host_and_port_ + req.path; |     req2.path = "http://" + host_and_port_ + req.path; | ||||||
|     ret = process_request(strm, req2, res, close_connection); |     ret = process_request(strm, req2, res, close_connection, error); | ||||||
|   } else { |   } else { | ||||||
|     ret = process_request(strm, req, res, close_connection); |     ret = process_request(strm, req, res, close_connection, error); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!ret) { return false; } |   if (!ret) { return false; } | ||||||
|  |  | ||||||
|   if (300 < res.status && res.status < 400 && follow_location_) { |   if (300 < res.status && res.status < 400 && follow_location_) { | ||||||
|     ret = redirect(req, res); |     ret = redirect(req, res, error); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | ||||||
| @@ -5091,7 +5107,7 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req, | |||||||
|  |  | ||||||
|         Response new_res; |         Response new_res; | ||||||
|  |  | ||||||
|         ret = send(new_req, new_res); |         ret = send(new_req, new_res, error); | ||||||
|         if (ret) { res = new_res; } |         if (ret) { res = new_res; } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -5101,9 +5117,10 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req, | |||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::redirect(const Request &req, Response &res) { | inline bool ClientImpl::redirect(const Request &req, Response &res, | ||||||
|  |                                  Error &error) { | ||||||
|   if (req.redirect_count_ == 0) { |   if (req.redirect_count_ == 0) { | ||||||
|     error_ = Error::ExceedRedirectCount; |     error = Error::ExceedRedirectCount; | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -5135,30 +5152,27 @@ inline bool ClientImpl::redirect(const Request &req, Response &res) { | |||||||
|   if (next_path.empty()) { next_path = "/"; } |   if (next_path.empty()) { next_path = "/"; } | ||||||
|  |  | ||||||
|   if (next_scheme == scheme && next_host == host_ && next_port == port_) { |   if (next_scheme == scheme && next_host == host_ && next_port == port_) { | ||||||
|     return detail::redirect(*this, req, res, next_path, location); |     return detail::redirect(*this, req, res, next_path, location, error); | ||||||
|   } else { |   } else { | ||||||
|     if (next_scheme == "https") { |     if (next_scheme == "https") { | ||||||
| #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | #ifdef CPPHTTPLIB_OPENSSL_SUPPORT | ||||||
|       SSLClient cli(next_host.c_str(), next_port); |       SSLClient cli(next_host.c_str(), next_port); | ||||||
|       cli.copy_settings(*this); |       cli.copy_settings(*this); | ||||||
|       auto ret = detail::redirect(cli, req, res, next_path, location); |       return detail::redirect(cli, req, res, next_path, location, error); | ||||||
|       if (!ret) { error_ = cli.get_last_error(); } |  | ||||||
|       return ret; |  | ||||||
| #else | #else | ||||||
|       return false; |       return false; | ||||||
| #endif | #endif | ||||||
|     } else { |     } else { | ||||||
|       ClientImpl cli(next_host.c_str(), next_port); |       ClientImpl cli(next_host.c_str(), next_port); | ||||||
|       cli.copy_settings(*this); |       cli.copy_settings(*this); | ||||||
|       auto ret = detail::redirect(cli, req, res, next_path, location); |       return detail::redirect(cli, req, res, next_path, location, error); | ||||||
|       if (!ret) { error_ = cli.get_last_error(); } |  | ||||||
|       return ret; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::write_content_with_provider(Stream &strm, | inline bool ClientImpl::write_content_with_provider(Stream &strm, | ||||||
|                                                     const Request &req) { |                                                     const Request &req, | ||||||
|  |                                                     Error &error) { | ||||||
|   auto is_shutting_down = []() { return false; }; |   auto is_shutting_down = []() { return false; }; | ||||||
|  |  | ||||||
|   if (req.is_chunked_content_provider_) { |   if (req.is_chunked_content_provider_) { | ||||||
| @@ -5174,15 +5188,15 @@ inline bool ClientImpl::write_content_with_provider(Stream &strm, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     return detail::write_content_chunked(strm, req.content_provider_, |     return detail::write_content_chunked(strm, req.content_provider_, | ||||||
|                                          is_shutting_down, *compressor, error_); |                                          is_shutting_down, *compressor, error); | ||||||
|   } else { |   } else { | ||||||
|     return detail::write_content(strm, req.content_provider_, 0, |     return detail::write_content(strm, req.content_provider_, 0, | ||||||
|                                  req.content_length_, is_shutting_down, error_); |                                  req.content_length_, is_shutting_down, error); | ||||||
|   } |   } | ||||||
| } // namespace httplib | } // namespace httplib | ||||||
|  |  | ||||||
| inline bool ClientImpl::write_request(Stream &strm, const Request &req, | inline bool ClientImpl::write_request(Stream &strm, const Request &req, | ||||||
|                                       bool close_connection) { |                                       bool close_connection, Error &error) { | ||||||
|   detail::BufferStream bstrm; |   detail::BufferStream bstrm; | ||||||
|  |  | ||||||
|   // Request line |   // Request line | ||||||
| @@ -5265,13 +5279,13 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req, | |||||||
|   // Flush buffer |   // Flush buffer | ||||||
|   auto &data = bstrm.get_buffer(); |   auto &data = bstrm.get_buffer(); | ||||||
|   if (!detail::write_data(strm, data.data(), data.size())) { |   if (!detail::write_data(strm, data.data(), data.size())) { | ||||||
|     error_ = Error::Write; |     error = Error::Write; | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Body |   // Body | ||||||
|   if (req.body.empty()) { |   if (req.body.empty()) { | ||||||
|     return write_content_with_provider(strm, req); |     return write_content_with_provider(strm, req, error); | ||||||
|   } else { |   } else { | ||||||
|     return detail::write_data(strm, req.body.data(), req.body.size()); |     return detail::write_data(strm, req.body.data(), req.body.size()); | ||||||
|   } |   } | ||||||
| @@ -5284,7 +5298,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider( | |||||||
|     const std::string &body, size_t content_length, |     const std::string &body, size_t content_length, | ||||||
|     ContentProvider content_provider, |     ContentProvider content_provider, | ||||||
|     ContentProviderWithoutLength content_provider_without_length, |     ContentProviderWithoutLength content_provider_without_length, | ||||||
|     const char *content_type) { |     const char *content_type, Error &error) { | ||||||
|  |  | ||||||
|   Request req; |   Request req; | ||||||
|   req.method = method; |   req.method = method; | ||||||
| @@ -5330,7 +5344,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider( | |||||||
|  |  | ||||||
|       while (ok && offset < content_length) { |       while (ok && offset < content_length) { | ||||||
|         if (!content_provider(offset, content_length - offset, data_sink)) { |         if (!content_provider(offset, content_length - offset, data_sink)) { | ||||||
|           error_ = Error::Canceled; |           error = Error::Canceled; | ||||||
|           return nullptr; |           return nullptr; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -5340,6 +5354,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider( | |||||||
|                                  req.body.append(data, data_len); |                                  req.body.append(data, data_len); | ||||||
|                                  return true; |                                  return true; | ||||||
|                                })) { |                                })) { | ||||||
|  |         error = Error::Compression; | ||||||
|         return nullptr; |         return nullptr; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -5362,25 +5377,38 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider( | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   auto res = detail::make_unique<Response>(); | ||||||
|  |   return send(req, *res, error) ? std::move(res) : nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|   return send(req, *res) ? std::move(res) : nullptr; | inline Result ClientImpl::send_with_content_provider( | ||||||
|  |     const char *method, const char *path, const Headers &headers, | ||||||
|  |     const std::string &body, size_t content_length, | ||||||
|  |     ContentProvider content_provider, | ||||||
|  |     ContentProviderWithoutLength content_provider_without_length, | ||||||
|  |     const char *content_type) { | ||||||
|  |   auto error = Error::Success; | ||||||
|  |   auto res = send_with_content_provider( | ||||||
|  |       method, path, headers, body, content_length, std::move(content_provider), | ||||||
|  |       std::move(content_provider_without_length), content_type, error); | ||||||
|  |   return Result{std::move(res), error}; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool ClientImpl::process_request(Stream &strm, const Request &req, | inline bool ClientImpl::process_request(Stream &strm, const Request &req, | ||||||
|                                         Response &res, bool close_connection) { |                                         Response &res, bool close_connection, | ||||||
|  |                                         Error &error) { | ||||||
|   // Send request |   // Send request | ||||||
|   if (!write_request(strm, req, close_connection)) { return false; } |   if (!write_request(strm, req, close_connection, error)) { return false; } | ||||||
|  |  | ||||||
|   // Receive response and headers |   // Receive response and headers | ||||||
|   if (!read_response_line(strm, res) || |   if (!read_response_line(strm, res) || | ||||||
|       !detail::read_headers(strm, res.headers)) { |       !detail::read_headers(strm, res.headers)) { | ||||||
|     error_ = Error::Read; |     error = Error::Read; | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (req.response_handler_) { |   if (req.response_handler_) { | ||||||
|     if (!req.response_handler_(res)) { |     if (!req.response_handler_(res)) { | ||||||
|       error_ = Error::Canceled; |       error = Error::Canceled; | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -5392,7 +5420,7 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req, | |||||||
|             ? static_cast<ContentReceiverWithProgress>( |             ? static_cast<ContentReceiverWithProgress>( | ||||||
|                   [&](const char *buf, size_t n, uint64_t off, uint64_t len) { |                   [&](const char *buf, size_t n, uint64_t off, uint64_t len) { | ||||||
|                     auto ret = req.content_receiver_(buf, n, off, len); |                     auto ret = req.content_receiver_(buf, n, off, len); | ||||||
|                     if (!ret) { error_ = Error::Canceled; } |                     if (!ret) { error = Error::Canceled; } | ||||||
|                     return ret; |                     return ret; | ||||||
|                   }) |                   }) | ||||||
|             : static_cast<ContentReceiverWithProgress>( |             : static_cast<ContentReceiverWithProgress>( | ||||||
| @@ -5408,17 +5436,23 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req, | |||||||
|     auto progress = [&](uint64_t current, uint64_t total) { |     auto progress = [&](uint64_t current, uint64_t total) { | ||||||
|       if (!req.progress_) { return true; } |       if (!req.progress_) { return true; } | ||||||
|       auto ret = req.progress_(current, total); |       auto ret = req.progress_(current, total); | ||||||
|       if (!ret) { error_ = Error::Canceled; } |       if (!ret) { error = Error::Canceled; } | ||||||
|       return ret; |       return ret; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     int dummy_status; |     int dummy_status; | ||||||
|  |     // std::cout << "A" << std::endl; | ||||||
|     if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(), |     if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(), | ||||||
|                               dummy_status, std::move(progress), std::move(out), |                               dummy_status, std::move(progress), std::move(out), | ||||||
|                               decompress_)) { |                               decompress_)) { | ||||||
|       if (error_ != Error::Canceled) { error_ = Error::Read; } |       // std::cout << "B" << std::endl; | ||||||
|  |       if (error != Error::Canceled) { | ||||||
|  |         // std::cout << "C" << std::endl; | ||||||
|  |         error = Error::Read; | ||||||
|  |       } | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |     // std::cout << "D" << std::endl; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (res.get_header_value("Connection") == "close" || |   if (res.get_header_value("Connection") == "close" || | ||||||
| @@ -5473,9 +5507,7 @@ inline Result ClientImpl::Get(const char *path, const Headers &headers, | |||||||
|   req.headers.insert(headers.begin(), headers.end()); |   req.headers.insert(headers.begin(), headers.end()); | ||||||
|   req.progress_ = std::move(progress); |   req.progress_ = std::move(progress); | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   return send(req); | ||||||
|   auto ret = send(req, *res); |  | ||||||
|   return Result{ret ? std::move(res) : nullptr, get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Get(const char *path, | inline Result ClientImpl::Get(const char *path, | ||||||
| @@ -5541,9 +5573,7 @@ inline Result ClientImpl::Get(const char *path, const Headers &headers, | |||||||
|       }; |       }; | ||||||
|   req.progress_ = std::move(progress); |   req.progress_ = std::move(progress); | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   return send(req); | ||||||
|   auto ret = send(req, *res); |  | ||||||
|   return Result{ret ? std::move(res) : nullptr, get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Head(const char *path) { | inline Result ClientImpl::Head(const char *path) { | ||||||
| @@ -5557,9 +5587,7 @@ inline Result ClientImpl::Head(const char *path, const Headers &headers) { | |||||||
|   req.headers.insert(headers.begin(), headers.end()); |   req.headers.insert(headers.begin(), headers.end()); | ||||||
|   req.path = path; |   req.path = path; | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   return send(req); | ||||||
|   auto ret = send(req, *res); |  | ||||||
|   return Result{ret ? std::move(res) : nullptr, get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Post(const char *path) { | inline Result ClientImpl::Post(const char *path) { | ||||||
| @@ -5574,9 +5602,8 @@ inline Result ClientImpl::Post(const char *path, const std::string &body, | |||||||
| inline Result ClientImpl::Post(const char *path, const Headers &headers, | inline Result ClientImpl::Post(const char *path, const Headers &headers, | ||||||
|                                const std::string &body, |                                const std::string &body, | ||||||
|                                const char *content_type) { |                                const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("POST", path, headers, body, 0, nullptr, |   return send_with_content_provider("POST", path, headers, body, 0, nullptr, | ||||||
|                                     nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Post(const char *path, const Params ¶ms) { | inline Result ClientImpl::Post(const char *path, const Params ¶ms) { | ||||||
| @@ -5600,19 +5627,17 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers, | |||||||
|                                size_t content_length, |                                size_t content_length, | ||||||
|                                ContentProvider content_provider, |                                ContentProvider content_provider, | ||||||
|                                const char *content_type) { |                                const char *content_type) { | ||||||
|   auto ret = send_with_content_provider( |   return send_with_content_provider("POST", path, headers, std::string(), | ||||||
|       "POST", path, headers, std::string(), content_length, |                                     content_length, std::move(content_provider), | ||||||
|       std::move(content_provider), nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Post(const char *path, const Headers &headers, | inline Result ClientImpl::Post(const char *path, const Headers &headers, | ||||||
|                                ContentProviderWithoutLength content_provider, |                                ContentProviderWithoutLength content_provider, | ||||||
|                                const char *content_type) { |                                const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("POST", path, headers, std::string(), 0, |   return send_with_content_provider("POST", path, headers, std::string(), 0, | ||||||
|                                     nullptr, std::move(content_provider), |                                     nullptr, std::move(content_provider), | ||||||
|                                     content_type); |                                     content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Post(const char *path, const Headers &headers, | inline Result ClientImpl::Post(const char *path, const Headers &headers, | ||||||
| @@ -5636,8 +5661,7 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers, | |||||||
|   for (size_t i = 0; i < boundary.size(); i++) { |   for (size_t i = 0; i < boundary.size(); i++) { | ||||||
|     char c = boundary[i]; |     char c = boundary[i]; | ||||||
|     if (!std::isalnum(c) && c != '-' && c != '_') { |     if (!std::isalnum(c) && c != '-' && c != '_') { | ||||||
|       error_ = Error::UnsupportedMultipartBoundaryChars; |       return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; | ||||||
|       return Result{nullptr, error_}; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -5675,9 +5699,8 @@ inline Result ClientImpl::Put(const char *path, const std::string &body, | |||||||
| inline Result ClientImpl::Put(const char *path, const Headers &headers, | inline Result ClientImpl::Put(const char *path, const Headers &headers, | ||||||
|                               const std::string &body, |                               const std::string &body, | ||||||
|                               const char *content_type) { |                               const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("PUT", path, headers, body, 0, nullptr, |   return send_with_content_provider("PUT", path, headers, body, 0, nullptr, | ||||||
|                                     nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Put(const char *path, size_t content_length, | inline Result ClientImpl::Put(const char *path, size_t content_length, | ||||||
| @@ -5697,19 +5720,17 @@ inline Result ClientImpl::Put(const char *path, const Headers &headers, | |||||||
|                               size_t content_length, |                               size_t content_length, | ||||||
|                               ContentProvider content_provider, |                               ContentProvider content_provider, | ||||||
|                               const char *content_type) { |                               const char *content_type) { | ||||||
|   auto ret = send_with_content_provider( |   return send_with_content_provider("PUT", path, headers, std::string(), | ||||||
|       "PUT", path, headers, std::string(), content_length, |                                     content_length, std::move(content_provider), | ||||||
|       std::move(content_provider), nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Put(const char *path, const Headers &headers, | inline Result ClientImpl::Put(const char *path, const Headers &headers, | ||||||
|                               ContentProviderWithoutLength content_provider, |                               ContentProviderWithoutLength content_provider, | ||||||
|                               const char *content_type) { |                               const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("PUT", path, headers, std::string(), 0, |   return send_with_content_provider("PUT", path, headers, std::string(), 0, | ||||||
|                                     nullptr, std::move(content_provider), |                                     nullptr, std::move(content_provider), | ||||||
|                                     content_type); |                                     content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Put(const char *path, const Params ¶ms) { | inline Result ClientImpl::Put(const char *path, const Params ¶ms) { | ||||||
| @@ -5730,9 +5751,8 @@ inline Result ClientImpl::Patch(const char *path, const std::string &body, | |||||||
| inline Result ClientImpl::Patch(const char *path, const Headers &headers, | inline Result ClientImpl::Patch(const char *path, const Headers &headers, | ||||||
|                                 const std::string &body, |                                 const std::string &body, | ||||||
|                                 const char *content_type) { |                                 const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("PATCH", path, headers, body, 0, |   return send_with_content_provider("PATCH", path, headers, body, 0, nullptr, | ||||||
|                                         nullptr, nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Patch(const char *path, size_t content_length, | inline Result ClientImpl::Patch(const char *path, size_t content_length, | ||||||
| @@ -5752,19 +5772,17 @@ inline Result ClientImpl::Patch(const char *path, const Headers &headers, | |||||||
|                                 size_t content_length, |                                 size_t content_length, | ||||||
|                                 ContentProvider content_provider, |                                 ContentProvider content_provider, | ||||||
|                                 const char *content_type) { |                                 const char *content_type) { | ||||||
|   auto ret = send_with_content_provider( |   return send_with_content_provider("PATCH", path, headers, std::string(), | ||||||
|       "PATCH", path, headers, std::string(), content_length, |                                     content_length, std::move(content_provider), | ||||||
|       std::move(content_provider), nullptr, content_type); |                                     nullptr, content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Patch(const char *path, const Headers &headers, | inline Result ClientImpl::Patch(const char *path, const Headers &headers, | ||||||
|                                 ContentProviderWithoutLength content_provider, |                                 ContentProviderWithoutLength content_provider, | ||||||
|                                 const char *content_type) { |                                 const char *content_type) { | ||||||
|   auto ret = send_with_content_provider("PATCH", path, headers, std::string(), |   return send_with_content_provider("PATCH", path, headers, std::string(), 0, | ||||||
|                                         0, nullptr, std::move(content_provider), |                                     nullptr, std::move(content_provider), | ||||||
|                                     content_type); |                                     content_type); | ||||||
|   return Result{std::move(ret), get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Delete(const char *path) { | inline Result ClientImpl::Delete(const char *path) { | ||||||
| @@ -5792,9 +5810,7 @@ inline Result ClientImpl::Delete(const char *path, const Headers &headers, | |||||||
|   if (content_type) { req.headers.emplace("Content-Type", content_type); } |   if (content_type) { req.headers.emplace("Content-Type", content_type); } | ||||||
|   req.body = body; |   req.body = body; | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   return send(req); | ||||||
|   auto ret = send(req, *res); |  | ||||||
|   return Result{ret ? std::move(res) : nullptr, get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline Result ClientImpl::Options(const char *path) { | inline Result ClientImpl::Options(const char *path) { | ||||||
| @@ -5808,9 +5824,7 @@ inline Result ClientImpl::Options(const char *path, const Headers &headers) { | |||||||
|   req.headers.insert(headers.begin(), headers.end()); |   req.headers.insert(headers.begin(), headers.end()); | ||||||
|   req.path = path; |   req.path = path; | ||||||
|  |  | ||||||
|   auto res = detail::make_unique<Response>(); |   return send(req); | ||||||
|   auto ret = send(req, *res); |  | ||||||
|   return Result{ret ? std::move(res) : nullptr, get_last_error()}; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| inline size_t ClientImpl::is_socket_open() const { | inline size_t ClientImpl::is_socket_open() const { | ||||||
| @@ -5820,10 +5834,6 @@ inline size_t ClientImpl::is_socket_open() const { | |||||||
|  |  | ||||||
| inline void ClientImpl::stop() { | inline void ClientImpl::stop() { | ||||||
|   std::lock_guard<std::mutex> guard(socket_mutex_); |   std::lock_guard<std::mutex> guard(socket_mutex_); | ||||||
|   // There is no guarantee that this doesn't get overwritten later, but set it |  | ||||||
|   // so that there is a good chance that any threads stopping as a result pick |  | ||||||
|   // up this error. |  | ||||||
|   error_ = Error::Canceled; |  | ||||||
|  |  | ||||||
|   // If there is anything ongoing right now, the ONLY thread-safe thing we can |   // If there is anything ongoing right now, the ONLY thread-safe thing we can | ||||||
|   // do is to shutdown_socket, so that threads using this socket suddenly |   // do is to shutdown_socket, so that threads using this socket suddenly | ||||||
| @@ -5832,6 +5842,7 @@ inline void ClientImpl::stop() { | |||||||
|   // not thread-safe. |   // not thread-safe. | ||||||
|   if (socket_requests_in_flight_ > 0) { |   if (socket_requests_in_flight_ > 0) { | ||||||
|     shutdown_socket(socket_); |     shutdown_socket(socket_); | ||||||
|  |  | ||||||
|     // Aside from that, we set a flag for the socket to be closed when we're |     // Aside from that, we set a flag for the socket to be closed when we're | ||||||
|     // done. |     // done. | ||||||
|     socket_should_be_closed_when_request_is_done_ = true; |     socket_should_be_closed_when_request_is_done_ = true; | ||||||
| @@ -6327,13 +6338,13 @@ inline long SSLClient::get_openssl_verify_result() const { | |||||||
|  |  | ||||||
| inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; } | inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; } | ||||||
|  |  | ||||||
| inline bool SSLClient::create_and_connect_socket(Socket &socket) { | inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) { | ||||||
|   return is_valid() && ClientImpl::create_and_connect_socket(socket); |   return is_valid() && ClientImpl::create_and_connect_socket(socket, error); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Assumes that socket_mutex_ is locked and that there are no requests in flight | // Assumes that socket_mutex_ is locked and that there are no requests in flight | ||||||
| inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, | inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, | ||||||
|                                           bool &success) { |                                           bool &success, Error &error) { | ||||||
|   success = true; |   success = true; | ||||||
|   Response res2; |   Response res2; | ||||||
|   if (!detail::process_client_socket( |   if (!detail::process_client_socket( | ||||||
| @@ -6342,7 +6353,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, | |||||||
|             Request req2; |             Request req2; | ||||||
|             req2.method = "CONNECT"; |             req2.method = "CONNECT"; | ||||||
|             req2.path = host_and_port_; |             req2.path = host_and_port_; | ||||||
|             return process_request(strm, req2, res2, false); |             return process_request(strm, req2, res2, false, error); | ||||||
|           })) { |           })) { | ||||||
|     // Thread-safe to close everything because we are assuming there are no |     // Thread-safe to close everything because we are assuming there are no | ||||||
|     // requests in flight |     // requests in flight | ||||||
| @@ -6369,7 +6380,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, | |||||||
|                       req3, auth, 1, detail::random_string(10), |                       req3, auth, 1, detail::random_string(10), | ||||||
|                       proxy_digest_auth_username_, proxy_digest_auth_password_, |                       proxy_digest_auth_username_, proxy_digest_auth_password_, | ||||||
|                       true)); |                       true)); | ||||||
|                   return process_request(strm, req3, res3, false); |                   return process_request(strm, req3, res3, false, error); | ||||||
|                 })) { |                 })) { | ||||||
|           // Thread-safe to close everything because we are assuming there are |           // Thread-safe to close everything because we are assuming there are | ||||||
|           // no requests in flight |           // no requests in flight | ||||||
| @@ -6416,13 +6427,13 @@ inline bool SSLClient::load_certs() { | |||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool SSLClient::initialize_ssl(Socket &socket) { | inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { | ||||||
|   auto ssl = detail::ssl_new( |   auto ssl = detail::ssl_new( | ||||||
|       socket.sock, ctx_, ctx_mutex_, |       socket.sock, ctx_, ctx_mutex_, | ||||||
|       [&](SSL *ssl) { |       [&](SSL *ssl) { | ||||||
|         if (server_certificate_verification_) { |         if (server_certificate_verification_) { | ||||||
|           if (!load_certs()) { |           if (!load_certs()) { | ||||||
|             error_ = Error::SSLLoadingCerts; |             error = Error::SSLLoadingCerts; | ||||||
|             return false; |             return false; | ||||||
|           } |           } | ||||||
|           SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr); |           SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr); | ||||||
| @@ -6431,7 +6442,7 @@ inline bool SSLClient::initialize_ssl(Socket &socket) { | |||||||
|         if (!detail::ssl_connect_or_accept_nonblocking( |         if (!detail::ssl_connect_or_accept_nonblocking( | ||||||
|                 socket.sock, ssl, SSL_connect, connection_timeout_sec_, |                 socket.sock, ssl, SSL_connect, connection_timeout_sec_, | ||||||
|                 connection_timeout_usec_)) { |                 connection_timeout_usec_)) { | ||||||
|           error_ = Error::SSLConnection; |           error = Error::SSLConnection; | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -6439,20 +6450,20 @@ inline bool SSLClient::initialize_ssl(Socket &socket) { | |||||||
|           verify_result_ = SSL_get_verify_result(ssl); |           verify_result_ = SSL_get_verify_result(ssl); | ||||||
|  |  | ||||||
|           if (verify_result_ != X509_V_OK) { |           if (verify_result_ != X509_V_OK) { | ||||||
|             error_ = Error::SSLServerVerification; |             error = Error::SSLServerVerification; | ||||||
|             return false; |             return false; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           auto server_cert = SSL_get_peer_certificate(ssl); |           auto server_cert = SSL_get_peer_certificate(ssl); | ||||||
|  |  | ||||||
|           if (server_cert == nullptr) { |           if (server_cert == nullptr) { | ||||||
|             error_ = Error::SSLServerVerification; |             error = Error::SSLServerVerification; | ||||||
|             return false; |             return false; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           if (!verify_host(server_cert)) { |           if (!verify_host(server_cert)) { | ||||||
|             X509_free(server_cert); |             X509_free(server_cert); | ||||||
|             error_ = Error::SSLServerVerification; |             error = Error::SSLServerVerification; | ||||||
|             return false; |             return false; | ||||||
|           } |           } | ||||||
|           X509_free(server_cert); |           X509_free(server_cert); | ||||||
| @@ -6880,10 +6891,12 @@ inline Result Client::Options(const char *path, const Headers &headers) { | |||||||
|   return cli_->Options(path, headers); |   return cli_->Options(path, headers); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool Client::send(const Request &req, Response &res) { | inline bool Client::send(const Request &req, Response &res, Error &error) { | ||||||
|   return cli_->send(req, res); |   return cli_->send(req, res, error); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | inline Result Client::send(const Request &req) { return cli_->send(req); } | ||||||
|  |  | ||||||
| inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); } | inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); } | ||||||
|  |  | ||||||
| inline void Client::stop() { cli_->stop(); } | inline void Client::stop() { cli_->stop(); } | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								test/test.cc
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								test/test.cc
									
									
									
									
									
								
							| @@ -2,10 +2,10 @@ | |||||||
|  |  | ||||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <future> | #include <future> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <atomic> |  | ||||||
|  |  | ||||||
| #define SERVER_CERT_FILE "./cert.pem" | #define SERVER_CERT_FILE "./cert.pem" | ||||||
| #define SERVER_CERT2_FILE "./cert2.pem" | #define SERVER_CERT2_FILE "./cert2.pem" | ||||||
| @@ -1759,7 +1759,8 @@ TEST_F(ServerTest, LongHeader) { | |||||||
|       "@@@@@@@@@@@@@@@@"); |       "@@@@@@@@@@@@@@@@"); | ||||||
|  |  | ||||||
|   auto res = std::make_shared<Response>(); |   auto res = std::make_shared<Response>(); | ||||||
|   auto ret = cli_.send(req, *res); |   auto error = Error::Success; | ||||||
|  |   auto ret = cli_.send(req, *res, error); | ||||||
|  |  | ||||||
|   ASSERT_TRUE(ret); |   ASSERT_TRUE(ret); | ||||||
|   EXPECT_EQ(200, res->status); |   EXPECT_EQ(200, res->status); | ||||||
| @@ -1819,7 +1820,8 @@ TEST_F(ServerTest, TooLongHeader) { | |||||||
|       "@@@@@@@@@@@@@@@@@"); |       "@@@@@@@@@@@@@@@@@"); | ||||||
|  |  | ||||||
|   auto res = std::make_shared<Response>(); |   auto res = std::make_shared<Response>(); | ||||||
|   auto ret = cli_.send(req, *res); |   auto error = Error::Success; | ||||||
|  |   auto ret = cli_.send(req, *res, error); | ||||||
|  |  | ||||||
|   ASSERT_TRUE(ret); |   ASSERT_TRUE(ret); | ||||||
|   EXPECT_EQ(200, res->status); |   EXPECT_EQ(200, res->status); | ||||||
| @@ -1908,7 +1910,8 @@ TEST_F(ServerTest, CaseInsensitiveTransferEncoding) { | |||||||
|   req.body = "4\r\ndech\r\nf\r\nunked post body\r\n0\r\n\r\n"; |   req.body = "4\r\ndech\r\nf\r\nunked post body\r\n0\r\n\r\n"; | ||||||
|  |  | ||||||
|   auto res = std::make_shared<Response>(); |   auto res = std::make_shared<Response>(); | ||||||
|   auto ret = cli_.send(req, *res); |   auto error = Error::Success; | ||||||
|  |   auto ret = cli_.send(req, *res, error); | ||||||
|  |  | ||||||
|   ASSERT_TRUE(ret); |   ASSERT_TRUE(ret); | ||||||
|   EXPECT_EQ(200, res->status); |   EXPECT_EQ(200, res->status); | ||||||
| @@ -2125,7 +2128,8 @@ TEST_F(ServerTest, LargeChunkedPost) { | |||||||
|   req.body = chunk + chunk + chunk + chunk + chunk + chunk + "0\r\n\r\n"; |   req.body = chunk + chunk + chunk + chunk + chunk + chunk + "0\r\n\r\n"; | ||||||
|  |  | ||||||
|   auto res = std::make_shared<Response>(); |   auto res = std::make_shared<Response>(); | ||||||
|   auto ret = cli_.send(req, *res); |   auto error = Error::Success; | ||||||
|  |   auto ret = cli_.send(req, *res, error); | ||||||
|  |  | ||||||
|   ASSERT_TRUE(ret); |   ASSERT_TRUE(ret); | ||||||
|   EXPECT_EQ(200, res->status); |   EXPECT_EQ(200, res->status); | ||||||
| @@ -2551,7 +2555,8 @@ TEST_F(ServerTest, HTTP2Magic) { | |||||||
|   req.body = "SM"; |   req.body = "SM"; | ||||||
|  |  | ||||||
|   auto res = std::make_shared<Response>(); |   auto res = std::make_shared<Response>(); | ||||||
|   auto ret = cli_.send(req, *res); |   auto error = Error::Success; | ||||||
|  |   auto ret = cli_.send(req, *res, error); | ||||||
|  |  | ||||||
|   ASSERT_TRUE(ret); |   ASSERT_TRUE(ret); | ||||||
|   EXPECT_EQ(400, res->status); |   EXPECT_EQ(400, res->status); | ||||||
| @@ -2762,7 +2767,7 @@ TEST_F(ServerTest, Brotli) { | |||||||
| // Sends a raw request to a server listening at HOST:PORT. | // Sends a raw request to a server listening at HOST:PORT. | ||||||
| static bool send_request(time_t read_timeout_sec, const std::string &req, | static bool send_request(time_t read_timeout_sec, const std::string &req, | ||||||
|                          std::string *resp = nullptr) { |                          std::string *resp = nullptr) { | ||||||
|   std::atomic<Error> error(Error::Success); |   auto error = Error::Success; | ||||||
|  |  | ||||||
|   auto client_sock = |   auto client_sock = | ||||||
|       detail::create_client_socket(HOST, PORT, false, nullptr, |       detail::create_client_socket(HOST, PORT, false, nullptr, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user