diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp index 78593c79d..05c3f878e 100644 --- a/include/libtorrent/http_connection.hpp +++ b/include/libtorrent/http_connection.hpp @@ -70,6 +70,7 @@ struct http_connection : boost::enable_shared_from_this, boost: , m_download_quota(0) , m_limiter_timer_active(false) , m_limiter_timer(ios) + , m_redirect(true) { assert(!m_handler.empty()); } @@ -81,10 +82,11 @@ struct http_connection : boost::enable_shared_from_this, boost: std::string sendbuffer; - void get(std::string const& url, time_duration timeout = seconds(30)); + void get(std::string const& url, time_duration timeout = seconds(30) + , bool handle_redirect = true); void start(std::string const& hostname, std::string const& port - , time_duration timeout); + , time_duration timeout, bool handle_redirect = true); void close(); private: @@ -133,6 +135,10 @@ private: // the timer fires every 250 millisecond as long // as all the quota was used. deadline_timer m_limiter_timer; + + // if set to true, the connection should handle + // HTTP redirects. + bool m_redirect; }; } diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 701b2edbf..a828a3c2e 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -42,8 +42,10 @@ using boost::bind; namespace libtorrent { -void http_connection::get(std::string const& url, time_duration timeout) +void http_connection::get(std::string const& url, time_duration timeout + , bool handle_redirect) { + m_redirect = handle_redirect; std::string protocol; std::string hostname; std::string path; @@ -54,13 +56,15 @@ void http_connection::get(std::string const& url, time_duration timeout) "Host:" << hostname << "Connection: close\r\n" "\r\n\r\n"; + m_path = path; sendbuffer = headers.str(); start(hostname, boost::lexical_cast(port), timeout); } void http_connection::start(std::string const& hostname, std::string const& port - , time_duration timeout) + , time_duration timeout, bool handle_redirect = true) { + m_redirect = handle_redirect; m_timeout = timeout; m_timer.expires_from_now(m_timeout); m_timer.async_wait(bind(&http_connection::on_timeout @@ -213,6 +217,36 @@ void http_connection::on_read(asio::error_code const& e m_read_pos += bytes_transferred; assert(m_read_pos <= int(m_recvbuffer.size())); + // having a nonempty path means we should handle redirects + if (m_redirect && m_parser.header_finished()) + { + int code = m_parser.status_code(); + if (code >= 300 && code < 400) + { + // attempt a redirect + std::string url = m_parser.header("location"); + if (url.empty()) + { + // missing location header + if (m_bottled && m_called) return; + m_called = true; + m_handler(e, m_parser, 0, 0); + return; + } + + m_limiter_timer_active = false; + m_timer.cancel(); + m_limiter_timer.cancel(); + m_sock.close(); + m_hostname.clear(); + m_port.clear(); + get(url, m_timeout); + return; + } + + m_redirect = false; + } + if (m_bottled || !m_parser.header_finished()) { libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]