From: Gregor Jasny Date: Wed, 14 Jul 2021 09:36:48 +0000 (+0200) Subject: HTTP storage: Implement timeout support (#896) X-Git-Tag: v4.4~128 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=28e77f33cd6ba43f8aa5ff0d8141987782e4f781;p=thirdparty%2Fccache.git HTTP storage: Implement timeout support (#896) Closes #888. --- diff --git a/doc/MANUAL.adoc b/doc/MANUAL.adoc index 6cd295908..87ad74493 100644 --- a/doc/MANUAL.adoc +++ b/doc/MANUAL.adoc @@ -947,9 +947,13 @@ Examples: * `http://localhost:8080/` * `http://someusername:p4ssw0rd@example.com/cache` +Optional attributes: + +* *connect-timeout*: Timeout (in ms) for network connection. The default is 100. +* *operation-timeout*: Timeout (in ms) for HTTP requests. The default is 10000. + Known issues and limitations: -* There are no HTTP timeouts implemented or configured. * HTTPS is not yet supported. * URLs containing IPv6 addresses like `http://[::1]/` are not supported. diff --git a/src/storage/secondary/HttpStorage.cpp b/src/storage/secondary/HttpStorage.cpp index 3d16e42b4..07c35f93c 100644 --- a/src/storage/secondary/HttpStorage.cpp +++ b/src/storage/secondary/HttpStorage.cpp @@ -35,6 +35,9 @@ namespace secondary { namespace { +const auto DEFAULT_CONNECT_TIMEOUT = std::chrono::milliseconds{100}; +const auto DEFAULT_OPERATION_TIMEOUT = std::chrono::milliseconds{10000}; + nonstd::string_view to_string(const httplib::Error error) { @@ -107,19 +110,48 @@ make_client(const Url& url) return client; } +std::chrono::milliseconds +parse_timeout_attribute(const AttributeMap& attributes, + const std::string& name, + const std::chrono::milliseconds default_value) +{ + const auto it = attributes.find(name); + if (it == attributes.end()) { + return default_value; + } else { + auto timeout_in_ms = + Util::parse_unsigned(it->second, 1, 1000 * 3600, "timeout"); + return std::chrono::milliseconds{timeout_in_ms}; + } +} + } // namespace -HttpStorage::HttpStorage(const Url& url, const AttributeMap&) +HttpStorage::HttpStorage(const Url& url, const AttributeMap& attributes) : m_url_path(get_url_path(url)), m_http_client(make_client(url)) { m_http_client->set_default_headers( {{"User-Agent", FMT("{}/{}", CCACHE_NAME, CCACHE_VERSION)}}); m_http_client->set_keep_alive(true); + configure_timeouts(attributes); } HttpStorage::~HttpStorage() = default; +void +HttpStorage::configure_timeouts(const AttributeMap& attributes) +{ + const auto connection_timeout = parse_timeout_attribute( + attributes, "connect-timeout", DEFAULT_CONNECT_TIMEOUT); + const auto operation_timeout = parse_timeout_attribute( + attributes, "operation-timeout", DEFAULT_OPERATION_TIMEOUT); + + m_http_client->set_connection_timeout(connection_timeout); + m_http_client->set_read_timeout(operation_timeout); + m_http_client->set_write_timeout(operation_timeout); +} + nonstd::expected, SecondaryStorage::Error> HttpStorage::get(const Digest& key) { diff --git a/src/storage/secondary/HttpStorage.hpp b/src/storage/secondary/HttpStorage.hpp index f9d46ba23..ca1a573d0 100644 --- a/src/storage/secondary/HttpStorage.hpp +++ b/src/storage/secondary/HttpStorage.hpp @@ -50,6 +50,7 @@ private: const std::string m_url_path; std::unique_ptr m_http_client; + void configure_timeouts(const AttributeMap& attributes); std::string get_entry_path(const Digest& key) const; };