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