diff --git a/CMakeLists.txt b/CMakeLists.txt index be1b7cc..2eea00d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,11 +62,12 @@ add_executable(ezremote_client source/windows.cpp source/zip_util.cpp source/split_file.cpp + source/mem_file.cpp ) add_self(ezremote_client) -add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.23" 32 0) +add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.24" 32 0) target_link_libraries(ezremote_client c diff --git a/source/clients/baseclient.cpp b/source/clients/baseclient.cpp index 25cc46b..d8032de 100644 --- a/source/clients/baseclient.cpp +++ b/source/clients/baseclient.cpp @@ -345,3 +345,20 @@ std::string BaseClient::UnEscape(const std::string &url) } return ""; } + +void *BaseClient::Open(const std::string &path, int flags) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return nullptr; +} + +int BaseClient::Read(void **fp, void *buf, uint64_t size) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return -1; +} + +void BaseClient::Close(void **fp) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); +} diff --git a/source/clients/baseclient.h b/source/clients/baseclient.h index d55dabc..0c58326 100644 --- a/source/clients/baseclient.h +++ b/source/clients/baseclient.h @@ -33,6 +33,9 @@ public: std::vector ListDir(const std::string &path); std::string GetPath(std::string path1, std::string path2); std::string GetFullPath(std::string path1); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); bool IsConnected(); bool Ping(); const char *LastResponse(); diff --git a/source/clients/ftpclient.cpp b/source/clients/ftpclient.cpp index 7ffe123..c141f6e 100644 --- a/source/clients/ftpclient.cpp +++ b/source/clients/ftpclient.cpp @@ -1744,7 +1744,7 @@ ClientType FtpClient::clientType() uint32_t FtpClient::SupportedActions() { - return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE; + return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ; } std::string FtpClient::GetPath(std::string ppath1, std::string ppath2) @@ -1783,4 +1783,18 @@ int FtpClient::Head(const std::string &path, void *buffer, uint64_t len) if (l != len) return 0; return 1; -} \ No newline at end of file +} + +void *FtpClient::Open(const std::string &path, int flags) +{ + return nullptr; +} + +int FtpClient::Read(void **fp, void *buf, uint64_t size) +{ + return -1; +} + +void FtpClient::Close(void **fp) +{ +} diff --git a/source/clients/ftpclient.h b/source/clients/ftpclient.h index a25c728..2ed020f 100644 --- a/source/clients/ftpclient.h +++ b/source/clients/ftpclient.h @@ -87,6 +87,9 @@ public: int Copy(const std::string &from, const std::string &to); int Move(const std::string &from, const std::string &to); int Head(const std::string &path, void *buffer, uint64_t len); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); std::vector ListDir(const std::string &path); void SetCallbackXferFunction(FtpCallbackXfer pointer); void SetCallbackArg(void *arg); diff --git a/source/clients/gdrive.cpp b/source/clients/gdrive.cpp index 15ca02d..0317037 100644 --- a/source/clients/gdrive.cpp +++ b/source/clients/gdrive.cpp @@ -887,7 +887,7 @@ ClientType GDriveClient::clientType() uint32_t GDriveClient::SupportedActions() { - return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE; + return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ; } void *GDriveClient::RefreshTokenThread(void *argp) @@ -941,4 +941,21 @@ void GDriveClient::SetAccessToken(const std::string &token) { if (this->client != nullptr) this->client->set_bearer_token_auth(token); -} \ No newline at end of file +} + +void *GDriveClient::Open(const std::string &path, int flags) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return nullptr; +} + +int GDriveClient::Read(void **fp, void *buf, uint64_t size) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return -1; +} + +void GDriveClient::Close(void **fp) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); +} diff --git a/source/clients/gdrive.h b/source/clients/gdrive.h index 36c88ae..b377e64 100644 --- a/source/clients/gdrive.h +++ b/source/clients/gdrive.h @@ -32,6 +32,9 @@ public: bool FileExists(const std::string &path); void SetAccessToken(const std::string &token); std::vector ListDir(const std::string &path); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); static void *RefreshTokenThread(void *argp); static void StartRefreshToken(); static void StopRefreshToken(); diff --git a/source/clients/nfsclient.cpp b/source/clients/nfsclient.cpp index 4ba0662..cf4b953 100644 --- a/source/clients/nfsclient.cpp +++ b/source/clients/nfsclient.cpp @@ -553,6 +553,23 @@ int NfsClient::Head(const std::string &ppath, void *buffer, uint64_t len) return 1; } +void *NfsClient::Open(const std::string &path, int flags) +{ + struct nfsfh *nfsfh = nullptr; + nfs_open(nfs, path.c_str(), 0400, &nfsfh);; + return nfsfh; +} + +int NfsClient::Read(void **fp, void *buf, uint64_t size) +{ + return nfs_read(nfs, (struct nfsfh*)*fp, size, buf); +} + +void NfsClient::Close(void **fp) +{ + nfs_close(nfs, (struct nfsfh*)*fp); +} + ClientType NfsClient::clientType() { return CLIENT_TYPE_NFS; diff --git a/source/clients/nfsclient.h b/source/clients/nfsclient.h index d30b483..f2b9f33 100644 --- a/source/clients/nfsclient.h +++ b/source/clients/nfsclient.h @@ -32,6 +32,9 @@ public: int Copy(const std::string &from, const std::string &to); int Move(const std::string &from, const std::string &to); std::vector ListDir(const std::string &path); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); bool IsConnected(); bool Ping(); const char *LastResponse(); diff --git a/source/clients/remote_client.h b/source/clients/remote_client.h index 1876c36..78af67c 100644 --- a/source/clients/remote_client.h +++ b/source/clients/remote_client.h @@ -21,7 +21,8 @@ enum RemoteActions REMOTE_ACTION_EDIT = 512, REMOTE_ACTION_NEW_FILE = 1024, REMOTE_ACTION_EXTRACT = 2048, - REMOTE_ACTION_ALL = 4095 + REMOTE_ACTION_RAW_READ = 4096, + REMOTE_ACTION_ALL = 8191 }; enum ClientType @@ -58,6 +59,9 @@ public: virtual int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) = 0; virtual bool FileExists(const std::string &path) = 0; virtual std::vector ListDir(const std::string &path) = 0; + virtual void *Open(const std::string &path, int flags) = 0; + virtual int Read(void **fp, void *buf, uint64_t size) = 0; + virtual void Close(void **fp) = 0; virtual std::string GetPath(std::string path1, std::string path2) = 0; virtual bool IsConnected() = 0; virtual bool Ping() = 0; diff --git a/source/clients/sftpclient.cpp b/source/clients/sftpclient.cpp index 1192998..96ba675 100644 --- a/source/clients/sftpclient.cpp +++ b/source/clients/sftpclient.cpp @@ -642,6 +642,23 @@ int SFTPClient::Quit() return 1; } +void *SFTPClient::Open(const std::string &path, int flags) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return nullptr; +} + +int SFTPClient::Read(void **fp, void *buf, uint64_t size) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); + return -1; +} + +void SFTPClient::Close(void **fp) +{ + sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]); +} + ClientType SFTPClient::clientType() { return CLIENT_TYPE_SFTP; diff --git a/source/clients/sftpclient.h b/source/clients/sftpclient.h index b29dce7..c65b3d3 100644 --- a/source/clients/sftpclient.h +++ b/source/clients/sftpclient.h @@ -30,6 +30,9 @@ public: int Head(const std::string &path, void *buffer, uint64_t len); bool FileExists(const std::string &path); std::vector ListDir(const std::string &path); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); std::string GetPath(std::string path1, std::string path2); bool IsConnected(); bool Ping(); diff --git a/source/clients/smbclient.cpp b/source/clients/smbclient.cpp index 12d18a7..62226a4 100644 --- a/source/clients/smbclient.cpp +++ b/source/clients/smbclient.cpp @@ -567,6 +567,22 @@ int SmbClient::Head(const std::string &ppath, void *buffer, uint64_t len) return 1; } +void *SmbClient::Open(const std::string &path, int flags) +{ + struct smb2fh* in = smb2_open(smb2, path.c_str(), flags); + return in; +} + +int SmbClient::Read(void **fp, void *buf, uint64_t size) +{ + return smb2_read(smb2, (struct smb2fh*) *fp, (uint8_t*)buf, size); +} + +void SmbClient::Close(void **fp) +{ + smb2_close(smb2, (struct smb2fh*)*fp); +} + ClientType SmbClient::clientType() { return CLIENT_TYPE_SMB; diff --git a/source/clients/smbclient.h b/source/clients/smbclient.h index 561b61d..3e0d939 100644 --- a/source/clients/smbclient.h +++ b/source/clients/smbclient.h @@ -34,6 +34,9 @@ public: int Move(const std::string &from, const std::string &to); int CopyToSocket(const std::string &path, int socket_fd); std::vector ListDir(const std::string &path); + void *Open(const std::string &path, int flags); + int Read(void **fp, void *buf, uint64_t size); + void Close(void **fp); bool IsConnected(); bool Ping(); const char *LastResponse(); diff --git a/source/mem_file.cpp b/source/mem_file.cpp new file mode 100644 index 0000000..ae67a72 --- /dev/null +++ b/source/mem_file.cpp @@ -0,0 +1,197 @@ +#include +#include +#include + +#include "common.h" +#include "mem_file.h" + +MemFile::MemFile(const std::string &path, size_t block_size) +{ + this->block_size = block_size; + this->complete = false; + sem_init(&this->block_ready, 0, 0); +} + +MemFile::~MemFile() +{ + for (int i = 0; i < this->mem_blocks.size(); i++) + { + if (this->mem_blocks[i] != nullptr && this->mem_blocks[i]->status != MEM_BLOCK_STATUS_DELETED) + { + if (this->mem_blocks[i]->buf != nullptr) + { + free(this->mem_blocks[i]->buf); + this->mem_blocks[i]->buf = nullptr; + } + free(this->mem_blocks[i]); + } + } + sem_destroy(&this->block_ready); +}; + +int MemFile::Open() +{ + this->block_in_progress = NewBlock(); + this->block_in_progress->buf = malloc(block_size); + + return (block_in_progress->buf == nullptr); +} + +size_t MemFile::Read(char *buf, size_t buf_size, size_t offset) +{ + int first_block_num, block_num; + size_t block_offset; + size_t remaining; + size_t bytes_read; + size_t total_bytes_read; + MemBlock *block; + char *p; + + first_block_num= offset / this->block_size; + block_num = first_block_num; + block_offset = offset % this->block_size; + + while ((block_num >= this->mem_blocks.size() && !this->complete) || + (block_num < this->mem_blocks.size() && this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS)) + { + sem_wait(&this->block_ready); + } + + block = this->mem_blocks[block_num]; + if (block->status == MEM_BLOCK_STATUS_DELETED) + { + return -1; + } + + if (block_offset > block->size - 1 && this->complete) + { + // requested offset is pass the end of split file + return 0; + } + + remaining = buf_size; + bool eof = false; + total_bytes_read = 0; + p = buf; + + while (remaining > 0 && !eof) + { + uint8_t *src = (uint8_t*)block->buf; + src += block_offset; + bytes_read = block_size - block_offset; + memcpy(p, src, bytes_read); + + if (bytes_read == remaining) + { + p += bytes_read; + total_bytes_read += bytes_read; + } + else + { + p += bytes_read; + total_bytes_read += bytes_read; + if (block->is_last) + { + eof = true; + continue; + } + } + + remaining -= bytes_read; + + if (remaining == 0) + continue; + + block_num++; + block_offset = 0; + + while ((block_num > this->mem_blocks.size() - 1 && !this->complete) || + this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS) + { + sem_wait(&this->block_ready); + } + + block = this->mem_blocks[block_num]; + } + + // delete blocks before the first read offset block. Assumuption, that reads are always + // forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks + for (int j=0; j < first_block_num - 2; j++) + { + if (this->mem_blocks[j]->status == MEM_BLOCK_STATUS_CREATED) + { + if (this->mem_blocks[j]->buf != nullptr) + { + free(this->mem_blocks[j]->buf); + this->mem_blocks[j]->buf = nullptr; + } + this->mem_blocks[j]->status = MEM_BLOCK_STATUS_DELETED; + } + } + + return total_bytes_read; +} + +size_t MemFile::Write(char *buf, size_t buf_size) +{ + size_t bytes_written; + size_t block_space_remaining; + size_t bytes_to_write; + + char *p = buf; + size_t total_bytes_written = 0; + size_t remaining_to_write = buf_size; + + while (remaining_to_write > 0) + { + block_space_remaining = this->block_size - block_in_progress->size; + bytes_to_write = MIN(remaining_to_write, block_space_remaining); + memcpy(block_in_progress->buf, p, bytes_to_write); + bytes_written = bytes_to_write; + block_in_progress->size += bytes_written; + total_bytes_written += bytes_written; + remaining_to_write -= bytes_written; + block_space_remaining -= bytes_written; + p += bytes_written; + + // error if bytes_to_write != bytes_written + if (bytes_written != bytes_to_write) + { + break; + } + + if (block_space_remaining == 0) + { + block_in_progress->status = MEM_BLOCK_STATUS_CREATED; + this->mem_blocks.push_back(block_in_progress); + sem_post(&this->block_ready); + + block_in_progress = NewBlock(); + } + } + + return total_bytes_written; +} + +int MemFile::Close() +{ + block_in_progress->status = MEM_BLOCK_STATUS_CREATED; + block_in_progress->is_last = true; + this->mem_blocks.push_back(block_in_progress); + this->complete = true; + sem_post(&this->block_ready); + + return 0; +} + +MemBlock *MemFile::NewBlock() +{ + MemBlock *block = (MemBlock *)malloc(sizeof(MemBlock)); + memset(block, 0, sizeof(MemBlock)); + + block->is_last = false; + block->size = 0; + block->buf = malloc(block_size); + + return block; +} \ No newline at end of file diff --git a/source/mem_file.h b/source/mem_file.h new file mode 100644 index 0000000..3b79416 --- /dev/null +++ b/source/mem_file.h @@ -0,0 +1,46 @@ +#ifndef MEM_FILE_H +#define MEM_FILE_H + +#include +#include +#include +#include + +enum MemBlockStatus +{ + MEM_BLOCK_STATUS_NOT_EXISTS, + MEM_BLOCK_STATUS_CREATED, + MEM_BLOCK_STATUS_DELETED +}; + +typedef struct +{ + size_t size; + void* buf; + bool is_last; + MemBlockStatus status; +} MemBlock; + +class MemFile +{ +public: + MemFile(const std::string& path, size_t block_size); + ~MemFile(); + size_t Read(char* buf, size_t buf_size, size_t offset); + size_t Write(char* buf, size_t buf_size); + int Open(); + int Close(); + +private: + std::vector mem_blocks; + size_t write_offset; + size_t block_size; + int write_error; + bool complete; + MemBlock *block_in_progress; + sem_t block_ready; + + MemBlock *NewBlock(); +}; + +#endif \ No newline at end of file diff --git a/source/server/http_server.cpp b/source/server/http_server.cpp index 6210503..8b227a5 100644 --- a/source/server/http_server.cpp +++ b/source/server/http_server.cpp @@ -8,6 +8,12 @@ #include "clients/smbclient.h" #include "clients/ftpclient.h" #include "clients/nfsclient.h" +#include "clients/webdav.h" +#include "clients/apache.h" +#include "clients/iis.h" +#include "clients/nginx.h" +#include "clients/npxserve.h" +#include "clients/rclone.h" #include "filehost/filehost.h" #include "config.h" #include "fs.h" @@ -27,6 +33,14 @@ using namespace httplib; +struct RemoteDownloadData +{ + RemoteClient *client = nullptr; + std::map fp_handles; +}; + +static RemoteDownloadData remote_data[100]; + Server *svr; int http_server_port = 8080; char compressed_file_path[1024]; @@ -91,22 +105,22 @@ namespace HttpServer return s; } - void failed(Response & res, int status, const std::string &msg) + void failed(Response &res, int status, const std::string &msg) { res.status = status; - char response_msg[msg.length()+strlen(FAILURE_MSG)+2]; + char response_msg[msg.length() + strlen(FAILURE_MSG) + 2]; snprintf(response_msg, sizeof(response_msg), "{ \"result\": { \"success\": false, \"error\": \"%s\" } }", msg.c_str()); res.set_content(response_msg, strlen(response_msg), "application/json"); return; } - void bad_request(Response & res, const std::string &msg) + void bad_request(Response &res, const std::string &msg) { failed(res, 200, msg); return; } - void success(Response & res) + void success(Response &res) { res.status = 200; res.set_content(SUCCESS_MSG, SUCCESS_MSG_LEN, "application/json"); @@ -182,15 +196,77 @@ namespace HttpServer return 1; } + static RemoteClient *GetRemoteClient(int site_idx, bool new_client) + { + RemoteClient *tmp_client; + RemoteSettings *tmp_settings = &site_settings[sites[site_idx]]; + + if (!new_client) + { + tmp_client = remote_data[site_idx].client; + if (tmp_client != nullptr) + return tmp_client; + } + + if (tmp_settings->type == CLIENT_TYPE_SFTP) + { + tmp_client = new SFTPClient(); + } + else if (tmp_settings->type == CLIENT_TYPE_SMB) + { + tmp_client = new SmbClient(); + } + else if (tmp_settings->type == CLIENT_TYPE_FTP) + { + tmp_client = new FtpClient(); + } + else if (tmp_settings->type == CLIENT_TYPE_NFS) + { + tmp_client = new NfsClient(); + } + else if (tmp_settings->type == CLIENT_TYPE_WEBDAV) + { + tmp_client = new WebDAVClient(); + } + else if (tmp_settings->type == CLIENT_TYPE_HTTP_SERVER) + { + if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0) + tmp_client = new ApacheClient(); + else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MS_IIS) == 0) + tmp_client = new IISClient(); + else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NGINX) == 0) + tmp_client = new NginxClient(); + else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0) + tmp_client = new NpxServeClient(); + else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0) + tmp_client = new RCloneClient(); + } + tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password); + + if (!new_client && tmp_client->clientType() != CLIENT_TYPE_FTP) + { + remote_data[site_idx].client = tmp_client; + } + + return tmp_client; + } + + static void DeleteRemoteClient(RemoteClient *tmp_client, int site_idx) + { + if (tmp_client != nullptr) + { + tmp_client->Quit(); + delete tmp_client; + } + } + void *ServerThread(void *argp) { - svr->Get("/", [&](const Request & req, Response & res) - { - res.set_redirect("/index.html"); - }); + svr->Get("/", [&](const Request &req, Response &res) + { res.set_redirect("/index.html"); }); - svr->Get("/index.html", [&](const Request & req, Response & res) - { + svr->Get("/index.html", [&](const Request &req, Response &res) + { FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html"); size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html"); res.set_content_provider( @@ -206,11 +282,10 @@ namespace HttpServer }, [in](bool success) { FS::Close(in); - }); - }); + }); }); - svr->Get("/favicon.ico", [&](const Request & req, Response & res) - { + svr->Get("/favicon.ico", [&](const Request &req, Response &res) + { FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico"); size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico"); res.set_content_provider( @@ -226,11 +301,10 @@ namespace HttpServer }, [in](bool success) { FS::Close(in); - }); - }); + }); }); - svr->Post("/__local__/list", [&](const Request & req, Response & res) - { + svr->Post("/__local__/list", [&](const Request &req, Response &res) + { const char *path; bool onlyFolders = false; json_object *jobj = json_tokener_parse(req.body.c_str()); @@ -276,11 +350,10 @@ namespace HttpServer json_object_object_add(results, "result", json_files); const char *results_str = json_object_to_json_string(results); res.status = 200; - res.set_content(results_str, strlen(results_str), "application/json"); - }); + res.set_content(results_str, strlen(results_str), "application/json"); }); - svr->Post("/__local__/rename", [&](const Request & req, Response & res) - { + svr->Post("/__local__/rename", [&](const Request &req, Response &res) + { const char *item; const char *newItemPath; json_object *jobj = json_tokener_parse(req.body.c_str()); @@ -302,11 +375,10 @@ namespace HttpServer FS::Rename(item, newItemPath); success(res); - return; - }); + return; }); - svr->Post("/__local__/move", [&](const Request & req, Response & res) - { + svr->Post("/__local__/move", [&](const Request &req, Response &res) + { const json_object *items; const char *newPath; json_object *jobj = json_tokener_parse(req.body.c_str()); @@ -357,11 +429,10 @@ namespace HttpServer failed(res, 200, error_msg); } else - success(res); - }); + success(res); }); - svr->Post("/__local__/copy", [&](const Request & req, Response & res) - { + svr->Post("/__local__/copy", [&](const Request &req, Response &res) + { const json_object *items; const char *newPath; const char *singleFilename; @@ -432,11 +503,10 @@ namespace HttpServer failed(res, 200, error_msg); } else - success(res); - }); + success(res); }); - svr->Post("/__local__/remove", [&](const Request & req, Response & res) - { + svr->Post("/__local__/remove", [&](const Request &req, Response &res) + { json_object *items; json_object *jobj = json_tokener_parse(req.body.c_str()); if (jobj != nullptr) @@ -472,11 +542,10 @@ namespace HttpServer failed(res, 200, error_msg); } else - success(res); - }); + success(res); }); - svr->Post("/__local__/install", [&](const Request & req, Response & res) - { + svr->Post("/__local__/install", [&](const Request &req, Response &res) + { json_object *items; json_object *jobj = json_tokener_parse(req.body.c_str()); if (jobj != nullptr) @@ -509,11 +578,10 @@ namespace HttpServer failed(res, 200, error_msg); } else - success(res); - }); + success(res); }); - svr->Post("/__local__/edit", [&](const Request & req, Response & res) - { + svr->Post("/__local__/edit", [&](const Request &req, Response &res) + { const char *item; const char *content; size_t content_len; @@ -543,11 +611,10 @@ namespace HttpServer return; } - success(res); - }); + success(res); }); - svr->Post("/__local__/getContent", [&](const Request & req, Response & res) - { + svr->Post("/__local__/getContent", [&](const Request &req, Response &res) + { const char *item; json_object *jobj = json_tokener_parse(req.body.c_str()); if (jobj != nullptr) @@ -570,11 +637,10 @@ namespace HttpServer json_object_object_add(result, "result", json_object_new_string(content.data())); const char *result_str = json_object_to_json_string(result); res.status = 200; - res.set_content(result_str, strlen(result_str), "application/json"); - }); + res.set_content(result_str, strlen(result_str), "application/json"); }); - svr->Post("/__local__/createFolder", [&](const Request & req, Response & res) - { + svr->Post("/__local__/createFolder", [&](const Request &req, Response &res) + { const char *newPath; json_object *jobj = json_tokener_parse(req.body.c_str()); if (jobj != nullptr) @@ -593,16 +659,13 @@ namespace HttpServer } FS::MkDirs(newPath); - success(res); - }); + success(res); }); - svr->Post("/__local__/permission", [&](const Request & req, Response & res) - { - failed(res, 200, "Operation not supported"); - }); + svr->Post("/__local__/permission", [&](const Request &req, Response &res) + { failed(res, 200, "Operation not supported"); }); - svr->Post("/__local__/compress", [&](const Request & req, Response & res) - { + svr->Post("/__local__/compress", [&](const Request &req, Response &res) + { json_object *items; const char* destination; const char* compressedFilename; @@ -652,11 +715,10 @@ namespace HttpServer else { failed(res, 200, "Failed to create zip"); - } - }); + } }); - svr->Post("/__local__/extract", [&](const Request & req, Response & res) - { + svr->Post("/__local__/extract", [&](const Request &req, Response &res) + { const char* item; const char* destination; const char* folderName; @@ -692,11 +754,10 @@ namespace HttpServer else if (ret == -1) failed(res, 200, "Unsupported compressed file format"); else - success(res); - }); + success(res); }); svr->Get("/__local__/uploadResumeSize", [&](const Request &req, Response &res) - { + { std::string destination = req.get_param_value("destination"); std::string filename = req.get_param_value("filename"); std::string file_path = destination + "/" + filename; @@ -705,11 +766,10 @@ namespace HttpServer size = FS::GetSize(file_path); std::string result_str = "{\"size\":" + std::to_string(size) + "}"; res.status = 200; - res.set_content(result_str.c_str(), result_str.length(), "application/json"); - }); + res.set_content(result_str.c_str(), result_str.length(), "application/json"); }); svr->Post("/__local__/upload", [&](const Request &req, Response &res, const ContentReader &content_reader) - { + { MultipartFormDataItems items; std::string destination; size_t chunk_size = 0; @@ -775,12 +835,11 @@ namespace HttpServer { FS::Close(out); } - success(res); - }); + success(res); }); // Download multiple files as ZIP - svr->Get("/__local__/downloadMultiple", [&](const Request & req, Response & res) - { + svr->Get("/__local__/downloadMultiple", [&](const Request &req, Response &res) + { if (req.get_param_value_count("items") == 0 || req.get_param_value_count("toFilename") == 0) { failed(res, 200, "Required items and toFilename parameter missing"); @@ -834,12 +893,11 @@ namespace HttpServer else { failed(res, 200, "Failed to create zip"); - } - }); + } }); // Download single file - svr->Get("/__local__/downloadFile", [&](const Request & req, Response & res) - { + svr->Get("/__local__/downloadFile", [&](const Request &req, Response &res) + { std::string path = req.get_param_value("path", 0); if (path.empty()) { @@ -869,11 +927,10 @@ namespace HttpServer }, [in](bool success) { FS::Close(in); - }); - }); + }); }); svr->Get("/google_auth", [](const Request &req, Response &res) - { + { std::string auth_code = req.get_param_value("code"); Client client(GOOGLE_OAUTH_HOST); client.set_follow_location(true); @@ -919,12 +976,11 @@ namespace HttpServer } login_state = -1; std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google"; - res.set_content(str.c_str(), "text/plain"); - }); + res.set_content(str.c_str(), "text/plain"); }); - svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res) - { - RemoteClient *tmp_client; + svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request &req, Response &res) + { + RemoteClient *tmp_client = nullptr; RemoteSettings *tmp_settings; auto site_idx = std::stoi(req.matches[1])-1; std::string path; @@ -932,33 +988,6 @@ namespace HttpServer if (site_idx != 98) { path = std::string("/") + std::string(req.matches[3]); - - tmp_settings = &site_settings[sites[site_idx]]; - - if (tmp_settings->type == CLIENT_TYPE_SFTP) - { - tmp_client = new SFTPClient(); - tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password); - } - else if (tmp_settings->type == CLIENT_TYPE_SMB) - { - tmp_client = new SmbClient(); - tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password); - } - else if (tmp_settings->type == CLIENT_TYPE_FTP) - { - tmp_client = new FtpClient(); - tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password); - } - else if (tmp_settings->type == CLIENT_TYPE_NFS) - { - tmp_client = new NfsClient(); - tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password); - } - else - { - tmp_client = remoteclient; - } } else { @@ -973,33 +1002,34 @@ namespace HttpServer tmp_client->Connect(host, "", ""); } - if (tmp_client == nullptr || !tmp_client->IsConnected()) - { - res.status = 404; - return; - } - - if (req.method == "HEAD") { int64_t file_size; int ret; + if (site_idx != 98) + tmp_client = GetRemoteClient(site_idx, true); + ret = tmp_client->Size(path, &file_size); if (!ret) { res.status = 500; + DeleteRemoteClient(tmp_client, site_idx); return; } res.status = 204; res.set_header("Content-Length", std::to_string(file_size)); res.set_header("Accept-Ranges", "bytes"); + DeleteRemoteClient(tmp_client, site_idx); return; } if (req.ranges.empty()) { res.status = 200; + if (site_idx != 98) + tmp_client = GetRemoteClient(site_idx, true); + res.set_content_provider( (1024*128), "application/octet-stream", [tmp_client, path](size_t offset, size_t length, DataSink &sink) { @@ -1007,15 +1037,7 @@ namespace HttpServer return (ret == 1); }, [tmp_client, path, site_idx](bool success) { - if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP - || tmp_client->clientType() == CLIENT_TYPE_SMB - || tmp_client->clientType() == CLIENT_TYPE_FTP - || tmp_client->clientType() == CLIENT_TYPE_NFS - || (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98))) - { - tmp_client->Quit(); - delete tmp_client; - } + DeleteRemoteClient(tmp_client, site_idx); }); } else @@ -1027,6 +1049,11 @@ namespace HttpServer range_len = 524288ul; res.set_header("Content-Length", std::to_string(range_len)); res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len)); + tmp_client = GetRemoteClient(site_idx, true); + } + else + { + tmp_client = GetRemoteClient(site_idx, false); } std::pair range = req.ranges[0]; res.set_content_provider( @@ -1035,22 +1062,18 @@ namespace HttpServer int ret = tmp_client->GetRange(path, sink, range_len, range.first); return (ret == 1); }, - [tmp_client, site_idx, path, range, range_len](bool success) { - if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP - || tmp_client->clientType() == CLIENT_TYPE_SMB - || tmp_client->clientType() == CLIENT_TYPE_FTP - || tmp_client->clientType() == CLIENT_TYPE_NFS - || (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98))) + [tmp_client, path, range, site_idx](bool success) { + if (range.second >= 18000000000000000000ul || + (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98) || + tmp_client->clientType() == CLIENT_TYPE_FTP) { - tmp_client->Quit(); - delete tmp_client; + DeleteRemoteClient(tmp_client, site_idx); } }); - } - }); + } }); - svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res) - { + svr->Get("/archive_inst/(.*)", [&](const Request &req, Response &res) + { RemoteClient *tmp_client; RemoteSettings *tmp_settings; std::string hash = req.matches[1]; @@ -1104,11 +1127,10 @@ namespace HttpServer [](bool success) { return true; }); - } - }); + } }); - svr->Post("/__local__/install_url", [&](const Request & req, Response & res) - { + svr->Post("/__local__/install_url", [&](const Request &req, Response &res) + { std::string url; const char *url_param; bool use_alldebrid = false; @@ -1231,21 +1253,17 @@ namespace HttpServer return; } } - success(res); - }); + success(res); }); svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/) - { - svr->stop(); - }); + { svr->stop(); }); svr->set_error_handler([](const Request & /*req*/, Response &res) - { + { const char *fmt = "

Error Status: %d

"; char buf[BUFSIZ]; snprintf(buf, sizeof(buf), fmt, res.status); - res.set_content(buf, "text/html"); - }); + res.set_content(buf, "text/html"); }); /* svr->set_logger([](const Request &req, const Response &res) @@ -1253,11 +1271,11 @@ namespace HttpServer dbglogger_log("%s", log(req, res).c_str()); }); */ - + svr->set_payload_max_length(1024 * 1024 * 12); svr->set_tcp_nodelay(true); svr->set_mount_point("/", "/"); - + if (web_server_enabled) svr->listen("0.0.0.0", http_server_port); else