46inline std::vector<uint8_t>
http_download([[maybe_unused]]
const std::string& url,
47 [[maybe_unused]]
size_t start_byte = 0,
48 [[maybe_unused]]
size_t end_byte = 0)
54 size_t proto_end = url.find(
"://");
55 if (proto_end == std::string::npos) {
59 size_t host_start = proto_end + 3;
60 size_t path_start = url.find(
'/', host_start);
61 if (path_start == std::string::npos) {
65 std::string host = url.substr(host_start, path_start - host_start);
66 std::string path = url.substr(path_start);
69 httplib::Client cli(
"http://" + host);
70 cli.set_follow_location(
true);
71 cli.set_connection_timeout(30);
72 cli.set_read_timeout(60);
75 httplib::Headers headers;
76 if (end_byte > 0 && end_byte >= start_byte) {
80 constexpr int max_attempts = 3;
84 constexpr int retry_timeout_seconds = 5;
86 std::chrono::milliseconds backoff{ 1000 };
87 std::string last_error;
88 for (
int attempt = 1; attempt <= max_attempts; ++attempt) {
90 cli.set_connection_timeout(retry_timeout_seconds);
91 cli.set_read_timeout(retry_timeout_seconds);
94 auto res = cli.Get(path.c_str(), headers);
96 if (res && (res->status == 200 || res->status == 206)) {
97 const std::string& body = res->body;
98 return std::vector<uint8_t>(body.begin(), body.end());
101 bool retryable =
false;
103 last_error = httplib::to_string(res.error());
108 retryable = res->status >= 500 || res->status == 429;
111 if (!retryable || attempt == max_attempts) {
113 " attempt" + (attempt == 1 ?
"" :
"s") +
")");
116 vinfo(
"HTTP download of ", url,
" failed (", last_error,
"), retrying in ", backoff.count(),
"ms");
117 std::this_thread::sleep_for(backoff);
121 throw_or_abort(
"HTTP request failed for " + url +
": " + last_error);
std::vector< uint8_t > http_download(const std::string &url, size_t start_byte=0, size_t end_byte=0)
Download data from a URL with optional Range header support.