1 /* 2 3 Copyright (c) 2007-2018, Arvid Norberg 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in 14 the documentation and/or other materials provided with the distribution. 15 * Neither the name of the author nor the names of its 16 contributors may be used to endorse or promote products derived 17 from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 POSSIBILITY OF SUCH DAMAGE. 30 31 */ 32 33 #ifndef TORRENT_HTTP_CONNECTION 34 #define TORRENT_HTTP_CONNECTION 35 36 #ifdef TORRENT_USE_OPENSSL 37 // there is no forward declaration header for asio 38 namespace boost { 39 namespace asio { 40 namespace ssl { 41 class context; 42 } 43 } 44 } 45 #endif 46 47 #include <functional> 48 #include <vector> 49 #include <string> 50 51 #include "libtorrent/socket.hpp" 52 #include "libtorrent/error_code.hpp" 53 #include "libtorrent/http_parser.hpp" 54 #include "libtorrent/deadline_timer.hpp" 55 #include "libtorrent/assert.hpp" 56 #include "libtorrent/i2p_stream.hpp" 57 #include "libtorrent/aux_/socket_type.hpp" 58 #include "libtorrent/aux_/vector.hpp" 59 #include "libtorrent/resolver_interface.hpp" 60 #include "libtorrent/optional.hpp" 61 62 namespace libtorrent { 63 64 struct http_connection; 65 struct resolver_interface; 66 67 // internal 68 constexpr int default_max_bottled_buffer_size = 2 * 1024 * 1024; 69 70 using http_handler = std::function<void(error_code const& 71 , http_parser const&, span<char const> data, http_connection&)>; 72 73 using http_connect_handler = std::function<void(http_connection&)>; 74 75 using http_filter_handler = std::function<void(http_connection&, std::vector<tcp::endpoint>&)>; 76 using hostname_filter_handler = std::function<bool(http_connection&, string_view)>; 77 78 // when bottled, the last two arguments to the handler 79 // will always be 0 80 struct TORRENT_EXTRA_EXPORT http_connection 81 : std::enable_shared_from_this<http_connection> 82 { 83 http_connection(io_service& ios 84 , resolver_interface& resolver 85 , http_handler const& handler 86 , bool bottled 87 , int max_bottled_buffer_size 88 , http_connect_handler const& ch 89 , http_filter_handler const& fh 90 , hostname_filter_handler const& hfh 91 #ifdef TORRENT_USE_OPENSSL 92 , ssl::context* ssl_ctx 93 #endif 94 ); 95 96 // non-copyable 97 http_connection(http_connection const&) = delete; 98 http_connection& operator=(http_connection const&) = delete; 99 100 virtual ~http_connection(); 101 102 void rate_limit(int limit); 103 rate_limitlibtorrent::http_connection104 int rate_limit() const 105 { return m_rate_limit; } 106 107 std::string m_sendbuffer; 108 109 void get(std::string const& url, time_duration timeout = seconds(30) 110 , int prio = 0, aux::proxy_settings const* ps = nullptr, int handle_redirects = 5 111 , std::string const& user_agent = std::string() 112 , boost::optional<address> const& bind_addr = boost::optional<address>() 113 , resolver_flags resolve_flags = resolver_flags{}, std::string const& auth_ = std::string() 114 #if TORRENT_USE_I2P 115 , i2p_connection* i2p_conn = nullptr 116 #endif 117 ); 118 119 void start(std::string const& hostname, int port 120 , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = nullptr 121 , bool ssl = false, int handle_redirect = 5 122 , boost::optional<address> const& bind_addr = boost::optional<address>() 123 , resolver_flags resolve_flags = resolver_flags{} 124 #if TORRENT_USE_I2P 125 , i2p_connection* i2p_conn = nullptr 126 #endif 127 ); 128 129 void close(bool force = false); 130 socketlibtorrent::http_connection131 aux::socket_type const& socket() const { return m_sock; } 132 endpointslibtorrent::http_connection133 std::vector<tcp::endpoint> const& endpoints() const { return m_endpoints; } 134 urllibtorrent::http_connection135 std::string const& url() const { return m_url; } 136 137 private: 138 139 #if TORRENT_USE_I2P 140 void connect_i2p_tracker(char const* destination); 141 void on_i2p_resolve(error_code const& e 142 , char const* destination); 143 #endif 144 void on_resolve(error_code const& e 145 , std::vector<address> const& addresses); 146 void connect(); 147 void on_connect(error_code const& e); 148 void on_write(error_code const& e); 149 void on_read(error_code const& e, std::size_t bytes_transferred); 150 static void on_timeout(std::weak_ptr<http_connection> p 151 , error_code const& e); 152 void on_assign_bandwidth(error_code const& e); 153 154 void callback(error_code e, span<char> data = {}); 155 156 aux::vector<char> m_recvbuffer; 157 158 std::string m_hostname; 159 std::string m_url; 160 std::string m_user_agent; 161 162 aux::vector<tcp::endpoint> m_endpoints; 163 164 // if the current connection attempt fails, we'll connect to the 165 // endpoint with this index (in m_endpoints) next 166 int m_next_ep; 167 168 aux::socket_type m_sock; 169 170 #ifdef TORRENT_USE_OPENSSL 171 ssl::context* m_ssl_ctx; 172 #endif 173 174 #if TORRENT_USE_I2P 175 i2p_connection* m_i2p_conn; 176 #endif 177 resolver_interface& m_resolver; 178 179 http_parser m_parser; 180 http_handler m_handler; 181 http_connect_handler m_connect_handler; 182 http_filter_handler m_filter_handler; 183 hostname_filter_handler m_hostname_filter_handler; 184 deadline_timer m_timer; 185 186 time_duration m_completion_timeout; 187 188 // the timer fires every 250 millisecond as long 189 // as all the quota was used. 190 deadline_timer m_limiter_timer; 191 192 time_point m_last_receive; 193 time_point m_start_time; 194 195 // specifies whether or not the connection is 196 // configured to use a proxy 197 aux::proxy_settings m_proxy; 198 199 // the address to bind to. unset means do not bind 200 boost::optional<address> m_bind_addr; 201 202 // if username password was passed in, remember it in case we need to 203 // re-issue the request for a redirect 204 std::string m_auth; 205 206 int m_read_pos; 207 208 // the number of redirects to follow (in sequence) 209 int m_redirects; 210 211 // maximum size of bottled buffer 212 int m_max_bottled_buffer_size; 213 214 // the current download limit, in bytes per second 215 // 0 is unlimited. 216 int m_rate_limit; 217 218 // the number of bytes we are allowed to receive 219 int m_download_quota; 220 221 // the priority we have in the connection queue. 222 // 0 is normal, 1 is high 223 int m_priority; 224 225 // used for DNS lookups 226 resolver_flags m_resolve_flags; 227 228 std::uint16_t m_port; 229 230 // bottled means that the handler is called once, when 231 // everything is received (and buffered in memory). 232 // non bottled means that once the headers have been 233 // received, data is streamed to the handler 234 bool m_bottled; 235 236 // set to true the first time the handler is called 237 bool m_called = false; 238 239 // only hand out new quota 4 times a second if the 240 // quota is 0. If it isn't 0 wait for it to reach 241 // 0 and continue to hand out quota at that time. 242 bool m_limiter_timer_active = false; 243 244 // true if the connection is using ssl 245 bool m_ssl = false; 246 247 bool m_abort = false; 248 249 // true while waiting for an async_connect 250 bool m_connecting = false; 251 252 // true while resolving hostname 253 bool m_resolving_host = false; 254 }; 255 256 } 257 258 #endif 259