improve magnet link support. in RSS feeds for instance. Parsing of magnet links was factored out and moved to the proper place, in session_impl::add_torrent

This commit is contained in:
Arvid Norberg 2012-03-08 09:54:44 +00:00
parent 9bd40e950b
commit 341967dab7
10 changed files with 129 additions and 67 deletions

View File

@ -4,6 +4,8 @@
#include <list> #include <list>
#include <string> #include <string>
#include "Python.h"
#include <cctype>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <libtorrent/session.hpp> #include <libtorrent/session.hpp>
#include <libtorrent/settings.hpp> // for bencode_map_entry #include <libtorrent/settings.hpp> // for bencode_map_entry
@ -154,12 +156,6 @@ namespace
if (params.has_key("ti")) if (params.has_key("ti"))
p.ti = extract<intrusive_ptr<torrent_info> >(params["ti"]); p.ti = extract<intrusive_ptr<torrent_info> >(params["ti"]);
std::string url;
if (params.has_key("tracker_url"))
{
string_storage.push_back(extract<std::string>(params["tracker_url"]));
p.tracker_url = string_storage.back().c_str();
}
if (params.has_key("info_hash")) if (params.has_key("info_hash"))
p.info_hash = extract<sha1_hash>(params["info_hash"]); p.info_hash = extract<sha1_hash>(params["info_hash"]);
if (params.has_key("name")) if (params.has_key("name"))
@ -179,7 +175,28 @@ namespace
if (params.has_key("storage_mode")) if (params.has_key("storage_mode"))
p.storage_mode = extract<storage_mode_t>(params["storage_mode"]); p.storage_mode = extract<storage_mode_t>(params["storage_mode"]);
if (params.has_key("tracker_url"))
{
list l = extract<list>(params["trackers"]);
int n = boost::python::len(l);
for(int i = 0; i < n; i++)
p.trackers.push_back(extract<std::string>(l[i]));
}
if (params.has_key("dht_nodes"))
{
list l = extract<list>(params["dht_nodes"]);
int n = boost::python::len(l);
for(int i = 0; i < n; i++)
p.dht_nodes.push_back(extract<std::pair<std::string, int> >(l[i]));
}
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
std::string url;
if (params.has_key("tracker_url"))
{
string_storage.push_back(extract<std::string>(params["tracker_url"]));
p.tracker_url = string_storage.back().c_str();
}
if (params.has_key("seed_mode")) if (params.has_key("seed_mode"))
p.seed_mode = params["seed_mode"]; p.seed_mode = params["seed_mode"];
if (params.has_key("upload_mode")) if (params.has_key("upload_mode"))

View File

@ -399,10 +399,14 @@ async_add_torrent() add_torrent()
int version; int version;
boost::intrusive_ptr<torrent_info> ti; boost::intrusive_ptr<torrent_info> ti;
#ifndef TORRENT_NO_DEPRECATE
char const* tracker_url; char const* tracker_url;
#endif
std::vector<std::string> trackers;
std::vector<std::pair<std::string, int> > dht_nodes;
sha1_hash info_hash; sha1_hash info_hash;
char const* name; std::string name;
fs::path save_path; std::string save_path;
std::vector<char>* resume_data; std::vector<char>* resume_data;
storage_mode_t storage_mode; storage_mode_t storage_mode;
storage_constructor_type storage; storage_constructor_type storage;
@ -438,18 +442,22 @@ torrent file), the ``info_hash`` (the info hash of the torrent) or the ``url``
info-hash, the torrent file will be downloaded from peers, which requires them to info-hash, the torrent file will be downloaded from peers, which requires them to
support the metadata extension. For the metadata extension to work, libtorrent must support the metadata extension. For the metadata extension to work, libtorrent must
be built with extensions enabled (``TORRENT_DISABLE_EXTENSIONS`` must not be be built with extensions enabled (``TORRENT_DISABLE_EXTENSIONS`` must not be
defined). It also takes an optional ``name`` argument. This may be 0 in case no defined). It also takes an optional ``name`` argument. This may be left empty in case no
name should be assigned to the torrent. In case it's not 0, the name is used for name should be assigned to the torrent. In case it's not, the name is used for
the torrent as long as it doesn't have metadata. See ``torrent_handle::name``. the torrent as long as it doesn't have metadata. See ``torrent_handle::name``.
If the torrent doesn't have a tracker, but relies on the DHT to find peers, the If the torrent doesn't have a tracker, but relies on the DHT to find peers, the
``tracker_url`` can be 0, otherwise you might specify a tracker url that tracks this ``trackers`` (or the deprecated ``tracker_url``) can specify tracker urls that
torrent. for the torrent.
If you specify a ``url``, the torrent will be set in ``downloading_metadata`` state If you specify a ``url``, the torrent will be set in ``downloading_metadata`` state
until the .torrent file has been downloaded. If there's any error while downloading, until the .torrent file has been downloaded. If there's any error while downloading,
the torrent will be stopped and the torrent error state (``torrent_status::error``) the torrent will be stopped and the torrent error state (``torrent_status::error``)
will indicate what went wrong. The ``url`` may also refer to a magnet link. will indicate what went wrong. The ``url`` may refer to a magnet link or a regular
http URL.
``dht_nodes`` is 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.
If the torrent you are trying to add already exists in the session (is either queued If the torrent you are trying to add already exists in the session (is either queued
for checking, being checked or downloading) ``add_torrent()`` will throw for checking, being checked or downloading) ``add_torrent()`` will throw
@ -6031,6 +6039,8 @@ it will throw libtorrent_exception_.
add_magnet_uri() add_magnet_uri()
---------------- ----------------
*deprecated*
:: ::
torrent_handle add_magnet_uri(session& ses, std::string const& uri torrent_handle add_magnet_uri(session& ses, std::string const& uri
@ -6052,6 +6062,16 @@ link through ``add_torrent_params::url`` argument to ``session::add_torrent()``.
For more information about magnet links, see `magnet links`_. For more information about magnet links, see `magnet links`_.
parse_magnet_uri()
------------------
::
void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec);
This function parses out information from the magnet link and populates the
``add_torrent_params`` object.
make_magnet_uri() make_magnet_uri()
----------------- -----------------

View File

@ -49,8 +49,9 @@ namespace libtorrent
{ {
add_torrent_params(storage_constructor_type sc = default_storage_constructor) add_torrent_params(storage_constructor_type sc = default_storage_constructor)
: version(LIBTORRENT_VERSION_NUM) : version(LIBTORRENT_VERSION_NUM)
#ifndef TORRENT_NO_DEPRECATE
, tracker_url(0) , tracker_url(0)
, name(0) #endif
, resume_data(0) , resume_data(0)
, storage_mode(storage_mode_sparse) , storage_mode(storage_mode_sparse)
, storage(sc) , storage(sc)
@ -114,9 +115,13 @@ namespace libtorrent
// libtorrent version. Used for forward binary compatibility // libtorrent version. Used for forward binary compatibility
int version; int version;
boost::intrusive_ptr<torrent_info> ti; boost::intrusive_ptr<torrent_info> ti;
#ifndef TORRENT_NO_DEPRECATE
char const* tracker_url; char const* tracker_url;
#endif
std::vector<std::string> trackers;
std::vector<std::pair<std::string, int> > dht_nodes;
sha1_hash info_hash; sha1_hash info_hash;
char const* name; std::string name;
std::string save_path; std::string save_path;
std::vector<char>* resume_data; std::vector<char>* resume_data;
storage_mode_t storage_mode; storage_mode_t storage_mode;

View File

@ -46,23 +46,31 @@ namespace libtorrent
std::string TORRENT_EXPORT make_magnet_uri(torrent_handle const& handle); std::string TORRENT_EXPORT make_magnet_uri(torrent_handle const& handle);
std::string TORRENT_EXPORT make_magnet_uri(torrent_info const& info); std::string TORRENT_EXPORT make_magnet_uri(torrent_info const& info);
#ifndef BOOST_NO_EXCEPTIONS
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_EXCEPTIONS
// deprecated in 0.14 // deprecated in 0.14
TORRENT_DEPRECATED_PREFIX
torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri
, std::string const& save_path , std::string const& save_path
, storage_mode_t storage_mode = storage_mode_sparse , storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false , bool paused = false
, storage_constructor_type sc = default_storage_constructor , storage_constructor_type sc = default_storage_constructor
, void* userdata = 0) TORRENT_DEPRECATED; , void* userdata = 0) TORRENT_DEPRECATED;
// deprecated in 0.16. Instead, pass in the magnet link as add_torrent_params::url
TORRENT_DEPRECATED_PREFIX
torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri
, add_torrent_params p) TORRENT_DEPRECATED;
#endif #endif
// deprecated in 0.16. Instead, pass in the magnet link as add_torrent_params::url
TORRENT_DEPRECATED_PREFIX
torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri
, add_torrent_params p); , add_torrent_params p, error_code& ec) TORRENT_DEPRECATED;
#endif #endif
torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri TORRENT_EXPORT void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec);
, add_torrent_params p, error_code& ec);
} }
#endif #endif

View File

@ -137,8 +137,16 @@ namespace libtorrent
return ret; return ret;
} }
#endif #endif
torrent_handle add_magnet_uri(session& ses, std::string const& uri torrent_handle add_magnet_uri(session& ses, std::string const& uri
, add_torrent_params p, error_code& ec) , add_torrent_params p, error_code& ec)
{
parse_magnet_uri(uri, p, ec);
if (ec) return torrent_handle();
return ses.add_torrent(p, ec);
}
void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec)
{ {
std::string name; std::string name;
std::string tracker; std::string tracker;
@ -146,21 +154,32 @@ namespace libtorrent
error_code e; error_code e;
std::string display_name = url_has_argument(uri, "dn"); std::string display_name = url_has_argument(uri, "dn");
if (!display_name.empty()) name = unescape_string(display_name.c_str(), e); if (!display_name.empty()) name = unescape_string(display_name.c_str(), e);
// parse trackers out of the magnet link
std::string::size_type pos = std::string::npos; std::string::size_type pos = std::string::npos;
std::string tracker_string = url_has_argument(uri, "tr", &pos); do
if (!tracker_string.empty()) tracker = unescape_string(tracker_string.c_str(), e); {
pos = uri.find("&tr=", pos);
if (pos == std::string::npos) break;
pos += 4;
error_code e;
std::string url = unescape_string(uri.substr(pos, uri.find('&', pos) - pos), e);
if (e) continue;
p.trackers.push_back(url);
}
while (pos != std::string::npos);
std::string btih = url_has_argument(uri, "xt"); std::string btih = url_has_argument(uri, "xt");
if (btih.empty()) if (btih.empty())
{ {
ec = errors::missing_info_hash_in_uri; ec = errors::missing_info_hash_in_uri;
return torrent_handle(); return;
} }
if (btih.compare(0, 9, "urn:btih:") != 0) if (btih.compare(0, 9, "urn:btih:") != 0)
{ {
ec = errors::missing_info_hash_in_uri; ec = errors::missing_info_hash_in_uri;
return torrent_handle(); return;
} }
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
@ -173,7 +192,7 @@ namespace libtorrent
{ {
int port = atoi(node.c_str()+divider+1); int port = atoi(node.c_str()+divider+1);
if (port != 0) if (port != 0)
ses.add_dht_node(std::make_pair(node.substr(0, divider), port)); p.dht_nodes.push_back(std::make_pair(node.substr(0, divider), port));
} }
node_pos = uri.find("&dht=", node_pos); node_pos = uri.find("&dht=", node_pos);
@ -187,26 +206,8 @@ namespace libtorrent
if (btih.size() == 40 + 9) from_hex(&btih[9], 40, (char*)&info_hash[0]); if (btih.size() == 40 + 9) from_hex(&btih[9], 40, (char*)&info_hash[0]);
else info_hash.assign(base32decode(btih.substr(9))); else info_hash.assign(base32decode(btih.substr(9)));
if (!tracker.empty()) p.tracker_url = tracker.c_str();
p.info_hash = info_hash; p.info_hash = info_hash;
if (!name.empty()) p.name = name.c_str(); if (!name.empty()) p.name = name;
torrent_handle ret = ses.add_torrent(p, ec);
int tier = 1;
// there might be more trackers in the url
while (pos != std::string::npos)
{
pos = uri.find("&tr=", pos);
if (pos == std::string::npos) break;
pos += 4;
error_code e;
std::string url = unescape_string(uri.substr(pos, uri.find('&', pos) - pos), e);
if (e) continue;
announce_entry ae(url);
ae.tier = tier++;
ret.add_tracker(ae);
}
return ret;
} }
} }

View File

@ -391,7 +391,6 @@ void feed::on_feed(error_code const& ec
p.name = i->title.c_str(); p.name = i->title.c_str();
error_code e; error_code e;
// #error session_impl::add_torrent doesn't support magnet links via url
torrent_handle h = m_ses.add_torrent(p, e); torrent_handle h = m_ses.add_torrent(p, e);
m_ses.m_alerts.post_alert(add_torrent_alert(h, p, e)); m_ses.m_alerts.post_alert(add_torrent_alert(h, p, e));
m_added.insert(make_pair(i->url, now)); m_added.insert(make_pair(i->url, now));

View File

@ -591,13 +591,6 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
torrent_handle session::add_torrent(add_torrent_params const& params) torrent_handle session::add_torrent(add_torrent_params const& params)
{ {
if (string_begins_no_case("magnet:", params.url.c_str()))
{
add_torrent_params p(params);
p.url.clear();
return add_magnet_uri(*this, params.url, p);
}
error_code ec; error_code ec;
TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec)); TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec));
if (ec) throw libtorrent_exception(ec); if (ec) throw libtorrent_exception(ec);
@ -608,13 +601,6 @@ namespace libtorrent
torrent_handle session::add_torrent(add_torrent_params const& params, error_code& ec) torrent_handle session::add_torrent(add_torrent_params const& params, error_code& ec)
{ {
ec.clear(); ec.clear();
if (string_begins_no_case("magnet:", params.url.c_str()))
{
add_torrent_params p(params);
p.url.clear();
return add_magnet_uri(*this, params.url, p, ec);
}
TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec)); TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec));
return r; return r;
} }
@ -623,8 +609,6 @@ namespace libtorrent
{ {
add_torrent_params* p = new add_torrent_params(params); add_torrent_params* p = new add_torrent_params(params);
if (params.resume_data) p->resume_data = new std::vector<char>(*params.resume_data); if (params.resume_data) p->resume_data = new std::vector<char>(*params.resume_data);
if (params.tracker_url) p->tracker_url = strdup(params.tracker_url);
if (params.name) p->name = strdup(params.name);
TORRENT_ASYNC_CALL1(async_add_torrent, p); TORRENT_ASYNC_CALL1(async_add_torrent, p);
} }

View File

@ -81,6 +81,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/build_config.hpp" #include "libtorrent/build_config.hpp"
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/random.hpp" #include "libtorrent/random.hpp"
#include "libtorrent/magnet_uri.hpp"
#if defined TORRENT_STATS && defined __MACH__ #if defined TORRENT_STATS && defined __MACH__
#include <mach/task.h> #include <mach/task.h>
@ -4724,26 +4725,42 @@ namespace aux {
torrent_handle handle = add_torrent(*params, ec); torrent_handle handle = add_torrent(*params, ec);
m_alerts.post_alert(add_torrent_alert(handle, *params, ec)); m_alerts.post_alert(add_torrent_alert(handle, *params, ec));
delete params->resume_data; delete params->resume_data;
free((char*)params->tracker_url);
free((char*)params->name);
delete params; delete params;
} }
torrent_handle session_impl::add_torrent(add_torrent_params const& params torrent_handle session_impl::add_torrent(add_torrent_params const& p
, error_code& ec) , error_code& ec)
{ {
TORRENT_ASSERT(!params.save_path.empty()); TORRENT_ASSERT(!p.save_path.empty());
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
params.update_flags(); p.update_flags();
#endif #endif
add_torrent_params params = p;
if (string_begins_no_case("magnet:", params.url.c_str()))
{
parse_magnet_uri(params.url, params, ec);
if (ec) return torrent_handle();
params.url.clear();
}
if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0) if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0)
{ {
ec = errors::no_files_in_torrent; ec = errors::no_files_in_torrent;
return torrent_handle(); return torrent_handle();
} }
#ifndef TORRENT_DISABLE_DHT
// add p.dht_nodes to the DHT, if enabled
if (m_dht && !p.dht_nodes.empty())
{
for (std::vector<std::pair<std::string, int> >::const_iterator i = p.dht_nodes.begin()
, end(p.dht_nodes.end()); i != end; ++i)
m_dht->add_node(*i);
}
#endif
// INVARIANT_CHECK; // INVARIANT_CHECK;
if (is_aborted()) if (is_aborted())

View File

@ -520,7 +520,7 @@ namespace libtorrent
} }
else else
{ {
if (p.name) m_name.reset(new std::string(p.name)); if (!p.name.empty()) m_name.reset(new std::string(p.name));
} }
if (!m_url.empty() && m_uuid.empty()) m_uuid = m_url; if (!m_url.empty() && m_uuid.empty()) m_uuid = m_url;
@ -554,6 +554,7 @@ namespace libtorrent
if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url)); if (!m_name && !m_url.empty()) m_name.reset(new std::string(m_url));
#ifndef TORRENT_NO_DEPRECATE
if (p.tracker_url && std::strlen(p.tracker_url) > 0) if (p.tracker_url && std::strlen(p.tracker_url) > 0)
{ {
m_trackers.push_back(announce_entry(p.tracker_url)); m_trackers.push_back(announce_entry(p.tracker_url));
@ -561,6 +562,16 @@ namespace libtorrent
m_trackers.back().source = announce_entry::source_magnet_link; m_trackers.back().source = announce_entry::source_magnet_link;
m_torrent_file->add_tracker(p.tracker_url); m_torrent_file->add_tracker(p.tracker_url);
} }
#endif
for (std::vector<std::string>::const_iterator i = p.trackers.begin()
, end(p.trackers.end()); i != end; ++i)
{
m_trackers.push_back(announce_entry(*i));
m_trackers.back().fail_limit = 0;
m_trackers.back().source = announce_entry::source_magnet_link;
m_torrent_file->add_tracker(*i);
}
if (settings().prefer_udp_trackers) if (settings().prefer_udp_trackers)
prioritize_udp_trackers(); prioritize_udp_trackers();

View File

@ -1132,7 +1132,7 @@ int test_main()
TEST_CHECK(f.open("test_file", file::read_write, ec)); TEST_CHECK(f.open("test_file", file::read_write, ec));
#endif #endif
TEST_CHECK(!ec); TEST_CHECK(!ec);
file::iovec_t b = {"test", 4}; file::iovec_t b = {(void*)"test", 4};
TEST_CHECK(f.writev(0, &b, 1, ec) == 4); TEST_CHECK(f.writev(0, &b, 1, ec) == 4);
TEST_CHECK(!ec); TEST_CHECK(!ec);
char test_buf[5] = {0}; char test_buf[5] = {0};