Downloader as part of main app WIP

This commit is contained in:
David Kocik 2022-06-29 17:00:14 +02:00
parent b733284039
commit e2c5cfcdb5
13 changed files with 278 additions and 55 deletions

View File

@ -115,7 +115,8 @@ int CLI::run(int argc, char **argv)
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
bool start_as_downloader = false;
bool start_downloader = false;
std::string download_url;
bool start_as_gcodeviewer =
#ifdef _WIN32
false;
@ -177,14 +178,13 @@ int CLI::run(int argc, char **argv)
start_as_gcodeviewer = true;
break;
}
for (const std::string& file : m_input_files) {
//if (boost::starts_with(file, "open?file=")) {
start_as_downloader = true;
break;
//}
}
if (!start_as_gcodeviewer && !start_as_downloader) {
if (!start_as_gcodeviewer) {
for (const std::string& file : m_input_files) {
if (boost::starts_with(file, "prusaslicer://")) {
start_downloader = true;
download_url = file;
continue;
}
if (!boost::filesystem::exists(file)) {
boost::nowide::cerr << "No such file: " << file << std::endl;
exit(1);
@ -625,7 +625,8 @@ int CLI::run(int argc, char **argv)
params.extra_config = std::move(m_extra_config);
params.input_files = std::move(m_input_files);
params.start_as_gcodeviewer = start_as_gcodeviewer;
params.start_as_downloader = start_as_downloader;
params.start_downloader = start_downloader;
params.download_url = download_url;
return Slic3r::GUI::GUI_Run(params);
#else // SLIC3R_GUI
// No GUI support. Just print out a help.

View File

@ -1253,11 +1253,13 @@ PageUpdate::PageUpdate(ConfigWizard *parent)
boost::filesystem::path binary_path(resources_dir());
binary_path = binary_path.parent_path() / "prusa-slicer-downloader.exe";
//binary_path = binary_path.parent_path() / "prusa-slicer-downloader.exe";
binary_path = binary_path.parent_path() / "prusa-slicer-console.exe";
std::string binary_string = binary_path.string();
std::string key_string = "\"" + binary_string + "\" \"-u\" \"%1\"";
//std::string key_string = "\"" + binary_string + "\" \"-u\" \"%1\"";
std::string key_string = "\"" + binary_string + "\" \"%1\"";
wxRegKey key_first(wxRegKey::HKCU, "Software\\Classes\\prusaslicer");
wxRegKey key_full(wxRegKey::HKCU, "Software\\Classes\\prusaslicer\\shell\\open\\command");

View File

@ -1,6 +1,9 @@
#include "Download.hpp"
#include "Downloader.hpp"
#include "GUI_App.hpp"
#include "NotificationManager.hpp"
namespace Downloader{
namespace Slic3r {
namespace GUI {
namespace {
std::string filename_from_url(const std::string& url)
@ -44,4 +47,75 @@ void Download::resume()
m_state = DownloadState::DownloadOngoing;
m_file_get->resume();
}
Downloader::Downloader()
: wxEvtHandler()
{
Bind(EVT_DWNLDR_FILE_COMPLETE, [](const wxCommandEvent& evt) {});
Bind(EVT_DWNLDR_FILE_PROGRESS, [](const wxCommandEvent& evt) {});
Bind(EVT_DWNLDR_FILE_ERROR, [](const wxCommandEvent& evt) {});
Bind(EVT_DWNLDR_FILE_NAME_CHANGE, [](const wxCommandEvent& evt) {});
Bind(EVT_DWNLDR_FILE_COMPLETE, &Downloader::on_complete, this);
Bind(EVT_DWNLDR_FILE_PROGRESS, &Downloader::on_progress, this);
Bind(EVT_DWNLDR_FILE_ERROR, &Downloader::on_error, this);
Bind(EVT_DWNLDR_FILE_NAME_CHANGE, &Downloader::on_name_change, this);
}
void Downloader::start_download(const std::string& full_url)
{
assert(m_initialized);
// prusaslicer://open/?file=https%3A%2F%2Fmedia.prusaverse.coex.cz%2Fmedia%2Fprints%2F78695%2Fstls%2F847188_185abf43-1439-4466-8777-3f625719498f%2Farm-upper-arm.stl
if (full_url.rfind("prusaslicer://open/?file=", 0) != 0) {
BOOST_LOG_TRIVIAL(error) << "Could not start download due to wrong url: " << full_url << " " << full_url.rfind("prusaslicer://open?file=", 0);
return;
}
size_t id = get_next_id();
std::string escaped_url = FileGet::escape_url(full_url.substr(25));
std::string text(escaped_url);
m_downloads.emplace_back(std::make_unique<Download>(id, std::move(escaped_url), this, m_dest_folder));
NotificationManager* ntf_mngr = wxGetApp().notification_manager();
ntf_mngr->push_download_URL_progress_notification(id, text, std::bind(&Downloader::cancel_callback, this));
m_downloads.back()->start();
BOOST_LOG_TRIVIAL(error) << "started download";
}
void Downloader::on_progress(wxCommandEvent& event)
{
size_t id = event.GetInt();
float percent = (float)std::stoi(boost::nowide::narrow(event.GetString())) / 100.f;
BOOST_LOG_TRIVIAL(error) << "progress " << id << ": " << percent;
NotificationManager* ntf_mngr = wxGetApp().notification_manager();
ntf_mngr->set_download_URL_progress(id, percent);
}
void Downloader::on_error(wxCommandEvent& event)
{
set_download_state(event.GetInt(), DownloadState::DownloadError);
}
void Downloader::on_complete(wxCommandEvent& event)
{
set_download_state(event.GetInt(), DownloadState::DownloadDone);
}
bool Downloader::cancel_callback()
{
//TODO
return true;
}
void Downloader::on_name_change(wxCommandEvent& event)
{
}
void Downloader::set_download_state(size_t id, DownloadState state)
{
for (size_t i = 0; i < m_downloads.size(); ++i) {
if (m_downloads[i]->get_id() == id) {
m_downloads[i]->set_state(state);
return;
}
}
}
}
}

View File

@ -1,11 +1,14 @@
#ifndef slic3r_Download_hpp_
#define slic3r_Download_hpp_
#include "FileGet.hpp"
#ifndef slic3r_Downloader_hpp_
#define slic3r_Downloader_hpp_
#include "DownloaderFileGet.hpp"
#include <boost/filesystem/path.hpp>
#include <wx/wx.h>
namespace Downloader {
namespace Slic3r {
namespace GUI {
class NotificationManager;
enum DownloadState
{
@ -20,7 +23,7 @@ enum DownloadState
class Download {
public:
Download(int ID, std::string url, wxEvtHandler* evt_handler,const boost::filesystem::path& dest_folder);
Download(int ID, std::string url, wxEvtHandler* evt_handler, const boost::filesystem::path& dest_folder);
void start();
void cancel();
void pause();
@ -38,6 +41,47 @@ private:
std::shared_ptr<FileGet> m_file_get;
DownloadState m_state { DownloadState::DownloadPending };
};
}
class Downloader : public wxEvtHandler {
public:
Downloader();
bool get_initialized() { return m_initialized; }
void init(const boost::filesystem::path& dest_folder)
{
m_dest_folder = dest_folder;
m_initialized = true;
}
void start_download(const std::string& full_url);
bool cancel_callback();
private:
bool m_initialized { false };
std::vector<std::unique_ptr<Download>> m_downloads;
boost::filesystem::path m_dest_folder;
size_t m_next_id { 0 };
size_t get_next_id() { return ++m_next_id; }
void on_progress(wxCommandEvent& event);
void on_error(wxCommandEvent& event);
void on_complete(wxCommandEvent& event);
void on_name_change(wxCommandEvent& event);
void set_download_state(size_t id, DownloadState state);
/*
bool is_in_state(int id, DownloadState state) const;
DownloadState get_download_state(int id) const;
bool cancel_download(int id);
bool pause_download(int id);
bool resume_download(int id);
bool delete_download(int id);
wxString get_path_of(int id) const;
wxString get_folder_path_of(int id) const;
*/
};
}
}
#endif

View File

@ -1,13 +1,12 @@
#include "FileGet.hpp"
#include "DownloaderFileGet.hpp"
#include <thread>
#include <curl/curl.h>
#include <boost/nowide/fstream.hpp>
#include <iostream>
namespace Downloader {
namespace Slic3r {
namespace GUI {
const size_t DOWNLOAD_MAX_CHUNK_SIZE = 10 * 1024 * 1024;
const size_t DOWNLOAD_SIZE_LIMIT = 1024 * 1024 * 1024;
@ -39,13 +38,13 @@ unsigned get_current_pid()
}
// int = DOWNLOAD ID; string = file path
wxDEFINE_EVENT(EVT_FILE_COMPLETE, wxCommandEvent);
wxDEFINE_EVENT(EVT_DWNLDR_FILE_COMPLETE, wxCommandEvent);
// int = DOWNLOAD ID; string = error msg
wxDEFINE_EVENT(EVT_FILE_ERROR, wxCommandEvent);
wxDEFINE_EVENT(EVT_DWNLDR_FILE_ERROR, wxCommandEvent);
// int = DOWNLOAD ID; string = progress percent
wxDEFINE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent);
wxDEFINE_EVENT(EVT_DWNLDR_FILE_PROGRESS, wxCommandEvent);
// int = DOWNLOAD ID; string = name
wxDEFINE_EVENT(EVT_FILE_NAME_CHANGE, wxCommandEvent);
wxDEFINE_EVENT(EVT_DWNLDR_FILE_NAME_CHANGE, wxCommandEvent);
struct FileGet::priv
@ -99,7 +98,7 @@ void FileGet::priv::get_perform()
m_tmp_path = m_dest_folder / (m_filename + "." + std::to_string(get_current_pid()) + ".download");
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_NAME_CHANGE);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_NAME_CHANGE);
evt->SetString(boost::nowide::widen(m_filename));
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
@ -120,10 +119,10 @@ void FileGet::priv::get_perform()
size_t written_previously = m_written;
size_t written_this_session = 0;
Downloader::Http::get(m_url)
Http::get(m_url)
.size_limit(DOWNLOAD_SIZE_LIMIT) //more?
.set_range(range_string)
.on_progress([&](Downloader::Http::Progress progress, bool& cancel) {
.on_progress([&](Http::Progress progress, bool& cancel) {
if (m_cancel) {
fclose(file);
// remove canceled file
@ -139,7 +138,7 @@ void FileGet::priv::get_perform()
return;
}
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_PROGRESS);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_PROGRESS);
/*if (progress.dlnow == 0 && m_written == 0) {
evt->SetString("0");
evt->SetInt(m_id);
@ -155,7 +154,7 @@ void FileGet::priv::get_perform()
catch (const std::exception& e)
{
// fclose(file); do it?
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
evt->SetString(e.what());
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
@ -173,7 +172,7 @@ void FileGet::priv::get_perform()
})
.on_error([&](std::string body, std::string error, unsigned http_status) {
fclose(file);
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
evt->SetString(error);
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
@ -202,14 +201,14 @@ void FileGet::priv::get_perform()
{
//TODO: report?
//error_message = GUI::format("Failed to write and move %1% to %2%", tmp_path, dest_path);
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_ERROR);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
evt->SetString("Failed to write and move.");
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
return;
}
wxCommandEvent* evt = new wxCommandEvent(EVT_FILE_COMPLETE);
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_COMPLETE);
evt->SetString(dest_path.string());
evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt);
@ -276,5 +275,5 @@ void FileGet::resume()
p->get_perform();
});
}
}
}

View File

@ -1,7 +1,7 @@
#ifndef slic3r_FileGet_hpp_
#define slic3r_FileGet_hpp_
#ifndef slic3r_DownloaderFileGet_hpp_
#define slic3r_DownloaderFileGet_hpp_
#include "FromSlicer/Http.hpp"
#include "../Utils/Http.hpp"
#include <memory>
#include <string>
@ -9,7 +9,8 @@
#include <wx/frame.h>
#include <boost/filesystem.hpp>
namespace Downloader {
namespace Slic3r {
namespace GUI {
class FileGet : public std::enable_shared_from_this<FileGet> {
private:
struct priv;
@ -27,12 +28,13 @@ private:
std::unique_ptr<priv> p;
};
// int = DOWNLOAD ID; string = file path
wxDECLARE_EVENT(EVT_FILE_COMPLETE, wxCommandEvent);
wxDECLARE_EVENT(EVT_DWNLDR_FILE_COMPLETE, wxCommandEvent);
// int = DOWNLOAD ID; string = error msg
wxDECLARE_EVENT(EVT_FILE_PROGRESS, wxCommandEvent);
wxDECLARE_EVENT(EVT_DWNLDR_FILE_PROGRESS, wxCommandEvent);
// int = DOWNLOAD ID; string = progress percent
wxDECLARE_EVENT(EVT_FILE_ERROR, wxCommandEvent);
wxDECLARE_EVENT(EVT_DWNLDR_FILE_ERROR, wxCommandEvent);
// int = DOWNLOAD ID; string = name
wxDECLARE_EVENT(EVT_FILE_NAME_CHANGE, wxCommandEvent);
wxDECLARE_EVENT(EVT_DWNLDR_FILE_NAME_CHANGE, wxCommandEvent);
}
}
#endif

View File

@ -76,6 +76,7 @@
#include "PrintHostDialogs.hpp"
#include "DesktopIntegrationDialog.hpp"
#include "SendSystemInfoDialog.hpp"
#include "Downloader.hpp"
#include "BitmapCache.hpp"
#include "Notebook.hpp"
@ -741,13 +742,16 @@ void GUI_App::post_init()
if (! this->init_params->input_files.empty())
this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str()));
}
if (this->init_params->start_as_downloader) {
if (this->init_params->start_downloader) {
/*
std::string msg;
for (int i = 0; i < this->init_params->input_files.size(); ++i)
{
msg += this->init_params->input_files[i];
}
show_error(nullptr, "Got url msg." + msg);
*/
start_download(this->init_params->download_url);
}
else {
if (! this->init_params->preset_substitutions.empty())
@ -826,6 +830,7 @@ GUI_App::GUI_App(EAppMode mode)
, m_imgui(new ImGuiWrapper())
, m_removable_drive_manager(std::make_unique<RemovableDriveManager>())
, m_other_instance_message_handler(std::make_unique<OtherInstanceMessageHandler>())
, m_downloader(std::make_unique<Downloader>())
{
//app config initializes early becasuse it is used in instance checking in PrusaSlicer.cpp
this->init_app_config();
@ -1255,7 +1260,8 @@ bool GUI_App::on_init_inner()
Bind(EVT_SLIC3R_APP_OPEN_FAILED, [](const wxCommandEvent& evt) {
show_error(nullptr, evt.GetString());
});
});
}
else {
#ifdef __WXMSW__
@ -2831,11 +2837,16 @@ wxBookCtrlBase* GUI_App::tab_panel() const
return mainframe->m_tabpanel;
}
NotificationManager * GUI_App::notification_manager()
NotificationManager* GUI_App::notification_manager()
{
return plater_->get_notification_manager();
}
Downloader* GUI_App::downloader()
{
return m_downloader.get();
}
// extruders count from selected printer preset
int GUI_App::extruders_cnt() const
{
@ -3364,5 +3375,16 @@ void GUI_App::app_version_check(bool from_user)
m_app_updater->sync_version(version_check_url, from_user);
}
void GUI_App::start_download(std::string url)
{
if (!plater_) {
BOOST_LOG_TRIVIAL(error) << "Could not start URL download: plater is nullptr.";
return;
}
if (!m_downloader->get_initialized())
m_downloader->init(boost::dll::program_location().parent_path()); // TODO WHERE
m_downloader->start_download(url);
}
} // GUI
} //Slic3r

View File

@ -46,6 +46,7 @@ class ObjectList;
class ObjectLayers;
class Plater;
class NotificationManager;
class Downloader;
struct GUI_InitParams;
@ -161,6 +162,7 @@ private:
std::unique_ptr <OtherInstanceMessageHandler> m_other_instance_message_handler;
std::unique_ptr <AppUpdater> m_app_updater;
std::unique_ptr <wxSingleInstanceChecker> m_single_instance_checker;
std::unique_ptr <Downloader> m_downloader;
std::string m_instance_hash_string;
size_t m_instance_hash_int;
@ -295,7 +297,8 @@ public:
Plater* plater();
const Plater* plater() const;
Model& model();
NotificationManager * notification_manager();
NotificationManager* notification_manager();
Downloader* downloader();
// Parameters extracted from the command line to be passed to GUI after initialization.
GUI_InitParams* init_params { nullptr };
@ -372,6 +375,9 @@ private:
void app_version_check(bool from_user);
bool m_datadir_redefined { false };
// URL download - PrusaSlicer gets system call to open prusaslicer:// URL which should contain address of download
void start_download(std::string url);
};
DECLARE_APP(GUI_App)

View File

@ -21,7 +21,8 @@ struct GUI_InitParams
std::vector<std::string> input_files;
bool start_as_gcodeviewer;
bool start_as_downloader;
bool start_downloader;
std::string download_url;
};
int GUI_Run(GUI_InitParams &params);

View File

@ -1864,7 +1864,6 @@ void NotificationManager::upload_job_notification_show_error(int id, const std::
}
}
}
void NotificationManager::push_download_progress_notification(const std::string& text, std::function<bool()> cancel_callback)
{
// If already exists, change text and reset progress
@ -1896,6 +1895,41 @@ void NotificationManager::set_download_progress_percentage(float percentage)
}
}
void NotificationManager::push_download_URL_progress_notification(size_t id, const std::string& text, std::function<bool()> cancel_callback)
{
// If already exists
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::URLDownload && dynamic_cast<URLDownloadNotification*>(notification.get())->get_download_id() == id) {
return;
}
}
// push new one
NotificationData data{ NotificationType::URLDownload, NotificationLevel::ProgressBarNotificationLevel, 10, text };
push_notification_data(std::make_unique<NotificationManager::URLDownloadNotification>(data, m_id_provider, m_evt_handler, id, cancel_callback), 0);
}
void NotificationManager::set_download_URL_progress(size_t id, float percentage)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::URLDownload) {
URLDownloadNotification* ntf = dynamic_cast<URLDownloadNotification*>(notification.get());
if (ntf->get_download_id() != id)
continue;
// if this changes the percentage, it should be shown now
BOOST_LOG_TRIVIAL(error) << percentage;
float percent_b4 = ntf->get_percentage();
ntf->set_percentage(percentage);
if (ntf->get_percentage() != percent_b4)
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
return;
}
}
}
void NotificationManager::set_download_URL_canceled(size_t id, const std::string& text)
{}
void NotificationManager::set_download_URL_error(size_t id, const std::string& text)
{}
void NotificationManager::init_slicing_progress_notification(std::function<bool()> cancel_callback)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {

View File

@ -115,6 +115,8 @@ enum class NotificationType
NetfabbFinished,
// Short meesage to fill space between start and finish of export
ExportOngoing,
// Progressbar of download from prusaslicer:// url
URLDownload
};
class NotificationManager
@ -208,6 +210,11 @@ public:
// Download App progress
void push_download_progress_notification(const std::string& text, std::function<bool()> cancel_callback);
void set_download_progress_percentage(float percentage);
// Download URL progress notif
void push_download_URL_progress_notification(size_t id, const std::string& text, std::function<bool()> cancel_callback);
void set_download_URL_progress(size_t id, float percentage);
void set_download_URL_canceled(size_t id, const std::string& text);
void set_download_URL_error(size_t id, const std::string& text);
// slicing progress
void init_slicing_progress_notification(std::function<bool()> cancel_callback);
void set_slicing_progress_began();
@ -495,6 +502,22 @@ private:
long m_hover_time{ 0 };
};
class URLDownloadNotification : public ProgressBarNotification//ProgressBarWithCancelNotification
{
public:
URLDownloadNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, size_t download_id, std::function<bool()> cancel_callback)
//: ProgressBarWithCancelNotification(n, id_provider, evt_handler, cancel_callback)
: ProgressBarNotification(n, id_provider, evt_handler)
, m_download_id(download_id)
{
}
size_t get_download_id() { return m_download_id; }
protected:
size_t m_download_id;
};
class PrintHostUploadNotification : public ProgressBarNotification
{
public:

View File

@ -144,6 +144,7 @@ struct Http::priv
void set_post_body(const fs::path &path);
void set_post_body(const std::string &body);
void set_put_body(const fs::path &path);
void set_range(const std::string& range);
std::string curl_error(CURLcode curlcode);
std::string body_size_error();
@ -225,7 +226,7 @@ int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_o
bool cb_cancel = false;
if (self->progressfn) {
Progress progress(dltotal, dlnow, ultotal, ulnow);
Progress progress(dltotal, dlnow, ultotal, ulnow, self->buffer);
self->progressfn(progress, cb_cancel);
}
@ -313,6 +314,11 @@ void Http::priv::set_put_body(const fs::path &path)
}
}
void Http::priv::set_range(const std::string& range)
{
::curl_easy_setopt(curl, CURLOPT_RANGE, range.c_str());
}
std::string Http::priv::curl_error(CURLcode curlcode)
{
return (boost::format("%1%:\n%2%\n[Error %3%]")
@ -370,7 +376,7 @@ void Http::priv::http_perform()
if (res == CURLE_ABORTED_BY_CALLBACK) {
if (cancel) {
// The abort comes from the request being cancelled programatically
Progress dummyprogress(0, 0, 0, 0);
Progress dummyprogress(0, 0, 0, 0, std::string());
bool cancel = true;
if (progressfn) { progressfn(dummyprogress, cancel); }
} else {
@ -438,6 +444,12 @@ Http& Http::size_limit(size_t sizeLimit)
return *this;
}
Http& Http::set_range(const std::string& range)
{
if (p) { p->set_range(range); }
return *this;
}
Http& Http::header(std::string name, const std::string &value)
{
if (!p) { return * this; }

View File

@ -21,9 +21,10 @@ public:
size_t dlnow; // Bytes downloaded so far
size_t ultotal; // Total bytes to upload
size_t ulnow; // Bytes uploaded so far
const std::string& buffer; // reference to buffer containing all data
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) :
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow)
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow, const std::string& buffer) :
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow), buffer(buffer)
{}
};
@ -65,6 +66,8 @@ public:
// Sets a maximum size of the data that can be received.
// A value of zero sets the default limit, which is is 5MB.
Http& size_limit(size_t sizeLimit);
// range of donloaded bytes. example: curl_easy_setopt(curl, CURLOPT_RANGE, "0-199");
Http& set_range(const std::string& range);
// Sets a HTTP header field.
Http& header(std::string name, const std::string &value);
// Removes a header field.