support http basic auth in http_connection passed in from the outside as opposed to part of the url

This commit is contained in:
Arvid Norberg 2015-02-08 16:03:09 +00:00
parent 04c33d6fb2
commit 1b9b6f7292
9 changed files with 51 additions and 27 deletions

View File

@ -97,12 +97,13 @@ struct TORRENT_EXTRA_EXPORT http_connection
int rate_limit() const int rate_limit() const
{ return m_rate_limit; } { return m_rate_limit; }
std::string sendbuffer; std::string m_sendbuffer;
void get(std::string const& url, time_duration timeout = seconds(30) void get(std::string const& url, time_duration timeout = seconds(30)
, int prio = 0, proxy_settings const* ps = 0, int handle_redirects = 5 , int prio = 0, proxy_settings const* ps = 0, int handle_redirects = 5
, std::string const& user_agent = "", address const& bind_addr = address_v4::any() , std::string const& user_agent = std::string()
, int resolve_flags = 0 , address const& bind_addr = address_v4::any()
, int resolve_flags = 0, std::string const& auth_ = std::string()
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
, i2p_connection* i2p_conn = 0 , i2p_connection* i2p_conn = 0
#endif #endif
@ -150,12 +151,13 @@ private:
std::vector<tcp::endpoint> m_endpoints; std::vector<tcp::endpoint> m_endpoints;
socket_type m_sock;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
asio::ssl::context* m_ssl_ctx; asio::ssl::context* m_ssl_ctx;
bool m_own_ssl_context; bool m_own_ssl_context;
#endif #endif
socket_type m_sock;
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
i2p_connection* m_i2p_conn; i2p_connection* m_i2p_conn;
#endif #endif
@ -185,6 +187,10 @@ private:
// means do not bind // means do not bind
address m_bind_addr; address m_bind_addr;
// if username password was passed in, remember it in case we need to
// re-issue the request for a redirect
std::string m_auth;
int m_read_pos; int m_read_pos;
// the number of redirects to follow (in sequence) // the number of redirects to follow (in sequence)

View File

@ -61,16 +61,15 @@ http_connection::http_connection(io_service& ios
, boost::asio::ssl::context* ssl_ctx , boost::asio::ssl::context* ssl_ctx
#endif #endif
) )
: : m_sock(ios)
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
m_ssl_ctx(ssl_ctx), , m_ssl_ctx(ssl_ctx)
m_own_ssl_context(false), , m_own_ssl_context(false)
#endif #endif
m_sock(ios),
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
m_i2p_conn(0), , m_i2p_conn(0)
#endif #endif
m_resolver(resolver) , m_resolver(resolver)
, m_handler(handler) , m_handler(handler)
, m_connect_handler(ch) , m_connect_handler(ch)
, m_filter_handler(fh) , m_filter_handler(fh)
@ -105,7 +104,7 @@ http_connection::~http_connection()
void http_connection::get(std::string const& url, time_duration timeout, int prio void http_connection::get(std::string const& url, time_duration timeout, int prio
, proxy_settings const* ps, int handle_redirects, std::string const& user_agent , proxy_settings const* ps, int handle_redirects, std::string const& user_agent
, address const& bind_addr, int resolve_flags , address const& bind_addr, int resolve_flags, std::string const& auth_
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
, i2p_connection* i2p_conn , i2p_connection* i2p_conn
#endif #endif
@ -124,6 +123,10 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri
boost::tie(protocol, auth, hostname, port, path) boost::tie(protocol, auth, hostname, port, path)
= parse_url_components(url, ec); = parse_url_components(url, ec);
if (auth.empty()) auth = auth_;
m_auth = auth;
int default_port = protocol == "https" ? 443 : 80; int default_port = protocol == "https" ? 443 : 80;
if (port == -1) port = default_port; if (port == -1) port = default_port;
@ -204,7 +207,7 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri
APPEND_FMT("Connection: close\r\n\r\n"); APPEND_FMT("Connection: close\r\n\r\n");
sendbuffer.assign(request); m_sendbuffer.assign(request);
m_url = url; m_url = url;
start(hostname, port, timeout, prio start(hostname, port, timeout, prio
, ps, ssl, handle_redirects, bind_addr, m_resolve_flags , ps, ssl, handle_redirects, bind_addr, m_resolve_flags
@ -264,7 +267,7 @@ void http_connection::start(std::string const& hostname, int port
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("http_connection::on_write"); add_outstanding_async("http_connection::on_write");
#endif #endif
async_write(m_sock, asio::buffer(sendbuffer) async_write(m_sock, asio::buffer(m_sendbuffer)
, boost::bind(&http_connection::on_write, me, _1)); , boost::bind(&http_connection::on_write, me, _1));
} }
else else
@ -602,7 +605,7 @@ void http_connection::on_connect(error_code const& e)
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("http_connection::on_write"); add_outstanding_async("http_connection::on_write");
#endif #endif
async_write(m_sock, asio::buffer(sendbuffer) async_write(m_sock, asio::buffer(m_sendbuffer)
, boost::bind(&http_connection::on_write, shared_from_this(), _1)); , boost::bind(&http_connection::on_write, shared_from_this(), _1));
} }
else if (!m_endpoints.empty() && !m_abort) else if (!m_endpoints.empty() && !m_abort)
@ -674,7 +677,7 @@ void http_connection::on_write(error_code const& e)
if (m_abort) return; if (m_abort) return;
std::string().swap(sendbuffer); std::string().swap(m_sendbuffer);
m_recvbuffer.resize(4096); m_recvbuffer.resize(4096);
int amount_to_read = m_recvbuffer.size() - m_read_pos; int amount_to_read = m_recvbuffer.size() - m_read_pos;
@ -792,7 +795,7 @@ void http_connection::on_read(error_code const& e
std::string url = resolve_redirect_location(m_url, location); std::string url = resolve_redirect_location(m_url, location);
get(url, m_completion_timeout, m_priority, &m_proxy, m_redirects - 1 get(url, m_completion_timeout, m_priority, &m_proxy, m_redirects - 1
, m_user_agent, m_bind_addr, m_resolve_flags , m_user_agent, m_bind_addr, m_resolve_flags, m_auth
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
, m_i2p_conn , m_i2p_conn
#endif #endif

View File

@ -82,8 +82,6 @@ namespace libtorrent
void http_tracker_connection::start() void http_tracker_connection::start()
{ {
// TODO: 3 take tracker_req().auth into account. Use it when making the
// request
std::string url = tracker_req().url; std::string url = tracker_req().url;
if (tracker_req().kind == tracker_request::scrape_request) if (tracker_req().kind == tracker_request::scrape_request)
@ -225,6 +223,7 @@ namespace libtorrent
, tracker_req().event == tracker_request::stopped , tracker_req().event == tracker_request::stopped
? resolver_interface::prefer_cache ? resolver_interface::prefer_cache
: resolver_interface::abort_on_shutdown : resolver_interface::abort_on_shutdown
, tracker_req().auth
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
, tracker_req().i2pconn , tracker_req().i2pconn
#endif #endif

View File

@ -866,11 +866,6 @@ namespace libtorrent
// the common pieces first, just to make // the common pieces first, just to make
// it more likely for all snubbed peers to // it more likely for all snubbed peers to
// request blocks from the same piece // request blocks from the same piece
// TODO: 3 this may cause a priority inversion! making a snubbed peer
// open up a new piece may cause that piece to become the highest
// priority. Unless there is some way to mark pieces as low-priority
// this is probably not a good idea. We just want to make all snubbed
// peers pick the same common piece.
ret |= piece_picker::reverse; ret |= piece_picker::reverse;
} }

View File

@ -4869,6 +4869,7 @@ namespace libtorrent
alerts().post_alert(torrent_paused_alert(get_handle())); alerts().post_alert(torrent_paused_alert(get_handle()));
} }
// TODO: 2 the tracker login feature should probably be deprecated
std::string torrent::tracker_login() const std::string torrent::tracker_login() const
{ {
if (m_username.empty() && m_password.empty()) return ""; if (m_username.empty() && m_password.empty()) return "";

View File

@ -230,7 +230,7 @@ namespace libtorrent
} }
} }
// ir all endpoints were filtered by the IP filter, we can't connect // if all endpoints were filtered by the IP filter, we can't connect
if (m_endpoints.empty()) if (m_endpoints.empty())
{ {
fail(error_code(errors::banned_by_ip_filter)); fail(error_code(errors::banned_by_ip_filter));

View File

@ -669,7 +669,7 @@ void upnp::post(upnp::rootdevice const& d, char const* soap
, int(strlen(soap)), d.service_namespace, soap_action , int(strlen(soap)), d.service_namespace, soap_action
, soap); , soap);
d.upnp_connection->sendbuffer = header; d.upnp_connection->m_sendbuffer = header;
char msg[1024]; char msg[1024];
snprintf(msg, sizeof(msg), "sending: %s", header); snprintf(msg, sizeof(msg), "sending: %s", header);

View File

@ -104,7 +104,8 @@ void reset_globals()
} }
void run_test(std::string const& url, int size, int status, int connected void run_test(std::string const& url, int size, int status, int connected
, boost::optional<error_code> ec, proxy_settings const& ps) , boost::optional<error_code> ec, proxy_settings const& ps
, std::string const& auth = std::string())
{ {
reset_globals(); reset_globals();
@ -118,7 +119,8 @@ void run_test(std::string const& url, int size, int status, int connected
boost::shared_ptr<http_connection> h(new http_connection(ios boost::shared_ptr<http_connection> h(new http_connection(ios
, res, &::http_handler, true, 1024*1024, &::http_connect_handler)); , res, &::http_handler, true, 1024*1024, &::http_connect_handler));
h->get(url, seconds(1), 0, &ps); h->get(url, seconds(1), 0, &ps, 5, "test/user-agent", address_v4::any()
, 0, auth);
ios.reset(); ios.reset();
error_code e; error_code e;
ios.run(e); ios.run(e);
@ -166,6 +168,8 @@ void run_suite(std::string const& protocol, proxy_settings ps, int port)
run_test(url_base + "test_file", 3216, 200, 1, error_code(), ps); run_test(url_base + "test_file", 3216, 200, 1, error_code(), ps);
run_test(url_base + "test_file.gz", 3216, 200, 1, error_code(), ps); run_test(url_base + "test_file.gz", 3216, 200, 1, error_code(), ps);
run_test(url_base + "non-existing-file", -1, 404, 1, err(), ps); run_test(url_base + "non-existing-file", -1, 404, 1, err(), ps);
run_test(url_base + "password_protected", 3216, 200, 1, error_code(), ps
, "testuser:testpass");
// only run the tests to handle NX_DOMAIN if we have a proper internet // only run the tests to handle NX_DOMAIN if we have a proper internet
// connection that doesn't inject false DNS responses (like Comcast does) // connection that doesn't inject false DNS responses (like Comcast does)

View File

@ -4,6 +4,7 @@ import sys
import os import os
import ssl import ssl
import gzip import gzip
import base64
chunked_encoding = False chunked_encoding = False
keepalive = True keepalive = True
@ -41,6 +42,21 @@ class http_handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
file_path = os.path.normpath(s.path) file_path = os.path.normpath(s.path)
if s.path == '/password_protected':
passed = False
if 'Authorization' in s.headers:
auth = s.headers['Authorization']
passed = auth == 'Basic %s' % base64.b64encode('testuser:testpass')
if not passed:
s.send_response(401)
s.send_header("Connection", "close")
s.end_headers()
return
s.path = '/test_file'
file_path = os.path.normpath('/test_file')
if s.path == '/redirect': if s.path == '/redirect':
s.send_response(301) s.send_response(301)
s.send_header("Location", "/test_file") s.send_header("Location", "/test_file")