diff --git a/include/libtorrent/add_torrent_params.hpp b/include/libtorrent/add_torrent_params.hpp index f3fb21d07..7e4c3e77b 100644 --- a/include/libtorrent/add_torrent_params.hpp +++ b/include/libtorrent/add_torrent_params.hpp @@ -247,6 +247,9 @@ namespace libtorrent // ``trackers`` can specify tracker URLs for the torrent. std::vector trackers; + // url seeds to be added to the torrent (`BEP 17`_). + std::vector url_seeds; + // a list of hostname and port pairs, representing DHT nodes to be // added to the session (if DHT is enabled). The hostname may be an IP address. std::vector > dht_nodes; diff --git a/src/magnet_uri.cpp b/src/magnet_uri.cpp index a4d871a82..f95e13a36 100644 --- a/src/magnet_uri.cpp +++ b/src/magnet_uri.cpp @@ -50,7 +50,6 @@ namespace libtorrent ret += to_hex(ih.to_string()); torrent_status st = handle.status(torrent_handle::query_name); - if (!st.name.empty()) { ret += "&dn="; @@ -58,13 +57,20 @@ namespace libtorrent } std::vector const& tr = handle.trackers(); - for (std::vector::const_iterator i = tr.begin(), end(tr.end()); i != end; ++i) { ret += "&tr="; ret += escape_string(i->url.c_str(), i->url.length()); } + std::set seeds = handle.url_seeds(); + for (std::set::iterator i = seeds.begin() + , end(seeds.end()); i != end; ++i) + { + ret += "&ws="; + ret += escape_string(i->c_str(), i->length()); + } + return ret; } @@ -91,6 +97,16 @@ namespace libtorrent ret += escape_string(i->url.c_str(), i->url.length()); } + std::vector const& seeds = info.web_seeds(); + for (std::vector::const_iterator i = seeds.begin() + , end(seeds.end()); i != end; ++i) + { + if (i->type != web_seed_entry::url_seed) continue; + + ret += "&ws="; + ret += escape_string(i->url.c_str(), i->url.length()); + } + return ret; } @@ -170,7 +186,22 @@ namespace libtorrent pos += 4; url = uri.substr(pos, uri.find('&', pos) - pos); } - + + // parse web seeds out of the magnet link + pos = std::string::npos; + url = url_has_argument(uri, "ws", &pos); + while (pos != std::string::npos) + { + error_code e; + url = unescape_string(url, e); + if (e) continue; + p.url_seeds.push_back(url); + pos = uri.find("&ws=", pos); + if (pos == std::string::npos) break; + pos += 4; + url = uri.substr(pos, uri.find('&', pos) - pos); + } + std::string btih = url_has_argument(uri, "xt"); if (btih.empty()) { diff --git a/src/torrent.cpp b/src/torrent.cpp index 89d2b9fef..3a6985383 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -344,6 +344,13 @@ namespace libtorrent if (!m_torrent_file) m_torrent_file = (p.ti ? p.ti : new torrent_info(info_hash)); + // add web seeds from add_torrent_params + for (std::vector::const_iterator i = p.url_seeds.begin() + , end(p.url_seeds.end()); i != end; ++i) + { + m_web_seeds.push_back(web_seed_entry(*i, web_seed_entry::url_seed)); + } + m_trackers = m_torrent_file->trackers(); if (m_torrent_file->is_valid()) { diff --git a/test/test_magnet.cpp b/test/test_magnet.cpp index e8906b723..d28cc803a 100644 --- a/test/test_magnet.cpp +++ b/test/test_magnet.cpp @@ -161,6 +161,14 @@ int test_main() TEST_CHECK(ec == error_code(errors::missing_info_hash_in_uri)); ec.clear(); + // parse_magnet_uri + parse_magnet_uri("magnet:?xt=urn:btih:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd&ws=http://foo.com/bar&ws=http://bar.com/foo", p, ec); + TEST_CHECK(!ec); + TEST_EQUAL(p.url_seeds.size(), 2); + TEST_EQUAL(p.url_seeds[0], "http://foo.com/bar"); + TEST_EQUAL(p.url_seeds[1], "http://bar.com/foo"); + ec.clear(); + parse_magnet_uri("magnet:?xt=blah&dn=foo&dht=127.0.0.1:43", p, ec); TEST_CHECK(ec == error_code(errors::missing_info_hash_in_uri)); ec.clear(); @@ -263,6 +271,30 @@ int test_main() printf("%s len: %d\n", magnet.c_str(), int(magnet.size())); } + // make_magnet_uri + { + entry info; + info["pieces"] = "aaaaaaaaaaaaaaaaaaaa"; + info["name"] = "test"; + info["name.utf-8"] = "test"; + info["piece length"] = 16 * 1024; + info["length"] = 3245; + entry torrent; + torrent["info"] = info; + + torrent["url-list"] = "http://foo.com/bar"; + + std::vector buf; + bencode(std::back_inserter(buf), torrent); + buf.push_back('\0'); + printf("%s\n", &buf[0]); + error_code ec; + torrent_info ti(&buf[0], buf.size(), ec); + + std::string magnet = make_magnet_uri(ti); + printf("%s len: %d\n", magnet.c_str(), int(magnet.size())); + TEST_CHECK(magnet.find("&ws=http%3a%2f%2ffoo.com%2fbar") != std::string::npos); + } return 0; }