Removed std::atomic<Error> error_

This commit is contained in:
yhirose 2020-12-01 15:17:34 +00:00
parent b952376968
commit 88c961f37e
2 changed files with 166 additions and 148 deletions

295
httplib.h
View file

@ -753,7 +753,8 @@ enum Error {
SSLConnection,
SSLLoadingCerts,
SSLServerVerification,
UnsupportedMultipartBoundaryChars
UnsupportedMultipartBoundaryChars,
Compression,
};
class Result {
@ -878,7 +879,8 @@ public:
Result Options(const char *path);
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;
@ -931,7 +933,7 @@ protected:
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:
// shutdown_ssl
@ -949,16 +951,13 @@ protected:
void lock_socket_and_shutdown_and_close();
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);
Error get_last_error() const;
bool write_content_with_provider(Stream &strm, const Request &req,
Error &error);
void copy_settings(const ClientImpl &rhs);
// Error state
mutable std::atomic<Error> error_;
// Socket endoint information
const std::string host_;
const int port_;
@ -970,7 +969,7 @@ protected:
std::recursive_mutex request_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();
bool socket_should_be_closed_when_request_is_done_ = false;
@ -1025,13 +1024,20 @@ protected:
Logger logger_;
private:
socket_t create_client_socket() const;
socket_t create_client_socket(Error &error) const;
bool read_response_line(Stream &strm, Response &res);
bool write_request(Stream &strm, const Request &req, bool close_connection);
bool redirect(const Request &req, Response &res);
bool write_request(Stream &strm, const Request &req, bool close_connection,
Error &error);
bool redirect(const Request &req, Response &res, Error &error);
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(
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 std::string &body, size_t content_length,
ContentProvider content_provider,
@ -1149,7 +1155,8 @@ public:
Result Options(const char *path);
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;
@ -1260,15 +1267,16 @@ public:
SSL_CTX *ssl_context() const;
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;
bool process_socket(const Socket &socket,
std::function<bool(Stream &strm)> callback) override;
bool is_ssl() const override;
bool connect_with_proxy(Socket &sock, Response &res, bool &success);
bool initialize_ssl(Socket &socket);
bool connect_with_proxy(Socket &sock, Response &res, bool &success,
Error &error);
bool initialize_ssl(Socket &socket, Error &error);
bool load_certs();
@ -2056,8 +2064,7 @@ inline socket_t create_client_socket(const char *host, int port,
bool tcp_nodelay,
SocketOptions socket_options,
time_t timeout_sec, time_t timeout_usec,
const std::string &intf,
std::atomic<Error> &error) {
const std::string &intf, Error &error) {
auto sock = create_socket(
host, port, 0, tcp_nodelay, std::move(socket_options),
[&](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>
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
size_t offset, size_t length, T is_shutting_down,
std::atomic<Error> &error) {
Error &error) {
size_t end_offset = offset + length;
auto ok = true;
DataSink data_sink;
@ -2840,7 +2847,7 @@ template <typename T>
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
size_t offset, size_t length,
const T &is_shutting_down) {
std::atomic<Error> error;
auto error = Error::Success;
return write_content(strm, content_provider, offset, length, is_shutting_down,
error);
}
@ -2874,10 +2881,9 @@ write_content_without_length(Stream &strm,
}
template <typename T, typename U>
inline bool write_content_chunked(Stream &strm,
const ContentProvider &content_provider,
const T &is_shutting_down, U &compressor,
std::atomic<Error> &error) {
inline bool
write_content_chunked(Stream &strm, const ContentProvider &content_provider,
const T &is_shutting_down, U &compressor, Error &error) {
size_t offset = 0;
auto data_available = true;
auto ok = true;
@ -2960,14 +2966,15 @@ template <typename T, typename U>
inline bool write_content_chunked(Stream &strm,
const ContentProvider &content_provider,
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,
compressor, error);
}
template <typename T>
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;
new_req.path = path;
new_req.redirect_count_ -= 1;
@ -2980,7 +2987,7 @@ inline bool redirect(T &cli, const Request &req, Response &res,
Response new_res;
auto ret = cli.send(new_req, new_res);
auto ret = cli.send(new_req, new_res, error);
if (ret) {
new_res.location = location;
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,
const std::string &client_cert_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_)),
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 Error ClientImpl::get_last_error() const { return error_; }
inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
client_cert_path_ = rhs.client_cert_path_;
client_key_path_ = rhs.client_key_path_;
@ -4879,19 +4885,20 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
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) {
return detail::create_client_socket(
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(
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) {
auto sock = create_client_socket();
inline bool ClientImpl::create_and_connect_socket(Socket &socket,
Error &error) {
auto sock = create_client_socket(error);
if (sock == INVALID_SOCKET) { return false; }
socket.sock = sock;
return true;
@ -4919,6 +4926,7 @@ inline void ClientImpl::close_socket(Socket &socket) {
// than the one they intended!
assert(socket_requests_in_flight_ == 0 ||
socket_requests_are_from_thread_ == std::this_thread::get_id());
// It is also a bug if this happens while SSL is still active
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
assert(socket.ssl == nullptr);
@ -4964,7 +4972,7 @@ inline bool ClientImpl::read_response_line(Stream &strm, Response &res) {
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_);
{
@ -4989,7 +4997,7 @@ inline bool ClientImpl::send(const Request &req, Response &res) {
}
if (!is_alive) {
if (!create_and_connect_socket(socket_)) { return false; }
if (!create_and_connect_socket(socket_, error)) { return false; }
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// TODO: refactoring
@ -4997,12 +5005,12 @@ inline bool ClientImpl::send(const Request &req, Response &res) {
auto &scli = static_cast<SSLClient &>(*this);
if (!proxy_host_.empty() && proxy_port_ != -1) {
bool success = false;
if (!scli.connect_with_proxy(socket_, res, success)) {
if (!scli.connect_with_proxy(socket_, res, success, error)) {
return success;
}
}
if (!scli.initialize_ssl(socket_)) { return false; }
if (!scli.initialize_ssl(socket_, error)) { return false; }
}
#endif
}
@ -5019,7 +5027,7 @@ inline bool ClientImpl::send(const Request &req, Response &res) {
auto close_connection = !keep_alive_;
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
@ -5040,16 +5048,24 @@ inline bool ClientImpl::send(const Request &req, Response &res) {
}
if (!ret) {
if (error_ == Error::Success) { error_ = Error::Unknown; }
if (error == Error::Success) { error = Error::Unknown; }
}
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,
Response &res, bool close_connection) {
Response &res, bool close_connection,
Error &error) {
if (req.path.empty()) {
error_ = Error::Connection;
error = Error::Connection;
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) {
auto req2 = req;
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 {
ret = process_request(strm, req, res, close_connection);
ret = process_request(strm, req, res, close_connection, error);
}
if (!ret) { return false; }
if (300 < res.status && res.status < 400 && follow_location_) {
ret = redirect(req, res);
ret = redirect(req, res, error);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@ -5091,7 +5107,7 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req,
Response new_res;
ret = send(new_req, new_res);
ret = send(new_req, new_res, error);
if (ret) { res = new_res; }
}
}
@ -5101,9 +5117,10 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req,
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) {
error_ = Error::ExceedRedirectCount;
error = Error::ExceedRedirectCount;
return false;
}
@ -5135,30 +5152,27 @@ inline bool ClientImpl::redirect(const Request &req, Response &res) {
if (next_path.empty()) { next_path = "/"; }
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 {
if (next_scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(next_host.c_str(), next_port);
cli.copy_settings(*this);
auto ret = detail::redirect(cli, req, res, next_path, location);
if (!ret) { error_ = cli.get_last_error(); }
return ret;
return detail::redirect(cli, req, res, next_path, location, error);
#else
return false;
#endif
} else {
ClientImpl cli(next_host.c_str(), next_port);
cli.copy_settings(*this);
auto ret = detail::redirect(cli, req, res, next_path, location);
if (!ret) { error_ = cli.get_last_error(); }
return ret;
return detail::redirect(cli, req, res, next_path, location, error);
}
}
}
inline bool ClientImpl::write_content_with_provider(Stream &strm,
const Request &req) {
const Request &req,
Error &error) {
auto is_shutting_down = []() { return false; };
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_,
is_shutting_down, *compressor, error_);
is_shutting_down, *compressor, error);
} else {
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
inline bool ClientImpl::write_request(Stream &strm, const Request &req,
bool close_connection) {
bool close_connection, Error &error) {
detail::BufferStream bstrm;
// Request line
@ -5265,13 +5279,13 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req,
// Flush buffer
auto &data = bstrm.get_buffer();
if (!detail::write_data(strm, data.data(), data.size())) {
error_ = Error::Write;
error = Error::Write;
return false;
}
// Body
if (req.body.empty()) {
return write_content_with_provider(strm, req);
return write_content_with_provider(strm, req, error);
} else {
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,
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const char *content_type) {
const char *content_type, Error &error) {
Request req;
req.method = method;
@ -5330,7 +5344,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
while (ok && offset < content_length) {
if (!content_provider(offset, content_length - offset, data_sink)) {
error_ = Error::Canceled;
error = Error::Canceled;
return nullptr;
}
}
@ -5340,6 +5354,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
req.body.append(data, data_len);
return true;
})) {
error = Error::Compression;
return nullptr;
}
}
@ -5362,25 +5377,38 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
}
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,
Response &res, bool close_connection) {
Response &res, bool close_connection,
Error &error) {
// 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
if (!read_response_line(strm, res) ||
!detail::read_headers(strm, res.headers)) {
error_ = Error::Read;
error = Error::Read;
return false;
}
if (req.response_handler_) {
if (!req.response_handler_(res)) {
error_ = Error::Canceled;
error = Error::Canceled;
return false;
}
}
@ -5392,7 +5420,7 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
? static_cast<ContentReceiverWithProgress>(
[&](const char *buf, size_t n, uint64_t off, uint64_t len) {
auto ret = req.content_receiver_(buf, n, off, len);
if (!ret) { error_ = Error::Canceled; }
if (!ret) { error = Error::Canceled; }
return ret;
})
: 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) {
if (!req.progress_) { return true; }
auto ret = req.progress_(current, total);
if (!ret) { error_ = Error::Canceled; }
if (!ret) { error = Error::Canceled; }
return ret;
};
int dummy_status;
// std::cout << "A" << std::endl;
if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
dummy_status, std::move(progress), std::move(out),
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;
}
// std::cout << "D" << std::endl;
}
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.progress_ = std::move(progress);
auto res = detail::make_unique<Response>();
auto ret = send(req, *res);
return Result{ret ? std::move(res) : nullptr, get_last_error()};
return send(req);
}
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);
auto res = detail::make_unique<Response>();
auto ret = send(req, *res);
return Result{ret ? std::move(res) : nullptr, get_last_error()};
return send(req);
}
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.path = path;
auto res = detail::make_unique<Response>();
auto ret = send(req, *res);
return Result{ret ? std::move(res) : nullptr, get_last_error()};
return send(req);
}
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,
const std::string &body,
const char *content_type) {
auto ret = send_with_content_provider("POST", path, headers, body, 0, nullptr,
nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("POST", path, headers, body, 0, nullptr,
nullptr, content_type);
}
inline Result ClientImpl::Post(const char *path, const Params &params) {
@ -5600,19 +5627,17 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const char *content_type) {
auto ret = send_with_content_provider(
"POST", path, headers, std::string(), content_length,
std::move(content_provider), nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("POST", path, headers, std::string(),
content_length, std::move(content_provider),
nullptr, content_type);
}
inline Result ClientImpl::Post(const char *path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const char *content_type) {
auto ret = send_with_content_provider("POST", path, headers, std::string(), 0,
nullptr, std::move(content_provider),
content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("POST", path, headers, std::string(), 0,
nullptr, std::move(content_provider),
content_type);
}
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++) {
char c = boundary[i];
if (!std::isalnum(c) && c != '-' && c != '_') {
error_ = Error::UnsupportedMultipartBoundaryChars;
return Result{nullptr, error_};
return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
}
}
@ -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,
const std::string &body,
const char *content_type) {
auto ret = send_with_content_provider("PUT", path, headers, body, 0, nullptr,
nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PUT", path, headers, body, 0, nullptr,
nullptr, content_type);
}
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,
ContentProvider content_provider,
const char *content_type) {
auto ret = send_with_content_provider(
"PUT", path, headers, std::string(), content_length,
std::move(content_provider), nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PUT", path, headers, std::string(),
content_length, std::move(content_provider),
nullptr, content_type);
}
inline Result ClientImpl::Put(const char *path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const char *content_type) {
auto ret = send_with_content_provider("PUT", path, headers, std::string(), 0,
nullptr, std::move(content_provider),
content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PUT", path, headers, std::string(), 0,
nullptr, std::move(content_provider),
content_type);
}
inline Result ClientImpl::Put(const char *path, const Params &params) {
@ -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,
const std::string &body,
const char *content_type) {
auto ret = send_with_content_provider("PATCH", path, headers, body, 0,
nullptr, nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PATCH", path, headers, body, 0, nullptr,
nullptr, content_type);
}
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,
ContentProvider content_provider,
const char *content_type) {
auto ret = send_with_content_provider(
"PATCH", path, headers, std::string(), content_length,
std::move(content_provider), nullptr, content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PATCH", path, headers, std::string(),
content_length, std::move(content_provider),
nullptr, content_type);
}
inline Result ClientImpl::Patch(const char *path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const char *content_type) {
auto ret = send_with_content_provider("PATCH", path, headers, std::string(),
0, nullptr, std::move(content_provider),
content_type);
return Result{std::move(ret), get_last_error()};
return send_with_content_provider("PATCH", path, headers, std::string(), 0,
nullptr, std::move(content_provider),
content_type);
}
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); }
req.body = body;
auto res = detail::make_unique<Response>();
auto ret = send(req, *res);
return Result{ret ? std::move(res) : nullptr, get_last_error()};
return send(req);
}
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.path = path;
auto res = detail::make_unique<Response>();
auto ret = send(req, *res);
return Result{ret ? std::move(res) : nullptr, get_last_error()};
return send(req);
}
inline size_t ClientImpl::is_socket_open() const {
@ -5820,10 +5834,6 @@ inline size_t ClientImpl::is_socket_open() const {
inline void ClientImpl::stop() {
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
// do is to shutdown_socket, so that threads using this socket suddenly
@ -5832,6 +5842,7 @@ inline void ClientImpl::stop() {
// not thread-safe.
if (socket_requests_in_flight_ > 0) {
shutdown_socket(socket_);
// Aside from that, we set a flag for the socket to be closed when we're
// done.
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 bool SSLClient::create_and_connect_socket(Socket &socket) {
return is_valid() && ClientImpl::create_and_connect_socket(socket);
inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
return is_valid() && ClientImpl::create_and_connect_socket(socket, error);
}
// Assumes that socket_mutex_ is locked and that there are no requests in flight
inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
bool &success) {
bool &success, Error &error) {
success = true;
Response res2;
if (!detail::process_client_socket(
@ -6342,7 +6353,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
Request req2;
req2.method = "CONNECT";
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
// requests in flight
@ -6369,7 +6380,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
req3, auth, 1, detail::random_string(10),
proxy_digest_auth_username_, proxy_digest_auth_password_,
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
// no requests in flight
@ -6416,13 +6427,13 @@ inline bool SSLClient::load_certs() {
return ret;
}
inline bool SSLClient::initialize_ssl(Socket &socket) {
inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
auto ssl = detail::ssl_new(
socket.sock, ctx_, ctx_mutex_,
[&](SSL *ssl) {
if (server_certificate_verification_) {
if (!load_certs()) {
error_ = Error::SSLLoadingCerts;
error = Error::SSLLoadingCerts;
return false;
}
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(
socket.sock, ssl, SSL_connect, connection_timeout_sec_,
connection_timeout_usec_)) {
error_ = Error::SSLConnection;
error = Error::SSLConnection;
return false;
}
@ -6439,20 +6450,20 @@ inline bool SSLClient::initialize_ssl(Socket &socket) {
verify_result_ = SSL_get_verify_result(ssl);
if (verify_result_ != X509_V_OK) {
error_ = Error::SSLServerVerification;
error = Error::SSLServerVerification;
return false;
}
auto server_cert = SSL_get_peer_certificate(ssl);
if (server_cert == nullptr) {
error_ = Error::SSLServerVerification;
error = Error::SSLServerVerification;
return false;
}
if (!verify_host(server_cert)) {
X509_free(server_cert);
error_ = Error::SSLServerVerification;
error = Error::SSLServerVerification;
return false;
}
X509_free(server_cert);
@ -6880,10 +6891,12 @@ inline Result Client::Options(const char *path, const Headers &headers) {
return cli_->Options(path, headers);
}
inline bool Client::send(const Request &req, Response &res) {
return cli_->send(req, res);
inline bool Client::send(const Request &req, Response &res, Error &error) {
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 void Client::stop() { cli_->stop(); }

View file

@ -2,10 +2,10 @@
#include <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <future>
#include <thread>
#include <atomic>
#define SERVER_CERT_FILE "./cert.pem"
#define SERVER_CERT2_FILE "./cert2.pem"
@ -1759,7 +1759,8 @@ TEST_F(ServerTest, LongHeader) {
"@@@@@@@@@@@@@@@@");
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);
EXPECT_EQ(200, res->status);
@ -1819,7 +1820,8 @@ TEST_F(ServerTest, TooLongHeader) {
"@@@@@@@@@@@@@@@@@");
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);
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";
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);
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";
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);
EXPECT_EQ(200, res->status);
@ -2551,7 +2555,8 @@ TEST_F(ServerTest, HTTP2Magic) {
req.body = "SM";
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);
EXPECT_EQ(400, res->status);
@ -2762,7 +2767,7 @@ TEST_F(ServerTest, Brotli) {
// Sends a raw request to a server listening at HOST:PORT.
static bool send_request(time_t read_timeout_sec, const std::string &req,
std::string *resp = nullptr) {
std::atomic<Error> error(Error::Success);
auto error = Error::Success;
auto client_sock =
detail::create_client_socket(HOST, PORT, false, nullptr,