diff --git a/CMakeLists.txt b/CMakeLists.txt index 8986c62..9ca63b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,12 +22,6 @@ add_executable(ezremote_client source/imgui/imgui_widgets.cpp source/imgui/imgui.cpp source/pugixml/pugixml.cpp - source/web/callback.cpp - source/web/fsinfo.cpp - source/web/header.cpp - source/web/request.cpp - source/web/urn.cpp - source/webdav/client.cpp source/http/httplib.cpp source/clients/baseclient.cpp source/clients/apache.cpp @@ -38,9 +32,9 @@ add_executable(ezremote_client source/clients/npxserve.cpp source/clients/nfsclient.cpp source/clients/smbclient.cpp - source/clients/webdavclient.cpp source/clients/sftpclient.cpp source/clients/rclone.cpp + source/clients/webdav.cpp source/filehost/alldebrid.cpp source/filehost/realdebrid.cpp source/filehost/directhost.cpp @@ -72,7 +66,7 @@ add_executable(ezremote_client add_self(ezremote_client) -add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.19" 32 0) +add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.20" 32 0) target_link_libraries(ezremote_client c @@ -88,7 +82,6 @@ target_link_libraries(ezremote_client jbc crypto ssl - curl lexbor smb2 nfs diff --git a/source/actions.cpp b/source/actions.cpp index 3e164d4..1f30890 100644 --- a/source/actions.cpp +++ b/source/actions.cpp @@ -8,7 +8,7 @@ #include "clients/gdrive.h" #include "clients/ftpclient.h" #include "clients/smbclient.h" -#include "clients/webdavclient.h" +#include "clients/webdav.h" #include "clients/apache.h" #include "clients/nginx.h" #include "clients/npxserve.h" @@ -25,8 +25,6 @@ #include "lang.h" #include "actions.h" #include "installer.h" -#include "web/request.hpp" -#include "web/urn.hpp" #include "system.h" #include "sfo.h" #include "zip_util.h" @@ -1102,14 +1100,14 @@ namespace Actions std::string host = full_url.substr(0, path_pos); std::string path = full_url.substr(path_pos); - WebDAV::WebDavClient tmp_client; - tmp_client.Connect(host.c_str(), install_pkg_url.username, install_pkg_url.password, false); + WebDAVClient tmp_client; + tmp_client.Connect(host.c_str(), install_pkg_url.username, install_pkg_url.password); sprintf(activity_message, "%s URL to %s", lang_strings[STR_DOWNLOADING], filename); int s = sizeof(pkg_header); memset(&header, 0, s); - WebDAV::dict_t response_headers{}; - int ret = tmp_client.GetHeaders(path.c_str(), &response_headers); + + int ret = tmp_client.Size(path, &bytes_to_download); if (!ret) { sprintf(status_message, "%s - %s", lang_strings[STR_FAILED], lang_strings[STR_CANNOT_READ_PKG_HDR_MSG]); @@ -1119,13 +1117,8 @@ namespace Actions return NULL; } - auto content_length = WebDAV::get(response_headers, "content-length"); - if (content_length.length() > 0) - bytes_to_download = std::stol(content_length); - else - bytes_to_download = 1; file_transfering = 1; - int is_performed = tmp_client.Get(filename, path.c_str()); + int is_performed = tmp_client.Get(path, filename); if (is_performed == 0) { @@ -1213,7 +1206,7 @@ namespace Actions } else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0) { - remoteclient = new WebDAV::WebDavClient(); + remoteclient = new WebDAVClient(); } else if (strncmp(remote_settings->server, "smb://", 6) == 0) { diff --git a/source/clients/baseclient.cpp b/source/clients/baseclient.cpp index 8af032f..607bcf4 100644 --- a/source/clients/baseclient.cpp +++ b/source/clients/baseclient.cpp @@ -10,6 +10,7 @@ using httplib::Client; using httplib::Headers; using httplib::Result; +using httplib::DataSink; BaseClient::BaseClient(){}; @@ -21,15 +22,15 @@ BaseClient::~BaseClient() int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password) { - std::string scheme_host_port = url; + this->host_url = url; size_t scheme_pos = url.find("://"); size_t root_pos = url.find("/", scheme_pos + 3); if (root_pos != std::string::npos) { - scheme_host_port = url.substr(0, root_pos); + this->host_url = url.substr(0, root_pos); this->base_path = url.substr(root_pos); } - client = new httplib::Client(scheme_host_port); + client = new httplib::Client(this->host_url); if (username.length() > 0) client->set_basic_auth(username, password); client->set_keep_alive(true); @@ -82,10 +83,13 @@ int BaseClient::Size(const std::string &path, int64_t *size) { if (auto res = client->Head(GetFullPath(path))) { - std::string content_length = res->get_header_value("Content-Length"); - if (content_length.length() > 0) - *size = atoll(content_length.c_str()); - return 1; + if (HTTP_SUCCESS(res->status)) + { + std::string content_length = res->get_header_value("Content-Length"); + if (content_length.length() > 0) + *size = atoll(content_length.c_str()); + return 1; + } } else { @@ -309,35 +313,10 @@ uint32_t BaseClient::SupportedActions() std::string BaseClient::EncodeUrl(const std::string &url) { - CURL *curl = curl_easy_init(); - if (curl) - { - char *output = curl_easy_escape(curl, url.c_str(), url.length()); - if (output) - { - std::string encoded_url = std::string(output); - curl_free(output); - return encoded_url; - } - curl_easy_cleanup(curl); - } - return ""; + return httplib::detail::encode_url(url); } std::string BaseClient::DecodeUrl(const std::string &url) { - CURL *curl = curl_easy_init(); - if (curl) - { - int decode_len; - char *output = curl_easy_unescape(curl, url.c_str(), url.length(), &decode_len); - if (output) - { - std::string decoded_url = std::string(output, decode_len); - curl_free(output); - return decoded_url; - } - curl_easy_cleanup(curl); - } - return ""; + return httplib::detail::decode_url(url, true); } diff --git a/source/clients/baseclient.h b/source/clients/baseclient.h index 2c1691f..db7256a 100644 --- a/source/clients/baseclient.h +++ b/source/clients/baseclient.h @@ -45,6 +45,7 @@ public: protected: httplib::Client *client; std::string base_path; + std::string host_url; char response[512]; bool connected = false; }; diff --git a/source/clients/webdav.cpp b/source/clients/webdav.cpp new file mode 100644 index 0000000..afe1bed --- /dev/null +++ b/source/clients/webdav.cpp @@ -0,0 +1,283 @@ +#include +#include "common.h" +#include "clients/remote_client.h" +#include "clients/webdav.h" +#include "pugixml/pugiext.hpp" +#include "fs.h" +#include "lang.h" +#include "util.h" +#include "system.h" +#include "windows.h" + +using httplib::Client; +using httplib::Headers; +using httplib::Progress; +using httplib::Result; +using httplib::ContentProvider; + +static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +std::string WebDAVClient::GetHttpUrl(std::string url) +{ + std::string http_url = std::regex_replace(url, std::regex("webdav://"), "http://"); + http_url = std::regex_replace(http_url, std::regex("webdavs://"), "https://"); + return http_url; +} + +int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass) +{ + std::string url = GetHttpUrl(host); + return BaseClient::Connect(url, user, pass); +} + +Result WebDAVClient::PropFind(const std::string &path, int depth) +{ + Request req; + Headers header = {{"Accept", "*/*"}, {"Depth", std::to_string(depth)}}; + + req.method = "PROPFIND"; + req.path = path; + req.headers = header; + req.progress = Progress(); + + return client->send(req); +} + +std::vector WebDAVClient::ListDir(const std::string &path) +{ + std::vector out; + DirEntry entry; + Util::SetupPreviousFolder(path, &entry); + out.push_back(entry); + + std::string encoded_path = httplib::detail::encode_url(GetFullPath(path)); + if (auto res = PropFind(encoded_path, 1)) + { + pugi::xml_document document; + document.load_buffer(res->body.c_str(), res->body.length()); + auto multistatus = document.select_node("*[local-name()='multistatus']").node(); + auto responses = multistatus.select_nodes("*[local-name()='response']"); + for (auto response : responses) + { + pugi::xml_node href = response.node().select_node("*[local-name()='href']").node(); + std::string resource_path = httplib::detail::decode_url(href.first_child().value(), true); + + auto target_path_without_sep = GetFullPath(path); + if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/') + target_path_without_sep.resize(target_path_without_sep.length() - 1); + auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1); + size_t pos = resource_path_without_sep.find(this->host_url); + if (pos != std::string::npos) + resource_path_without_sep.erase(pos, this->host_url.length()); + + if (resource_path_without_sep == target_path_without_sep) + continue; + + pos = resource_path_without_sep.find_last_of('/'); + auto name = resource_path_without_sep.substr(pos + 1); + auto propstat = response.node().select_node("*[local-name()='propstat']").node(); + auto prop = propstat.select_node("*[local-name()='prop']").node(); + std::string creation_date = prop.select_node("*[local-name()='creationdate']").node().first_child().value(); + std::string content_length = prop.select_node("*[local-name()='getcontentlength']").node().first_child().value(); + std::string m_date = prop.select_node("*[local-name()='getlastmodified']").node().first_child().value(); + std::string resource_type = prop.select_node("*[local-name()='resourcetype']").node().first_child().name(); + + DirEntry entry; + memset(&entry, 0, sizeof(entry)); + entry.selectable = true; + sprintf(entry.directory, "%s", path.c_str()); + sprintf(entry.name, "%s", name.c_str()); + + if (path.length() == 1 and path[0] == '/') + { + sprintf(entry.path, "%s%s", path.c_str(), name.c_str()); + } + else + { + sprintf(entry.path, "%s/%s", path.c_str(), name.c_str()); + } + + entry.isDir = resource_type.find("collection") != std::string::npos; + entry.file_size = 0; + if (!entry.isDir) + { + entry.file_size = std::stoll(content_length); + DirEntry::SetDisplaySize(&entry); + } + else + { + sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); + } + + char modified_date[32]; + char *p_char = NULL; + sprintf(modified_date, "%s", m_date.c_str()); + p_char = strchr(modified_date, ' '); + if (p_char) + { + OrbisDateTime gmt; + OrbisDateTime lt; + char month[5]; + sscanf(p_char, "%hd %s %hd %hd:%hd:%hd", &gmt.day, month, &gmt.year, &gmt.hour, &gmt.minute, &gmt.second); + for (int k = 0; k < 12; k++) + { + if (strcmp(month, months[k]) == 0) + { + gmt.month = k + 1; + break; + } + } + convertUtcToLocalTime(&gmt, <); + entry.modified.day = lt.day; + entry.modified.month = lt.month; + entry.modified.year = lt.year; + entry.modified.hours = lt.hour; + entry.modified.minutes = lt.minute; + entry.modified.seconds = lt.second; + } + out.push_back(entry); + } + } + else + { + sprintf(this->response, "%s", httplib::to_string(res.error()).c_str()); + return out; + } + + return out; +} + +int WebDAVClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset) +{ + size_t bytes_remaining = FS::GetSize(inputfile); + bytes_transfered = 0; + + FILE* in = FS::OpenRead(inputfile); + + if (auto res = client->Put(GetFullPath(path), + [&](size_t offset, DataSink &sink) + { + size_t buf_size = MIN(bytes_remaining, CPPHTTPLIB_RECV_BUFSIZ); + char* buf = (char*) malloc(buf_size); + FS::Seek(in, offset); + + while (bytes_remaining > 0) + { + size_t bytes_read = FS::Read(in, buf, buf_size); + sink.write(buf, bytes_read); + bytes_transfered += bytes_read; + bytes_remaining -= bytes_read; + } + sink.done(); + free(buf); + return true; + }, + "application/octet-stream")) + { + if (HTTP_SUCCESS(res->status)) + { + FS::Close(in); + return 1; + } + } + + FS::Close(in); + return 0; +} + +int WebDAVClient::Mkdir(const std::string &path) +{ + Request req; + Headers header = {{"Accept", "*/*"}, {"Connection", "Keep-Alive"}}; + + req.method = "MKCOL"; + req.path = httplib::detail::encode_url(GetFullPath((path))); + req.headers = header; + req.progress = Progress(); + + if (auto res = client->send(req)) + { + if (HTTP_SUCCESS(res->status)) + return 1; + } + + return 0; +} + +int WebDAVClient::Rmdir(const std::string &path, bool recursive) +{ + return Delete(path); +} + +int WebDAVClient::Rename(const std::string &src, const std::string &dst) +{ + return Move(src, dst); +} + +int WebDAVClient::Delete(const std::string &path) +{ + Request req; + Headers header = {{"Accept", "*/*"}, {"Connection", "Keep-Alive"}}; + + req.method = "DELETE"; + req.path = httplib::detail::encode_url(GetFullPath((path))); + req.headers = header; + req.progress = Progress(); + + if (auto res = client->send(req)) + { + if (HTTP_SUCCESS(res->status)) + return 1; + } + + return 0; + +} + +int WebDAVClient::Copy(const std::string &from, const std::string &to) +{ + Request req; + Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }}; + + req.method = "COPY"; + req.path = httplib::detail::encode_url(GetFullPath(from)); + req.headers = header; + req.progress = Progress(); + + if (auto res = client->send(req)) + { + if (HTTP_SUCCESS(res->status)) + return 1; + } + + return 0; +} + +int WebDAVClient::Move(const std::string &from, const std::string &to) +{ + Request req; + Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }}; + + req.method = "MOVE"; + req.path = httplib::detail::encode_url(GetFullPath(from)); + req.headers = header; + req.progress = Progress(); + + if (auto res = client->send(req)) + { + if (HTTP_SUCCESS(res->status)) + return 1; + } + + return 0; +} + +ClientType WebDAVClient::clientType() +{ + return CLIENT_TYPE_WEBDAV; +} + +uint32_t WebDAVClient::SupportedActions() +{ + return REMOTE_ACTION_ALL; +} \ No newline at end of file diff --git a/source/clients/webdav.h b/source/clients/webdav.h new file mode 100644 index 0000000..f3f6e20 --- /dev/null +++ b/source/clients/webdav.h @@ -0,0 +1,31 @@ +#ifndef WEBDAV_H +#define WEBDAV_H + +#include +#include +#include "http/httplib.h" +#include "clients/baseclient.h" +#include "clients/remote_client.h" +#include "common.h" + +class WebDAVClient : public BaseClient +{ +public: + int Connect(const std::string &url, const std::string &user, const std::string &pass); + int Mkdir(const std::string &path); + int Rmdir(const std::string &path, bool recursive); + int Rename(const std::string &src, const std::string &dst); + int Delete(const std::string &path); + int Copy(const std::string &from, const std::string &to); + int Move(const std::string &from, const std::string &to); + int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0); + std::vector ListDir(const std::string &path); + ClientType clientType(); + uint32_t SupportedActions(); + static std::string GetHttpUrl(std::string url); + +private: + Result PropFind(const std::string &path, int depth); +}; + +#endif \ No newline at end of file diff --git a/source/clients/webdavclient.cpp b/source/clients/webdavclient.cpp deleted file mode 100644 index 6f43ac3..0000000 --- a/source/clients/webdavclient.cpp +++ /dev/null @@ -1,387 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lang.h" -#include "webdav/client.hpp" -#include "clients/webdavclient.h" -#include "windows.h" -#include "util.h" -#include "system.h" - -static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -namespace WebDAV -{ - static int DownloadCallback(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) - { - int64_t *bytes_transfered = (int64_t *)context; - *bytes_transfered = reinterpret_cast(dlnow); - return CURLE_OK; - } - - static int UploadCallback(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) - { - int64_t *bytes_transfered = (int64_t *)context; - *bytes_transfered = reinterpret_cast(ulnow); - return CURLE_OK; - } - - int WebDavClient::Connect(const std::string &host, const std::string &user, const std::string &pass) - { - return Connect(host, user, pass, true); - } - - WebDavClient::WebDavClient() {}; - - int WebDavClient::Connect(const std::string &host, const std::string &user, const std::string &pass, bool check_enabled) - { - std::string url = GetHttpUrl(host); - std::size_t scheme_pos = url.find_first_of("://"); - std::string root_folder = "/"; - if (scheme_pos != std::string::npos) - { - std::size_t root_folder_pos = url.find_first_of("/", scheme_pos + 3); - if (root_folder_pos != std::string::npos) - { - root_folder = url.substr(root_folder_pos); - url = url.substr(0, root_folder_pos); - } - } - WebDAV::dict_t options = { - {"webdav_hostname", url}, - {"webdav_root", root_folder}, - {"webdav_username", user}, - {"webdav_password", pass}, - {"check_enabled", check_enabled ? "1" : "0"}}; - client = new WebDAV::Client(options); - connected = true; - - return 1; - } - - /* - * LastResponse - return a pointer to the last response received - */ - const char *WebDavClient::LastResponse() - { - return (const char *)response; - } - - /* - * IsConnected - return true if connected to remote - */ - bool WebDavClient::IsConnected() - { - return connected; - } - - /* - * Ping - return true if connected to remote - */ - bool WebDavClient::Ping() - { - connected = client->check(); - sprintf(response, "Http Code %ld", client->status_code()); - return connected; - } - - /* - * Quit - disconnect from remote - * - * return 1 if successful, 0 otherwise - */ - int WebDavClient::Quit() - { - if (client != NULL) - delete (client); - client = NULL; - connected = false; - return 1; - } - - /* - * Mkdir - create a directory at server - * - * return 1 if successful, 0 otherwise - */ - int WebDavClient::Mkdir(const std::string &ppath) - { - bool ret = client->create_directory(ppath); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - /* - * Rmdir - remove directory and all files under directory at remote - * - * return 1 if successful, 0 otherwise - */ - int WebDavClient::_Rmdir(const std::string &ppath) - { - bool ret = client->clean(ppath); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - /* - * Rmdir - remove directory and all files under directory at remote - * - * return 1 if successful, 0 otherwise - */ - int WebDavClient::Rmdir(const std::string &path, bool recursive) - { - if (stop_activity) - return 1; - - std::vector list = ListDir(path); - int ret; - for (int i = 0; i < list.size(); i++) - { - if (stop_activity) - return 1; - - if (list[i].isDir && recursive) - { - if (strcmp(list[i].name, "..") == 0) - continue; - ret = Rmdir(list[i].path, recursive); - if (ret == 0) - { - sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], list[i].path); - return 0; - } - } - else - { - sprintf(activity_message, "%s %s\n", lang_strings[STR_DELETING], list[i].path); - ret = Delete(list[i].path); - if (ret == 0) - { - sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], list[i].path); - return 0; - } - } - } - ret = _Rmdir(path); - if (ret == 0) - { - sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str()); - return 0; - } - - return 1; - } - - /* - * Get - issue a GET command and write received data to output - * - * return 1 if successful, 0 otherwise - */ - - int WebDavClient::Get(const std::string &outputfile, const std::string &ppath, uint64_t offset) - { - bool ret = client->download(ppath, outputfile, &bytes_transfered, DownloadCallback); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - bool WebDavClient::FileExists(const std::string &ppath) - { - std::string path = ppath; - path = Util::Ltrim(path, "/"); - bool ret = client->check(path); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset) - { - char *buffer_ptr = nullptr; - unsigned long long buffer_size = 0; - - bool ret = client->download_range_to(path, buffer_ptr, buffer_size, offset, offset+size-1); - sprintf(response, "Http Code %ld", client->status_code()); - if (buffer_size != size) - { - return 0; - } - memcpy(buffer, buffer_ptr, size); - return 1; - } - - int WebDavClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) - { - return client->download_range_to(path, sink, offset, offset+size-1); - } - - /* - * Put - issue a PUT command and send data from input - * - * return 1 if successful, 0 otherwise - */ - int WebDavClient::Put(const std::string &inputfile, const std::string &ppath, uint64_t offset) - { - bool ret = client->upload(ppath, inputfile, &bytes_transfered, UploadCallback); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::Rename(const std::string &src, const std::string &dst) - { - bool ret = client->move(src, dst); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::Delete(const std::string &ppath) - { - bool ret = client->clean(ppath); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::Copy(const std::string &from, const std::string &to) - { - bool ret = client->copy(from, to); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::Move(const std::string &from, const std::string &to) - { - bool ret = client->move(from, to); - sprintf(response, "Http Code %ld", client->status_code()); - return ret; - } - - int WebDavClient::Size(const std::string &ppath, int64_t *size) - { - WebDAV::dict_t file_info = client->info(ppath); - std::string file_size = WebDAV::get(file_info, "size"); - if (file_size.empty()) - return 0; - *size = std::stoll(file_size); - return 1; - } - - std::vector WebDavClient::ListDir(const std::string &path) - { - std::vector out; - DirEntry entry; - Util::SetupPreviousFolder(path, &entry); - out.push_back(entry); - - WebDAV::dict_items_t files = client->list(path); - for (int i = 0; i < files.size(); i++) - { - DirEntry entry; - memset(&entry, 0, sizeof(entry)); - entry.selectable = true; - sprintf(entry.directory, "%s", path.c_str()); - sprintf(entry.name, "%s", WebDAV::get(files[i], "name").c_str()); - - if (path.length() == 1 and path[0] == '/') - { - sprintf(entry.path, "%s%s", path.c_str(), WebDAV::get(files[i], "name").c_str()); - } - else - { - sprintf(entry.path, "%s/%s", path.c_str(), WebDAV::get(files[i], "name").c_str()); - } - - std::string resource_type = WebDAV::get(files[i], "type"); - entry.isDir = resource_type.find("collection") != std::string::npos; - entry.file_size = 0; - if (!entry.isDir) - { - entry.file_size = std::stoll(WebDAV::get(files[i], "size")); - DirEntry::SetDisplaySize(&entry); - } - else - { - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - } - - char modified_date[32]; - char *p_char = NULL; - sprintf(modified_date, "%s", WebDAV::get(files[i], "modified").c_str()); - p_char = strchr(modified_date, ' '); - if (p_char) - { - OrbisDateTime gmt; - OrbisDateTime lt; - char month[5]; - sscanf(p_char, "%hd %s %hd %hd:%hd:%hd", &gmt.day, month, &gmt.year, &gmt.hour, &gmt.minute, &gmt.second); - for (int k = 0; k < 12; k++) - { - if (strcmp(month, months[k]) == 0) - { - gmt.month = k + 1; - break; - } - } - convertUtcToLocalTime(&gmt, <); - entry.modified.day = lt.day; - entry.modified.month = lt.month; - entry.modified.year = lt.year; - entry.modified.hours = lt.hour; - entry.modified.minutes = lt.minute; - entry.modified.seconds = lt.second; - } - out.push_back(entry); - } - - return out; - } - - std::string WebDavClient::GetPath(std::string ppath1, std::string ppath2) - { - std::string path1 = ppath1; - std::string path2 = ppath2; - path1 = Util::Rtrim(Util::Trim(path1, " "), "/"); - path2 = Util::Rtrim(Util::Trim(path2, " "), "/"); - path1 = path1 + "/" + path2; - return path1; - } - - int WebDavClient::Head(const std::string &path, void *buffer, uint64_t len) - { - char *buffer_ptr = nullptr; - unsigned long long buffer_size = 0; - - bool ret = client->download_range_to(path, buffer_ptr, buffer_size, 0, len - 1); - sprintf(response, "Http Code %ld", client->status_code()); - if (buffer_size != len) - { - return 0; - } - memcpy(buffer, buffer_ptr, len); - return 1; - } - - bool WebDavClient::GetHeaders(const std::string &path, dict_t *headers) - { - return client->head(path, headers); - } - - WebDAV::Client *WebDavClient::GetClient() - { - return this->client; - } - - ClientType WebDavClient::clientType() - { - return CLIENT_TYPE_WEBDAV; - } - - uint32_t WebDavClient::SupportedActions() - { - return REMOTE_ACTION_ALL; - } -} \ No newline at end of file diff --git a/source/clients/webdavclient.h b/source/clients/webdavclient.h deleted file mode 100644 index b0efd9e..0000000 --- a/source/clients/webdavclient.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef WEBDAVCLIENT_H -#define WEBDAVCLIENT_H - -#include -#include -#include -#include -#include "http/httplib.h" -#include "webdav/client.hpp" -#include "clients/remote_client.h" -#include "common.h" - -using namespace httplib; - -namespace WebDAV -{ - inline std::string GetHttpUrl(std::string url) - { - std::string http_url = std::regex_replace(url, std::regex("webdav://"), "http://"); - http_url = std::regex_replace(http_url, std::regex("webdavs://"), "https://"); - return http_url; - } - - class WebDavClient : public RemoteClient - { - public: - WebDavClient(); - int Connect(const std::string &url, const std::string &user, const std::string &pass); - int Connect(const std::string &url, const std::string &user, const std::string &pass, bool check_enabled); - int Mkdir(const std::string &path); - int Rmdir(const std::string &path, bool recursive); - int Size(const std::string &path, int64_t *size); - int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0); - int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset); - int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset); - int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0); - int Rename(const std::string &src, const std::string &dst); - int Delete(const std::string &path); - int Copy(const std::string &from, const std::string &to); - int Move(const std::string &from, const std::string &to); - bool FileExists(const std::string &path); - std::vector ListDir(const std::string &path); - bool IsConnected(); - bool Ping(); - const char *LastResponse(); - int Quit(); - std::string GetPath(std::string path1, std::string path2); - int Head(const std::string &path, void *buffer, uint64_t len); - bool GetHeaders(const std::string &path, dict_t *headers); - WebDAV::Client *GetClient(); - ClientType clientType(); - uint32_t SupportedActions(); - - private: - int _Rmdir(const std::string &path); - WebDAV::Client *client; - char response[1024]; - bool connected = false; - }; - -} -#endif \ No newline at end of file diff --git a/source/http/httplib.cpp b/source/http/httplib.cpp index 127588c..1b5f6d7 100644 --- a/source/http/httplib.cpp +++ b/source/http/httplib.cpp @@ -562,7 +562,7 @@ private: size_t read_buff_off_ = 0; size_t read_buff_content_size_ = 0; - static const size_t read_buff_size_ = 1024 * 16; + static const size_t read_buff_size_ = 1024 * 512; }; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT diff --git a/source/http/httplib.h b/source/http/httplib.h index 6009a2b..14aa264 100644 --- a/source/http/httplib.h +++ b/source/http/httplib.h @@ -87,11 +87,11 @@ #endif #ifndef CPPHTTPLIB_RECV_BUFSIZ -#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u) +#define CPPHTTPLIB_RECV_BUFSIZ size_t(524288u) #endif #ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ -#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u) +#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(524288u) #endif #ifndef CPPHTTPLIB_THREAD_POOL_COUNT diff --git a/source/installer.cpp b/source/installer.cpp index 317a890..fabe101 100644 --- a/source/installer.cpp +++ b/source/installer.cpp @@ -10,9 +10,8 @@ #include #include #include -#include -#include -#include +#include "clients/webdav.h" +#include "clients/remote_client.h" #include "server/http_server.h" #include "installer.h" #include "util.h" @@ -22,8 +21,6 @@ #include "system.h" #include "fs.h" #include "sfo.h" -#include "clients/webdavclient.h" -#include "clients/remote_client.h" #define BGFT_HEAP_SIZE (1 * 1024 * 1024) @@ -205,7 +202,7 @@ namespace INSTALLER if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 && (remoteclient->clientType() == CLIENT_TYPE_WEBDAV || remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER)) { - std::string full_url = WebDAV::GetHttpUrl(remote_settings->server + path); + std::string full_url = WebDAVClient::GetHttpUrl(remote_settings->server + path); size_t scheme_pos = full_url.find("://"); if (scheme_pos == std::string::npos) return ""; @@ -215,24 +212,15 @@ namespace INSTALLER if (encodeUrl) { - Web::Urn::Path uri(path); - CURL *curl = curl_easy_init(); - path = uri.quote(curl); - curl_easy_cleanup(curl); + path = httplib::detail::encode_url(path); } return host + path; } else { - std::string encoded_path = path; - std::string encoded_site_name = remote_settings->site_name; - Web::Urn::Path uri(encoded_path); - Web::Urn::Path site_name(encoded_site_name); - CURL *curl = curl_easy_init(); - encoded_path = uri.quote(curl); - encoded_site_name = site_name.quote(curl); - curl_easy_cleanup(curl); + std::string encoded_path = httplib::detail::encode_url(path); + std::string encoded_site_name = httplib::detail::encode_url(remote_settings->site_name); std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path; return full_url; diff --git a/source/web/pugiext.hpp b/source/pugixml/pugiext.hpp similarity index 100% rename from source/web/pugiext.hpp rename to source/pugixml/pugiext.hpp diff --git a/source/web/callback.cpp b/source/web/callback.cpp deleted file mode 100644 index 4d8fac1..0000000 --- a/source/web/callback.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include -#include -#include -#include "http/httplib.h" - -#include "callback.hpp" - -using namespace httplib; - -namespace Web -{ - namespace Callback - { - namespace Read - { - size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream) - { - auto in_stream = reinterpret_cast(stream); - auto read_bytes = static_cast(item_size * item_count); - auto position = static_cast(in_stream->tellg()); - in_stream->seekg(0, std::ios::end); - auto size = static_cast(in_stream->tellg()); - in_stream->seekg(position, std::ios::beg); - auto rest_bytes = size - position; - read_bytes = std::min(read_bytes, rest_bytes); - in_stream->read(ptr, read_bytes); - return read_bytes; - } - - size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer) - { - auto data = (Data*)buffer; - auto size = static_cast(item_size * item_count); - auto rest_bytes = data->size - data->position; - auto copied_bytes = std::min(size, rest_bytes); - memcpy(ptr, data->buffer, copied_bytes); - data->position += copied_bytes; - return copied_bytes; - } - } // namespace Read - - namespace Write - { - size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream) - { - auto out_stream = reinterpret_cast(stream); - size_t write_bytes = item_size * item_count; - out_stream->write(ptr, write_bytes); - return write_bytes; - } - - size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer) - { - auto data = reinterpret_cast(buffer); - auto size = static_cast(item_size * item_count); - auto rest_bytes = data->size - data->position; - auto copied_bytes = std::min(size, rest_bytes); - memcpy(data->buffer, ptr, copied_bytes); - data->position += copied_bytes; - return copied_bytes; - } - } // namespace Write - - namespace Append - { - size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer) - { - auto data = reinterpret_cast(buffer); - auto append_size = item_size * item_count; - auto new_buffer_size = data->size + append_size; - auto new_buffer = new char[new_buffer_size]; - if (data->size != 0) memcpy(new_buffer, data->buffer, data->size); - memcpy(new_buffer + data->size, ptr, append_size); - delete[] data->buffer; - data->buffer = new_buffer; - data->size = new_buffer_size; - return append_size; - } - - size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream) - { - auto out_stream = reinterpret_cast(stream); - size_t write_bytes = item_size * item_count; - out_stream->seekp(0, std::ios::end); - out_stream->write(ptr, write_bytes); - return write_bytes; - } - - size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink) - { - auto ostream = reinterpret_cast(sink); - size_t write_bytes = item_size * item_count; - ostream->write(ptr, write_bytes); - return write_bytes; - } - } // namespace Append - } // namespace Callback -} // namespace Web diff --git a/source/web/callback.hpp b/source/web/callback.hpp deleted file mode 100644 index 7e44867..0000000 --- a/source/web/callback.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEB_CALLBACK_HPP -#define WEB_CALLBACK_HPP - -namespace Web -{ - struct Data - { - char* buffer; - unsigned long long position; - unsigned long long size; - void reset() - { - buffer = nullptr; - position = 0; - size = 0; - } - ~Data() - { - delete[] buffer; - } - }; - - namespace Callback - { - namespace Read - { - size_t stream(char* data, size_t size, size_t count, void* stream); - size_t buffer(char* data, size_t size, size_t count, void* buffer); - } - - namespace Write - { - size_t stream(char* data, size_t size, size_t count, void* stream); - size_t buffer(char* data, size_t size, size_t count, void* buffer); - } - - namespace Append - { - size_t stream(char* data, size_t size, size_t count, void* stream); - size_t buffer(char* data, size_t size, size_t count, void* buffer); - size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink); - } - } -} // namespace Web - -#endif diff --git a/source/web/fsinfo.cpp b/source/web/fsinfo.cpp deleted file mode 100644 index 342a881..0000000 --- a/source/web/fsinfo.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include "fsinfo.hpp" -#include - -namespace Web -{ - namespace FileInfo - { - auto exists(const std::string& path) -> bool - { - std::ifstream file(path); - return file.good(); - } - - auto size(const std::string& path_file) -> unsigned long long - { - std::ifstream file(path_file, std::ios::binary | std::ios::ate); - return static_cast(file.tellg()); - } - } // namespace FileInfo -} // namespace Web diff --git a/source/web/fsinfo.hpp b/source/web/fsinfo.hpp deleted file mode 100644 index 62cc389..0000000 --- a/source/web/fsinfo.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEB_FSINFO_HPP -#define WEB_FSINFO_HPP - -#include -#include - -namespace Web -{ - namespace FileInfo - { - auto exists(const std::string& path) -> bool; - auto size(const std::string& path_file) -> unsigned long long; - } // namespace FileInfo -} // namespace Web - -#endif diff --git a/source/web/header.cpp b/source/web/header.cpp deleted file mode 100644 index ac0dd80..0000000 --- a/source/web/header.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include "header.hpp" - -#include - -namespace Web -{ - Header::Header(const std::initializer_list& init_list) noexcept : handle(nullptr) - { - for (auto& item : init_list) - { - this->append(item); - } - } - - Header::~Header() noexcept - { - curl_slist_free_all(reinterpret_cast(this->handle)); - } - - Header::Header(Header&& other) noexcept - { - handle = other.handle; - other.handle = nullptr; - } - - auto Header::operator=(Header&& other) noexcept -> Header& - { - if (this != &other) - { - Header(std::move(other)).swap(*this); - } - - return *this; - } - - auto Header::swap(Header& other) noexcept -> void - { - using std::swap; - swap(handle, other.handle); - } - - void - Header::append(const std::string& item) noexcept - { - this->handle = curl_slist_append(reinterpret_cast(this->handle), item.c_str()); - } -} // namespace Web diff --git a/source/web/header.hpp b/source/web/header.hpp deleted file mode 100644 index abbfedd..0000000 --- a/source/web/header.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEB_HEADER_HPP -#define WEB_HEADER_HPP - -#include -#include - -namespace Web -{ - class Header final - { - public: - void* handle; - - Header(const std::initializer_list& init_list) noexcept; - Header(const Header& other) = delete; - Header(Header&& other) noexcept; - ~Header() noexcept; - - auto operator=(const Header& other) -> Header& = delete; - auto operator=(Header&& other) noexcept -> Header&; - - void append(const std::string& item) noexcept; - - private: - auto swap(Header& other) noexcept -> void; - }; -} // namespace Web - -#endif diff --git a/source/web/request.cpp b/source/web/request.cpp deleted file mode 100644 index b8ba10a..0000000 --- a/source/web/request.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include "request.hpp" -#include "fsinfo.hpp" -#include "util.h" - -namespace Web -{ - static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) - { - int const size = 1048576; - if (setsockopt(curlfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1) - { - return CURL_SOCKOPT_ERROR; - } - if (setsockopt(curlfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1) - { - return CURL_SOCKOPT_ERROR; - } - - return CURL_SOCKOPT_OK; - } - - auto inline get(const dict_t &options, const std::string &&name) -> std::string - { - auto it = options.find(name); - if (it == options.end()) - { - return std::string{""}; - } - else - { - return it->second; - } - } - - Request::Request(dict_t &&options_) : options(options_) - { - auto hostname = get(options, "hostname"); - auto username = get(options, "username"); - auto password = get(options, "password"); - auto timeout = get(options, "password"); - - auto proxy_hostname = get(options, "proxy_hostname"); - auto proxy_username = get(options, "proxy_username"); - auto proxy_password = get(options, "proxy_password"); - - auto cert_path = get(options, "cert_path"); - auto key_path = get(options, "key_path"); - - this->handle = curl_easy_init(); - - this->set(CURLOPT_SSL_VERIFYHOST, 0); - this->set(CURLOPT_SSL_VERIFYPEER, 0); - -#ifdef _DEBUG - this->set(CURLOPT_VERBOSE, 1); -#else - this->set(CURLOPT_VERBOSE, 0); -#endif - if (this->cert_required()) - { - this->set(CURLOPT_SSLCERTTYPE, "PEM"); - this->set(CURLOPT_SSLKEYTYPE, "PEM"); - this->set(CURLOPT_SSLCERT, const_cast(cert_path.c_str())); - this->set(CURLOPT_SSLKEY, const_cast(key_path.c_str())); - } - - this->set(CURLOPT_URL, const_cast(hostname.c_str())); - if (!username.empty()) - { - this->set(CURLOPT_HTTPAUTH, static_cast(CURLAUTH_BASIC)); - auto token = username + ":" + password; - this->set(CURLOPT_USERPWD, const_cast(token.c_str())); - } - this->set(CURLOPT_SOCKOPTFUNCTION, sockopt_callback); - this->set(CURLOPT_FOLLOWLOCATION, 1); - this->set(CURLOPT_COOKIEJAR, "/data/ps4-webdav-client/cookies.txt"); - this->set(CURLOPT_COOKIEFILE, "/data/ps4-webdav-client/cookies.txt"); - if (timeout.empty()) - { - this->set(CURLOPT_CONNECTTIMEOUT, 15L); - } - else - { - this->set(CURLOPT_CONNECTTIMEOUT, atoi(timeout.c_str())); - } - - if (!this->proxy_enabled()) - return; - - this->set(CURLOPT_PROXY, const_cast(proxy_hostname.c_str())); - this->set(CURLOPT_PROXYAUTH, static_cast(CURLAUTH_BASIC)); - - if (proxy_username.empty()) - return; - - if (proxy_password.empty()) - { - this->set(CURLOPT_PROXYUSERNAME, const_cast(proxy_username.c_str())); - } - else - { - if (!username.empty() && !password.empty()) - { - auto token = proxy_username + ":" + proxy_password; - this->set(CURLOPT_PROXYUSERPWD, const_cast(token.c_str())); - } - } - } - - Request::~Request() noexcept - { - if (this->handle != nullptr) - curl_easy_cleanup(this->handle); - } - - auto Request::swap(Request &other) noexcept -> void - { - using std::swap; - swap(handle, other.handle); - } - - Request::Request(Request &&other) noexcept : handle{ - other.handle} - { - other.handle = nullptr; - } - - auto Request::operator=(Request &&other) noexcept -> Request & - { - if (this != &other) - { - Request(std::move(other)).swap(*this); - } - return *this; - } - - bool Request::perform() noexcept - { - if (this->handle == nullptr) - return false; - this->res = curl_easy_perform(this->handle); - auto is_performed = this->res == CURLE_OK; - if (!is_performed) - return false; - this->http_code = 0; - curl_easy_getinfo(this->handle, CURLINFO_RESPONSE_CODE, &this->http_code); - if (this->http_code < 200 || this->http_code > 299) - return false; - return true; - } - - bool Request::proxy_enabled() const noexcept - { - auto proxy_hostname = get(options, "proxy_hostname"); - auto proxy_username = get(options, "proxy_username"); - auto proxy_password = get(options, "proxy_password"); - bool proxy_hostname_presented = !proxy_hostname.empty(); - if (!proxy_hostname_presented) - return false; - bool proxy_username_presented = !proxy_username.empty(); - bool proxy_password_presented = !proxy_password.empty(); - if (proxy_password_presented && !proxy_username_presented) - return false; - return true; - } - - bool Request::cert_required() const noexcept - { - const auto cert_path = get(options, "cert_path"); - const auto key_path = get(options, "key_path"); - if (cert_path.empty()) - return false; - bool cert_is_existed = FileInfo::exists(cert_path); - if (!cert_is_existed) - return false; - if (key_path.empty()) - return false; - return FileInfo::exists(key_path); - } - - long Request::status_code() const noexcept - { - return this->http_code; - } - - int Request::result() const noexcept - { - return this->res; - } - - class Environment - { - public: - Environment() - { - curl_global_init(CURL_GLOBAL_ALL); - } - ~Environment() - { - curl_global_cleanup(); - } - }; -} // namespace Web - -static const Web::Environment env; \ No newline at end of file diff --git a/source/web/request.hpp b/source/web/request.hpp deleted file mode 100644 index b3ea20e..0000000 --- a/source/web/request.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEB_REQUEST_HPP -#define WEB_REQUEST_HPP - -#include -#include -#include - -namespace Web -{ - bool inline check_code(CURLcode code) - { - return code == CURLE_OK; - } - - using dict_t = std::map; - - class Request - { - public: - explicit Request(dict_t &&options_); - Request(const Request &other) = delete; - Request(Request &&other) noexcept; - ~Request() noexcept; - - auto operator=(const Request &other) -> Request & = delete; - auto operator=(Request &&other) noexcept -> Request &; - - template - auto set(CURLoption option, T value) const noexcept -> bool - { - if (this->handle == nullptr) - return false; - return check_code(curl_easy_setopt(this->handle, option, value)); - } - - bool perform() noexcept; - long status_code() const noexcept; - int result() const noexcept; - void *handle; - - private: - const dict_t options; - dict_t response_header = {}; - long http_code; - int res; - bool proxy_enabled() const noexcept; - bool cert_required() const noexcept; - auto swap(Request &other) noexcept -> void; - }; -} // namespace Web - -#endif diff --git a/source/web/urn.cpp b/source/web/urn.cpp deleted file mode 100644 index 680f0d1..0000000 --- a/source/web/urn.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include - -#include -#include -#include -#include -#include - -using std::string; -using std::vector; - -#include "urn.hpp" - -namespace Web -{ - namespace Urn - { - - const string Path::separate = "/"; - const string Path::root = "/"; - const string Path::param_separate = "&"; - const string Path::query_separate = "?"; - - string encodeUrl(const string &url, void *request) - { - size_t scheme_pos = url.find("://"); - size_t root_pos = url.find("/", scheme_pos+3); - if (root_pos == string::npos) - return url; - - string uri = url.substr(root_pos); - auto path = Path(uri); - return url.substr(0, root_pos) + path.quote(request); - } - - Path::Path(const string& path_, bool force_dir) - { - string path = path_; - if (path_.empty()) path = Path::root; - auto first_position = path.find(Path::separate); - if (first_position != 0) path = Path::root + path; - - auto last_symbol_index = path.length() - 1; - auto last_symbol = path.substr(last_symbol_index, 1); - auto is_dir = last_symbol == Path::separate; - - if (force_dir && !is_dir) path += Path::separate; - m_path = path; - auto double_separte = Path::separate + Path::separate; - bool is_find = false; - do - { - auto first_position = m_path.find(double_separte); - is_find = first_position != m_path.npos; - if (is_find) - { - m_path.replace(first_position, double_separte.size(), Path::separate); - } - } - while (is_find); - } - - Path::Path(std::nullptr_t) - { - m_path = nullptr; - } - - auto Path::path() const -> string - { - return m_path; - } - - auto escape(void* request, const string& name) -> string - { - string path = curl_easy_escape(request, name.c_str(), static_cast(name.length())); - return path; - } - - auto split(const string& text, const string& delims) -> vector - { - vector tokens; - auto start = text.find_first_not_of(delims); - auto end = text.npos; - - while ((end = text.find_first_of(delims, start)) != text.npos) - { - tokens.push_back(text.substr(start, end - start)); - start = text.find_first_not_of(delims, end); - } - if (start != text.npos) - { - tokens.push_back(text.substr(start)); - } - return tokens; - } - - auto Path::quote(void* request) const -> string - { - if (this->is_root()) return m_path; - - size_t query_pos = m_path.find_first_of(Path::query_separate); - string query; - string path; - if (query_pos != string::npos) - { - query = m_path.substr(query_pos+1); - path = m_path.substr(0, query_pos); - } - else - { - path = m_path; - } - auto names = split(path, Path::separate); - string quote_path; - - std::for_each(names.begin(), names.end(), ["e_path, request](string & name) - { - auto escape_name = escape(request, name); - quote_path.append(Path::separate); - quote_path.append(escape_name); - }); - - if (is_directory()) - { - quote_path.append(Path::separate); - } - - if (query.length()>0) - { - auto params = split(query, Path::param_separate); - if (params.size() > 0) - quote_path.append(Path::query_separate); - std::for_each(params.begin(), params.end(), ["e_path, request](string & param) - { - auto param_pair = split(param, "="); - if (param_pair.size() == 0) - { - quote_path.append(Path::param_separate); - } - else - { - quote_path.append(escape(request, param_pair[0])); - quote_path.append("="); - if (param_pair.size() > 1) - { - quote_path.append(escape(request, param_pair[1])); - } - quote_path.append(Path::param_separate); - } - }); - quote_path.pop_back(); - } - return quote_path; - } - - auto Path::name() const -> string - { - auto path = this->path(); - auto is_root = path == Path::separate; - if (is_root) return string{""}; - - if (this->is_directory()) - { - auto path_without_slash = path.substr(0, path.length() - 1); - auto pre_last_separate_position = path_without_slash.rfind(Path::separate); - auto name = path.substr(pre_last_separate_position + 1); - return name; - } - else - { - auto last_separate_position = path.rfind(Path::separate); - auto name = path.substr(last_separate_position + 1); - return name; - } - } - - auto Path::parent() const -> Path - { - if (this->is_root()) return Path{m_path}; - - auto last_separate_position = m_path.rfind(Path::separate, m_path.length() - 2); - if (last_separate_position == 0) return Path{Path::separate}; - - auto parent = m_path.substr(0, last_separate_position + 1); - return Path{parent}; - } - - auto Path::is_directory() const -> bool - { - auto path = this->path(); - auto last_symbol_index = path.length() - 1; - auto last_symbol = path.substr(last_symbol_index, 1); - auto is_equal = last_symbol == Path::separate; - return is_equal; - } - - auto Path::is_root() const -> bool - { - return m_path == Path::separate; - } - - auto Path::operator+(const string& rhs) const -> Path - { - return Path{ m_path + rhs }; - } - - auto Path::operator==(const Path& rhs) const -> bool - { - if (this->is_root() && rhs.is_root()) return true; - if (!this->is_root() && rhs.is_root()) return false; - - string lhs_path; - bool is_dir = is_directory(); - if (is_dir) - { - lhs_path = m_path.substr(0, m_path.length() - 1); - } - else - { - lhs_path = m_path; - } - string rhs_path; - if (rhs.is_directory()) - { - rhs_path = rhs.path(); - rhs_path = rhs_path.substr(0, rhs_path.length() - 1); - } - else - { - rhs_path = rhs.path(); - } - return lhs_path == rhs_path; - } - } // namespace Urn -} // namespace Web - -auto operator<<(std::ostream& stream, const Web::Urn::Path& path) -> std::ostream& -{ - return stream << path.path(); -} diff --git a/source/web/urn.hpp b/source/web/urn.hpp deleted file mode 100644 index e4b3dcf..0000000 --- a/source/web/urn.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEB_URN_HPP -#define WEB_URN_HPP - -#include -#include -#include - -namespace Web -{ - namespace Urn - { - using std::string; - using std::nullptr_t; - - string encodeUrl(const string &url, void *request); - - class Path - { - public: - - explicit Path(const string& path_, bool force_dir = false); - explicit Path(nullptr_t); - - auto operator+(const std::string& rhs) const -> Path; - auto operator==(const Path& rhs) const -> bool; - - auto is_directory() const -> bool; - auto is_root() const -> bool; - auto name() const -> string; - auto parent() const -> Path; - auto path() const -> string; - auto quote(void* request) const -> string; - - private: - - string m_path; - - static const string separate; - static const string root; - static const string param_separate; - static const string query_separate; - }; - } -} - -auto operator<<(std::ostream& stream, const Web::Urn::Path& path) -> std::ostream&; - -#endif diff --git a/source/webdav/client.cpp b/source/webdav/client.cpp deleted file mode 100644 index ef4c9d9..0000000 --- a/source/webdav/client.cpp +++ /dev/null @@ -1,1043 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#include - -#include "web/callback.hpp" -#include "web/fsinfo.hpp" -#include "web/header.hpp" -#include "web/pugiext.hpp" -#include "web/request.hpp" -#include "web/urn.hpp" -#include "util.h" -#include "http/httplib.h" -#include -#include - -namespace WebDAV -{ - using Web::Urn::Path; - using Web::Request; - using Web::Data; - using Web::Header; - - using progress_funptr = int (*)(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); - - static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) - { - std::string header(reinterpret_cast(buffer), size * nitems); - dict_t *headers = (dict_t *)userdata; - size_t seperator = header.find_first_of(":"); - - if (seperator != std::string::npos) - { - std::string key = header.substr(0, seperator); - key = Util::Trim(key, " "); - key = Util::ToLower(key); - std::string value = header.substr(seperator + 1); - value = Util::Trim(value, " "); - headers->erase(key); - headers->insert(std::make_pair(key, value)); - } - - return (size * nitems); - } - - dict_t - Client::options() - { - return dict_t{ - {"hostname", this->webdav_hostname}, - {"username", this->webdav_username}, - {"password", this->webdav_password}, - {"proxy_hostname", this->proxy_hostname}, - {"proxy_username", this->proxy_username}, - {"proxy_password", this->proxy_password}, - {"cert_path", this->cert_path}, - {"key_path", this->key_path}, - }; - } - - long - Client::status_code() - { - return this->http_code; - } - - bool - Client::sync_download( - const std::string &remote_file, - const std::string &local_file, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = this->check(remote_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - std::ofstream file_stream(local_file, std::ios::binary); - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - request.set(CURLOPT_CUSTOMREQUEST, "GET"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HEADER, 0L); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&file_stream)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Write::stream)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - if (callback != nullptr) - callback(is_performed); - return is_performed; - } - - bool - Client::sync_download_to( - const std::string &remote_file, - char *&buffer_ptr, - unsigned long long &buffer_size, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = this->check(remote_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - request.set(CURLOPT_CUSTOMREQUEST, "GET"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HEADER, 0L); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - if (callback != nullptr) - callback(is_performed); - if (!is_performed) - return false; - - buffer_ptr = data.buffer; - buffer_size = data.size; - data.reset(); - return true; - } - -bool - Client::sync_download_range_to( - const std::string &remote_file, - char *&buffer_ptr, - unsigned long long &buffer_size, - uint64_t range_from, - uint64_t range_to, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = this->check(remote_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - struct curl_slist *list = NULL; - char range_header[64]; - sprintf(range_header, "Range: bytes=%lu-%lu", range_from, range_to); - list = curl_slist_append(list, range_header); - request.set(CURLOPT_CUSTOMREQUEST, "GET"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HEADER, 0L); - request.set(CURLOPT_HTTPHEADER, list); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (callback != nullptr) - callback(is_performed); - if (!is_performed) - return false; - - buffer_ptr = data.buffer; - buffer_size = data.size; - data.reset(); - return true; - } - -bool - Client::sync_download_range_to( - const std::string &remote_file, - DataSink &sink, - uint64_t range_from, - uint64_t range_to, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = this->check(remote_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - struct curl_slist *list = NULL; - char range_header[64]; - sprintf(range_header, "Range: bytes=%lu-%lu", range_from, range_to); - list = curl_slist_append(list, range_header); - request.set(CURLOPT_CUSTOMREQUEST, "GET"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HEADER, 0L); - request.set(CURLOPT_HTTPHEADER, list); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&sink)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::stream2sink)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (callback != nullptr) - callback(is_performed); - if (!is_performed) - return false; - - return true; - } - - bool - Client::sync_download_to( - const std::string &remote_file, - std::ostream &stream, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = this->check(remote_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "GET"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HEADER, 0L); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&stream)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Write::stream)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (callback != nullptr) - callback(is_performed); - - return is_performed; - } - - bool - Client::sync_upload( - const std::string &remote_file, - const std::string &local_file, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - bool is_existed = Web::FileInfo::exists(local_file); - if (!is_existed) - return false; - - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - std::ifstream file_stream(local_file, std::ios::binary); - auto size = Web::FileInfo::size(local_file); - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - - Data response = {nullptr, 0, 0}; - - request.set(CURLOPT_UPLOAD, 1L); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_READDATA, reinterpret_cast(&file_stream)); - request.set(CURLOPT_READFUNCTION, reinterpret_cast(Web::Callback::Read::stream)); - request.set(CURLOPT_INFILESIZE_LARGE, static_cast(size)); - request.set(CURLOPT_BUFFERSIZE, static_cast(Client::buffer_size)); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&response)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (callback != nullptr) - callback(is_performed); - return is_performed; - } - - bool - Client::sync_upload_from( - const std::string &remote_file, - char *buffer_ptr, - unsigned long long buffer_size, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Data data = {buffer_ptr, 0, buffer_size}; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - - Data response = {nullptr, 0, 0}; - - request.set(CURLOPT_UPLOAD, 1L); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_READDATA, reinterpret_cast(&data)); - request.set(CURLOPT_READFUNCTION, reinterpret_cast(Web::Callback::Read::buffer)); - request.set(CURLOPT_INFILESIZE_LARGE, static_cast(buffer_size)); - request.set(CURLOPT_BUFFERSIZE, static_cast(Client::buffer_size)); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&response)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (callback != nullptr) - callback(is_performed); - - data.reset(); - return is_performed; - } - - bool - Client::sync_upload_from( - const std::string &remote_file, - std::istream &stream, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - auto root_urn = Path(this->webdav_root, true); - auto file_urn = root_urn + remote_file; - - Request request(this->options()); - - auto url = this->webdav_hostname + file_urn.quote(request.handle); - stream.seekg(0, std::ios::end); - size_t stream_size = stream.tellg(); - stream.seekg(0, std::ios::beg); - - Data response = {nullptr, 0, 0}; - - request.set(CURLOPT_UPLOAD, 1L); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_READDATA, reinterpret_cast(&stream)); - request.set(CURLOPT_READFUNCTION, reinterpret_cast(Web::Callback::Read::stream)); - request.set(CURLOPT_INFILESIZE_LARGE, static_cast(stream_size)); - request.set(CURLOPT_BUFFERSIZE, static_cast(Client::buffer_size)); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&response)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - if (progress != nullptr) - { - request.set(CURLOPT_XFERINFODATA, progress_data); - request.set(CURLOPT_XFERINFOFUNCTION, progress); - request.set(CURLOPT_NOPROGRESS, 0L); - } - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - if (callback != nullptr) - callback(is_performed); - return is_performed; - } - - Client::Client(const dict_t &options) - { - this->webdav_hostname = get(options, "webdav_hostname"); - this->webdav_root = get(options, "webdav_root"); - this->webdav_username = get(options, "webdav_username"); - this->webdav_password = get(options, "webdav_password"); - - this->proxy_hostname = get(options, "proxy_hostname"); - this->proxy_username = get(options, "proxy_username"); - this->proxy_password = get(options, "proxy_password"); - - this->cert_path = get(options, "cert_path"); - this->key_path = get(options, "key_path"); - - auto check = get(options, "check_enabled"); - if (check.length() > 0) - this->check_enabled = std::stoi(check); - else - this->check_enabled = 0; - } - - unsigned long long - Client::free_size() - { - Header header = - { - "Accept: */*", - "Depth: 0", - "Content-Type: text/xml"}; - - pugi::xml_document document; - auto propfind = document.append_child("D:propfind"); - propfind.append_attribute("xmlns:D") = "DAV:"; - - auto prop = propfind.append_child("D:prop"); - prop.append_child("D:quokta-available-bytes"); - prop.append_child("D:quota-used-bytes"); - - auto document_print = pugi::node_to_string(document); - size_t size = document_print.length() * sizeof((document_print.c_str())[0]); - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); - request.set(CURLOPT_POSTFIELDS, document_print.c_str()); - request.set(CURLOPT_POSTFIELDSIZE, static_cast(size)); - request.set(CURLOPT_HEADER, 0); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - auto is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - if (!is_performed) - return 0; - - document.load_buffer(data.buffer, static_cast(data.size)); - - pugi::xml_node multistatus = document.select_node("*[local-name()='multistatus']").node(); - pugi::xml_node response = multistatus.select_node("*[local-name()='response']").node(); - pugi::xml_node propstat = response.select_node("*[local-name()='propstat']").node(); - prop = propstat.select_node("*[local-name()='prop']").node(); - pugi::xml_node quota_available_bytes = prop.select_node("*[local-name()='quota-available-bytes']").node(); - std::string free_size_text = quota_available_bytes.first_child().value(); - - return std::stoll(free_size_text); - } - - bool - Client::check(const std::string &remote_resource) - { - if (!this->check_enabled) - return true; - auto root_urn = Path(this->webdav_root, true); - auto resource_urn = root_urn + remote_resource; - - Header header = - { - "Accept: */*", - "Depth: 0"}; - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - auto url = this->webdav_hostname + resource_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - return is_performed; - } - - dict_t - Client::info(const std::string &remote_resource) - { - auto root_urn = Path(this->webdav_root, true); - auto target_urn = root_urn + remote_resource; - - Header header = - { - "Accept: */*", - "Depth: 0"}; - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - auto url = this->webdav_hostname + target_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - if (!is_performed) - return dict_t{}; - - pugi::xml_document document; - document.load_buffer(data.buffer, static_cast(data.size)); - -#ifdef WDC_VERBOSE - document.save(std::cout); -#endif - auto multistatus = document.select_node("*[local-name()='multistatus']").node(); - auto responses = multistatus.select_nodes("*[local-name()='response']"); - for (auto response : responses) - { - pugi::xml_node href = response.node().select_node("*[local-name()='href']").node(); - std::string encode_file_name = href.first_child().value(); - std::string resource_path = curl_unescape(encode_file_name.c_str(), static_cast(encode_file_name.length())); - auto target_path = target_urn.path(); - auto target_path_without_sep = target_urn.path(); - if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/') - target_path_without_sep.resize(target_path_without_sep.length() - 1); - auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1); - size_t pos = resource_path_without_sep.find(this->webdav_hostname); - if (pos != std::string::npos) - resource_path_without_sep.erase(pos, this->webdav_hostname.length()); - - if (resource_path_without_sep == target_path_without_sep) - { - auto propstat = response.node().select_node("*[local-name()='propstat']").node(); - auto prop = propstat.select_node("*[local-name()='prop']").node(); - auto creation_date = prop.select_node("*[local-name()='creationdate']").node(); - auto display_name = prop.select_node("*[local-name()='displayname']").node(); - auto content_length = prop.select_node("*[local-name()='getcontentlength']").node(); - auto modified_date = prop.select_node("*[local-name()='getlastmodified']").node(); - auto resource_type = prop.select_node("*[local-name()='resourcetype']").node(); - - std::string name = target_urn.name(); - dict_t information = - { - {"created", creation_date.first_child().value()}, - {"name", Util::Rtrim(name, "/")}, - {"size", content_length.first_child().value()}, - {"modified", modified_date.first_child().value()}, - {"type", resource_type.first_child().name()}}; - - return information; - } - } - - return dict_t{}; - } - - bool - Client::head(const std::string &remote_resource, dict_t *headers) - { - auto root_urn = Path(this->webdav_root, true); - auto target_urn = root_urn + remote_resource; - - Header header = - {"Accept: */*"}; - - Request request(this->options()); - - auto url = this->webdav_hostname + target_urn.quote(request.handle); - request.set(CURLOPT_CUSTOMREQUEST, "HEAD"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); - request.set(CURLOPT_HEADERDATA, headers); - request.set(CURLOPT_HEADERFUNCTION, header_callback); - request.set(CURLOPT_NOBODY, 1L); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - return is_performed; - } - - bool - Client::is_directory(const std::string &remote_resource) - { - auto information = this->info(remote_resource); - auto resource_type = information["type"]; - bool is_dir = resource_type == "d:collection" || resource_type == "D:collection"; - return is_dir; - } - - dict_items_t - Client::list(const std::string &remote_directory) - { - bool is_existed = this->check(remote_directory); - if (!is_existed) - return dict_items_t{}; - - auto target_urn = Path(this->webdav_root, true) + remote_directory; - target_urn = Path(target_urn.path(), true); - - Header header = - { - "Accept: */*", - "Depth: 1"}; - - Data data = {nullptr, 0, 0}; - - Request request(this->options()); - - auto url = this->webdav_hostname + target_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "PROPFIND"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); - request.set(CURLOPT_HEADER, 0); - request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data)); - request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast(Web::Callback::Append::buffer)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - - if (!is_performed) - return dict_items_t{}; - - dict_items_t resources; - - pugi::xml_document document; - document.load_buffer(data.buffer, static_cast(data.size)); - auto multistatus = document.select_node("*[local-name()='multistatus']").node(); - auto responses = multistatus.select_nodes("*[local-name()='response']"); - for (auto response : responses) - { - pugi::xml_node href = response.node().select_node("*[local-name()='href']").node(); - std::string encode_file_name = href.first_child().value(); - std::string resource_path = curl_unescape(encode_file_name.c_str(), static_cast(encode_file_name.length())); - auto target_path = target_urn.path(); - - auto target_path_without_sep = target_urn.path(); - if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/') - target_path_without_sep.resize(target_path_without_sep.length() - 1); - auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1); - size_t pos = resource_path_without_sep.find(this->webdav_hostname); - if (pos != std::string::npos) - resource_path_without_sep.erase(pos, this->webdav_hostname.length()); - - if (resource_path_without_sep == target_path_without_sep) - continue; - - auto propstat = response.node().select_node("*[local-name()='propstat']").node(); - auto prop = propstat.select_node("*[local-name()='prop']").node(); - auto creation_date = prop.select_node("*[local-name()='creationdate']").node(); - auto display_name = prop.select_node("*[local-name()='displayname']").node(); - auto content_length = prop.select_node("*[local-name()='getcontentlength']").node(); - auto modified_date = prop.select_node("*[local-name()='getlastmodified']").node(); - auto resource_type = prop.select_node("*[local-name()='resourcetype']").node(); - - Path resource_urn(resource_path); - std::string name = resource_urn.name(); - dict_t item = { - {"created", creation_date.first_child().value()}, - {"name", Util::Rtrim(name, "/")}, - {"size", content_length.first_child().value()}, - {"modified", modified_date.first_child().value()}, - {"type", resource_type.first_child().name()}}; - resources.push_back(item); - } - - return resources; - } - - bool Client::download( - const std::string &remote_file, - const std::string &local_file, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_download(remote_file, local_file, nullptr, progress_data, std::move(progress)); - } - - void - Client::async_download( - const std::string &remote_file, - const std::string &local_file, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - std::thread downloading([=]() - { this->sync_download(remote_file, local_file, callback, progress_data, std::move(progress)); }); - downloading.detach(); - } - - bool - Client::download_to( - const std::string &remote_file, - char *&buffer_ptr, - unsigned long long &buffer_size, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_download_to(remote_file, buffer_ptr, buffer_size, nullptr, progress_data, std::move(progress)); - } - - bool - Client::download_range_to( - const std::string &remote_file, - char *&buffer_ptr, - unsigned long long &buffer_size, - uint64_t range_from, - uint64_t range_to, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_download_range_to(remote_file, buffer_ptr, buffer_size, range_from, range_to, nullptr, progress_data, std::move(progress)); - } - - bool - Client::download_range_to( - const std::string &remote_file, - DataSink &sink, - uint64_t range_from, - uint64_t range_to, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_download_range_to(remote_file, sink, range_from, range_to, nullptr, progress_data, std::move(progress)); - } - - bool - Client::download_to( - const std::string &remote_file, - std::ostream &stream, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_download_to(remote_file, stream, nullptr, progress_data, std::move(progress)); - } - - bool - Client::create_directory(const std::string &remote_directory, bool recursive) - { - bool is_existed = this->check(remote_directory); - if (is_existed) - return true; - - bool resource_is_dir = true; - Path directory_urn(remote_directory, resource_is_dir); - - if (recursive) - { - auto remote_parent_directory = directory_urn.parent().path(); - if (remote_parent_directory == remote_directory) - return false; - bool is_created = this->create_directory(remote_parent_directory, true); - if (!is_created) - return false; - } - - Header header = - { - "Accept: */*", - "Connection: Keep-Alive"}; - - auto target_urn = Path(this->webdav_root, true) + remote_directory; - target_urn = Path(target_urn.path(), true); - - Request request(this->options()); - - auto url = this->webdav_hostname + target_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "MKCOL"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - return is_performed; - } - - bool - Client::move(const std::string &remote_source_resource, const std::string &remote_destination_resource) - { - bool is_existed = this->check(remote_source_resource); - if (!is_existed) - return false; - - Path root_urn(this->webdav_root, true); - - auto source_resource_urn = root_urn + remote_source_resource; - auto destination_resource_urn = root_urn + remote_destination_resource; - - Request request(this->options()); - Header header = - { - "Accept: */*", - "Destination: " + destination_resource_urn.quote(request.handle)}; - - - auto url = this->webdav_hostname + source_resource_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "MOVE"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - return is_performed; - } - - bool - Client::copy(const std::string &remote_source_resource, const std::string &remote_destination_resource) - { - bool is_existed = this->check(remote_source_resource); - if (!is_existed) - return false; - - Path root_urn(this->webdav_root, true); - - auto source_resource_urn = root_urn + remote_source_resource; - auto destination_resource_urn = root_urn + remote_destination_resource; - - Request request(this->options()); - Header header = - { - "Accept: */*", - "Destination: " + destination_resource_urn.quote(request.handle)}; - - auto url = this->webdav_hostname + source_resource_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "COPY"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - return is_performed; - } - - bool - Client::upload( - const std::string &remote_file, - const std::string &local_file, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_upload(remote_file, local_file, nullptr, progress_data, std::move(progress)); - } - - void - Client::async_upload( - const std::string &remote_file, - const std::string &local_file, - callback_t callback, - progress_data_t progress_data, - progress_t progress) - { - std::thread uploading([=]() - { this->sync_upload(remote_file, local_file, callback, progress_data, std::move(progress)); }); - uploading.detach(); - } - - bool - Client::upload_from( - const std::string &remote_file, - std::istream &stream, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_upload_from(remote_file, stream, nullptr, progress_data, std::move(progress)); - } - - bool - Client::upload_from( - const std::string &remote_file, - char *buffer_ptr, - unsigned long long buffer_size, - progress_data_t progress_data, - progress_t progress) - { - return this->sync_upload_from(remote_file, buffer_ptr, buffer_size, nullptr, progress_data, std::move(progress)); - } - - bool - Client::clean(const std::string &remote_resource) - { - bool is_existed = this->check(remote_resource); - if (!is_existed) - return true; - - auto root_urn = Path(this->webdav_root, true); - auto resource_urn = root_urn + remote_resource; - - Header header = - { - "Accept: */*", - "Connection: Keep-Alive"}; - - Request request(this->options()); - - auto url = this->webdav_hostname + resource_urn.quote(request.handle); - - request.set(CURLOPT_CUSTOMREQUEST, "DELETE"); - request.set(CURLOPT_URL, url.c_str()); - request.set(CURLOPT_HTTPHEADER, reinterpret_cast(header.handle)); -#ifdef WDC_VERBOSE - request.set(CURLOPT_VERBOSE, 1); -#endif - - bool is_performed = request.perform(); - this->http_code = request.status_code(); - this->result = request.result(); - return is_performed; - } - -} // namespace WebDAV - diff --git a/source/webdav/client.hpp b/source/webdav/client.hpp deleted file mode 100644 index ee9c2aa..0000000 --- a/source/webdav/client.hpp +++ /dev/null @@ -1,419 +0,0 @@ -/*#*************************************************************************** -# __ __ _____ _____ -# Project | | | | | \ / ___| -# | |__| | | |\ \ / / -# | | | | ) ) ( ( -# | /\ | | |/ / \ \___ -# \_/ \_/ |_____/ \_____| -# -# Copyright (C) 2018, The WDC Project, , et al. -# -# This software is licensed as described in the file LICENSE, which -# you should have received as part of this distribution. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the LICENSE file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -############################################################################*/ - -#ifndef WEBDAV_CLIENT_HPP -#define WEBDAV_CLIENT_HPP - -#include -#include -#include -#include -#include -#include -#include "http/httplib.h" - -using namespace httplib; - -namespace WebDAV -{ - using progress_data_t = void*; - - using progress_t = int(void* context, - curl_off_t dltotal, - curl_off_t dlnow, - curl_off_t ultotal, - curl_off_t ulnow); - - using callback_t = std::function ; - - using strings_t = std::vector; - using dict_t = std::map; - using dict_items_t = std::vector; - - auto inline get(const dict_t& options, const std::string&& name) -> std::string - { - auto it = options.find(name); - if (it == options.end()) return ""; - else return it->second; - } - - /// - /// \brief WebDAV Client - /// \author designerror - /// \version 1.1.4 - /// \date 3/16/2018 - /// - class Client - { - public: - - /// - /// \param[in] webdav_hostname - /// \param[in] webdav_root - /// \param[in] webdav_username - /// \param[in] webdav_password - /// \param[in] proxy_hostname - /// \param[in] proxy_username - /// \param[in] proxy_password - /// \param[in] cert_path - /// \param[in] key_path - /// \include client/init.cpp - /// - explicit Client(const dict_t& options); - - /// - /// Get free size of the WebDAV server - /// \return size in bytes - /// \include client/size.cpp - /// - auto free_size() -> unsigned long long; - - /// - /// Check for existence of a remote resource - /// \param[in] remote_resource - /// \include client/check.cpp - /// - auto check(const std::string& remote_resource = "/") -> bool; - - /// - /// Get information of a remote resource - /// \param[in] remote_resource - /// \include client/info.cpp - /// - auto info(const std::string& remote_resource) -> dict_t; - - /// - /// Get information of a remote resource - /// \param[in] remote_resource - /// \include client/info.cpp - /// - auto head(const std::string& remote_resource, dict_t *headers) -> bool; - - /// - /// Clean an remote resource - /// \param[in] remote_resource - /// \include client/clean.cpp - /// - auto clean(const std::string& remote_resource) -> bool; - - /// - /// Checks whether the resource directory - /// \param[in] remote_resource - /// - auto is_directory(const std::string& remote_resource) -> bool; - - /// - /// List a remote directory - /// \param[in] remote_directory - /// \include client/list.cpp - /// - auto list(const std::string& remote_directory = "") -> dict_items_t; - - /// - /// Create a remote directory - /// \param[in] remote_directory - /// \param[in] recursive - /// \include client/mkdir.cpp - /// - auto create_directory( - const std::string& remote_directory, - bool recursive = false - ) -> bool; - - /// - /// Move a remote resource - /// \param[in] remote_source_resource - /// \param[in] remote_destination_resource - /// \include client/move.cpp - /// - auto move( - const std::string& remote_source_resource, - const std::string& remote_destination_resource - ) -> bool; - - /// - /// Copy a remote resource - /// \param[in] remote_source_resource - /// \param[in] remote_destination_resource - /// \include client/copy.cpp - /// - auto copy( - const std::string& remote_source_resource, - const std::string& remote_destination_resource - ) -> bool; - - /// - /// Download a remote file to a local file - /// \param[in] remote_file - /// \param[in] local_file - /// \param[in] progress - /// \snippet client/download.cpp download_to_file - /// - auto download( - const std::string& remote_file, - const std::string& local_file, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Download a remote file to a buffer - /// \param[in] remote_file - /// \param[out] buffer_ptr - /// \param[out] buffer_size - /// \param[in] progress - /// \snippet client/download.cpp download_to_buffer - /// - auto download_to( - const std::string& remote_file, - char*& buffer_ptr, - unsigned long long& buffer_size, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Download a remote file to a buffer for specified range - /// \param[in] remote_file - /// \param[out] buffer_ptr - /// \param[out] buffer_size - /// \param[in] range_from, - /// \param[in] range_to - /// \param[in] progress - /// \snippet client/download.cpp download_to_buffer - /// - auto download_range_to( - const std::string& remote_file, - char*& buffer_ptr, - unsigned long long& buffer_size, - uint64_t range_from, - uint64_t range_to, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Download a remote file to a buffer for specified range - /// \param[in] remote_file - /// \param[out] sink, - /// \param[in] range_from, - /// \param[in] range_to - /// \param[in] progress - /// \snippet client/download.cpp download_to_buffer - /// - auto download_range_to( - const std::string &remote_file, - DataSink &sink, - uint64_t range_from, - uint64_t range_to, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Download a remote file to a stream - /// \param[in] remote_file - /// \param[out] stream - /// \param[in] progress - /// \snippet client/download.cpp download_to_stream - /// - auto download_to( - const std::string& remote_file, - std::ostream& stream, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Asynchronously download a remote file to a local file - /// \param[in] remote_file - /// \param[in] local_file - /// \param[in] callback - /// \param[in] progress - /// \snippet client/download.cpp async_download_to_file - /// - auto async_download( - const std::string& remote_file, - const std::string& local_file, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> void; - - /// - /// Upload a remote file from a local file - /// \param[in] remote_file - /// \param[in] local_file - /// \param[in] progress - /// \snippet client/upload.cpp upload_from_file - /// - auto upload( - const std::string& remote_file, - const std::string& local_file, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Upload a remote file from a buffer - /// \param[in] remote_file - /// \param[in] buffer_ptr - /// \param[in] buffer_size - /// \param[in] progress - /// \snippet client/upload.cpp upload_from_buffer - /// - auto upload_from( - const std::string& remote_file, - char* buffer_ptr, - unsigned long long buffer_size, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Upload a remote file from a stream - /// \param[in] remote_file - /// \param[in] stream - /// \param[in] progress - /// \snippet client/upload.cpp upload_from_stream - /// - auto upload_from( - const std::string& remote_file, - std::istream& stream, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - /// - /// Asynchronously upload a remote file from a local file - /// \param[in] remote_file - /// \param[in] local_file - /// \param[in] callback - /// \param[in] progress - /// \snippet client/upload.cpp async_upload_from_file - /// - auto async_upload( - const std::string& remote_file, - const std::string& local_file, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> void; - - long status_code(); - - private: - - auto sync_download( - const std::string& remote_file, - const std::string& local_file, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - auto sync_download_to( - const std::string& remote_file, - char*& buffer_ptr, - unsigned long long& buffer_size, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - auto sync_download_range_to( - const std::string& remote_file, - char*& buffer_ptr, - unsigned long long& buffer_size, - uint64_t range_from, - uint64_t range_to, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - auto sync_download_range_to( - const std::string &remote_file, - DataSink &sink, - uint64_t range_from, - uint64_t range_to, - callback_t callback, - progress_data_t progress_data, - progress_t progress - ) -> bool; - - bool sync_download_to( - const std::string& remote_file, - std::ostream& stream, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ); - - bool sync_upload( - const std::string& remote_file, - const std::string& local_file, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ); - - auto sync_upload_from( - const std::string& remote_file, - char* buffer_ptr, - unsigned long long buffer_size, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - auto sync_upload_from( - const std::string& remote_file, - std::istream& stream, - callback_t callback = nullptr, - progress_data_t progress_data = nullptr, - progress_t progress = nullptr - ) -> bool; - - enum { buffer_size = 1000 * 1000 }; - - std::string webdav_hostname; - std::string webdav_root; - std::string webdav_username; - std::string webdav_password; - - std::string proxy_hostname; - std::string proxy_username; - std::string proxy_password; - - std::string cert_path; - std::string key_path; - - dict_t options(); - - long http_code; - int result; - int check_enabled = 0; - }; -} // namespace WebDAV - -#endif