20 #include <ripple/net/SSLHTTPDownloader.h>
21 #include <boost/asio/ssl.hpp>
26 boost::asio::io_service& io_service,
31 , ssl_ctx_(config, j,
boost::asio::ssl::context::tlsv12_client)
34 , sessionActive_(false)
44 boost::filesystem::path
const& dstPath,
50 if (!
strand_.running_in_this_thread())
73 std::placeholders::_1));
101 boost::filesystem::path dstPath,
103 boost::asio::yield_context yield)
106 using namespace boost::beast;
108 boost::system::error_code ec;
118 ip::tcp::resolver resolver {
strand_.context()};
119 auto const results = resolver.async_resolve(host, port, yield[ec]);
121 return fail(dstPath, complete, ec,
"async_resolve",
parser);
129 return fail(dstPath, complete, ec,
135 return fail(dstPath, complete, ec,
"preConnectVerify",
parser);
137 boost::asio::async_connect(
138 stream_->next_layer(), results.begin(), results.end(), yield[ec]);
140 return fail(dstPath, complete, ec,
"async_connect",
parser);
144 return fail(dstPath, complete, ec,
"postConnectVerify",
parser);
146 stream_->async_handshake(ssl::stream_base::client, yield[ec]);
148 return fail(dstPath, complete, ec,
"async_handshake",
parser);
151 http::request<http::empty_body> req {http::verb::head, target, version};
152 req.set(http::field::host, host);
153 req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
158 req.set(http::field::range,
159 (boost::format(
"bytes=%llu-") % rangeStart).str());
162 http::async_write(*
stream_, req, yield[ec]);
164 return fail(dstPath, complete, ec,
"async_write",
parser);
168 http::response_parser<http::empty_body> p;
172 return fail(dstPath, complete, ec,
"async_read",
parser);
175 if(p.get().result() == http::status::range_not_satisfiable)
177 req.erase(http::field::range);
179 http::async_write(*
stream_, req, yield[ec]);
181 return fail(dstPath, complete, ec,
182 "async_write_range_verify",
parser);
184 http::response_parser<http::empty_body> p;
189 return fail(dstPath, complete, ec,
190 "async_read_range_verify",
parser);
193 if(p.content_length() == rangeStart)
196 return fail(dstPath, complete, ec,
197 "range_not_satisfiable",
parser);
199 else if (rangeStart &&
200 p.get().result() != http::status::partial_content)
202 ec.assign(boost::system::errc::not_supported,
203 boost::system::generic_category());
205 return fail(dstPath, complete, ec,
206 "Range request ignored",
parser);
208 else if (
auto len = p.content_length())
212 if (*len > space(dstPath.parent_path()).available)
214 return fail(dstPath, complete, ec,
215 "Insufficient disk space for download",
parser);
220 return fail(dstPath, complete, ec,
229 req.method(http::verb::get);
233 req.set(http::field::range,
234 (boost::format(
"bytes=%llu-") % rangeStart).str());
238 http::async_write(*
stream_, req, yield[ec]);
240 return fail(dstPath, complete, ec,
"async_write",
parser);
245 auto close = [&](
auto p)
250 stream_->async_shutdown(yield[ec]);
251 if (ec == boost::asio::error::eof)
252 ec.assign(0, ec.category());
258 "async_shutdown: " << ec.message();
266 auto p = this->
getParser(dstPath, complete, ec);
268 fail(dstPath, complete, ec,
"getParser", p);
299 if (!connect(p) || ec)
306 while (!p->is_done())
318 "download completed: " << dstPath.string();
324 complete(std::move(dstPath));
329 boost::filesystem::path dstPath,
330 std::function<
void(boost::filesystem::path)>
const& complete,
331 boost::system::error_code
const& ec,
340 else if (ec != boost::asio::error::operation_aborted)
343 errMsg <<
": " << ec.message();
356 <<
" in function: " << __func__;
358 complete(std::move(dstPath));