mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 05:39:22 +00:00
Stuff.
This commit is contained in:
+204
-77
@@ -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,75 +103,135 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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);
|
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_raw_data(const std::string& input) {
|
||||||
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() 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DownloadFactory::commit() {
|
DownloadFactory::commit_trusted() {
|
||||||
|
if (!m_trusted)
|
||||||
|
throw torrent::internal_error("DownloadFactory::commit_trusted() 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::commit_untrusted() {
|
||||||
if (m_stream)
|
if (m_trusted)
|
||||||
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
|
throw torrent::internal_error("DownloadFactory::commit_untrusted() called on a trusted object");
|
||||||
|
|
||||||
if (is_network_uri(m_uri)) {
|
m_task_commit.slot() = [this]() { receive_commit(); };
|
||||||
m_stream.reset(new std::stringstream);
|
torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms);
|
||||||
|
}
|
||||||
|
|
||||||
auto done_fn = [this]() { receive_loaded(); };
|
void
|
||||||
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
|
DownloadFactory::process_load_network_uri() {
|
||||||
|
m_stream.reset(new std::stringstream);
|
||||||
|
|
||||||
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
|
// TODO: Add trusted flag.
|
||||||
|
|
||||||
m_variables["tied_to_file"] = (int64_t)false;
|
auto done_fn = [this]() { receive_loaded(); };
|
||||||
return;
|
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
|
||||||
}
|
|
||||||
|
|
||||||
if (is_magnet_uri(m_uri)) {
|
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
|
||||||
// DEBUG: Use m_object.
|
|
||||||
m_stream.reset(new std::stringstream());
|
|
||||||
*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();
|
void
|
||||||
return;
|
DownloadFactory::process_load_magnet_uri() {
|
||||||
}
|
m_stream.reset(new std::stringstream());
|
||||||
|
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
|
||||||
|
|
||||||
|
m_variables["tied_to_file"] = (int64_t)false;
|
||||||
|
|
||||||
|
receive_loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +250,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 +292,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 +364,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 +406,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 +430,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 +450,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 +464,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 +502,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 +525,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 +557,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
@@ -24,15 +24,19 @@ 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_untrusted(const std::string& uri);
|
||||||
|
|
||||||
void load_raw_data(const std::string& input);
|
void load_raw_data(const std::string& input);
|
||||||
void commit();
|
|
||||||
|
void commit_trusted();
|
||||||
|
void commit_untrusted();
|
||||||
|
|
||||||
command_list_type& commands() { return m_commands; }
|
command_list_type& commands() { return m_commands; }
|
||||||
torrent::Object::map_type& variables() { return m_variables; }
|
torrent::Object::map_type& variables() { return m_variables; }
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
+68
-26
@@ -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;
|
||||||
@@ -204,13 +206,15 @@ 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(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(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(uri);
|
||||||
}
|
}
|
||||||
@@ -218,6 +222,26 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
|
|||||||
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);
|
||||||
@@ -243,9 +267,42 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding download.
|
||||||
|
DownloadFactory* f = new DownloadFactory(this);
|
||||||
|
|
||||||
|
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 internal_error("Manager::try_create_download_untrusted() unimplemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
f->commit_untrusted();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -304,6 +361,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 +422,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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user