Compare commits

...

6 Commits

Author SHA1 Message Date
rakshasa 88782d005d Stuff. 2026-09-01 17:46:15 +02:00
rakshasa 5fcd779b15 Stuff. 2026-09-01 17:11:44 +02:00
rakshasa 7104512ac1 Stuff. 2026-09-01 17:10:29 +02:00
rakshasa bd82f6152e Stuff. 2026-09-01 16:40:37 +02:00
rakshasa 83eb4e016a Stuff. 2026-09-01 16:16:30 +02:00
rakshasa 6b60c219fa Stuff. 2026-08-31 09:52:34 +02:00
10 changed files with 407 additions and 202 deletions
+1
View File
@@ -187,6 +187,7 @@ libsub_root_a_SOURCES = \
command_helpers.cc \ command_helpers.cc \
command_helpers.h \ command_helpers.h \
command_groups.cc \ command_groups.cc \
command_load.cc \
command_local.cc \ command_local.cc \
command_logging.cc \ command_logging.cc \
command_network.cc \ command_network.cc \
+1 -36
View File
@@ -1,25 +1,17 @@
#include "config.h" #include "config.h"
#include <functional> #include <torrent/exceptions.h>
#include <cstdio>
#include <string>
#include <vector>
#include <torrent/rate.h>
#include <torrent/hash_string.h>
#include <torrent/utils/log.h> #include <torrent/utils/log.h>
#include <torrent/utils/directory_events.h> #include <torrent/utils/directory_events.h>
#include <torrent/utils/file_stat.h> #include <torrent/utils/file_stat.h>
#include <torrent/utils/string_manip.h> #include <torrent/utils/string_manip.h>
#include "globals.h"
#include "control.h" #include "control.h"
#include "command_helpers.h" #include "command_helpers.h"
#include "core/download.h" #include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h" #include "core/manager.h"
#include "core/view_manager.h" #include "core/view_manager.h"
#include "rpc/command_scheduler.h" #include "rpc/command_scheduler.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h" #include "rpc/parse_commands.h"
#include "utils/watch_ready_queue.h" #include "utils/watch_ready_queue.h"
@@ -146,24 +138,6 @@ apply_schedule(const torrent::Object::list_type& args, bool if_absent) {
return torrent::Object(); return torrent::Object();
} }
torrent::Object
apply_load(const torrent::Object::list_type& args, int flags) {
torrent::Object::list_const_iterator argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_expand(filename, flags, commands);
return torrent::Object();
}
void apply_import(const std::string& path) { if (!rpc::parse_command_file(path)) throw torrent::input_error("Could not open option file: " + path); } void apply_import(const std::string& path) { if (!rpc::parse_command_file(path)) throw torrent::input_error("Could not open option file: " + path); }
void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); } void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); }
@@ -368,15 +342,6 @@ initialize_command_events() {
CMD2_ANY_STRING_V("import", [](auto, auto& str) { return apply_import(str); }); CMD2_ANY_STRING_V("import", [](auto, auto& str) { return apply_import(str); });
CMD2_ANY_STRING_V("try_import", [](auto, auto& str) { return apply_try_import(str); }); CMD2_ANY_STRING_V("try_import", [](auto, auto& str) { return apply_try_import(str); });
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied); });
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied); });
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_VALUE ("close_low_diskspace", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 99); }); CMD2_ANY_VALUE ("close_low_diskspace", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 99); });
CMD2_ANY_VALUE ("close_low_diskspace.normal", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 3); }); CMD2_ANY_VALUE ("close_low_diskspace.normal", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 3); });
+81
View File
@@ -0,0 +1,81 @@
#include "config.h"
#include "command_helpers.h"
#include "control.h"
#include "core/manager.h"
torrent::Object
apply_load_trusted(const torrent::Object::list_type& args, int flags) {
auto argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_expand(filename, flags, commands);
return torrent::Object();
}
torrent::Object
apply_load_untrusted(const torrent::Object::list_type& args, int flags) {
auto argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_untrusted(filename, flags, commands);
return torrent::Object();
}
void
initialize_command_load() {
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_tied); });
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_tied); });
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.normal", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet); });
CMD2_ANY_LIST ("load.untrusted.verbose", [](auto, auto& args) { return apply_load_untrusted(args, 0); });
CMD2_ANY_LIST ("load.untrusted.start", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_start); });
CMD2_ANY_LIST ("load.untrusted.start_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_start); });
CMD2_ANY_LIST ("load.untrusted.raw", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_start", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_start_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_VALUE_V("load.untrusted.mark_safe", [](auto, auto& arg) {
if (arg == 0)
return;
// TODO: Add a bool to core::Manager.
rpc::rpc.mark_safe("load.untrusted.normal");
rpc::rpc.mark_safe("load.untrusted.verbose");
rpc::rpc.mark_safe("load.untrusted.start");
rpc::rpc.mark_safe("load.untrusted.start_verbose");
rpc::rpc.mark_safe("load.untrusted.raw");
rpc::rpc.mark_safe("load.untrusted.raw_verbose");
rpc::rpc.mark_safe("load.untrusted.raw_start");
rpc::rpc.mark_safe("load.untrusted.raw_start_verbose");
});
}
+210 -77
View File
@@ -27,6 +27,8 @@
namespace core { namespace core {
static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it";
bool bool
is_network_uri(const std::string& uri) { is_network_uri(const std::string& uri) {
return return
@@ -35,9 +37,15 @@ is_network_uri(const std::string& uri) {
std::strncmp(uri.c_str(), "ftp://", 6) == 0; std::strncmp(uri.c_str(), "ftp://", 6) == 0;
} }
static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it"; bool
is_magnet_uri(const std::string& uri) {
return
std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
}
static std::unique_ptr<torrent::Object> namespace {
std::unique_ptr<torrent::Object>
download_factory_load_stream(const char* filename, bool* is_invalid) { download_factory_load_stream(const char* filename, bool* is_invalid) {
std::fstream stream(filename, std::ios::in | std::ios::binary); std::fstream stream(filename, std::ios::in | std::ios::binary);
@@ -55,17 +63,34 @@ download_factory_load_stream(const char* filename, bool* is_invalid) {
return obj; return obj;
} }
bool std::unique_ptr<torrent::Object>
is_magnet_uri(const std::string& uri) { create_untrusted_object(torrent::Object& obj) {
return auto trusted_object = std::make_unique<torrent::Object>(torrent::Object::create_map());
std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
if (obj.has_key("info"))
trusted_object->insert_key_move("info", obj.get_key("info"));
if (obj.has_key("announce"))
trusted_object->insert_key_move("announce", obj.get_key("announce"));
if (obj.has_key("announce-list"))
trusted_object->insert_key_move("announce-list", obj.get_key("announce-list"));
if (obj.has_key("creation date"))
trusted_object->insert_key_move("creation date", obj.get_key("creation date"));
if (obj.has_key("created by"))
trusted_object->insert_key_move("created by", obj.get_key("created by"));
return trusted_object;
} }
DownloadFactory::DownloadFactory(Manager* m) : } // namespace anonymous
m_manager(m) {
m_task_load.slot() = std::bind(&DownloadFactory::receive_load, this);
m_task_commit.slot() = std::bind(&DownloadFactory::receive_commit, this); DownloadFactory::DownloadFactory(Manager* m, bool trusted)
: m_manager(m),
m_trusted(trusted) {
// m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech"); // m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech");
// m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed"); // m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed");
@@ -78,21 +103,49 @@ DownloadFactory::DownloadFactory(Manager* m) :
DownloadFactory::~DownloadFactory() { DownloadFactory::~DownloadFactory() {
torrent::this_thread::scheduler()->erase(&m_task_load); torrent::this_thread::scheduler()->erase(&m_task_load);
torrent::this_thread::scheduler()->erase(&m_task_commit); torrent::this_thread::scheduler()->erase(&m_task_commit);
delete m_object;
} }
void void
DownloadFactory::load(const std::string& uri) { DownloadFactory::load_trusted(const std::string& uri) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::load_trusted() called on an untrusted object");
m_uri = uri; m_uri = uri;
m_task_load.slot() = [this]() { receive_load_trusted(); };
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms); torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
} }
// This function must be called before DownloadFactory::commit().
void void
DownloadFactory::load_raw_data(const std::string& input) { DownloadFactory::load_untrusted(const std::string& uri) {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::load_untrusted() called on a trusted object");
m_uri = uri;
m_task_load.slot() = [this]() { receive_load_untrusted(); };
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
}
void
DownloadFactory::load_raw_data_trusted(const std::string& input) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::load_raw_data_trusted() called on an untrusted object");
if (m_stream) if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL"); throw torrent::internal_error("DownloadFactory::load_raw_data_trusted() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input));
m_loaded = true;
}
void
DownloadFactory::load_raw_data_untrusted(const std::string& input) {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::load_raw_data_untrusted() called on an trusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::load_raw_data_untrusted() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input)); m_stream.reset(new std::stringstream(input));
m_loaded = true; m_loaded = true;
@@ -100,53 +153,91 @@ DownloadFactory::load_raw_data(const std::string& input) {
void void
DownloadFactory::commit() { DownloadFactory::commit() {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::commit() called on an untrusted object");
m_task_commit.slot() = [this]() { receive_commit(); };
torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms); torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms);
} }
void void
DownloadFactory::receive_load() { DownloadFactory::process_load_network_uri() {
if (m_stream) m_stream.reset(new std::stringstream);
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
if (is_network_uri(m_uri)) { // TODO: Add trusted flag.
m_stream.reset(new std::stringstream);
auto done_fn = [this]() { receive_loaded(); }; auto done_fn = [this]() { receive_loaded(); };
auto failed_fn = [this](const std::string& error) { receive_failed(error); }; auto failed_fn = [this](const std::string& error) { receive_failed(error); };
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn); m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
m_variables["tied_to_file"] = (int64_t)false; m_variables["tied_to_file"] = (int64_t)false;
return; }
}
if (is_magnet_uri(m_uri)) { void
// DEBUG: Use m_object. DownloadFactory::process_load_magnet_uri() {
m_stream.reset(new std::stringstream()); m_stream.reset(new std::stringstream());
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e"; *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
m_variables["tied_to_file"] = (int64_t)false; m_variables["tied_to_file"] = (int64_t)false;
receive_loaded(); receive_loaded();
return; }
}
void
DownloadFactory::process_load_file_uri() {
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary); std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
if (!stream.is_open()) if (!stream.is_open())
return receive_failed("Could not open file"); return receive_failed("Could not open file");
m_object = new torrent::Object; m_object = std::make_unique<torrent::Object>();
stream >> *m_object; stream >> *m_object;
if (!stream.good()) if (!stream.good())
return receive_failed("Reading torrent file failed"); return receive_failed("Reading torrent file failed");
m_isFile = true; m_is_file = true;
receive_loaded(); receive_loaded();
} }
void
DownloadFactory::receive_load_trusted() {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an untrusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an object with null m_stream");
if (is_network_uri(m_uri))
return process_load_network_uri();
if (is_magnet_uri(m_uri))
return process_load_magnet_uri();
process_load_file_uri();
}
void
DownloadFactory::receive_load_untrusted() {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a trusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with null m_stream");
if (is_network_uri(m_uri))
return process_load_network_uri();
// TODO: Don't need to handle untrusted commands magnet URIs.
// if (is_magnet_uri(m_uri))
// return process_load_magnet_uri();
throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a non-network/magnet URI");
}
void void
DownloadFactory::receive_loaded() { DownloadFactory::receive_loaded() {
m_loaded = true; m_loaded = true;
@@ -165,30 +256,40 @@ DownloadFactory::receive_commit() {
void void
DownloadFactory::receive_success() { DownloadFactory::receive_success() {
bool session_invalid = false; if (!m_trusted && m_session)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true");
auto rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid); if (m_session && !m_is_file)
auto libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid); throw torrent::internal_error("DownloadFactory::receive_success() called on a non-file object with m_session == true");
if (session_invalid) bool session_invalid = false;
lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str()); uint32_t tracker_key = tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
uint32_t tracker_key; std::unique_ptr<torrent::Object> rtorrent_object, libtorrent_resume_object;
if (rtorrent_object && rtorrent_object->has_key_value("key")) if (m_session) {
tracker_key = rtorrent_object->get_key_value("key"); rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid);
else libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid);
tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
Download* download = m_stream != nullptr ? if (session_invalid)
m_manager->download_list()->create(m_stream.get(), tracker_key, m_printLog) : lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str());
m_manager->download_list()->create(m_object, tracker_key, m_printLog);
m_object = NULL; if (rtorrent_object && rtorrent_object->has_key_value("key"))
tracker_key = rtorrent_object->get_key_value("key");
}
if (download == NULL) { // TODO: This adds the torrent, so untrusted can add brokent torrents.
// core::Manager should already have added the error message to
// the log. if (m_stream != nullptr)
object_from_stream();
if (m_trusted)
m_object = create_untrusted_object(*m_object);
Download* download = m_manager->download_list()->create(std::move(m_object), tracker_key, m_print_log);
if (download == nullptr) {
// core::Manager should already have added the error message to the log.
m_slot_finished(); m_slot_finished();
return; return;
} }
@@ -197,39 +298,49 @@ DownloadFactory::receive_success() {
download->set_hash_failed(true); download->set_hash_failed(true);
download->set_message(session_invalid_message); download->set_message(session_invalid_message);
if (m_printLog) if (m_print_log)
m_manager->push_log_std(std::string(session_invalid_message) + ": \"" + m_uri + "\""); m_manager->push_log_std(std::string(session_invalid_message) + ": \"" + m_uri + "\"");
} }
torrent::Object* root = download->bencode(); torrent::Object* root = download->bencode();
if (download->download()->info()->is_meta_download()) { if (download->download()->info()->is_meta_download()) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with a meta download");
torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map()); torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map());
meta.insert_key("start", m_start); meta.insert_key("start", m_start);
meta.insert_key("print_log", m_printLog); meta.insert_key("print_log", m_print_log);
torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list(); // TODO: ADD UNTRUSTED!!!
auto& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
for (auto& m_command : m_commands) for (auto& m_command : m_commands)
commands.push_back(m_command); commands.push_back(m_command);
} }
if (m_session) { if (m_session) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true");
if (rtorrent_object) if (rtorrent_object)
root->insert_key_move("rtorrent", *rtorrent_object); root->insert_key_move("rtorrent", *rtorrent_object);
if (libtorrent_resume_object) if (libtorrent_resume_object)
root->insert_key_move("libtorrent_resume", *libtorrent_resume_object); root->insert_key_move("libtorrent_resume", *libtorrent_resume_object);
} else if (!m_trusted) {
if (root->has_key("rtorrent") || root->has_key("libtorrent_resume"))
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with 'rtorrent' or 'libtorrent_resume' keys");
} else { } else {
// We only allow session torrents to keep their // We only allow session torrents to keep their 'rtorrent/libtorrent' sections. The
// 'rtorrent/libtorrent' sections. The "fast_resume" section // "fast_resume" section should be safe to keep.
// should be safe to keep.
root->erase_key("rtorrent"); root->erase_key("rtorrent");
} }
torrent::Object* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second; auto* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second;
torrent::Object& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second; auto& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second;
rtorrent->insert_key("key", download->tracker_controller().key()); rtorrent->insert_key("key", download->tracker_controller().key());
@@ -259,7 +370,7 @@ DownloadFactory::receive_success() {
} }
// Skip forcing trackers to scrape when rtorrent starts // Skip forcing trackers to scrape when rtorrent starts
if (m_initLoad && rpc::call_command_value("trackers.delay_scrape")) if (m_init_load && rpc::call_command_value("trackers.delay_scrape"))
download->set_resume_flags(torrent::Download::start_skip_tracker); download->set_resume_flags(torrent::Download::start_skip_tracker);
// Check first if we already have these values set in the session // Check first if we already have these values set in the session
@@ -301,7 +412,7 @@ DownloadFactory::receive_success() {
lt_log_print(torrent::LOG_ERROR, "%s: %s", msg.c_str(), m_uri.c_str()); lt_log_print(torrent::LOG_ERROR, "%s: %s", msg.c_str(), m_uri.c_str());
if (m_printLog) if (m_print_log)
m_manager->push_log_std(msg + ": \"" + m_uri + "\""); m_manager->push_log_std(msg + ": \"" + m_uri + "\"");
download->set_hash_failed(true); download->set_hash_failed(true);
@@ -325,8 +436,13 @@ DownloadFactory::receive_success() {
if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid()) if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid())
log_created(download, rtorrent); log_created(download, rtorrent);
for (const auto& command : m_commands) if (m_trusted) {
rpc::parse_command_multiple_std(command, rpc::make_target(download)); for (const auto& command : m_commands)
rpc::parse_command_multiple_std(command, rpc::make_target(download));
} else {
// TODO: CALL UNTRUSTED COMMANDS
}
if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end()) if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
throw torrent::input_error("The newly created download was removed."); throw torrent::input_error("The newly created download was removed.");
@@ -340,7 +456,7 @@ DownloadFactory::receive_success() {
} catch (torrent::input_error& e) { } catch (torrent::input_error& e) {
std::string msg = "Command on torrent creation failed: " + std::string(e.what()); std::string msg = "Command on torrent creation failed: " + std::string(e.what());
if (m_printLog) if (m_print_log)
m_manager->push_log_std(msg); m_manager->push_log_std(msg);
if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) { if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) {
@@ -354,6 +470,18 @@ DownloadFactory::receive_success() {
m_slot_finished(); m_slot_finished();
} }
void
DownloadFactory::receive_failed(const std::string& msg) {
if (m_print_log) {
if (m_trusted)
m_manager->push_log_std("Failed to load torrent: " + msg + ": \"" + m_uri + "\"");
else
m_manager->push_log_std("Failed to load untrusted torrent: " + msg);
}
m_slot_finished();
}
void void
DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) { DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
std::stringstream dump; std::stringstream dump;
@@ -380,15 +508,6 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:"); lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:");
} }
void
DownloadFactory::receive_failed(const std::string& msg) {
// Add message to log.
if (m_printLog)
m_manager->push_log_std(msg + ": \"" + m_uri + "\"");
m_slot_finished();
}
void void
DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) { DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) {
auto cached_seconds = torrent::this_thread::cached_seconds().count(); auto cached_seconds = torrent::this_thread::cached_seconds().count();
@@ -412,7 +531,7 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0); rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0);
rtorrent->insert_preserve_copy("tied_to_file", ""); rtorrent->insert_preserve_copy("tied_to_file", "");
rtorrent->insert_key("loaded_file", m_isFile ? m_uri : std::string()); rtorrent->insert_key("loaded_file", m_is_file ? m_uri : std::string());
if (rtorrent->has_key_value("priority")) if (rtorrent->has_key_value("priority"))
rpc::call_command("d.priority.set", rtorrent->get_key_value("priority") % 4, rpc::make_target(download)); rpc::call_command("d.priority.set", rtorrent->get_key_value("priority") % 4, rpc::make_target(download));
@@ -444,4 +563,18 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
rtorrent->insert_preserve_copy("choke_heuristics.down.seed", std::string()); rtorrent->insert_preserve_copy("choke_heuristics.down.seed", std::string());
} }
void
DownloadFactory::object_from_stream() {
m_object = std::make_unique<torrent::Object>();
*m_stream >> *m_object;
if (!m_stream->good() || !m_object->is_map()) {
if (m_print_log)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, stream is not a valid torrent.");
throw torrent::input_error("Invalid torrent data");
}
}
} }
+27 -14
View File
@@ -24,14 +24,18 @@ public:
typedef std::vector<std::string> command_list_type; typedef std::vector<std::string> command_list_type;
// Do not destroy this object while it is in a HttpQueue. // Do not destroy this object while it is in a HttpQueue.
DownloadFactory(Manager* m); DownloadFactory(Manager* m, bool trusted);
~DownloadFactory(); ~DownloadFactory();
// Calling of receive_load() is delayed so you can change whatever // Calling of receive_load() is delayed so you can change whatever
// you want without fear of the slots being triggered as you call // you want without fear of the slots being triggered as you call
// load() or commit(). // load() or commit().
void load(const std::string& uri); void load_trusted(const std::string& uri);
void load_raw_data(const std::string& input); void load_untrusted(const std::string& uri);
void load_raw_data_trusted(const std::string& input);
void load_raw_data_untrusted(const std::string& input);
void commit(); void commit();
command_list_type& commands() { return m_commands; } command_list_type& commands() { return m_commands; }
@@ -43,16 +47,21 @@ public:
bool get_start() const { return m_start; } bool get_start() const { return m_start; }
void set_start(bool v) { m_start = v; } void set_start(bool v) { m_start = v; }
bool get_init_load() const { return m_initLoad; } bool get_init_load() const { return m_init_load; }
void set_init_load(bool v) { m_initLoad = v; } void set_init_load(bool v) { m_init_load = v; }
bool print_log() const { return m_printLog; } bool print_log() const { return m_print_log; }
void set_print_log(bool v) { m_printLog = v; } void set_print_log(bool v) { m_print_log = v; }
void slot_finished(slot_void s) { m_slot_finished = s; } void slot_finished(slot_void s) { m_slot_finished = s; }
private: private:
void receive_load(); void process_load_network_uri();
void process_load_magnet_uri();
void process_load_file_uri();
void receive_load_trusted();
void receive_load_untrusted();
void receive_loaded(); void receive_loaded();
void receive_commit(); void receive_commit();
void receive_success(); void receive_success();
@@ -62,19 +71,23 @@ private:
void initialize_rtorrent(Download* download, torrent::Object* rtorrent); void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
Manager* m_manager; void object_from_stream();
std::shared_ptr<std::iostream> m_stream;
torrent::Object* m_object{};
Manager* m_manager;
std::shared_ptr<std::iostream> m_stream;
std::unique_ptr<torrent::Object> m_object{};
bool m_trusted{};
bool m_commited{}; bool m_commited{};
bool m_loaded{}; bool m_loaded{};
std::string m_uri; std::string m_uri;
bool m_session{}; bool m_session{};
bool m_start{}; bool m_start{};
bool m_printLog{true}; bool m_print_log{true};
bool m_isFile{}; bool m_is_file{};
bool m_initLoad{}; bool m_init_load{};
command_list_type m_commands; command_list_type m_commands;
torrent::Object::map_type m_variables; torrent::Object::map_type m_variables;
+5 -37
View File
@@ -101,49 +101,17 @@ DownloadList::find_hex_ptr(const char* hash) {
} }
Download* Download*
DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog) { DownloadList::create(std::unique_ptr<torrent::Object> obj, uint32_t tracker_key, bool printLog) {
torrent::Download download; torrent::Download download;
try { auto obj_ptr = obj.get();
download = torrent::download_add(obj, tracker_key);
} catch (torrent::local_error& e) {
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
delete obj;
return NULL;
}
// There's no non-critical exceptions that should be throwable by
// the ctor, so don't catch.
return new Download(download);
}
Download*
DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) {
torrent::Object* object = new torrent::Object;
torrent::Download download;
try { try {
*str >> *object; download = torrent::download_add(obj.release(), tracker_key);
// Don't throw input_error from here as gcc-3.3.5 produces bad
// code.
if (str->fail()) {
delete object;
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
return NULL;
}
download = torrent::download_add(object, tracker_key);
} catch (torrent::local_error& e) { } catch (torrent::local_error& e) {
delete object; // TODO: Fix download_add so it takes the unique_ptr.
delete obj_ptr;
if (printLog) if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what()); lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
+1 -2
View File
@@ -52,8 +52,7 @@ public:
Download* find_hex_ptr(const char* hash); Download* find_hex_ptr(const char* hash);
// Might move this to DownloadFactory. // Might move this to DownloadFactory.
Download* create(std::istream* str, uint32_t tracker_key, bool printLog); Download* create(std::unique_ptr<torrent::Object> obj, uint32_t tracker_key, bool printLog);
Download* create(torrent::Object* obj, uint32_t tracker_key, bool printLog);
iterator insert(Download* d); iterator insert(Download* d);
+75 -32
View File
@@ -37,6 +37,8 @@
namespace core { namespace core {
void path_expand(std::vector<std::string>* paths, const std::string& pattern);
const int Manager::create_start; const int Manager::create_start;
const int Manager::create_tied; const int Manager::create_tied;
const int Manager::create_quiet; const int Manager::create_quiet;
@@ -195,7 +197,7 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
return; return;
// Adding download. // Adding download.
DownloadFactory* f = new DownloadFactory(this); DownloadFactory* f = new DownloadFactory(this, true);
f->variables()["tied_to_file"] = (int64_t)(bool)(flags & create_tied); f->variables()["tied_to_file"] = (int64_t)(bool)(flags & create_tied);
f->commands().insert(f->commands().end(), commands.begin(), commands.end()); f->commands().insert(f->commands().end(), commands.begin(), commands.end());
@@ -204,29 +206,52 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
f->set_print_log(!(flags & create_quiet)); f->set_print_log(!(flags & create_quiet));
f->slot_finished([f]() { delete f; }); f->slot_finished([f]() { delete f; });
if (is_data_uri(uri)) { if (flags & create_raw_data) {
f->load_raw_data_trusted(uri);
} else if (is_data_uri(uri)) {
// Allow the use of data URIs, primarily for JSON-RPC which // Allow the use of data URIs, primarily for JSON-RPC which
// doesn't have a defined mechanism for binary data // doesn't have a defined mechanism for binary data
f->load_raw_data(decode_data_uri(uri)); f->load_raw_data_trusted(decode_data_uri(uri));
f->variables()["tied_to_file"] = (int64_t)false; f->variables()["tied_to_file"] = (int64_t)false;
} else if (flags & create_raw_data) {
f->load_raw_data(uri);
} else { } else {
f->load(uri); f->load_trusted(uri);
} }
f->commit(); f->commit();
} }
void
Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) {
if (flags & create_raw_data) {
try_create_download(uri, flags, commands);
return;
}
std::vector<std::string> paths;
paths.reserve(256);
path_expand(&paths, uri);
if (!paths.empty())
for (auto& path : paths)
try_create_download(path, flags, commands);
else
try_create_download(uri, flags, commands);
}
void void
Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) { Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) {
DownloadFactory* f = new DownloadFactory(this); DownloadFactory* f = new DownloadFactory(this, true);
f->variables()["tied_to_file"] = (int64_t)true; f->variables()["tied_to_file"] = (int64_t)true;
f->variables()["tied_file"] = metafile; f->variables()["tied_file"] = metafile;
torrent::Object& meta = bencode->get_key("rtorrent_meta_download"); torrent::Object& meta = bencode->get_key("rtorrent_meta_download");
torrent::Object::list_type& commands = meta.get_key_list("commands"); torrent::Object::list_type& commands = meta.get_key_list("commands");
for (const auto& command : commands) for (const auto& command : commands)
f->commands().insert(f->commands().end(), command.as_string()); f->commands().insert(f->commands().end(), command.as_string());
@@ -239,13 +264,46 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
std::stringstream s; std::stringstream s;
s.imbue(std::locale::classic()); s.imbue(std::locale::classic());
s << *bencode; s << *bencode;
f->load_raw_data(s.str());
f->load_raw_data_trusted(s.str());
f->commit(); f->commit();
} }
utils::Directory void
path_expand_transform(std::string path, const utils::directory_entry& entry) { Manager::try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands) {
return path + entry.s_name; // TODO: Need to check if we are allowed, also rate limit.
if (!(flags & create_raw_data) &&
!is_network_uri(uri) &&
!is_magnet_uri(uri) &&
!is_data_uri(uri)) {
push_log_std("URI type not allowed for untrusted loads.");
return;
}
DownloadFactory* f = new DownloadFactory(this, false);
f->commands().insert(f->commands().end(), commands.begin(), commands.end());
f->set_start(flags & create_start);
f->set_print_log(!(flags & create_quiet));
f->slot_finished([f]() { delete f; });
if (flags & create_raw_data) {
f->load_raw_data_untrusted(uri);
} else if (is_data_uri(uri)) {
// Allow the use of data URIs, primarily for JSON-RPC which
// doesn't have a defined mechanism for binary data
f->load_raw_data_untrusted(decode_data_uri(uri));
f->variables()["tied_to_file"] = (int64_t)false;
} else {
// f->load_untrusted(uri);
throw torrent::internal_error("Manager::try_create_download_untrusted() unimplemented.");
}
f->commit();
} }
namespace { namespace {
@@ -304,6 +362,11 @@ split_iterator(const Sequence&) {
} }
utils::Directory
path_expand_transform(std::string path, const utils::directory_entry& entry) {
return path + entry.s_name;
}
// Move this somewhere better. // Move this somewhere better.
void void
path_expand(std::vector<std::string>* paths, const std::string& pattern) { path_expand(std::vector<std::string>* paths, const std::string& pattern) {
@@ -360,26 +423,6 @@ manager_equal_tied(const std::string& path, Download* download) {
return path == rpc::call_command_string("d.tied_to_file", rpc::make_target(download)); return path == rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
} }
void
Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) {
if (flags & create_raw_data) {
try_create_download(uri, flags, commands);
return;
}
std::vector<std::string> paths;
paths.reserve(256);
path_expand(&paths, uri);
if (!paths.empty())
for (auto& path : paths)
try_create_download(path, flags, commands);
else
try_create_download(uri, flags, commands);
}
// DownloadList's hashing related functions don't actually start the // DownloadList's hashing related functions don't actually start the
// hashing, it only reacts to events. This functions checks the // hashing, it only reacts to events. This functions checks the
// hashing view and starts hashing if nessesary. // hashing view and starts hashing if nessesary.
+2
View File
@@ -78,6 +78,8 @@ public:
void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type()); void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type());
void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile); void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile);
void try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands);
private: private:
void create_http(const std::string& uri); void create_http(const std::string& uri);
void create_final(std::istream* s); void create_final(std::istream* s);
+4 -4
View File
@@ -157,12 +157,12 @@ load_session_torrents(const std::string& path) {
if (!entry.is_file()) if (!entry.is_file())
continue; continue;
auto* f = new core::DownloadFactory(control->core()); auto* f = new core::DownloadFactory(control->core(), true);
f->set_session(true); f->set_session(true);
f->set_init_load(true); f->set_init_load(true);
f->slot_finished([f](){ delete f; }); f->slot_finished([f](){ delete f; });
f->load(entries.path() + entry.s_name); f->load_trusted(entries.path() + entry.s_name);
f->commit(); f->commit();
} }
} }
@@ -170,12 +170,12 @@ load_session_torrents(const std::string& path) {
void void
load_arg_torrents(char** first, char** last) { load_arg_torrents(char** first, char** last) {
for (; first != last; ++first) { for (; first != last; ++first) {
auto* f = new core::DownloadFactory(control->core()); auto* f = new core::DownloadFactory(control->core(), true);
f->set_start(true); f->set_start(true);
f->set_init_load(true); f->set_init_load(true);
f->slot_finished([f](){ delete f; }); f->slot_finished([f](){ delete f; });
f->load(*first); f->load_trusted(*first);
f->commit(); f->commit();
} }
} }