20 #include <ripple/net/SSLHTTPDownloader.h>
21 #include <boost/asio/ssl.hpp>
26 boost::asio::io_service& io_service,
30 , ssl_ctx_(config, j,
boost::asio::ssl::context::tlsv12_client)
32 , cancelDownloads_(false)
33 , sessionActive_(false)
43 boost::filesystem::path
const& dstPath,
58 if (!
strand_.running_in_this_thread())
80 std::placeholders::_1));
104 boost::filesystem::path dstPath,
106 boost::asio::yield_context yield)
109 using namespace boost::beast;
111 boost::system::error_code ec;
117 auto close = [&](
auto p) {
121 stream_->async_shutdown(yield[ec]);
122 if (ec == boost::asio::error::eof)
123 ec.assign(0, ec.category());
128 JLOG(
j_.
trace()) <<
"async_shutdown: " << ec.message();
138 auto exit = [
this]() {
144 auto failAndExit = [&exit, &dstPath, complete, &ec,
this](
147 fail(dstPath, complete, ec, errMsg, p);
155 auto p = this->
getParser(dstPath, complete, ec);
157 return failAndExit(
"getParser", p);
164 ip::tcp::resolver resolver{
strand_.context()};
165 auto const results = resolver.async_resolve(host, port, yield[ec]);
167 return failAndExit(
"async_resolve", p);
180 return failAndExit(
"preConnectVerify", p);
182 boost::asio::async_connect(
183 stream_->next_layer(), results.begin(), results.end(), yield[ec]);
185 return failAndExit(
"async_connect", p);
189 return failAndExit(
"postConnectVerify", p);
191 stream_->async_handshake(ssl::stream_base::client, yield[ec]);
193 return failAndExit(
"async_handshake", p);
196 http::request<http::empty_body> req{http::verb::head, target, version};
197 req.set(http::field::host, host);
198 req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
205 (boost::format(
"bytes=%llu-") % rangeStart).str());
208 http::async_write(*
stream_, req, yield[ec]);
210 return failAndExit(
"async_write", p);
214 http::response_parser<http::empty_body> connectParser;
215 connectParser.skip(
true);
218 return failAndExit(
"async_read", p);
221 if (connectParser.get().result() == http::status::range_not_satisfiable)
223 req.erase(http::field::range);
225 http::async_write(*
stream_, req, yield[ec]);
227 return failAndExit(
"async_write_range_verify", p);
229 http::response_parser<http::empty_body> rangeParser;
230 rangeParser.skip(
true);
234 return failAndExit(
"async_read_range_verify", p);
237 if (rangeParser.content_length() == rangeStart)
240 return failAndExit(
"range_not_satisfiable", p);
244 connectParser.get().result() != http::status::partial_content)
247 boost::system::errc::not_supported,
248 boost::system::generic_category());
250 return failAndExit(
"Range request ignored", p);
252 else if (
auto len = connectParser.content_length())
257 if (*len > space(dstPath.parent_path()).available)
260 "Insufficient disk space for download", p);
273 req.method(http::verb::get);
279 (boost::format(
"bytes=%llu-") % rangeStart).str());
283 http::async_write(*
stream_, req, yield[ec]);
285 return failAndExit(
"async_write", p);
294 while (!p->is_done())
305 JLOG(
j_.
trace()) <<
"download completed: " << dstPath.string();
311 complete(std::move(dstPath));
316 boost::filesystem::path dstPath,
317 std::function<
void(boost::filesystem::path)>
const& complete,
318 boost::system::error_code
const& ec,
326 else if (ec != boost::asio::error::operation_aborted)
328 JLOG(
j_.
error()) << errMsg <<
": " << ec.message();
341 <<
" in function: " << __func__;
343 complete(std::move(dstPath));