18std::size_t write_cb(
char* ptr, std::size_t size, std::size_t nmemb,
void* userdata) {
26std::size_t header_cb(
char* ptr, std::size_t size, std::size_t nmemb,
void* userdata) {
33 std::transform(s.begin(), s.end(), s.begin(),
55bool parse_content_range(
const std::string& v, std::uint64_t& start, std::uint64_t& end,
156 if (impl_->have_size)
159 std::vector<std::string> headers;
160 std::vector<std::uint8_t> body;
162 curl_easy_reset(impl_->easy);
163 impl_->apply_common();
164 curl_easy_setopt(impl_->easy, CURLOPT_NOBODY, 1L);
165 curl_easy_setopt(impl_->easy, CURLOPT_HEADERFUNCTION, header_cb);
166 curl_easy_setopt(impl_->easy, CURLOPT_HEADERDATA, &headers);
167 curl_easy_setopt(impl_->easy, CURLOPT_WRITEFUNCTION, write_cb);
168 curl_easy_setopt(impl_->easy, CURLOPT_WRITEDATA, &body);
171 const CURLcode rc = curl_easy_perform(impl_->easy);
172 if (rc != CURLE_OK) {
177 curl_easy_getinfo(impl_->easy, CURLINFO_RESPONSE_CODE, &status);
178 if (status < 200 || status >= 300) {
183 curl_easy_getinfo(impl_->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &len);
187 auto probe =
read(0, 1);
188 if (!impl_->have_size) {
194 impl_->capture_validator(headers);
195 impl_->size =
static_cast<std::uint64_t
>(len);
196 impl_->have_size =
true;
205 const std::string range = std::to_string(
offset) +
"-" + std::to_string(last);
207 std::vector<std::string> headers;
208 std::vector<std::uint8_t> body;
210 curl_easy_reset(impl_->easy);
211 impl_->apply_common();
212 impl_->rebuild_headers();
213 curl_easy_setopt(impl_->easy, CURLOPT_RANGE, range.c_str());
214 curl_easy_setopt(impl_->easy, CURLOPT_HEADERFUNCTION, header_cb);
215 curl_easy_setopt(impl_->easy, CURLOPT_HEADERDATA, &headers);
216 curl_easy_setopt(impl_->easy, CURLOPT_WRITEFUNCTION, write_cb);
217 curl_easy_setopt(impl_->easy, CURLOPT_WRITEDATA, &body);
220 const CURLcode rc = curl_easy_perform(impl_->easy);
221 if (rc != CURLE_OK) {
223 std::string(
"range request failed: ") + curl_easy_strerror(rc));
227 curl_easy_getinfo(impl_->easy, CURLINFO_RESPONSE_CODE, &status);
228 impl_->capture_validator(headers);
232 "the URL is not stable");
237 if (impl_->have_size &&
offset >= impl_->size)
245 const std::string cr = find_header(headers,
"Content-Range");
246 std::uint64_t s = 0, e = 0, total = 0;
247 if (!parse_content_range(cr, s, e, total)) {
252 std::to_string(s) +
", expected " +
255 if (body.size() != (e - s + 1)) {
258 if (!impl_->have_size) {
260 impl_->have_size =
true;
263 if (body.size() < length && (
offset + body.size()) < impl_->size) {
273 if (!impl_->have_size) {
274 impl_->size = body.size();
275 impl_->have_size =
true;
277 if (
offset >= body.size())
279 const std::uint64_t avail = body.size() -
offset;
280 const std::uint64_t n = std::min<std::uint64_t>(length, avail);
281 return std::vector<std::uint8_t>(body.begin() +
static_cast<std::ptrdiff_t
>(
offset),
282 body.begin() +
static_cast<std::ptrdiff_t
>(
offset + n));