aboutsummaryrefslogtreecommitdiff
path: root/src/common/download.cpp
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2017-12-25 21:20:22 +0200
committerRiccardo Spagni <ric@spagni.net>2017-12-25 21:20:22 +0200
commitb38f6dcf0bfce873f554746e31b0063ed6a5300d (patch)
treefb509202d6ee414b4d24dc2ff01b682e55dbcaf7 /src/common/download.cpp
parentMerge pull request #2928 (diff)
parentresumption support for updates using range requests (diff)
downloadmonero-b38f6dcf0bfce873f554746e31b0063ed6a5300d.tar.xz
Merge pull request #2929
ae55bacd resumption support for updates using range requests (moneromooo-monero) fe0fae50 epee: add a get_file_size function (moneromooo-monero)
Diffstat (limited to 'src/common/download.cpp')
-rw-r--r--src/common/download.cpp56
1 files changed, 49 insertions, 7 deletions
diff --git a/src/common/download.cpp b/src/common/download.cpp
index d330479de..87814fa5e 100644
--- a/src/common/download.cpp
+++ b/src/common/download.cpp
@@ -33,6 +33,7 @@
#include <boost/thread/thread.hpp>
#include "cryptonote_config.h"
#include "include_base_utils.h"
+#include "file_io_utils.h"
#include "net/http_client.h"
#include "download.h"
@@ -74,9 +75,20 @@ namespace tools
try
{
boost::unique_lock<boost::mutex> lock(control->mutex);
- MINFO("Downloading " << control->uri << " to " << control->path);
+ std::ios_base::openmode mode = std::ios_base::out | std::ios_base::binary;
+ uint64_t existing_size = 0;
+ if (epee::file_io_utils::get_file_size(control->path, existing_size) && existing_size > 0)
+ {
+ MINFO("Resuming downloading " << control->uri << " to " << control->path << " from " << existing_size);
+ mode |= std::ios_base::app;
+ }
+ else
+ {
+ MINFO("Downloading " << control->uri << " to " << control->path);
+ mode |= std::ios_base::trunc;
+ }
std::ofstream f;
- f.open(control->path, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
+ f.open(control->path, mode);
if (!f.good()) {
MERROR("Failed to open file " << control->path);
control->result_cb(control->path, control->uri, control->success);
@@ -85,11 +97,13 @@ namespace tools
class download_client: public epee::net_utils::http::http_simple_client
{
public:
- download_client(download_async_handle control, std::ofstream &f):
- control(control), f(f), content_length(-1), total(0) {}
+ download_client(download_async_handle control, std::ofstream &f, uint64_t offset = 0):
+ control(control), f(f), content_length(-1), total(0), offset(offset) {}
virtual ~download_client() { f.close(); }
virtual bool on_header(const epee::net_utils::http::http_response_info &headers)
{
+ for (const auto &kv: headers.m_header_info.m_etc_fields)
+ MDEBUG("Header: " << kv.first << ": " << kv.second);
ssize_t length;
if (epee::string_tools::get_xtype_from_string(length, headers.m_header_info.m_content_length) && length >= 0)
{
@@ -104,6 +118,26 @@ namespace tools
return false;
}
}
+ if (offset > 0)
+ {
+ // we requested a range, so check if we're getting it, otherwise truncate
+ bool got_range = false;
+ const std::string prefix = "bytes=" + std::to_string(offset) + "-";
+ for (const auto &kv: headers.m_header_info.m_etc_fields)
+ {
+ if (kv.first == "Content-Range" && strncmp(kv.second.c_str(), prefix.c_str(), prefix.size()))
+ {
+ got_range = true;
+ break;
+ }
+ }
+ if (!got_range)
+ {
+ MWARNING("We did not get the requested range, downloading from start");
+ f.close();
+ f.open(control->path, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
+ }
+ }
return true;
}
virtual bool handle_target_data(std::string &piece_of_transfer)
@@ -130,7 +164,8 @@ namespace tools
std::ofstream &f;
ssize_t content_length;
size_t total;
- } client(control, f);
+ uint64_t offset;
+ } client(control, f, existing_size);
epee::net_utils::http::url_content u_c;
if (!epee::net_utils::parse_url(control->uri, u_c))
{
@@ -160,7 +195,14 @@ namespace tools
}
MDEBUG("GETting " << u_c.uri);
const epee::net_utils::http::http_response_info *info = NULL;
- if (!client.invoke_get(u_c.uri, std::chrono::seconds(30), "", &info))
+ epee::net_utils::http::fields_list fields;
+ if (existing_size > 0)
+ {
+ const std::string range = "bytes=" + std::to_string(existing_size) + "-";
+ MDEBUG("Asking for range: " << range);
+ fields.push_back(std::make_pair("Range", range));
+ }
+ if (!client.invoke_get(u_c.uri, std::chrono::seconds(30), "", &info, fields))
{
boost::lock_guard<boost::mutex> lock(control->mutex);
MERROR("Failed to connect to " << control->uri);
@@ -190,7 +232,7 @@ namespace tools
MDEBUG("response body: " << info->m_body);
for (const auto &f: info->m_additional_fields)
MDEBUG("additional field: " << f.first << ": " << f.second);
- if (info->m_response_code != 200)
+ if (info->m_response_code != 200 && info->m_response_code != 206)
{
boost::lock_guard<boost::mutex> lock(control->mutex);
MERROR("Status code " << info->m_response_code);