mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 06:26:02 -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,
|
||||
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 ¶ms) {
|
||||
|
@ -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 ¶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,
|
||||
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(); }
|
||||
|
|
19
test/test.cc
19
test/test.cc
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue