initial https support for trackers and http_connection. Added support for proxies to http_connection

This commit is contained in:
Arvid Norberg 2008-01-27 22:39:50 +00:00
parent 69f9a5b5fc
commit 61bbc6e58f
15 changed files with 495 additions and 63 deletions

View File

@ -45,7 +45,7 @@ rule linking ( properties * )
}
else
{
result += <library>crypto ;
result += <library>crypto <library>ssl ;
}
}
@ -210,6 +210,7 @@ lib thread : : <name>boost_thread $(library-search-path) ;
# openssl on linux/bsd/macos etc.
lib crypto : : <name>crypto ;
lib ssl : : <name>ssl ;
# time functions used on linux require librt
lib librt : : <name>rt ;

View File

@ -45,6 +45,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/socket_type.hpp"
#ifdef TORRENT_USE_OPENSSL
#include "libtorrent/ssl_stream.hpp"
#include "libtorrent/variant_stream.hpp"
#endif
namespace libtorrent
{
@ -57,6 +63,7 @@ typedef boost::function<void(asio::error_code const&
typedef boost::function<void(http_connection&)> http_connect_handler;
// TODO: add bind interface
// TODO: add gzip support
// when bottled, the last two arguments to the handler
// will always be 0
@ -81,6 +88,7 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
, m_redirects(5)
, m_connection_ticket(-1)
, m_cc(cc)
, m_ssl(false)
{
TORRENT_ASSERT(!m_handler.empty());
}
@ -93,13 +101,19 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
std::string sendbuffer;
void get(std::string const& url, time_duration timeout = seconds(30)
, int handle_redirects = 5);
, proxy_settings const* ps = 0, int handle_redirects = 5);
void start(std::string const& hostname, std::string const& port
, time_duration timeout, int handle_redirect = 5);
, time_duration timeout, proxy_settings const* ps = 0, bool ssl = false
, int handle_redirect = 5);
void close();
tcp::socket const& socket() const { return m_sock; }
#ifdef TORRENT_USE_OPENSSL
variant_stream<socket_type, ssl_stream<socket_type> > const& socket() const { return m_sock; }
#else
socket_type const& socket() const { return m_sock; }
#endif
private:
@ -118,7 +132,11 @@ private:
void callback(asio::error_code const& e, char const* data = 0, int size = 0);
std::vector<char> m_recvbuffer;
tcp::socket m_sock;
#ifdef TORRENT_USE_OPENSSL
variant_stream<socket_type, ssl_stream<socket_type> > m_sock;
#else
socket_type m_sock;
#endif
int m_read_pos;
tcp::resolver m_resolver;
http_parser m_parser;
@ -158,6 +176,13 @@ private:
int m_connection_ticket;
connection_queue& m_cc;
// specifies whether or not the connection is
// configured to use a proxy
proxy_settings m_proxy;
// true if the connection is using ssl
bool m_ssl;
};
}

View File

@ -63,6 +63,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/http_parser.hpp"
#ifdef TORRENT_USE_OPENSSL
#include "libtorrent/ssl_stream.hpp"
#include "libtorrent/variant_stream.hpp"
#endif
namespace libtorrent
{
@ -77,6 +82,7 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, std::string const& protocol
, std::string const& hostname
, unsigned short port
, std::string request
@ -116,7 +122,12 @@ namespace libtorrent
tcp::resolver m_name_lookup;
int m_port;
#ifdef TORRENT_USE_OPENSSL
variant_stream<socket_type, ssl_stream<socket_type> > m_socket;
bool m_ssl;
#else
socket_type m_socket;
#endif
int m_recv_pos;
std::vector<char> m_buffer;
std::string m_send_buffer;

View File

@ -141,25 +141,25 @@ public:
}
#ifndef BOOST_NO_EXCEPTIONS
endpoint_type remote_endpoint()
endpoint_type remote_endpoint() const
{
return m_remote_endpoint;
}
#endif
endpoint_type remote_endpoint(asio::error_code& ec)
endpoint_type remote_endpoint(asio::error_code& ec) const
{
return m_remote_endpoint;
}
#ifndef BOOST_NO_EXCEPTIONS
endpoint_type local_endpoint()
endpoint_type local_endpoint() const
{
return m_sock.local_endpoint();
}
#endif
endpoint_type local_endpoint(asio::error_code& ec)
endpoint_type local_endpoint(asio::error_code& ec) const
{
return m_sock.local_endpoint(ec);
}
@ -174,6 +174,8 @@ public:
return m_sock.lowest_layer();
}
bool is_open() const { return m_sock.is_open(); }
protected:
stream_socket m_sock;

View File

@ -0,0 +1,224 @@
/*
Copyright (c) 2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_SSL_STREAM_HPP_INCLUDED
#define TORRENT_SSL_STREAM_HPP_INCLUDED
#include "libtorrent/socket.hpp"
#include <asio/ssl.hpp>
// openssl seems to believe it owns
// this name in every single scope
#undef set_key
namespace libtorrent {
template <class Stream>
class ssl_stream
{
public:
explicit ssl_stream(asio::io_service& io_service)
: m_context(io_service, asio::ssl::context::sslv23_client)
, m_sock(io_service, m_context)
{
m_context.set_verify_mode(asio::ssl::context::verify_none);
}
typedef Stream next_layer_type;
typedef typename Stream::lowest_layer_type lowest_layer_type;
typedef typename Stream::endpoint_type endpoint_type;
typedef typename Stream::protocol_type protocol_type;
typedef typename asio::ssl::stream<Stream> sock_type;
typedef boost::function<void(asio::error_code const&)> handler_type;
template <class Handler>
void async_connect(endpoint_type const& endpoint, Handler const& handler)
{
// the connect is split up in the following steps:
// 1. connect to peer
// 2. perform SSL client handshake
// to avoid unnecessary copying of the handler,
// store it in a shaed_ptr
boost::shared_ptr<handler_type> h(new handler_type(handler));
m_sock.next_layer().async_connect(endpoint
, boost::bind(&ssl_stream::connected, this, _1, h));
}
template <class Mutable_Buffers, class Handler>
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
{
m_sock.async_read_some(buffers, handler);
}
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
{
return m_sock.read_some(buffers, ec);
}
#ifndef BOOST_NO_EXCEPTIONS
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers)
{
return m_sock.read_some(buffers);
}
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc)
{
m_sock.next_layer().io_control(ioc);
}
#endif
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
{
m_sock.next_layer().io_control(ioc, ec);
}
template <class Const_Buffers, class Handler>
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
{
m_sock.async_write_some(buffers, handler);
}
#ifndef BOOST_NO_EXCEPTIONS
void bind(endpoint_type const& endpoint)
{
m_sock.next_layer().bind(endpoint);
}
#endif
void bind(endpoint_type const& endpoint, asio::error_code& ec)
{
m_sock.next_layer().bind(endpoint, ec);
}
#ifndef BOOST_NO_EXCEPTIONS
void open(protocol_type const& p)
{
m_sock.next_layer().open(p);
}
#endif
void open(protocol_type const& p, asio::error_code& ec)
{
m_sock.next_layer().open(p, ec);
}
bool is_open() const
{
return const_cast<sock_type&>(m_sock).next_layer().is_open();
}
#ifndef BOOST_NO_EXCEPTIONS
void close()
{
m_sock.next_layer().close();
}
#endif
void close(asio::error_code& ec)
{
m_sock.next_layer().close(ec);
}
#ifndef BOOST_NO_EXCEPTIONS
endpoint_type remote_endpoint() const
{
return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint();
}
#endif
endpoint_type remote_endpoint(asio::error_code& ec) const
{
return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint(ec);
}
#ifndef BOOST_NO_EXCEPTIONS
endpoint_type local_endpoint() const
{
return const_cast<sock_type&>(m_sock).next_layer().local_endpoint();
}
#endif
endpoint_type local_endpoint(asio::error_code& ec) const
{
return const_cast<sock_type&>(m_sock).next_layer().local_endpoint(ec);
}
asio::io_service& io_service()
{
return m_sock.io_service();
}
lowest_layer_type& lowest_layer()
{
return m_sock.lowest_layer();
}
next_layer_type& next_layer()
{
return m_sock.next_layer();
}
private:
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
{
if (e)
{
(*h)(e);
return;
}
m_sock.async_handshake(asio::ssl::stream_base::client
, boost::bind(&ssl_stream::handshake, this, _1, h));
}
void handshake(asio::error_code const& e, boost::shared_ptr<handler_type> h)
{
(*h)(e);
}
asio::ssl::context m_context;
asio::ssl::stream<Stream> m_sock;
};
}
#endif

View File

@ -182,6 +182,20 @@ namespace aux
Protocol const& proto;
};
// -------------- is_open -----------
struct is_open_visitor
: boost::static_visitor<bool>
{
is_open_visitor() {}
template <class T>
bool operator()(T const* p) const
{ return p->is_open(); }
bool operator()(boost::blank) const { return false; }
};
// -------------- close -----------
struct close_visitor_ec
@ -221,7 +235,7 @@ namespace aux
{}
template <class T>
EndpointType operator()(T* p) const
EndpointType operator()(T const* p) const
{ return p->remote_endpoint(error_code); }
EndpointType operator()(boost::blank) const
@ -235,7 +249,7 @@ namespace aux
: boost::static_visitor<EndpointType>
{
template <class T>
EndpointType operator()(T* p) const
EndpointType operator()(T const* p) const
{ return p->remote_endpoint(); }
EndpointType operator()(boost::blank) const
@ -253,7 +267,7 @@ namespace aux
{}
template <class T>
EndpointType operator()(T* p) const
EndpointType operator()(T const* p) const
{
return p->local_endpoint(error_code);
}
@ -271,7 +285,7 @@ namespace aux
: boost::static_visitor<EndpointType>
{
template <class T>
EndpointType operator()(T* p) const
EndpointType operator()(T const* p) const
{
return p->local_endpoint();
}
@ -379,7 +393,7 @@ namespace aux
{}
template <class T>
std::size_t operator()(T* p) const
std::size_t operator()(T const* p) const
{
return p->in_avail(ec);
}
@ -396,7 +410,7 @@ namespace aux
: boost::static_visitor<std::size_t>
{
template <class T>
std::size_t operator()(T* p) const
std::size_t operator()(T const* p) const
{
return p->in_avail();
}
@ -414,7 +428,7 @@ namespace aux
template <class T>
IOService& operator()(T* p) const
{
return p->io_service();
return p->get_io_service();
}
IOService& operator()(boost::blank) const
@ -471,11 +485,13 @@ public:
typedef typename S0::endpoint_type endpoint_type;
typedef typename S0::protocol_type protocol_type;
explicit variant_stream() : m_variant(boost::blank()) {}
explicit variant_stream(asio::io_service& ios)
: m_io_service(ios), m_variant(boost::blank()) {}
template <class S>
void instantiate(asio::io_service& ios)
{
TORRENT_ASSERT(&ios == &m_io_service);
std::auto_ptr<S> owned(new S(ios));
boost::apply_visitor(aux::delete_visitor(), m_variant);
m_variant = owned.get();
@ -594,6 +610,11 @@ public:
);
}
bool is_open() const
{
return boost::apply_visitor(aux::is_open_visitor(), m_variant);
}
void close()
{
if (!instantiated()) return;
@ -608,13 +629,13 @@ public:
);
}
std::size_t in_avail()
std::size_t in_avail() const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(aux::in_avail_visitor(), m_variant);
}
std::size_t in_avail(asio::error_code& ec)
std::size_t in_avail(asio::error_code& ec) const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(
@ -622,13 +643,13 @@ public:
);
}
endpoint_type remote_endpoint()
endpoint_type remote_endpoint() const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant);
}
endpoint_type remote_endpoint(asio::error_code& ec)
endpoint_type remote_endpoint(asio::error_code& ec) const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(
@ -636,13 +657,13 @@ public:
);
}
endpoint_type local_endpoint()
endpoint_type local_endpoint() const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant);
}
endpoint_type local_endpoint(asio::error_code& ec)
endpoint_type local_endpoint(asio::error_code& ec) const
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(
@ -650,12 +671,9 @@ public:
);
}
asio::io_service& io_service()
asio::io_service& get_io_service()
{
TORRENT_ASSERT(instantiated());
return boost::apply_visitor(
aux::io_service_visitor<asio::io_service>(), m_variant
);
return m_io_service;
}
lowest_layer_type& lowest_layer()
@ -667,6 +685,7 @@ public:
}
private:
asio::io_service& m_io_service;
variant_type m_variant;
};

View File

@ -1742,7 +1742,7 @@ namespace libtorrent
// vc,crypto_select,len(pad),pad, encrypt(handshake)
// 8+4+2+0+handshake_len
reset_recv_buffer(8+4+2+0+handshake_len);
reset_recv_buffer(8+4+2+0+handshake_len);
}
else
{

View File

@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/http_connection.hpp"
#include "libtorrent/escape_string.hpp"
#include "libtorrent/instantiate_connection.hpp"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
@ -46,7 +47,7 @@ namespace libtorrent
enum { max_bottled_buffer = 1024 * 1024 };
void http_connection::get(std::string const& url, time_duration timeout
, int handle_redirects)
, proxy_settings const* ps, int handle_redirects)
{
std::string protocol;
std::string auth;
@ -54,21 +55,55 @@ void http_connection::get(std::string const& url, time_duration timeout
std::string path;
int port;
boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
bool ssl = false;
if (protocol == "https") ssl = true;
#ifndef TORRENT_USE_OPENSSL
if (ssl)
{
callback(asio::error::not_supported);
return;
}
#endif
std::stringstream headers;
headers << "GET " << path << " HTTP/1.0\r\n"
"Host:" << hostname <<
"\r\nConnection: close\r\n";
if (ps && (ps->type == proxy_settings::http
|| ps->type == proxy_settings::http_pw)
&& !ssl)
{
// if we're using an http proxy and not an ssl
// connection, just do a regular http proxy request
headers << "GET " << url << " HTTP/1.0\r\n"
"Connection: close\r\n";
if (ps->type == proxy_settings::http_pw)
headers << "Proxy-Authorization: Basic " << base64encode(
ps->username + ":" + ps->password) << "\r\n";
hostname = ps->hostname;
port = ps->port;
ps = 0;
}
else
{
headers << "GET " << path << " HTTP/1.0\r\n"
"Host:" << hostname << "\r\n"
"Connection: close\r\n";
}
if (!auth.empty())
headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
headers << "\r\n";
sendbuffer = headers.str();
start(hostname, boost::lexical_cast<std::string>(port), timeout, handle_redirects);
start(hostname, boost::lexical_cast<std::string>(port), timeout, ps
, ssl, handle_redirects);
}
void http_connection::start(std::string const& hostname, std::string const& port
, time_duration timeout, int handle_redirects)
, time_duration timeout, proxy_settings const* ps, bool ssl, int handle_redirects)
{
m_redirects = handle_redirects;
if (ps) m_proxy = *ps;
m_ssl = ssl;
m_timeout = timeout;
asio::error_code ec;
m_timer.expires_from_now(m_timeout, ec);
@ -78,6 +113,7 @@ void http_connection::start(std::string const& hostname, std::string const& port
m_parser.reset();
m_recvbuffer.clear();
m_read_pos = 0;
if (m_sock.is_open() && m_hostname == hostname && m_port == port)
{
asio::async_write(m_sock, asio::buffer(sendbuffer)
@ -87,6 +123,27 @@ void http_connection::start(std::string const& hostname, std::string const& port
{
asio::error_code ec;
m_sock.close(ec);
#ifdef TORRENT_USE_OPENSSL
if (m_ssl)
{
m_sock.instantiate<ssl_stream<socket_type> >(m_resolver.get_io_service());
ssl_stream<socket_type>& s = m_sock.get<ssl_stream<socket_type> >();
bool ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, s.next_layer());
TORRENT_ASSERT(ret);
}
else
{
m_sock.instantiate<socket_type>(m_resolver.get_io_service());
bool ret = instantiate_connection(m_resolver.get_io_service()
, m_proxy, m_sock.get<socket_type>());
TORRENT_ASSERT(ret);
}
#else
bool ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, m_sock);
TORRENT_ASSERT(ret);
#endif
tcp::resolver::query query(hostname, port);
m_resolver.async_resolve(query, bind(&http_connection::on_resolve
, shared_from_this(), _1, _2));
@ -295,7 +352,7 @@ void http_connection::on_read(asio::error_code const& e
asio::error_code ec;
m_sock.close(ec);
get(url, m_timeout, m_redirects - 1);
get(url, m_timeout, &m_proxy, m_redirects - 1);
return;
}

View File

@ -100,6 +100,7 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, std::string const& protocol
, std::string const& hostname
, unsigned short port
, std::string request
@ -112,6 +113,10 @@ namespace libtorrent
, m_man(man)
, m_name_lookup(ios)
, m_port(port)
, m_socket(ios)
#ifdef TORRENT_USE_OPENSSL
, m_ssl(protocol == "https")
#endif
, m_recv_pos(0)
, m_buffer(http_buffer_size)
, m_settings(stn)
@ -390,9 +395,25 @@ namespace libtorrent
}
if (cb) cb->m_tracker_address = target_address;
bool ret = instantiate_connection(m_name_lookup.get_io_service(), m_proxy, m_socket);
asio::io_service& ios = m_name_lookup.io_service();
#ifdef TORRENT_USE_OPENSSL
if (m_ssl)
{
m_socket.instantiate<ssl_stream<socket_type> >(ios);
ssl_stream<socket_type>& s = m_socket.get<ssl_stream<socket_type> >();
bool ret = instantiate_connection(ios, m_proxy, s.next_layer());
TORRENT_ASSERT(ret);
}
else
{
m_socket.instantiate<socket_type>(ios);
bool ret = instantiate_connection(ios, m_proxy, m_socket.get<socket_type>());
TORRENT_ASSERT(ret);
}
#else
bool ret = instantiate_connection(ios, m_proxy, m_socket);
TORRENT_ASSERT(ret);
#endif
if (m_proxy.type == proxy_settings::http
|| m_proxy.type == proxy_settings::http_pw)

View File

@ -698,7 +698,7 @@ namespace detail
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " aborting all torrents\n";
(*m_logger) << time_now_string() << " aborting all torrents (" << m_torrents.size() << ")\n";
#endif
// abort all torrents
for (torrent_map::iterator i = m_torrents.begin()
@ -1006,7 +1006,7 @@ namespace detail
void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
{
shared_ptr<socket_type> c(new socket_type);
shared_ptr<socket_type> c(new socket_type(m_io_service));
c->instantiate<stream_socket>(m_io_service);
listener->async_accept(c->get<stream_socket>()
, bind(&session_impl::on_incoming_connection, this, c
@ -1622,8 +1622,9 @@ namespace detail
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " locking mutex\n";
#endif
session_impl::mutex_t::scoped_lock l(m_mutex);
session_impl::mutex_t::scoped_lock l(m_mutex);
/*
#ifndef NDEBUG
for (torrent_map::iterator i = m_torrents.begin();
i != m_torrents.end(); ++i)
@ -1631,7 +1632,7 @@ namespace detail
TORRENT_ASSERT(i->second->num_peers() == 0);
}
#endif
*/
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " cleaning up torrents\n";
#endif

View File

@ -520,7 +520,7 @@ namespace libtorrent
// tracker request
bool torrent::should_request()
{
INVARIANT_CHECK;
// INVARIANT_CHECK;
if (m_trackers.empty()) return false;
@ -1782,7 +1782,7 @@ namespace libtorrent
return;
}
boost::shared_ptr<socket_type> s(new socket_type);
boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
TORRENT_ASSERT(ret);
@ -2087,7 +2087,7 @@ namespace libtorrent
tcp::endpoint const& a(peerinfo->ip);
TORRENT_ASSERT((m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) == 0);
boost::shared_ptr<socket_type> s(new socket_type);
boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
TORRENT_ASSERT(ret);

View File

@ -355,7 +355,7 @@ namespace libtorrent
{
std::string hostname; // hostname only
std::string auth; // user:pass
std::string protocol; // should be http
std::string protocol; // http or https for instance
int port = 80;
std::string::iterator at;
@ -371,6 +371,8 @@ namespace libtorrent
= std::find(url.begin(), url.end(), ':');
protocol.assign(start, end);
if (protocol == "https") port = 443;
if (end == url.end()) goto exit;
++end;
if (end == url.end()) goto exit;
@ -453,13 +455,18 @@ exit:
boost::intrusive_ptr<tracker_connection> con;
#ifdef TORRENT_USE_OPENSSL
if (protocol == "http" || protocol == "https")
#else
if (protocol == "http")
#endif
{
con = new http_tracker_connection(
ios
, cc
, *this
, req
, protocol
, hostname
, port
, request_string

View File

@ -67,17 +67,34 @@ void stop_web_server(int port)
system(cmd.str().c_str());
}
void start_web_server(int port)
void start_web_server(int port, bool ssl)
{
stop_web_server(port);
std::ofstream f("./lighty_config");
if (ssl)
{
system("echo -e \"AU\\ntest province\\ntest city\\ntest company\\n"
"test department\\ntester\\ntest@test.com\" | "
"openssl req -new -x509 -keyout server.pem -out server.pem "
"-days 365 -nodes");
}
std::ofstream f("lighty_config");
f << "server.modules = (\"mod_access\", \"mod_redirect\")\n"
"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
"server.range-requests = \"enable\"\n"
"server.port = " << port << "\n"
"server.pid-file = \"./lighty" << port << ".pid\"\n"
"url.redirect = (\"^/redirect$\" => \"http://127.0.0.1:" << port << "/test_file\", "
"\"^/infinite_redirect$\" => \"http://127.0.0.1:" << port << "/infinite_redirect\")";
"url.redirect = (\"^/redirect$\" => \""
<< (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\", "
"\"^/infinite_redirect$\" => \""
<< (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\")\n";
// this requires lighttpd to be built with ssl support.
// The port distribution for mac is not built with ssl
// support by default.
if (ssl)
f << "ssl.engine = \"enable\"\n"
"ssl.pemfile = \"server.pem\"\n";
f.close();
system("lighttpd -f lighty_config &");
@ -98,7 +115,8 @@ void start_proxy(int port, int proxy_type)
stop_proxy(port);
std::stringstream cmd;
// we need to echo n since dg will ask us to configure it
cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com";
cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com "
"PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
switch (proxy_type)
{
case proxy_settings::socks4:
@ -118,6 +136,7 @@ void start_proxy(int port, int proxy_type)
break;
}
system(cmd.str().c_str());
test_sleep(1000);
}
using namespace libtorrent;

View File

@ -18,7 +18,7 @@ setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2
, libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true
, bool connect = true, std::string suffix = "");
void start_web_server(int port);
void start_web_server(int port, bool ssl = false);
void stop_web_server(int port);
void start_proxy(int port, int type);
void stop_proxy(int port);

View File

@ -66,7 +66,8 @@ void reset_globals()
error_code = asio::error_code();
}
void run_test(char const* url, int size, int status, int connected, boost::optional<asio::error_code> ec)
void run_test(std::string const& url, int size, int status, int connected
, boost::optional<asio::error_code> ec, proxy_settings const& ps)
{
reset_globals();
@ -74,7 +75,7 @@ void run_test(char const* url, int size, int status, int connected, boost::optio
boost::shared_ptr<http_connection> h(new http_connection(ios, cq
, &::http_handler, true, &::http_connect_handler));
h->get(url);
h->get(url, seconds(30), &ps);
ios.reset();
ios.run();
@ -90,19 +91,63 @@ void run_test(char const* url, int size, int status, int connected, boost::optio
TEST_CHECK(http_status == status || status == -1);
}
void run_suite(std::string const& protocol, proxy_settings const& ps)
{
if (ps.type != proxy_settings::none)
{
start_proxy(ps.port, ps.type);
}
char const* test_name[] = {"no", "SOCKS4", "SOCKS5"
, "SOCKS5 password protected", "HTTP", "HTTP password protected"};
std::cout << "\n\n********************** using " << test_name[ps.type]
<< " proxy **********************\n" << std::endl;
typedef boost::optional<asio::error_code> err;
run_test(protocol + "://127.0.0.1:8001/redirect", 3216, 200, 2, asio::error_code(), ps);
run_test(protocol + "://127.0.0.1:8001/infinite_redirect", 0, 301, 6, asio::error_code(), ps);
run_test(protocol + "://127.0.0.1:8001/test_file", 3216, 200, 1, asio::error_code(), ps);
run_test(protocol + "://127.0.0.1:8001/non-existing-file", -1, 404, 1, err(), ps);
// if we're going through an http proxy, we won't get the same error as if the hostname
// resolution failed
if ((ps.type == proxy_settings::http || ps.type == proxy_settings::http_pw) && protocol != "https")
run_test(protocol + "://non-existent-domain.se/non-existing-file", -1, 502, 1, err(), ps);
else
run_test(protocol + "://non-existent-domain.se/non-existing-file", -1, -1, 0, err(asio::error::host_not_found), ps);
if (ps.type != proxy_settings::none)
stop_proxy(ps.port);
}
int test_main()
{
typedef boost::optional<asio::error_code> err;
start_web_server(8001);
std::srand(std::time(0));
std::generate(data_buffer, data_buffer + sizeof(data_buffer), &std::rand);
std::ofstream("test_file").write(data_buffer, 3216);
run_test("http://127.0.0.1:8001/redirect", 3216, 200, 2, asio::error_code());
run_test("http://127.0.0.1:8001/infinite_redirect", 0, 301, 6, asio::error_code());
run_test("http://127.0.0.1:8001/test_file", 3216, 200, 1, asio::error_code());
run_test("http://127.0.0.1:8001/non-existing-file", -1, 404, 1, err());
run_test("http://non-existent-domain.se/non-existing-file", -1, -1, 0, err(asio::error::host_not_found));
proxy_settings ps;
ps.hostname = "127.0.0.1";
ps.port = 8034;
ps.username = "testuser";
ps.password = "testpass";
start_web_server(8001);
for (int i = 0; i < 5; ++i)
{
ps.type = (proxy_settings::proxy_type)i;
run_suite("http", ps);
}
stop_web_server(8001);
#ifdef TORRENT_USE_OPENSSL
start_web_server(8001, true);
for (int i = 0; i < 5; ++i)
{
ps.type = (proxy_settings::proxy_type)i;
run_suite("https", ps);
}
stop_web_server(8001);
#endif
std::remove("test_file");
return 0;
}