forked from premiere/premiere-libtorrent
initial https support for trackers and http_connection. Added support for proxies to http_connection
This commit is contained in:
parent
69f9a5b5fc
commit
61bbc6e58f
3
Jamfile
3
Jamfile
|
@ -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 ;
|
||||
|
|
|
@ -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,14 +101,20 @@ 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:
|
||||
|
||||
void on_resolve(asio::error_code const& e
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -124,7 +135,7 @@ namespace libtorrent
|
|||
session_settings const& m_settings;
|
||||
proxy_settings const& m_proxy;
|
||||
std::string m_password;
|
||||
|
||||
|
||||
bool m_timed_out;
|
||||
|
||||
int m_connection_ticket;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -173,6 +173,8 @@ public:
|
|||
{
|
||||
return m_sock.lowest_layer();
|
||||
}
|
||||
|
||||
bool is_open() const { return m_sock.is_open(); }
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue