forked from premiere/premiere-libtorrent
added support for authentication in the url_parser and added a test for it
This commit is contained in:
parent
e58c161057
commit
cbd67ed729
|
@ -76,7 +76,7 @@ namespace libtorrent
|
||||||
// returns -1 if gzip header is invalid or the header size in bytes
|
// returns -1 if gzip header is invalid or the header size in bytes
|
||||||
TORRENT_EXPORT int gzip_header(const char* buf, int size);
|
TORRENT_EXPORT int gzip_header(const char* buf, int size);
|
||||||
|
|
||||||
TORRENT_EXPORT boost::tuple<std::string, std::string, int, std::string>
|
TORRENT_EXPORT boost::tuple<std::string, std::string, std::string, int, std::string>
|
||||||
parse_url_components(std::string url);
|
parse_url_components(std::string url);
|
||||||
|
|
||||||
struct TORRENT_EXPORT tracker_request
|
struct TORRENT_EXPORT tracker_request
|
||||||
|
|
|
@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined (TORRENT_UPNP_LOGGING)
|
||||||
#define TORRENT_UPNP_LOGGING
|
#define TORRENT_UPNP_LOGGING
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string m_server_string;
|
std::string m_server_string;
|
||||||
http_parser m_parser;
|
http_parser m_parser;
|
||||||
|
std::string m_auth;
|
||||||
std::string m_host;
|
std::string m_host;
|
||||||
int m_port;
|
int m_port;
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
|
|
|
@ -47,15 +47,18 @@ void http_connection::get(std::string const& url, time_duration timeout
|
||||||
{
|
{
|
||||||
m_redirect = handle_redirect;
|
m_redirect = handle_redirect;
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
|
std::string auth;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
std::string path;
|
std::string path;
|
||||||
int port;
|
int port;
|
||||||
boost::tie(protocol, hostname, port, path) = parse_url_components(url);
|
boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
|
||||||
std::stringstream headers;
|
std::stringstream headers;
|
||||||
headers << "GET " << path << " HTTP/1.0\r\n"
|
headers << "GET " << path << " HTTP/1.0\r\n"
|
||||||
"Host:" << hostname <<
|
"Host:" << hostname <<
|
||||||
"\r\nConnection: close\r\n"
|
"\r\nConnection: close\r\n";
|
||||||
"\r\n";
|
if (!auth.empty())
|
||||||
|
headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
|
||||||
|
headers << "\r\n";
|
||||||
sendbuffer = headers.str();
|
sendbuffer = headers.str();
|
||||||
start(hostname, boost::lexical_cast<std::string>(port), timeout);
|
start(hostname, boost::lexical_cast<std::string>(port), timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2426,7 +2426,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(i->info[j].peer != m_remote || i->finished_blocks[j]);
|
assert(i->info[j].peer != m_remote || i->info[j].finished);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1383,12 +1383,15 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
|
std::string auth;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
int port;
|
int port;
|
||||||
std::string path;
|
std::string path;
|
||||||
boost::tie(protocol, hostname, port, path)
|
boost::tie(protocol, auth, hostname, port, path)
|
||||||
= parse_url_components(url);
|
= parse_url_components(url);
|
||||||
|
|
||||||
|
// TODO: should auth be used here?
|
||||||
|
|
||||||
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
|
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
|
||||||
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
||||||
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
|
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
|
||||||
|
@ -1427,11 +1430,11 @@ namespace libtorrent
|
||||||
if (m_ses.is_aborted()) return;
|
if (m_ses.is_aborted()) return;
|
||||||
|
|
||||||
tcp::endpoint a(host->endpoint());
|
tcp::endpoint a(host->endpoint());
|
||||||
std::string protocol;
|
|
||||||
|
using boost::tuples::ignore;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
int port;
|
int port;
|
||||||
std::string path;
|
boost::tie(ignore, ignore, hostname, port, ignore)
|
||||||
boost::tie(protocol, hostname, port, path)
|
|
||||||
= parse_url_components(url);
|
= parse_url_components(url);
|
||||||
|
|
||||||
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
||||||
|
|
|
@ -424,11 +424,13 @@ namespace libtorrent
|
||||||
|
|
||||||
m_connections.erase(i);
|
m_connections.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple<std::string, std::string, int, std::string>
|
// returns protocol, auth, hostname, port, path
|
||||||
|
tuple<std::string, std::string, std::string, int, std::string>
|
||||||
parse_url_components(std::string url)
|
parse_url_components(std::string url)
|
||||||
{
|
{
|
||||||
std::string hostname; // hostname only
|
std::string hostname; // hostname only
|
||||||
|
std::string auth; // user:pass
|
||||||
std::string protocol; // should be http
|
std::string protocol; // should be http
|
||||||
int port = 80;
|
int port = 80;
|
||||||
|
|
||||||
|
@ -439,7 +441,7 @@ namespace libtorrent
|
||||||
++start;
|
++start;
|
||||||
std::string::iterator end
|
std::string::iterator end
|
||||||
= std::find(url.begin(), url.end(), ':');
|
= std::find(url.begin(), url.end(), ':');
|
||||||
protocol = std::string(start, end);
|
protocol.assign(start, end);
|
||||||
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url");
|
if (end == url.end()) throw std::runtime_error("invalid url");
|
||||||
++end;
|
++end;
|
||||||
|
@ -451,7 +453,20 @@ namespace libtorrent
|
||||||
++end;
|
++end;
|
||||||
start = end;
|
start = end;
|
||||||
|
|
||||||
|
std::string::iterator at = std::find(start, url.end(), '@');
|
||||||
|
std::string::iterator colon = std::find(start, url.end(), ':');
|
||||||
end = std::find(start, url.end(), '/');
|
end = std::find(start, url.end(), '/');
|
||||||
|
|
||||||
|
if (at != url.end()
|
||||||
|
&& colon != url.end()
|
||||||
|
&& colon < at
|
||||||
|
&& at < end)
|
||||||
|
{
|
||||||
|
auth.assign(start, at);
|
||||||
|
start = at;
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
|
||||||
std::string::iterator port_pos
|
std::string::iterator port_pos
|
||||||
= std::find(start, url.end(), ':');
|
= std::find(start, url.end(), ':');
|
||||||
|
|
||||||
|
@ -475,7 +490,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
start = end;
|
start = end;
|
||||||
return make_tuple(protocol, hostname, port
|
return make_tuple(protocol, auth, hostname, port
|
||||||
, std::string(start, url.end()));
|
, std::string(start, url.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +514,9 @@ namespace libtorrent
|
||||||
int port;
|
int port;
|
||||||
std::string request_string;
|
std::string request_string;
|
||||||
|
|
||||||
boost::tie(protocol, hostname, port, request_string)
|
using boost::tuples::ignore;
|
||||||
|
// TODO: should auth be used here?
|
||||||
|
boost::tie(protocol, ignore, hostname, port, request_string)
|
||||||
= parse_url_components(req.url);
|
= parse_url_components(req.url);
|
||||||
|
|
||||||
boost::intrusive_ptr<tracker_connection> con;
|
boost::intrusive_ptr<tracker_connection> con;
|
||||||
|
|
|
@ -391,10 +391,14 @@ try
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
|
std::string auth;
|
||||||
// we don't have this device in our list. Add it
|
// we don't have this device in our list. Add it
|
||||||
boost::tie(protocol, d.hostname, d.port, d.path)
|
boost::tie(protocol, auth, d.hostname, d.port, d.path)
|
||||||
= parse_url_components(d.url);
|
= parse_url_components(d.url);
|
||||||
|
|
||||||
|
// ignore the auth here. It will be re-parsed
|
||||||
|
// by the http connection later
|
||||||
|
|
||||||
if (protocol != "http")
|
if (protocol != "http")
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_UPNP_LOGGING
|
#ifdef TORRENT_UPNP_LOGGING
|
||||||
|
|
|
@ -94,9 +94,12 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
boost::tie(protocol, m_host, m_port, m_path)
|
boost::tie(protocol, m_auth, m_host, m_port, m_path)
|
||||||
= parse_url_components(url);
|
= parse_url_components(url);
|
||||||
|
|
||||||
|
if (!m_auth.empty())
|
||||||
|
m_auth = base64encode(m_auth);
|
||||||
|
|
||||||
m_server_string = "URL seed @ ";
|
m_server_string = "URL seed @ ";
|
||||||
m_server_string += m_host;
|
m_server_string += m_host;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +204,11 @@ namespace libtorrent
|
||||||
request += "\r\nUser-Agent: ";
|
request += "\r\nUser-Agent: ";
|
||||||
request += m_ses.settings().user_agent;
|
request += m_ses.settings().user_agent;
|
||||||
}
|
}
|
||||||
|
if (!m_auth.empty())
|
||||||
|
{
|
||||||
|
request += "\r\nAuthorization: Basic ";
|
||||||
|
request += m_auth;
|
||||||
|
}
|
||||||
if (ps.type == proxy_settings::http_pw)
|
if (ps.type == proxy_settings::http_pw)
|
||||||
{
|
{
|
||||||
request += "\r\nProxy-Authorization: Basic ";
|
request += "\r\nProxy-Authorization: Basic ";
|
||||||
|
@ -253,6 +261,11 @@ namespace libtorrent
|
||||||
request += "\r\nUser-Agent: ";
|
request += "\r\nUser-Agent: ";
|
||||||
request += m_ses.settings().user_agent;
|
request += m_ses.settings().user_agent;
|
||||||
}
|
}
|
||||||
|
if (!m_auth.empty())
|
||||||
|
{
|
||||||
|
request += "\r\nAuthorization: Basic ";
|
||||||
|
request += m_auth;
|
||||||
|
}
|
||||||
if (ps.type == proxy_settings::http_pw)
|
if (ps.type == proxy_settings::http_pw)
|
||||||
{
|
{
|
||||||
request += "\r\nProxy-Authorization: Basic ";
|
request += "\r\nProxy-Authorization: Basic ";
|
||||||
|
|
|
@ -16,6 +16,7 @@ test-suite libtorrent :
|
||||||
[ run test_piece_picker.cpp ]
|
[ run test_piece_picker.cpp ]
|
||||||
# [ run test_entry.cpp ]
|
# [ run test_entry.cpp ]
|
||||||
[ run test_bencoding.cpp ]
|
[ run test_bencoding.cpp ]
|
||||||
|
[ run test_primitives.cpp ]
|
||||||
[ run test_ip_filter.cpp ]
|
[ run test_ip_filter.cpp ]
|
||||||
[ run test_hasher.cpp ]
|
[ run test_hasher.cpp ]
|
||||||
[ run test_metadata_extension.cpp ]
|
[ run test_metadata_extension.cpp ]
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
#include <boost/tuple/tuple_comparison.hpp>
|
||||||
|
|
||||||
|
#include "test.hpp"
|
||||||
|
|
||||||
|
using namespace libtorrent;
|
||||||
|
using namespace boost::tuples;
|
||||||
|
|
||||||
|
tuple<int, int> feed_bytes(http_parser& parser, char const* str)
|
||||||
|
{
|
||||||
|
tuple<int, int> ret(0, 0);
|
||||||
|
buffer::const_interval recv_buf(str, str + 1);
|
||||||
|
for (; *str; ++str)
|
||||||
|
{
|
||||||
|
recv_buf.end = str + 1;
|
||||||
|
int payload, protocol;
|
||||||
|
tie(payload, protocol) = parser.incoming(recv_buf);
|
||||||
|
ret.get<0>() += payload;
|
||||||
|
ret.get<1>() += protocol;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
TEST_CHECK(parse_url_components("http://foo:bar@host.com:80/path/to/file")
|
||||||
|
== make_tuple("http", "foo:bar", "host.com", 80, "/path/to/file"));
|
||||||
|
|
||||||
|
TEST_CHECK(parse_url_components("http://host.com/path/to/file")
|
||||||
|
== make_tuple("http", "", "host.com", 80, "/path/to/file"));
|
||||||
|
|
||||||
|
TEST_CHECK(parse_url_components("ftp://host.com:21/path/to/file")
|
||||||
|
== make_tuple("ftp", "", "host.com", 21, "/path/to/file"));
|
||||||
|
|
||||||
|
TEST_CHECK(parse_url_components("http://host.com/path?foo:bar@foo:")
|
||||||
|
== make_tuple("http", "", "host.com", 80, "/path?foo:bar@foo:"));
|
||||||
|
|
||||||
|
// base64 test vectors from http://www.faqs.org/rfcs/rfc4648.html
|
||||||
|
|
||||||
|
TEST_CHECK(base64encode("") == "");
|
||||||
|
TEST_CHECK(base64encode("f") == "Zg==");
|
||||||
|
TEST_CHECK(base64encode("fo") == "Zm8=");
|
||||||
|
TEST_CHECK(base64encode("foo") == "Zm9v");
|
||||||
|
TEST_CHECK(base64encode("foob") == "Zm9vYg==");
|
||||||
|
TEST_CHECK(base64encode("fooba") == "Zm9vYmE=");
|
||||||
|
TEST_CHECK(base64encode("foobar") == "Zm9vYmFy");
|
||||||
|
|
||||||
|
// HTTP request parser
|
||||||
|
|
||||||
|
http_parser parser;
|
||||||
|
boost::tuple<int, int> received = feed_bytes(parser
|
||||||
|
, "HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Length: 4\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"test");
|
||||||
|
|
||||||
|
TEST_CHECK(received == make_tuple(4, 64));
|
||||||
|
TEST_CHECK(parser.finished());
|
||||||
|
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end, "test"));
|
||||||
|
TEST_CHECK(parser.header<std::string>("content-type") == "text/plain");
|
||||||
|
TEST_CHECK(parser.header<int>("content-length") == 4);
|
||||||
|
|
||||||
|
parser.reset();
|
||||||
|
|
||||||
|
TEST_CHECK(!parser.finished());
|
||||||
|
|
||||||
|
char const* upnp_response =
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"ST:upnp:rootdevice\r\n"
|
||||||
|
"USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice\r\n"
|
||||||
|
"Location: http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc\r\n"
|
||||||
|
"Server: Custom/1.0 UPnP/1.0 Proc/Ver\r\n"
|
||||||
|
"EXT:\r\n"
|
||||||
|
"Cache-Control:max-age=180\r\n"
|
||||||
|
"DATE: Fri, 02 Jan 1970 08:10:38 GMT\r\n\r\n";
|
||||||
|
|
||||||
|
received = feed_bytes(parser, upnp_response);
|
||||||
|
|
||||||
|
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response))));
|
||||||
|
TEST_CHECK(parser.get_body().left() == 0);
|
||||||
|
TEST_CHECK(parser.header<std::string>("st") == "upnp:rootdevice");
|
||||||
|
TEST_CHECK(parser.header<std::string>("location")
|
||||||
|
== "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc");
|
||||||
|
TEST_CHECK(parser.header<std::string>("ext") == "");
|
||||||
|
TEST_CHECK(parser.header<std::string>("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue