mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Removed std::atomic<Error> error_
This commit is contained in:
parent
b952376968
commit
88c961f37e
2 changed files with 166 additions and 148 deletions
295
httplib.h
295
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,
|
||||||
|
|
Loading…
Reference in a new issue