From d113816ae6203f553a6ca183df6ee4ffca085831 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 29 Jun 2019 21:55:56 +0200 Subject: [PATCH] fix issue where trackers from magnet links were not included in create_torrent() --- ChangeLog | 1 + bindings/python/src/torrent_info.cpp | 18 +++++++----- include/libtorrent/torrent_handle.hpp | 3 +- include/libtorrent/torrent_info.hpp | 5 ++-- src/torrent.cpp | 21 +++++++++++++- src/torrent_info.cpp | 8 ++++- test/test_magnet.cpp | 42 +++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 943c8c32a..c5222fcc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix issue where trackers from magnet links were not included in create_torrent() * make peer_info::client a byte array in python binding * pick contiguous pieces from peers with high download rate * fix error handling of moving storage to a drive letter that isn't mounted diff --git a/bindings/python/src/torrent_info.cpp b/bindings/python/src/torrent_info.cpp index 11fd91146..04187dce2 100644 --- a/bindings/python/src/torrent_info.cpp +++ b/bindings/python/src/torrent_info.cpp @@ -234,6 +234,15 @@ void bind_torrent_info() .def_readwrite("size", &file_slice::size) ; + enum_("tracker_source") + .value("source_torrent", announce_entry::source_torrent) + .value("source_client", announce_entry::source_client) + .value("source_magnet_link", announce_entry::source_magnet_link) + .value("source_tex", announce_entry::source_tex) + ; + + using add_tracker1 = void (torrent_info::*)(std::string const&, int, announce_entry::tracker_source); + class_>("torrent_info", no_init) .def(init(arg("info_hash"))) .def("__init__", make_constructor(&bencoded_constructor0)) @@ -245,7 +254,7 @@ void bind_torrent_info() .def(init((arg("file")))) #endif - .def("add_tracker", &torrent_info::add_tracker, arg("url")) + .def("add_tracker", (add_tracker1)&torrent_info::add_tracker, arg("url"), arg("tier") = 0, arg("source") = announce_entry::source_client) .def("add_url_seed", &torrent_info::add_url_seed) .def("add_http_seed", &torrent_info::add_http_seed) .def("web_seeds", get_web_seeds) @@ -339,13 +348,6 @@ void bind_torrent_info() .def("trim", &announce_entry::trim) ; - enum_("tracker_source") - .value("source_torrent", announce_entry::source_torrent) - .value("source_client", announce_entry::source_client) - .value("source_magnet_link", announce_entry::source_magnet_link) - .value("source_tex", announce_entry::source_tex) - ; - implicitly_convertible, std::shared_ptr>(); boost::python::register_ptr_to_python>(); } diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index fc565c85e..649b17c44 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -831,8 +831,7 @@ namespace aux { // If the torrent doesn't have metadata, the pointer will not be // initialized (i.e. a nullptr). The torrent may be in a state // without metadata only if it was started without a .torrent file, e.g. - // by using the libtorrent extension of just supplying a tracker and - // info-hash. + // by being added by magnet link std::shared_ptr torrent_file() const; #if TORRENT_ABI_VERSION == 1 diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index e5e2c54e4..f3f2e1c19 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -51,10 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/sha1_hash.hpp" #include "libtorrent/file_storage.hpp" #include "libtorrent/aux_/vector.hpp" - -#if TORRENT_COMPLETE_TYPES_REQUIRED #include "libtorrent/announce_entry.hpp" -#endif namespace libtorrent { @@ -267,6 +264,8 @@ namespace libtorrent { // lower tier will always be tried before the one with higher tier // number. For more information, see announce_entry_. void add_tracker(std::string const& url, int tier = 0); + void add_tracker(std::string const& url, int tier + , announce_entry::tracker_source source); std::vector const& trackers() const { return m_urls; } // These two functions are related to `BEP 38`_ (mutable torrents). The diff --git a/src/torrent.cpp b/src/torrent.cpp index b0ac63b97..0cbed4004 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -252,6 +252,14 @@ bool is_downloading_state(int const st) if (!m_torrent_file) m_torrent_file = (p.ti ? p.ti : std::make_shared(m_info_hash)); + // in case we added the torrent via magnet link, make sure to preserve any + // DHT nodes passed in on the URI in the torrent file itself + if (!m_torrent_file->is_valid()) + { + for (auto const& n : p.dht_nodes) + m_torrent_file->add_node(n); + } + // --- WEB SEEDS --- // if override web seed flag is set, don't load any web seeds from the @@ -274,10 +282,16 @@ bool is_downloading_state(int const st) // correct URLs to end with a "/" for multi-file torrents if (multi_file) ensure_trailing_slash(ws.back().url); + if (!m_torrent_file->is_valid()) + m_torrent_file->add_url_seed(ws.back().url); } for (auto const& e : p.http_seeds) + { ws.emplace_back(e, web_seed_entry::http_seed); + if (!m_torrent_file->is_valid()) + m_torrent_file->add_http_seed(e); + } aux::random_shuffle(ws); for (auto& w : ws) m_web_seeds.emplace_back(std::move(w)); @@ -305,6 +319,11 @@ bool is_downloading_state(int const st) if (!find_tracker(e.url)) { m_trackers.push_back(e); + // add the tracker to the m_torrent_file here so that the trackers + // will be preserved via create_torrent() when passing in just the + // torrent_info object. + if (!m_torrent_file->is_valid()) + m_torrent_file->add_tracker(e.url, e.tier, announce_entry::tracker_source(e.source)); } } @@ -6067,7 +6086,7 @@ bool is_downloading_state(int const st) std::shared_ptr torrent::get_torrent_copy() { - if (!m_torrent_file->is_valid()) return std::shared_ptr(); + if (!m_torrent_file->is_valid()) return {}; return m_torrent_file; } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index d8cd7db99..9b3ba4c38 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -1510,6 +1510,12 @@ namespace { } void torrent_info::add_tracker(std::string const& url, int const tier) + { + add_tracker(url, tier, announce_entry::source_client); + } + + void torrent_info::add_tracker(std::string const& url, int const tier + , announce_entry::tracker_source const source) { auto const i = std::find_if(m_urls.begin(), m_urls.end() , [&url](announce_entry const& ae) { return ae.url == url; }); @@ -1517,7 +1523,7 @@ namespace { announce_entry e(url); e.tier = std::uint8_t(tier); - e.source = announce_entry::source_client; + e.source = source; m_urls.push_back(e); std::sort(m_urls.begin(), m_urls.end() diff --git a/test/test_magnet.cpp b/test/test_magnet.cpp index 26e534c14..441baa9d0 100644 --- a/test/test_magnet.cpp +++ b/test/test_magnet.cpp @@ -432,6 +432,48 @@ TORRENT_TEST(trailing_whitespace) TEST_CHECK(h.is_valid()); } +// These tests don't work because we don't hand out an incomplete torrent_info +// object. To make them work we would either have to set the correct metadata in +// the test, or change the behavior to make `h.torrent_file()` return the +// internal torrent_info object unconditionally +/* +TORRENT_TEST(preserve_trackers) +{ + session ses(settings()); + error_code ec; + add_torrent_params p = parse_magnet_uri("magnet:?xt=urn:btih:abaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&tr=https://test.com/announce", ec); + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + TEST_CHECK(h.is_valid()); + TEST_CHECK(h.torrent_file()->trackers().size() == 1); + TEST_CHECK(h.torrent_file()->trackers().at(0).url == "https://test.com/announce"); +} + +TORRENT_TEST(preserve_web_seeds) +{ + session ses(settings()); + error_code ec; + add_torrent_params p = parse_magnet_uri("magnet:?xt=urn:btih:abaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&ws=https://test.com/test", ec); + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + TEST_CHECK(h.is_valid()); + TEST_CHECK(h.torrent_file()->web_seeds().size() == 1); + TEST_CHECK(h.torrent_file()->web_seeds().at(0).url == "https://test.com/test"); +} + +TORRENT_TEST(preserve_dht_nodes) +{ + session ses(settings()); + error_code ec; + add_torrent_params p = parse_magnet_uri("magnet:?xt=urn:btih:abaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&dht=test:1234", ec); + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + TEST_CHECK(h.is_valid()); + TEST_CHECK(h.torrent_file()->nodes().size() == 1); + TEST_CHECK(h.torrent_file()->nodes().at(0).first == "test"); + TEST_CHECK(h.torrent_file()->nodes().at(0).second == 1234); +} +*/ TORRENT_TEST(invalid_tracker_escaping) { error_code ec;