20 #include <ripple/net/HTTPDownloader.h>
21 #include <boost/asio/ssl.hpp>
26 boost::asio::io_service& io_service,
32 , cancelDownloads_(false)
33 , sessionActive_(false)
43 boost::filesystem::path
const& dstPath,
59 if (!
strand_.running_in_this_thread())
83 std::placeholders::_1));
107 boost::filesystem::path dstPath,
110 boost::asio::yield_context yield)
113 using namespace boost::beast;
115 boost::system::error_code ec;
121 auto close = [&](
auto p) {
125 stream_->getStream().shutdown(socket_base::shutdown_both, ec);
126 if (ec == boost::asio::error::eof)
127 ec.assign(0, ec.category());
132 JLOG(
j_.
trace()) <<
"shutdown: " << ec.message();
143 auto exit = [
this]() {
149 auto failAndExit = [&exit, &dstPath, complete, &ec,
this](
152 fail(dstPath, complete, ec, errMsg, p);
160 auto p = this->
getParser(dstPath, complete, ec);
162 return failAndExit(
"getParser", p);
173 if (!
stream_->connect(error, host, port, yield))
174 return failAndExit(error, p);
177 http::request<http::empty_body> req{http::verb::head, target, version};
178 req.set(http::field::host, host);
179 req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
186 (boost::format(
"bytes=%llu-") % rangeStart).str());
189 stream_->asyncWrite(req, yield, ec);
191 return failAndExit(
"async_write", p);
195 http::response_parser<http::empty_body> connectParser;
196 connectParser.skip(
true);
199 return failAndExit(
"async_read", p);
202 if (connectParser.get().result() == http::status::range_not_satisfiable)
204 req.erase(http::field::range);
206 stream_->asyncWrite(req, yield, ec);
208 return failAndExit(
"async_write_range_verify", p);
210 http::response_parser<http::empty_body> rangeParser;
211 rangeParser.skip(
true);
215 return failAndExit(
"async_read_range_verify", p);
218 if (rangeParser.content_length() == rangeStart)
221 return failAndExit(
"range_not_satisfiable", p);
225 connectParser.get().result() != http::status::partial_content)
228 boost::system::errc::not_supported,
229 boost::system::generic_category());
231 return failAndExit(
"Range request ignored", p);
233 else if (
auto len = connectParser.content_length())
238 if (*len > space(dstPath.parent_path()).available)
241 "Insufficient disk space for download", p);
254 req.method(http::verb::get);
260 (boost::format(
"bytes=%llu-") % rangeStart).str());
264 stream_->asyncWrite(req, yield, ec);
266 return failAndExit(
"async_write", p);
275 while (!p->is_done())
286 JLOG(
j_.
trace()) <<
"download completed: " << dstPath.string();
292 complete(std::move(dstPath));
297 boost::filesystem::path dstPath,
298 std::function<
void(boost::filesystem::path)>
const& complete,
299 boost::system::error_code
const& ec,
307 else if (ec != boost::asio::error::operation_aborted)
309 JLOG(
j_.
error()) << errMsg <<
": " << ec.message();
322 <<
" in function: " << __func__;
324 complete(std::move(dstPath));