|
|
@@ -407,6 +407,43 @@ class HttpClient {
|
|
|
}
|
|
|
|
|
|
std::string output_file_partial;
|
|
|
+
|
|
|
+ if (!output_file.empty()) {
|
|
|
+ output_file_partial = output_file + ".partial";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (download(url, headers, output_file_partial, progress, response_str)) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!output_file.empty()) {
|
|
|
+ try {
|
|
|
+ std::filesystem::rename(output_file_partial, output_file);
|
|
|
+ } catch (const std::filesystem::filesystem_error & e) {
|
|
|
+ printe("Failed to rename '%s' to '%s': %s\n", output_file_partial.c_str(), output_file.c_str(), e.what());
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ~HttpClient() {
|
|
|
+ if (chunk) {
|
|
|
+ curl_slist_free_all(chunk);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (curl) {
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ CURL * curl = nullptr;
|
|
|
+ struct curl_slist * chunk = nullptr;
|
|
|
+
|
|
|
+ int download(const std::string & url, const std::vector<std::string> & headers, const std::string & output_file,
|
|
|
+ const bool progress, std::string * response_str = nullptr) {
|
|
|
curl = curl_easy_init();
|
|
|
if (!curl) {
|
|
|
return 1;
|
|
|
@@ -415,8 +452,7 @@ class HttpClient {
|
|
|
progress_data data;
|
|
|
File out;
|
|
|
if (!output_file.empty()) {
|
|
|
- output_file_partial = output_file + ".partial";
|
|
|
- if (!out.open(output_file_partial, "ab")) {
|
|
|
+ if (!out.open(output_file, "ab")) {
|
|
|
printe("Failed to open file for writing\n");
|
|
|
|
|
|
return 1;
|
|
|
@@ -430,7 +466,7 @@ class HttpClient {
|
|
|
}
|
|
|
|
|
|
set_write_options(response_str, out);
|
|
|
- data.file_size = set_resume_point(output_file_partial);
|
|
|
+ data.file_size = set_resume_point(output_file);
|
|
|
set_progress_options(progress, data);
|
|
|
set_headers(headers);
|
|
|
CURLcode res = perform(url);
|
|
|
@@ -438,27 +474,10 @@ class HttpClient {
|
|
|
printe("Fetching resource '%s' failed: %s\n", url.c_str(), curl_easy_strerror(res));
|
|
|
return 1;
|
|
|
}
|
|
|
- if (!output_file.empty()) {
|
|
|
- std::filesystem::rename(output_file_partial, output_file);
|
|
|
- }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- ~HttpClient() {
|
|
|
- if (chunk) {
|
|
|
- curl_slist_free_all(chunk);
|
|
|
- }
|
|
|
-
|
|
|
- if (curl) {
|
|
|
- curl_easy_cleanup(curl);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- CURL * curl = nullptr;
|
|
|
- struct curl_slist * chunk = nullptr;
|
|
|
-
|
|
|
void set_write_options(std::string * response_str, const File & out) {
|
|
|
if (response_str) {
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, capture_data);
|
|
|
@@ -507,6 +526,9 @@ class HttpClient {
|
|
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
|
|
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
|
|
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
|
|
+#ifdef _WIN32
|
|
|
+ curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
|
|
|
+#endif
|
|
|
return curl_easy_perform(curl);
|
|
|
}
|
|
|
|