mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Add missing template method implementations (#1013)
When using the split version of httplib.h the templated implementation of e.g. Client::set_connection_timeout ends up in httplib.cc and therefore results in a linker error since the needed template specialization has not been instantiated. Fix this by moving the implementation of template methods into the part that ends up in httplib.h after the split. Fixes #1008.
This commit is contained in:
parent
1b3b098329
commit
9c2c15ca45
1 changed files with 154 additions and 148 deletions
296
httplib.h
296
httplib.h
|
@ -1466,6 +1466,153 @@ private:
|
|||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Implementation of template methods.
|
||||
*/
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void duration_to_sec_and_usec(const T &duration, U callback) {
|
||||
auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
duration - std::chrono::seconds(sec))
|
||||
.count();
|
||||
callback(sec, usec);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T get_header_value(const Headers & /*headers*/, const char * /*key*/,
|
||||
size_t /*id*/ = 0, uint64_t /*def*/ = 0) {}
|
||||
|
||||
template <>
|
||||
inline uint64_t get_header_value<uint64_t>(const Headers &headers,
|
||||
const char *key, size_t id,
|
||||
uint64_t def) {
|
||||
auto rng = headers.equal_range(key);
|
||||
auto it = rng.first;
|
||||
std::advance(it, static_cast<ssize_t>(id));
|
||||
if (it != rng.second) {
|
||||
return std::strtoull(it->second.data(), nullptr, 10);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
inline T Request::get_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Response::get_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline ssize_t Stream::write_format(const char *fmt, const Args &... args) {
|
||||
const auto bufsiz = 2048;
|
||||
std::array<char, bufsiz> buf;
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
auto sn = _snprintf_s(buf.data(), bufsiz - 1, buf.size() - 1, fmt, args...);
|
||||
#else
|
||||
auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
|
||||
#endif
|
||||
if (sn <= 0) { return sn; }
|
||||
|
||||
auto n = static_cast<size_t>(sn);
|
||||
|
||||
if (n >= buf.size() - 1) {
|
||||
std::vector<char> glowable_buf(buf.size());
|
||||
|
||||
while (n >= glowable_buf.size() - 1) {
|
||||
glowable_buf.resize(glowable_buf.size() * 2);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
n = static_cast<size_t>(_snprintf_s(&glowable_buf[0], glowable_buf.size(),
|
||||
glowable_buf.size() - 1, fmt,
|
||||
args...));
|
||||
#else
|
||||
n = static_cast<size_t>(
|
||||
snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
|
||||
#endif
|
||||
}
|
||||
return write(&glowable_buf[0], n);
|
||||
} else {
|
||||
return write(buf.data(), n);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Result::get_request_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(request_headers_, key, id, 0);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_connection_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
|
||||
set_connection_timeout(sec, usec);
|
||||
});
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_read_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_write_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void Client::set_connection_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_connection_timeout(duration);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void
|
||||
Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_read_timeout(duration);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void
|
||||
Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_write_timeout(duration);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
|
@ -2798,23 +2945,6 @@ inline const char *get_header_value(const Headers &headers, const char *key,
|
|||
return def;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T get_header_value(const Headers & /*headers*/, const char * /*key*/,
|
||||
size_t /*id*/ = 0, uint64_t /*def*/ = 0) {}
|
||||
|
||||
template <>
|
||||
inline uint64_t get_header_value<uint64_t>(const Headers &headers,
|
||||
const char *key, size_t id,
|
||||
uint64_t def) {
|
||||
auto rng = headers.equal_range(key);
|
||||
auto it = rng.first;
|
||||
std::advance(it, static_cast<ssize_t>(id));
|
||||
if (it != rng.second) {
|
||||
return std::strtoull(it->second.data(), nullptr, 10);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool parse_header(const char *beg, const char *end, T fn) {
|
||||
// Skip trailing spaces and tabs.
|
||||
|
@ -3827,9 +3957,9 @@ inline std::pair<std::string, std::string> make_digest_authentication_header(
|
|||
|
||||
string response;
|
||||
{
|
||||
auto H = algo == "SHA-256" ? detail::SHA_256
|
||||
: algo == "SHA-512" ? detail::SHA_512
|
||||
: detail::MD5;
|
||||
auto H = algo == "SHA-256"
|
||||
? detail::SHA_256
|
||||
: algo == "SHA-512" ? detail::SHA_512 : detail::MD5;
|
||||
|
||||
auto A1 = username + ":" + auth.at("realm") + ":" + password;
|
||||
|
||||
|
@ -3912,15 +4042,6 @@ private:
|
|||
ContentProviderWithoutLength content_provider_;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void duration_to_sec_and_usec(const T &duration, U callback) {
|
||||
auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
duration - std::chrono::seconds(sec))
|
||||
.count();
|
||||
callback(sec, usec);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Header utilities
|
||||
|
@ -3963,11 +4084,6 @@ inline std::string Request::get_header_value(const char *key, size_t id) const {
|
|||
return detail::get_header_value(headers, key, id, "");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Request::get_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
}
|
||||
|
||||
inline size_t Request::get_header_value_count(const char *key) const {
|
||||
auto r = headers.equal_range(key);
|
||||
return static_cast<size_t>(std::distance(r.first, r.second));
|
||||
|
@ -4027,11 +4143,6 @@ inline std::string Response::get_header_value(const char *key,
|
|||
return detail::get_header_value(headers, key, id, "");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Response::get_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
}
|
||||
|
||||
inline size_t Response::get_header_value_count(const char *key) const {
|
||||
auto r = headers.equal_range(key);
|
||||
return static_cast<size_t>(std::distance(r.first, r.second));
|
||||
|
@ -4119,11 +4230,6 @@ inline std::string Result::get_request_header_value(const char *key,
|
|||
return detail::get_header_value(request_headers_, key, id, "");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Result::get_request_header_value(const char *key, size_t id) const {
|
||||
return detail::get_header_value<T>(request_headers_, key, id, 0);
|
||||
}
|
||||
|
||||
inline size_t Result::get_request_header_value_count(const char *key) const {
|
||||
auto r = request_headers_.equal_range(key);
|
||||
return static_cast<size_t>(std::distance(r.first, r.second));
|
||||
|
@ -4138,40 +4244,6 @@ inline ssize_t Stream::write(const std::string &s) {
|
|||
return write(s.data(), s.size());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
|
||||
const auto bufsiz = 2048;
|
||||
std::array<char, bufsiz> buf;
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
auto sn = _snprintf_s(buf.data(), bufsiz - 1, buf.size() - 1, fmt, args...);
|
||||
#else
|
||||
auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
|
||||
#endif
|
||||
if (sn <= 0) { return sn; }
|
||||
|
||||
auto n = static_cast<size_t>(sn);
|
||||
|
||||
if (n >= buf.size() - 1) {
|
||||
std::vector<char> glowable_buf(buf.size());
|
||||
|
||||
while (n >= glowable_buf.size() - 1) {
|
||||
glowable_buf.resize(glowable_buf.size() * 2);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
n = static_cast<size_t>(_snprintf_s(&glowable_buf[0], glowable_buf.size(),
|
||||
glowable_buf.size() - 1, fmt,
|
||||
args...));
|
||||
#else
|
||||
n = static_cast<size_t>(
|
||||
snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
|
||||
#endif
|
||||
}
|
||||
return write(&glowable_buf[0], n);
|
||||
} else {
|
||||
return write(buf.data(), n);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Socket stream implementation
|
||||
|
@ -4449,42 +4521,18 @@ inline Server &Server::set_read_timeout(time_t sec, time_t usec) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
|
||||
write_timeout_sec_ = sec;
|
||||
write_timeout_usec_ = usec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
|
||||
idle_interval_sec_ = sec;
|
||||
idle_interval_usec_ = usec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline Server &
|
||||
Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::set_payload_max_length(size_t length) {
|
||||
payload_max_length_ = length;
|
||||
return *this;
|
||||
|
@ -5642,9 +5690,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
|
|||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLClient cli(next_host.c_str(), next_port);
|
||||
cli.copy_settings(*this);
|
||||
if (ca_cert_store_) {
|
||||
cli.set_ca_cert_store(ca_cert_store_);
|
||||
}
|
||||
if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
|
||||
return detail::redirect(cli, req, res, next_path, location, error);
|
||||
#else
|
||||
return false;
|
||||
|
@ -6453,38 +6499,16 @@ inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
|
|||
connection_timeout_usec_ = usec;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_connection_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
|
||||
set_connection_timeout(sec, usec);
|
||||
});
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
|
||||
read_timeout_sec_ = sec;
|
||||
read_timeout_usec_ = usec;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_read_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
|
||||
write_timeout_sec_ = sec;
|
||||
write_timeout_usec_ = usec;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void ClientImpl::set_write_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
detail::duration_to_sec_and_usec(
|
||||
duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_basic_auth(const char *username,
|
||||
const char *password) {
|
||||
basic_auth_username_ = username;
|
||||
|
@ -7616,32 +7640,14 @@ inline void Client::set_connection_timeout(time_t sec, time_t usec) {
|
|||
cli_->set_connection_timeout(sec, usec);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void Client::set_connection_timeout(
|
||||
const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_connection_timeout(duration);
|
||||
}
|
||||
|
||||
inline void Client::set_read_timeout(time_t sec, time_t usec) {
|
||||
cli_->set_read_timeout(sec, usec);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void
|
||||
Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_read_timeout(duration);
|
||||
}
|
||||
|
||||
inline void Client::set_write_timeout(time_t sec, time_t usec) {
|
||||
cli_->set_write_timeout(sec, usec);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
inline void
|
||||
Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
|
||||
cli_->set_write_timeout(duration);
|
||||
}
|
||||
|
||||
inline void Client::set_basic_auth(const char *username, const char *password) {
|
||||
cli_->set_basic_auth(username, password);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue