make some web functions work

This commit is contained in:
Chee Yee
2023-07-14 01:09:58 -07:00
parent cc2eea9d68
commit 70007ee1f9
7 changed files with 1188 additions and 214 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

+13
View File
@@ -31,6 +31,19 @@
config.set({
appName: 'ezRemote Client',
listUrl: '/__local__/list',
uploadUrl: '/__local__/upload',
renameUrl: '/__local__/rename',
copyUrl: '/__local__/copy',
moveUrl: '/__local__/move',
removeUrl: '/__local__/remove',
editUrl: '/__local__/edit',
getContentUrl: '/__local__/getContent',
createFolderUrl: '/__local__/createFolder',
downloadFileUrl: '/__local__/downloadFile',
downloadMultipleUrl: '/__local__/downloadMultiple',
compressUrl: '/__local__/compress',
extractUrl: '/__local__/extract',
permissionsUrl: '/__local__/permission',
pickCallback: function(item) {
var msg = 'Picked %s "%s" for external use'
.replace('%s', item.type)
+25 -8
View File
@@ -77,6 +77,15 @@ namespace FS
return (stat(path.c_str(), &dir_stat) == 0);
}
int IsFolder(const std::string &path)
{
struct stat dir_stat = {0};
if (stat(path.c_str(), &dir_stat) != 0)
return -1;
if (S_ISDIR(dir_stat.st_mode))
return 1;
return 0;
}
void Rename(const std::string &from, const std::string &to)
{
int res = rename(from.c_str(), to.c_str());
@@ -121,7 +130,7 @@ namespace FS
int Write(FILE *f, const void *buffer, uint32_t size)
{
int write = fwrite(buffer, size, 1, f);
int write = fwrite(buffer, 1, size, f);
return write;
}
@@ -136,14 +145,17 @@ namespace FS
if (fd == nullptr)
return std::vector<char>(0);
const auto size = GetSize(path);
dbglogger_log("size=%lld", size);
std::vector<char> data(size);
const auto read = fread(data.data(), 1, data.size(), fd);
dbglogger_log("read=%lld", size);
fclose(fd);
if (read < 0)
return std::vector<char>(0);
data.resize(read);
data.resize(read+1);
data[data.size()-1]=0;
return data;
}
@@ -209,22 +221,23 @@ namespace FS
return true;
}
void Save(const std::string &path, const void *data, uint32_t size)
bool Save(const std::string &path, const void *data, uint32_t size)
{
FILE *fd = fopen(path.c_str(), "w+");
if (fd == nullptr)
return;
return false;
const char *data8 = static_cast<const char *>(data);
while (size != 0)
{
int written = fwrite(data8, size, 1, fd);
int written = fwrite(data8, 1, size, fd);
fclose(fd);
if (written <= 0)
return;
return false;
data8 += written;
size -= written;
}
return true;
}
std::vector<DirEntry> ListDir(const std::string &ppath, int *err)
@@ -304,9 +317,7 @@ namespace FS
entry.modified.seconds = lt.second;
entry.file_size = file_stat.st_size;
dbglogger_log("%04d-%02d-%02d %02d:%02d:%02d", lt.year, lt.month, lt.day, lt.hour, lt.minute, lt.second);
sprintf(entry.display_date, "%04d-%02d-%02d %02d:%02d:%02d", lt.year, lt.month, lt.day, lt.hour, lt.minute, lt.second);
dbglogger_log("display_date=%s", entry.display_date);
if (dirent->d_type & DT_DIR)
{
@@ -478,6 +489,9 @@ namespace FS
bool Copy(const std::string &from, const std::string &to)
{
MkDirs(to, true);
if (from.compare(to) == 0)
return true;
FILE *src = fopen(from.c_str(), "rb");
if (!src)
{
@@ -535,6 +549,9 @@ namespace FS
bool Move(const std::string &from, const std::string &to)
{
if (from.compare(to) == 0)
return true;
bool res = Copy(from, to);
if (res)
Rm(from);
+2 -1
View File
@@ -25,6 +25,7 @@ namespace FS
bool FileExists(const std::string &path);
bool FolderExists(const std::string &path);
int IsFolder(const std::string &path);
void Rename(const std::string &from, const std::string &to);
@@ -54,7 +55,7 @@ namespace FS
bool LoadText(std::vector<std::string> *lines, const std::string &path);
bool SaveText(std::vector<std::string> *lines, const std::string &path);
void Save(const std::string &path, const void *data, uint32_t size);
bool Save(const std::string &path, const void *data, uint32_t size);
std::vector<std::string> ListFiles(const std::string &path);
std::vector<DirEntry> ListDir(const std::string &path, int *err);
+516 -168
View File
File diff suppressed because it is too large Load Diff
+174 -34
View File
@@ -1,14 +1,14 @@
//
// httplib.h
//
// Copyright (c) 2022 Yuji Hirose. All rights reserved.
// Copyright (c) 2023 Yuji Hirose. All rights reserved.
// MIT License
//
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.12.0"
#define CPPHTTPLIB_VERSION "0.13.1"
/*
* Configuration
@@ -87,7 +87,7 @@
#endif
#ifndef CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
#endif
#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
@@ -172,9 +172,15 @@ using socket_t = SOCKET;
#else // not _WIN32
#include <arpa/inet.h>
#ifndef _AIX
#if !defined(_AIX) && !defined(__MVS__)
#include <ifaddrs.h>
#endif
#ifdef __MVS__
#include <strings.h>
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
#endif
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -223,6 +229,9 @@ using socket_t = int;
#include <string>
#include <sys/stat.h>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
#ifdef _WIN32
@@ -239,7 +248,13 @@ using socket_t = int;
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptui.lib")
#endif
#endif //_WIN32
#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_OSX
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#endif // TARGET_OS_OSX
#endif // _WIN32
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -308,6 +323,34 @@ struct ci {
}
};
// This is based on
// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
struct scope_exit {
explicit scope_exit(std::function<void(void)> &&f)
: exit_function(std::move(f)), execute_on_destruction{true} {}
scope_exit(scope_exit &&rhs)
: exit_function(std::move(rhs.exit_function)),
execute_on_destruction{rhs.execute_on_destruction} {
rhs.release();
}
~scope_exit() {
if (execute_on_destruction) { this->exit_function(); }
}
void release() { this->execute_on_destruction = false; }
private:
scope_exit(const scope_exit &) = delete;
void operator=(const scope_exit &) = delete;
scope_exit &operator=(scope_exit &&) = delete;
std::function<void(void)> exit_function;
bool execute_on_destruction;
};
} // namespace detail
using Headers = std::multimap<std::string, std::string, detail::ci>;
@@ -340,6 +383,7 @@ public:
std::function<bool(const char *data, size_t data_len)> write;
std::function<void()> done;
std::function<void(const Headers &trailer)> done_with_trailer;
std::ostream os;
private:
@@ -430,6 +474,7 @@ struct Request {
MultipartFormDataMap files;
Ranges ranges;
Match matches;
std::unordered_map<std::string, std::string> path_params;
// for client
ResponseHandler response_handler;
@@ -623,6 +668,76 @@ using SocketOptions = std::function<void(socket_t sock)>;
void default_socket_options(socket_t sock);
namespace detail {
class MatcherBase {
public:
virtual ~MatcherBase() = default;
// Match request path and populate its matches and
virtual bool match(Request &request) const = 0;
};
/**
* Captures parameters in request path and stores them in Request::path_params
*
* Capture name is a substring of a pattern from : to /.
* The rest of the pattern is matched agains the request path directly
* Parameters are captured starting from the next character after
* the end of the last matched static pattern fragment until the next /.
*
* Example pattern:
* "/path/fragments/:capture/more/fragments/:second_capture"
* Static fragments:
* "/path/fragments/", "more/fragments/"
*
* Given the following request path:
* "/path/fragments/:1/more/fragments/:2"
* the resulting capture will be
* {{"capture", "1"}, {"second_capture", "2"}}
*/
class PathParamsMatcher : public MatcherBase {
public:
PathParamsMatcher(const std::string &pattern);
bool match(Request &request) const override;
private:
static constexpr char marker = ':';
// Treat segment separators as the end of path parameter capture
// Does not need to handle query parameters as they are parsed before path
// matching
static constexpr char separator = '/';
// Contains static path fragments to match against, excluding the '/' after
// path params
// Fragments are separated by path params
std::vector<std::string> static_fragments_;
// Stores the names of the path parameters to be used as keys in the
// Request::path_params map
std::vector<std::string> param_names_;
};
/**
* Performs std::regex_match on request path
* and stores the result in Request::matches
*
* Note that regex match is performed directly on the whole request.
* This means that wildcard patterns may match multiple path segments with /:
* "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end".
*/
class RegexMatcher : public MatcherBase {
public:
RegexMatcher(const std::string &pattern) : regex_(pattern) {}
bool match(Request &request) const override;
private:
std::regex regex_;
};
} // namespace detail
class Server {
public:
using Handler = std::function<void(const Request &, Response &)>;
@@ -708,6 +823,7 @@ public:
bool listen(const std::string &host, int port, int socket_flags = 0);
bool is_running() const;
void wait_until_ready() const;
void stop();
std::function<TaskQueue *(void)> new_task_queue;
@@ -717,7 +833,7 @@ protected:
bool &connection_closed,
const std::function<void(Request &)> &setup_request);
std::atomic<socket_t> svr_sock_;
std::atomic<socket_t> svr_sock_{INVALID_SOCKET};
size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
@@ -729,9 +845,14 @@ protected:
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
private:
using Handlers = std::vector<std::pair<std::regex, Handler>>;
using Handlers =
std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;
using HandlersForContentReader =
std::vector<std::pair<std::regex, HandlerWithContentReader>>;
std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
HandlerWithContentReader>>;
static std::unique_ptr<detail::MatcherBase>
make_matcher(const std::string &pattern);
socket_t create_server_socket(const std::string &host, int port,
int socket_flags,
@@ -769,21 +890,23 @@ private:
ContentReceiver multipart_receiver);
bool read_content_core(Stream &strm, Request &req, Response &res,
ContentReceiver receiver,
MultipartContentHeader mulitpart_header,
MultipartContentHeader multipart_header,
ContentReceiver multipart_receiver);
virtual bool process_and_close_socket(socket_t sock);
std::atomic<bool> is_running_{false};
std::atomic<bool> done_{false};
struct MountPointEntry {
std::string mount_point;
std::string base_dir;
Headers headers;
};
std::vector<MountPointEntry> base_dirs_;
std::atomic<bool> is_running_;
std::map<std::string, std::string> file_extension_and_mimetype_map_;
Handler file_request_handler_;
Handlers get_handlers_;
Handlers post_handlers_;
HandlersForContentReader post_handlers_for_content_reader_;
@@ -794,13 +917,15 @@ private:
Handlers delete_handlers_;
HandlersForContentReader delete_handlers_for_content_reader_;
Handlers options_handlers_;
HandlerWithResponse error_handler_;
ExceptionHandler exception_handler_;
HandlerWithResponse pre_routing_handler_;
Handler post_routing_handler_;
Logger logger_;
Expect100ContinueHandler expect_100_continue_handler_;
Logger logger_;
int address_family_ = AF_UNSPEC;
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
SocketOptions socket_options_ = default_socket_options;
@@ -823,6 +948,9 @@ enum class Error {
UnsupportedMultipartBoundaryChars,
Compression,
ConnectionTimeout,
// For internal use only
SSLPeerCouldBeClosed_,
};
std::string to_string(const Error error);
@@ -831,6 +959,7 @@ std::ostream &operator<<(std::ostream &os, const Error &obj);
class Result {
public:
Result() = default;
Result(std::unique_ptr<Response> &&res, Error err,
Headers &&request_headers = Headers{})
: res_(std::move(res)), err_(err),
@@ -859,7 +988,7 @@ public:
private:
std::unique_ptr<Response> res_;
Error err_;
Error err_ = Error::Unknown;
Headers request_headers_;
};
@@ -1019,12 +1148,14 @@ public:
bool send(Request &req, Response &res, Error &error);
Result send(const Request &req);
size_t is_socket_open() const;
socket_t socket() const;
void stop();
std::string host() const;
int port() const;
size_t is_socket_open() const;
socket_t socket() const;
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
@@ -1077,6 +1208,7 @@ public:
void set_ca_cert_path(const std::string &ca_cert_file_path,
const std::string &ca_cert_dir_path = std::string());
void set_ca_cert_store(X509_STORE *ca_cert_store);
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size);
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -1095,8 +1227,6 @@ protected:
bool is_open() const { return sock != INVALID_SOCKET; }
};
Result send_(Request &&req);
virtual bool create_and_connect_socket(Socket &socket, Error &error);
// All of:
@@ -1118,7 +1248,7 @@ protected:
void copy_settings(const ClientImpl &rhs);
// Socket endoint information
// Socket endpoint information
const std::string host_;
const int port_;
const std::string host_and_port_;
@@ -1197,6 +1327,9 @@ protected:
Logger logger_;
private:
bool send_(Request &req, Response &res, Error &error);
Result send_(Request &&req);
socket_t create_client_socket(Error &error) const;
bool read_response_line(Stream &strm, const Request &req, Response &res);
bool write_request(Stream &strm, Request &req, bool close_connection,
@@ -1390,12 +1523,14 @@ public:
bool send(Request &req, Response &res, Error &error);
Result send(const Request &req);
size_t is_socket_open() const;
socket_t socket() const;
void stop();
std::string host() const;
int port() const;
size_t is_socket_open() const;
socket_t socket() const;
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
@@ -1456,6 +1591,7 @@ public:
const std::string &ca_cert_dir_path = std::string());
void set_ca_cert_store(X509_STORE *ca_cert_store);
void load_ca_cert_store(const char *ca_cert, std::size_t size);
long get_openssl_verify_result() const;
@@ -1515,6 +1651,7 @@ public:
bool is_valid() const override;
void set_ca_cert_store(X509_STORE *ca_cert_store);
void load_ca_cert_store(const char *ca_cert, std::size_t size);
long get_openssl_verify_result() const;
@@ -1624,22 +1761,22 @@ inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
inline void default_socket_options(socket_t sock) {
int yes = 1;
#ifdef _WIN32
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const char *>(&yes), sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
reinterpret_cast<char *>(&yes), sizeof(yes));
reinterpret_cast<const char *>(&yes), sizeof(yes));
#else
#ifdef SO_REUSEPORT
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<void *>(&yes),
sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
reinterpret_cast<const void *>(&yes), sizeof(yes));
#else
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<void *>(&yes),
sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const void *>(&yes), sizeof(yes));
#endif
#endif
int const size = 1048576;
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
//int const size = 1048576;
//setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
//setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}
template <class Rep, class Period>
@@ -1791,6 +1928,9 @@ std::string params_to_query_str(const Params &params);
void parse_query_text(const std::string &s, Params &params);
bool parse_multipart_boundary(const std::string &content_type,
std::string &boundary);
bool parse_range_header(const std::string &s, Ranges &ranges);
int close_socket(socket_t sock);
+458 -3
View File
@@ -8,10 +8,14 @@
#include "windows.h"
#include "lang.h"
#include "system.h"
#include "dbglogger.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
#define SERVER_PRIVATE_KEY_FILE "/app0/assets/certs/domain.key"
#define SERVER_PRIVATE_KEY_PASSWORD "12345678"
#define SUCCESS_MSG "{ \"result\": { \"success\": true, \"error\": null } }"
#define FAILURE_MSG "{ \"result\": { \"success\": false, \"error\": \"%s\" } }"
#define SUCCESS_MSG_LEN 48
using namespace httplib;
SSLServer *svr;
@@ -76,6 +80,99 @@ namespace HttpServer
return s;
}
void failed(Response & res, int status, const std::string &msg)
{
res.status = status;
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)
{
failed(res, 200, msg);
return;
}
void success(Response & res)
{
res.status = 200;
res.set_content(SUCCESS_MSG, SUCCESS_MSG_LEN, "application/json");
return;
}
int CopyOrMove(const DirEntry &src, const char *dest, bool isCopy)
{
int ret;
if (src.isDir)
{
int err;
std::vector<DirEntry> entries = FS::ListDir(src.path, &err);
FS::MkDirs(dest);
for (int i = 0; i < entries.size(); i++)
{
int path_length = strlen(dest) + strlen(entries[i].name) + 2;
char *new_path = (char *)malloc(path_length);
snprintf(new_path, path_length, "%s%s%s", dest, FS::hasEndSlash(dest) ? "" : "/", entries[i].name);
if (entries[i].isDir)
{
if (strcmp(entries[i].name, "..") == 0)
continue;
FS::MkDirs(new_path);
ret = CopyOrMove(entries[i], new_path, isCopy);
if (ret <= 0)
{
free(new_path);
return ret;
}
}
else
{
if (isCopy)
{
ret = FS::Copy(entries[i].path, new_path);
}
else
{
ret = FS::Move(entries[i].path, new_path);
}
if (ret <= 0)
{
free(new_path);
return ret;
}
}
free(new_path);
}
if (!isCopy)
FS::RmRecursive(src.path);
}
else
{
int path_length = strlen(dest) + strlen(src.name) + 2;
char *new_path = (char *)malloc(path_length);
snprintf(new_path, path_length, "%s%s%s", dest, FS::hasEndSlash(dest) ? "" : "/", src.name);
if (isCopy)
{
ret = FS::Copy(src.path, new_path);
}
else
{
ret = FS::Move(src.path, new_path);
}
if (ret <= 0)
{
free(new_path);
return 0;
}
free(new_path);
}
return 1;
}
void *ServerThread(void *argp)
{
svr->Get("/", [&](const Request & req, Response & res)
@@ -96,11 +193,15 @@ namespace HttpServer
onlyFolders = true;
if (path == nullptr)
{
res.status = 400;
res.set_content("path parameter is missing", 25, "text/plain");
bad_request(res, "Required path parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
int err;
std::vector<DirEntry> files = FS::ListDir(path, &err);
@@ -113,7 +214,7 @@ namespace HttpServer
json_object_object_add(new_file, "name", json_object_new_string(it->name));
json_object_object_add(new_file, "rights", json_object_new_string(it->isDir ? "drwxrwxrwx" : "rw-rw-rw-"));
json_object_object_add(new_file, "date", json_object_new_string(it->display_date));
json_object_object_add(new_file, "size", json_object_new_string(it->isDir ? "" : it->display_size));
json_object_object_add(new_file, "size", json_object_new_string(it->isDir ? "" : std::to_string(it->file_size).c_str()));
json_object_object_add(new_file, "type", json_object_new_string(it->isDir ? "dir" : "file"));
json_object_array_add(json_files, new_file);
}
@@ -126,6 +227,360 @@ namespace HttpServer
res.set_content(results_str, strlen(results_str), "application/json");
});
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());
if (jobj != nullptr)
{
item = json_object_get_string(json_object_object_get(jobj, "item"));
newItemPath = json_object_get_string(json_object_object_get(jobj, "newItemPath"));
if (item == nullptr || newItemPath == nullptr)
{
bad_request(res, "Required item or newItemPath parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
FS::Rename(item, newItemPath);
success(res);
return;
});
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());
if (jobj != nullptr)
{
items = json_object_object_get(jobj, "items");
newPath = json_object_get_string(json_object_object_get(jobj, "newPath"));
if (items == nullptr || newPath == nullptr)
{
bad_request(res, "Required items or newPath parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
std::string failed_items;
size_t len = json_object_array_length(items);
for (size_t i=0; i < len; i++)
{
const char *item = json_object_get_string(json_object_array_get_idx(items, i));
DirEntry entry;
std::string temp = std::string(item);
size_t slash_pos = temp.find_last_of("/");
sprintf(entry.name, "%s", temp.substr(slash_pos+1).c_str());
sprintf(entry.path, "%s", item);
entry.isDir = FS::IsFolder(item);
bool ret = CopyOrMove(entry, newPath, false);
if (!ret)
{
failed_items += std::string(item) + ",";
}
}
if (failed_items.length() > 0)
{
std::string error_msg = std::string("One or more file(s) failed to move. ") + failed_items;
failed(res, 200, error_msg);
}
else
success(res);
});
svr->Post("/__local__/copy", [&](const Request & req, Response & res)
{
const json_object *items;
const char *newPath;
const char *singleFilename;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
items = json_object_object_get(jobj, "items");
newPath = json_object_get_string(json_object_object_get(jobj, "newPath"));
singleFilename = json_object_get_string(json_object_object_get(jobj, "singleFilename"));
if (items == nullptr || newPath == nullptr)
{
bad_request(res, "Required items or newPath or singleFilename parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
std::string failed_items;
if (singleFilename != nullptr)
{
const char *src = json_object_get_string(json_object_array_get_idx(items, 0));
std::string dest = std::string(newPath) + "/" + singleFilename;
if (dest.compare(src) != 0 && !FS::Copy(src, dest))
{
failed_items += src;
}
}
else
{
size_t len = json_object_array_length(items);
for (size_t i=0; i < len; i++)
{
const char *item = json_object_get_string(json_object_array_get_idx(items, i));
DirEntry entry;
std::string temp = std::string(item);
size_t slash_pos = temp.find_last_of("/");
sprintf(entry.name, "%s", temp.substr(slash_pos+1).c_str());
sprintf(entry.path, "%s", item);
entry.isDir = FS::IsFolder(item);
bool ret = CopyOrMove(entry, newPath, true);
if (!ret)
{
failed_items += std::string(item) + ",";
}
}
}
if (failed_items.length() > 0)
{
std::string error_msg = std::string("One or more file(s) failed to copy. ") + failed_items;
failed(res, 200, error_msg);
}
else
success(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)
{
items = json_object_object_get(jobj, "items");
if (items == nullptr)
{
bad_request(res, "Required items parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
std::string failed_items;
size_t len = json_object_array_length(items);
for (size_t i=0; i < len; i++)
{
const char *item = json_object_get_string(json_object_array_get_idx(items, i));
bool ret = FS::RmRecursive(item);
if (!ret)
{
failed_items += std::string(item) + ",";
}
}
if (failed_items.length() > 0)
{
std::string error_msg = std::string("One or more file(s) failed to delete. ") + failed_items;
failed(res, 200, error_msg);
}
else
success(res);
});
svr->Post("/__local__/edit", [&](const Request & req, Response & res)
{
const char *item;
const char *content;
size_t content_len;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
item = json_object_get_string(json_object_object_get(jobj, "item"));
json_object *content_obj = json_object_object_get(jobj, "content");
content = json_object_get_string(content_obj);
content_len = json_object_get_string_len(content_obj);
if (item == nullptr || content == nullptr)
{
bad_request(res, "Required item or content parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
bool ret = FS::Save(item, content, content_len);
if (!ret)
{
failed(res, 200, "Failed to content to file.");
return;
}
success(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)
{
item = json_object_get_string(json_object_object_get(jobj, "item"));
if (item == nullptr)
{
bad_request(res, "Required item parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
std::vector<char> content = FS::Load(item);
json_object *result = json_object_new_object();
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");
});
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)
{
newPath = json_object_get_string(json_object_object_get(jobj, "newPath"));
if (newPath == nullptr)
{
bad_request(res, "Required newPath parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
FS::MkDirs(newPath);
success(res);
});
svr->Post("/__local__/permission", [&](const Request & req, Response & res)
{
failed(res, 200, "Operation not supported");
});
svr->Post("/__local__/compress", [&](const Request & req, Response & res)
{
failed(res, 200, "Operation not supported");
});
svr->Post("/__local__/extract", [&](const Request & req, Response & res)
{
failed(res, 200, "Operation not supported");
});
svr->Post("/__local__/upload", [&](const Request &req, Response &res, const ContentReader &content_reader)
{
MultipartFormDataItems items;
std::string destination;
FILE *out = nullptr;
std::string new_file;
content_reader(
[&](const MultipartFormData &item)
{
items.push_back(item);
if (item.name != "destination")
{
new_file = destination + "/" + item.filename;
if (out != nullptr)
{
FS::Close(out);
}
out = FS::Create(new_file);
}
return true;
},
[&](const char *data, size_t data_length)
{
items.back().content.append(data, data_length);
if (items.back().name == "destination")
{
destination = items.back().content;
}
else
{
dbglogger_log("data_length=%lld", data_length);
FS::Write(out, data, data_length);
}
return true;
});
if (out != nullptr)
{
FS::Close(out);
}
success(res);
});
// Download multiple files as ZIP
svr->Get("/__local__/downloadMultiple", [&](const Request & req, Response & res)
{
const char *path;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
path = json_object_get_string(json_object_object_get(jobj, "path"));
if (path == nullptr)
{
failed(res, 200, "One or more file(s) failed to download");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
});
// Download single file
svr->Get("/__local__/downloadFile", [&](const Request & req, Response & res)
{
std::string path = req.get_param_value("path", 0);
if (path.empty())
{
bad_request(res, "Failed to download");
return;
}
dbglogger_log("path=%s", path.c_str());
res.status = 200;
});
svr->Get("/google_auth", [](const Request &req, Response &res)
{
std::string auth_code = req.get_param_value("code");