mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4c5d94d74 | |||
| 63a96aeb20 | |||
| bbb83d12c1 | |||
| 2d4b42b70b | |||
| 1919d08f71 | |||
| 824c02fcd3 |
@@ -280,9 +280,10 @@ struct Request {
|
||||
|
||||
// for client
|
||||
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
||||
size_t authorization_count = 1;
|
||||
ResponseHandler response_handler;
|
||||
ContentReceiver content_receiver;
|
||||
size_t content_length = 0;
|
||||
ContentProvider content_provider;
|
||||
Progress progress;
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -305,8 +306,7 @@ struct Request {
|
||||
MultipartFormData get_file_value(const char *key) const;
|
||||
|
||||
// private members...
|
||||
size_t content_length;
|
||||
ContentProvider content_provider;
|
||||
size_t authorization_count_ = 1;
|
||||
};
|
||||
|
||||
struct Response {
|
||||
@@ -339,15 +339,15 @@ struct Response {
|
||||
Response(Response &&) = default;
|
||||
Response &operator=(Response &&) = default;
|
||||
~Response() {
|
||||
if (content_provider_resource_releaser) {
|
||||
content_provider_resource_releaser();
|
||||
if (content_provider_resource_releaser_) {
|
||||
content_provider_resource_releaser_();
|
||||
}
|
||||
}
|
||||
|
||||
// private members...
|
||||
size_t content_length = 0;
|
||||
ContentProvider content_provider;
|
||||
std::function<void()> content_provider_resource_releaser;
|
||||
size_t content_length_ = 0;
|
||||
ContentProvider content_provider_;
|
||||
std::function<void()> content_provider_resource_releaser_;
|
||||
};
|
||||
|
||||
class Stream {
|
||||
@@ -571,9 +571,13 @@ private:
|
||||
|
||||
class Client {
|
||||
public:
|
||||
explicit Client(const std::string &host, int port = 80,
|
||||
const std::string &client_cert_path = std::string(),
|
||||
const std::string &client_key_path = std::string());
|
||||
explicit Client(const std::string &host);
|
||||
|
||||
explicit Client(const std::string &host, int port);
|
||||
|
||||
explicit Client(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path);
|
||||
|
||||
virtual ~Client();
|
||||
|
||||
@@ -897,18 +901,22 @@ private:
|
||||
|
||||
class SSLClient : public Client {
|
||||
public:
|
||||
explicit SSLClient(const std::string &host, int port = 443,
|
||||
const std::string &client_cert_path = std::string(),
|
||||
const std::string &client_key_path = std::string());
|
||||
explicit SSLClient(const std::string &host);
|
||||
|
||||
SSLClient(const std::string &host, int port, X509 *client_cert,
|
||||
EVP_PKEY *client_key);
|
||||
explicit SSLClient(const std::string &host, int port);
|
||||
|
||||
explicit SSLClient(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path);
|
||||
|
||||
explicit SSLClient(const std::string &host, int port, X509 *client_cert,
|
||||
EVP_PKEY *client_key);
|
||||
|
||||
~SSLClient() override;
|
||||
|
||||
bool is_valid() const override;
|
||||
|
||||
void set_ca_cert_path(const char *ca_ceert_file_path,
|
||||
void set_ca_cert_path(const char *ca_cert_file_path,
|
||||
const char *ca_cert_dir_path = nullptr);
|
||||
|
||||
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
||||
@@ -2597,7 +2605,7 @@ inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
|
||||
[&](const std::string &token) { strm.write(token); },
|
||||
[&](const char *token) { strm.write(token); },
|
||||
[&](size_t offset, size_t length) {
|
||||
return write_content(strm, res.content_provider, offset, length) >= 0;
|
||||
return write_content(strm, res.content_provider_, offset, length) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2607,7 +2615,7 @@ get_range_offset_and_length(const Request &req, const Response &res,
|
||||
auto r = req.ranges[index];
|
||||
|
||||
if (r.second == -1) {
|
||||
r.second = static_cast<ssize_t>(res.content_length) - 1;
|
||||
r.second = static_cast<ssize_t>(res.content_length_) - 1;
|
||||
}
|
||||
|
||||
return std::make_pair(r.first, r.second - r.first + 1);
|
||||
@@ -2913,21 +2921,20 @@ inline void
|
||||
Response::set_content_provider(size_t in_length, ContentProvider provider,
|
||||
std::function<void()> resource_releaser) {
|
||||
assert(in_length > 0);
|
||||
content_length = in_length;
|
||||
content_provider = [provider](size_t offset, size_t length, DataSink &sink) {
|
||||
content_length_ = in_length;
|
||||
content_provider_ = [provider](size_t offset, size_t length, DataSink &sink) {
|
||||
return provider(offset, length, sink);
|
||||
};
|
||||
content_provider_resource_releaser = resource_releaser;
|
||||
content_provider_resource_releaser_ = resource_releaser;
|
||||
}
|
||||
|
||||
inline void Response::set_chunked_content_provider(
|
||||
ChunkedContentProvider provider,
|
||||
std::function<void()> resource_releaser) {
|
||||
content_length = 0;
|
||||
content_provider = [provider](size_t offset, size_t, DataSink &sink) {
|
||||
ChunkedContentProvider provider, std::function<void()> resource_releaser) {
|
||||
content_length_ = 0;
|
||||
content_provider_ = [provider](size_t offset, size_t, DataSink &sink) {
|
||||
return provider(offset, sink);
|
||||
};
|
||||
content_provider_resource_releaser = resource_releaser;
|
||||
content_provider_resource_releaser_ = resource_releaser;
|
||||
}
|
||||
|
||||
// Rstream implementation
|
||||
@@ -3250,7 +3257,7 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
|
||||
}
|
||||
|
||||
if (!res.has_header("Content-Type") &&
|
||||
(!res.body.empty() || res.content_length > 0)) {
|
||||
(!res.body.empty() || res.content_length_ > 0)) {
|
||||
res.set_header("Content-Type", "text/plain");
|
||||
}
|
||||
|
||||
@@ -3275,17 +3282,17 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
|
||||
}
|
||||
|
||||
if (res.body.empty()) {
|
||||
if (res.content_length > 0) {
|
||||
if (res.content_length_ > 0) {
|
||||
size_t length = 0;
|
||||
if (req.ranges.empty()) {
|
||||
length = res.content_length;
|
||||
length = res.content_length_;
|
||||
} else if (req.ranges.size() == 1) {
|
||||
auto offsets =
|
||||
detail::get_range_offset_and_length(req, res.content_length, 0);
|
||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||
auto offset = offsets.first;
|
||||
length = offsets.second;
|
||||
auto content_range = detail::make_content_range_header_field(
|
||||
offset, length, res.content_length);
|
||||
offset, length, res.content_length_);
|
||||
res.set_header("Content-Range", content_range);
|
||||
} else {
|
||||
length = detail::get_multipart_ranges_data_length(req, res, boundary,
|
||||
@@ -3293,7 +3300,7 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
|
||||
}
|
||||
res.set_header("Content-Length", std::to_string(length));
|
||||
} else {
|
||||
if (res.content_provider) {
|
||||
if (res.content_provider_) {
|
||||
res.set_header("Transfer-Encoding", "chunked");
|
||||
} else {
|
||||
res.set_header("Content-Length", "0");
|
||||
@@ -3341,7 +3348,7 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
|
||||
if (req.method != "HEAD") {
|
||||
if (!res.body.empty()) {
|
||||
if (!strm.write(res.body)) { return false; }
|
||||
} else if (res.content_provider) {
|
||||
} else if (res.content_provider_) {
|
||||
if (!write_content_with_provider(strm, req, res, boundary,
|
||||
content_type)) {
|
||||
return false;
|
||||
@@ -3359,18 +3366,18 @@ inline bool
|
||||
Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||
Response &res, const std::string &boundary,
|
||||
const std::string &content_type) {
|
||||
if (res.content_length) {
|
||||
if (res.content_length_) {
|
||||
if (req.ranges.empty()) {
|
||||
if (detail::write_content(strm, res.content_provider, 0,
|
||||
res.content_length) < 0) {
|
||||
if (detail::write_content(strm, res.content_provider_, 0,
|
||||
res.content_length_) < 0) {
|
||||
return false;
|
||||
}
|
||||
} else if (req.ranges.size() == 1) {
|
||||
auto offsets =
|
||||
detail::get_range_offset_and_length(req, res.content_length, 0);
|
||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||
auto offset = offsets.first;
|
||||
auto length = offsets.second;
|
||||
if (detail::write_content(strm, res.content_provider, offset, length) <
|
||||
if (detail::write_content(strm, res.content_provider_, offset, length) <
|
||||
0) {
|
||||
return false;
|
||||
}
|
||||
@@ -3384,7 +3391,7 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||
auto is_shutting_down = [this]() {
|
||||
return this->svr_sock_ == INVALID_SOCKET;
|
||||
};
|
||||
if (detail::write_content_chunked(strm, res.content_provider,
|
||||
if (detail::write_content_chunked(strm, res.content_provider_,
|
||||
is_shutting_down) < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -3787,6 +3794,12 @@ inline bool Server::process_and_close_socket(socket_t sock) {
|
||||
}
|
||||
|
||||
// HTTP client implementation
|
||||
inline Client::Client(const std::string &host)
|
||||
: Client(host, 80, std::string(), std::string()) {}
|
||||
|
||||
inline Client::Client(const std::string &host, int port)
|
||||
: Client(host, port, std::string(), std::string()) {}
|
||||
|
||||
inline Client::Client(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path)
|
||||
@@ -3902,7 +3915,7 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
if ((res.status == 401 || res.status == 407) &&
|
||||
req.authorization_count == 1) {
|
||||
req.authorization_count_ == 1) {
|
||||
auto is_proxy = res.status == 407;
|
||||
const auto &username =
|
||||
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
|
||||
@@ -3913,12 +3926,12 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
|
||||
std::map<std::string, std::string> auth;
|
||||
if (parse_www_authenticate(res, auth, is_proxy)) {
|
||||
Request new_req = req;
|
||||
new_req.authorization_count += 1;
|
||||
new_req.authorization_count_ += 1;
|
||||
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||
new_req.headers.erase(key);
|
||||
new_req.headers.insert(make_digest_authentication_header(
|
||||
req, auth, new_req.authorization_count, random_string(10), username,
|
||||
password, is_proxy));
|
||||
req, auth, new_req.authorization_count_, random_string(10),
|
||||
username, password, is_proxy));
|
||||
|
||||
Response new_res;
|
||||
|
||||
@@ -4066,7 +4079,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
|
||||
if (!req.has_header("Accept")) { headers.emplace("Accept", "*/*"); }
|
||||
|
||||
if (!req.has_header("User-Agent")) {
|
||||
headers.emplace("User-Agent", "cpp-httplib/0.5");
|
||||
headers.emplace("User-Agent", "cpp-httplib/0.6");
|
||||
}
|
||||
|
||||
if (req.body.empty()) {
|
||||
@@ -4846,6 +4859,12 @@ inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
||||
}
|
||||
|
||||
// SSL HTTP client implementation
|
||||
inline SSLClient::SSLClient(const std::string &host)
|
||||
: SSLClient(host, 443, std::string(), std::string()) {}
|
||||
|
||||
inline SSLClient::SSLClient(const std::string &host, int port)
|
||||
: SSLClient(host, port, std::string(), std::string()) {}
|
||||
|
||||
inline SSLClient::SSLClient(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path)
|
||||
@@ -5100,63 +5119,338 @@ inline bool SSLClient::check_host_name(const char *pattern,
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace url {
|
||||
class Client2 {
|
||||
public:
|
||||
explicit Client2(const char *scheme_host_port)
|
||||
: Client2(scheme_host_port, std::string(), std::string()) {}
|
||||
|
||||
struct Options {
|
||||
// TODO: support more options...
|
||||
bool follow_location = false;
|
||||
std::string client_cert_path;
|
||||
std::string client_key_path;
|
||||
explicit Client2(const char *scheme_host_port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path) {
|
||||
const static std::regex re(R"(^(https?)://([^:/?#]+)(?::(\d+))?)");
|
||||
|
||||
std::string ca_cert_file_path;
|
||||
std::string ca_cert_dir_path;
|
||||
bool server_certificate_verification = false;
|
||||
};
|
||||
std::cmatch m;
|
||||
if (std::regex_match(scheme_host_port, m, re)) {
|
||||
auto scheme = m[1].str();
|
||||
auto host = m[2].str();
|
||||
auto port_str = m[3].str();
|
||||
|
||||
inline std::shared_ptr<Response> Get(const char *url, Options &options) {
|
||||
const static std::regex re(
|
||||
R"(^(https?)://([^:/?#]+)(?::(\d+))?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
|
||||
auto port = !port_str.empty() ? std::stoi(port_str)
|
||||
: (scheme == "https" ? 443 : 80);
|
||||
|
||||
std::cmatch m;
|
||||
if (!std::regex_match(url, m, re)) { return nullptr; }
|
||||
|
||||
auto next_scheme = m[1].str();
|
||||
auto next_host = m[2].str();
|
||||
auto port_str = m[3].str();
|
||||
auto next_path = m[4].str();
|
||||
|
||||
auto next_port = !port_str.empty() ? std::stoi(port_str)
|
||||
: (next_scheme == "https" ? 443 : 80);
|
||||
|
||||
if (next_path.empty()) { next_path = "/"; }
|
||||
|
||||
if (next_scheme == "https") {
|
||||
if (scheme == "https") {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLClient cli(next_host.c_str(), next_port, options.client_cert_path,
|
||||
options.client_key_path);
|
||||
cli.set_follow_location(options.follow_location);
|
||||
cli.set_ca_cert_path(options.ca_cert_file_path.c_str(),
|
||||
options.ca_cert_dir_path.c_str());
|
||||
cli.enable_server_certificate_verification(
|
||||
options.server_certificate_verification);
|
||||
return cli.Get(next_path.c_str());
|
||||
#else
|
||||
return nullptr;
|
||||
is_ssl_ = true;
|
||||
cli_ = std::make_shared<SSLClient>(host.c_str(), port, client_cert_path,
|
||||
client_key_path);
|
||||
#endif
|
||||
} else {
|
||||
Client cli(next_host.c_str(), next_port, options.client_cert_path,
|
||||
options.client_key_path);
|
||||
cli.set_follow_location(options.follow_location);
|
||||
return cli.Get(next_path.c_str());
|
||||
} else {
|
||||
cli_ = std::make_shared<Client>(host.c_str(), port, client_cert_path,
|
||||
client_key_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Get(const char *url) {
|
||||
Options options;
|
||||
return Get(url, options);
|
||||
}
|
||||
~Client2() {}
|
||||
|
||||
} // namespace url
|
||||
bool is_valid() const { return cli_ != nullptr; }
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path) { return cli_->Get(path); }
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers) {
|
||||
return cli_->Get(path, headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, Progress progress) {
|
||||
return cli_->Get(path, progress);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
Progress progress) {
|
||||
return cli_->Get(path, headers, progress);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path,
|
||||
ContentReceiver content_receiver) {
|
||||
return cli_->Get(path, content_receiver);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ContentReceiver content_receiver) {
|
||||
return cli_->Get(path, headers, content_receiver);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response>
|
||||
Get(const char *path, ContentReceiver content_receiver, Progress progress) {
|
||||
return cli_->Get(path, content_receiver, progress);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress) {
|
||||
return cli_->Get(path, headers, content_receiver, progress);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver) {
|
||||
return cli_->Get(path, headers, response_handler, content_receiver);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress) {
|
||||
return cli_->Get(path, headers, response_handler, content_receiver,
|
||||
progress);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Head(const char *path) { return cli_->Head(path); }
|
||||
|
||||
std::shared_ptr<Response> Head(const char *path, const Headers &headers) {
|
||||
return cli_->Head(path, headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path) { return cli_->Post(path); }
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Post(path, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Post(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Post(path, content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Post(path, headers, content_length, content_provider,
|
||||
content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Params ¶ms) {
|
||||
return cli_->Post(path, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const Params ¶ms) {
|
||||
return cli_->Post(path, headers, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path,
|
||||
const MultipartFormDataItems &items) {
|
||||
return cli_->Post(path, items);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const MultipartFormDataItems &items) {
|
||||
return cli_->Post(path, headers, items);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path) { return cli_->Put(path); }
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Put(path, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Put(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Put(path, content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Put(path, headers, content_length, content_provider,
|
||||
content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Params ¶ms) {
|
||||
return cli_->Put(path, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Headers &headers,
|
||||
const Params ¶ms) {
|
||||
return cli_->Put(path, headers, params);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Patch(path, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Patch(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Patch(path, content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
return cli_->Patch(path, headers, content_length, content_provider,
|
||||
content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Delete(const char *path) {
|
||||
return cli_->Delete(path);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Delete(const char *path, const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Delete(path, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Delete(const char *path, const Headers &headers) {
|
||||
return cli_->Delete(path, headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Delete(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type) {
|
||||
return cli_->Delete(path, headers, body, content_type);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Options(const char *path) {
|
||||
return cli_->Options(path);
|
||||
}
|
||||
|
||||
std::shared_ptr<Response> Options(const char *path, const Headers &headers) {
|
||||
return cli_->Options(path, headers);
|
||||
}
|
||||
|
||||
bool send(const Request &req, Response &res) { return cli_->send(req, res); }
|
||||
|
||||
bool send(const std::vector<Request> &requests,
|
||||
std::vector<Response> &responses) {
|
||||
return cli_->send(requests, responses);
|
||||
}
|
||||
|
||||
void stop() { cli_->stop(); }
|
||||
|
||||
Client2 &set_timeout_sec(time_t timeout_sec) {
|
||||
cli_->set_timeout_sec(timeout_sec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_read_timeout(time_t sec, time_t usec) {
|
||||
cli_->set_read_timeout(sec, usec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_keep_alive_max_count(size_t count) {
|
||||
cli_->set_keep_alive_max_count(count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_basic_auth(const char *username, const char *password) {
|
||||
cli_->set_basic_auth(username, password);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
Client2 &set_digest_auth(const char *username, const char *password) {
|
||||
cli_->set_digest_auth(username, password);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Client2 &set_follow_location(bool on) {
|
||||
cli_->set_follow_location(on);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_compress(bool on) {
|
||||
cli_->set_compress(on);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_interface(const char *intf) {
|
||||
cli_->set_interface(intf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_proxy(const char *host, int port) {
|
||||
cli_->set_proxy(host, port);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_proxy_basic_auth(const char *username, const char *password) {
|
||||
cli_->set_proxy_basic_auth(username, password);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
Client2 &set_proxy_digest_auth(const char *username, const char *password) {
|
||||
cli_->set_proxy_digest_auth(username, password);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Client2 &set_logger(Logger logger) {
|
||||
cli_->set_logger(logger);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SSL
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
Client2 &set_ca_cert_path(const char *ca_cert_file_path,
|
||||
const char *ca_cert_dir_path = nullptr) {
|
||||
dynamic_cast<SSLClient &>(*cli_).set_ca_cert_path(ca_cert_file_path,
|
||||
ca_cert_dir_path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &set_ca_cert_store(X509_STORE *ca_cert_store) {
|
||||
dynamic_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Client2 &enable_server_certificate_verification(bool enabled) {
|
||||
dynamic_cast<SSLClient &>(*cli_).enable_server_certificate_verification(
|
||||
enabled);
|
||||
return *this;
|
||||
}
|
||||
|
||||
long get_openssl_verify_result() const {
|
||||
return dynamic_cast<SSLClient &>(*cli_).get_openssl_verify_result();
|
||||
}
|
||||
|
||||
SSL_CTX *ssl_context() const {
|
||||
return dynamic_cast<SSLClient &>(*cli_).ssl_context();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool is_ssl_ = false;
|
||||
std::shared_ptr<Client> cli_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
+11
-14
@@ -651,15 +651,15 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(YahooRedirectTestWithURL, Redirect) {
|
||||
auto res = httplib::url::Get("http://yahoo.com");
|
||||
TEST(YahooRedirectTest2, Redirect) {
|
||||
httplib::Client2 cli("http://yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(301, res->status);
|
||||
|
||||
httplib::url::Options options;
|
||||
options.follow_location = true;
|
||||
|
||||
res = httplib::url::Get("http://yahoo.com", options);
|
||||
cli.set_follow_location(true);
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
@@ -673,14 +673,11 @@ TEST(HttpsToHttpRedirectTest, Redirect) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(HttpsToHttpRedirectTestWithURL, Redirect) {
|
||||
httplib::url::Options options;
|
||||
options.follow_location = true;
|
||||
|
||||
auto res = httplib::url::Get(
|
||||
"https://httpbin.org/"
|
||||
"redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302",
|
||||
options);
|
||||
TEST(HttpsToHttpRedirectTest2, Redirect) {
|
||||
auto res =
|
||||
httplib::Client2("https://httpbin.org")
|
||||
.set_follow_location(true)
|
||||
.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
|
||||
Reference in New Issue
Block a user