55 class HttpsClientSession :
public std::enable_shared_from_this<HttpsClientSession>
57 tcp::resolver resolver_;
58#if USE_WINTLS_INSTEAD_OF_OPENSSL
59 wintls::stream<beast::tcp_stream> stream_;
60#elif BOOST_VERSION < 107000
61 ssl::stream<tcp::socket> stream_;
62#elif BOOST_VERSION < 108600
63 beast::ssl_stream<beast::tcp_stream> stream_;
65 ssl::stream<beast::tcp_stream> stream_;
67 boost::beast::flat_buffer buffer_;
68 http::request<http::empty_body> req_;
69 http::request<http::empty_body> proxyHandshake;
70 http::response<http::string_body> res_;
71 http::response<http::empty_body> proxyHandshakeResponse;
74 http::response_parser<http::empty_body> http_proxy_handshake_parser;
79 HttpsClientSession(boost::asio::io_context& ioc,
80#
if USE_WINTLS_INSTEAD_OF_OPENSSL
88 , http_proxy_handshake_parser(proxyHandshakeResponse)
95 const std::string& etpServerHost,
96 uint16_t etpServerPort,
97 const std::string& etpServerTarget,
99 std::string authorization =
"",
100 const std::string& proxyHost =
"",
101 uint16_t proxyPort = 80,
102 const std::string& proxyAuthorization =
"")
104#if USE_WINTLS_INSTEAD_OF_OPENSSL
106 stream_.set_server_hostname(etpServerHost);
109 stream_.set_certificate_revocation_check(
true);
112 if (!SSL_set_tlsext_host_name(stream_.native_handle(), etpServerHost.data()))
114 boost::system::error_code ec{
static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
115 std::cerr <<
"HTTPS on connect (SNI): " << ec.message() <<
"\n";
120#if BOOST_VERSION < 107300
121 stream_.set_verify_callback(ssl::rfc2818_verification(etpServerHost));
123 stream_.set_verify_callback(ssl::host_name_verification(etpServerHost));
128 req_.version(version);
129 req_.method(http::verb::get);
130 req_.target(etpServerTarget);
131 req_.set(http::field::host, etpServerHost +
':' + std::to_string(etpServerPort));
132 req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
133 if (!authorization.empty()) {
134 req_.set(http::field::authorization, authorization);
137 if (!proxyHost.empty()) {
138 proxyHandshake.version(version);
139 proxyHandshake.method(http::verb::connect);
140 proxyHandshake.target(etpServerHost +
':' + std::to_string(etpServerPort));
141 proxyHandshake.set(http::field::host, etpServerHost +
':' + std::to_string(etpServerPort));
142 if (!authorization.empty()) {
143 proxyHandshake.set(http::field::authorization, authorization);
145 if (!proxyAuthorization.empty()) {
146 proxyHandshake.set(http::field::proxy_authorization, proxyAuthorization);
151 resolver_.async_resolve(
152 proxyHost.empty() ? etpServerHost : proxyHost,
153 std::to_string(proxyHost.empty() ? etpServerPort : proxyPort),
155 &HttpsClientSession::on_resolve,
157 std::placeholders::_1,
158 std::placeholders::_2));
163 boost::system::error_code ec,
164 tcp::resolver::results_type results)
167 std::cerr <<
"HTTP over SSL resolve : " << ec.message() << std::endl;
172 std::vector<tcp::endpoint> endpoints(results.begin(), results.end());;
173 std::stable_partition(endpoints.begin(), endpoints.end(), [](
auto entry) {return entry.protocol() == tcp::v4(); });
176#if BOOST_VERSION < 107000
177 boost::asio::async_connect(
178 stream_.next_layer(),
182 &HttpsClientSession::on_connect,
184 std::placeholders::_1));
186 beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(3));
187 beast::get_lowest_layer(stream_).async_connect(
189 beast::bind_front_handler(
190 &HttpsClientSession::on_connect,
191 std::static_pointer_cast<HttpsClientSession>(shared_from_this())));
195#if BOOST_VERSION < 107000
196 void on_connect(boost::system::error_code ec)
198 void on_connect(boost::beast::error_code ec, tcp::resolver::results_type::endpoint_type)
202 std::cerr <<
"HTTP over SSL connect : " << ec.message() << std::endl;
206 if (proxyHandshake.count(http::field::host) > 0) {
208 http::async_write(stream_.next_layer(), proxyHandshake,
212 std::placeholders::_1,
213 std::placeholders::_2));
217 stream_.async_handshake(
218#
if USE_WINTLS_INSTEAD_OF_OPENSSL
219 wintls::handshake_type::client,
221 ssl::stream_base::client,
224 &HttpsClientSession::on_handshake,
226 std::placeholders::_1));
232 boost::system::error_code ec,
233 std::size_t bytes_transferred)
235 boost::ignore_unused(bytes_transferred);
238 std::cerr <<
"HTTP over SSL Proxy handshake write : " << ec.message() << std::endl;
254 http_proxy_handshake_parser.skip(
true);
257 http::async_read(stream_.next_layer(), buffer_, http_proxy_handshake_parser,
259 &HttpsClientSession::on_proxy_handshake_read,
261 std::placeholders::_1,
262 std::placeholders::_2));
266 on_proxy_handshake_read(
267 boost::system::error_code ec,
268 std::size_t bytes_transferred)
270 boost::ignore_unused(bytes_transferred);
272 std::cerr <<
"HTTP over SSL read : " << ec.message() << std::endl;
277 stream_.async_handshake(
278#
if USE_WINTLS_INSTEAD_OF_OPENSSL
279 wintls::handshake_type::client,
281 ssl::stream_base::client,
284 &HttpsClientSession::on_handshake,
286 std::placeholders::_1));
290 on_handshake(boost::system::error_code ec)
293 std::cerr <<
"HTTP over SSL handshake : " << ec.message() << std::endl;
298 http::async_write(stream_, req_,
300 &HttpsClientSession::on_write,
302 std::placeholders::_1,
303 std::placeholders::_2));
308 boost::system::error_code ec,
309 std::size_t bytes_transferred)
311 boost::ignore_unused(bytes_transferred);
314 std::cerr <<
"HTTP over SSL write : " << ec.message() << std::endl;
319 http::async_read(stream_, buffer_, res_,
321 &HttpsClientSession::on_read,
323 std::placeholders::_1,
324 std::placeholders::_2));
329 boost::system::error_code ec,
330 std::size_t bytes_transferred)
332 boost::ignore_unused(bytes_transferred);
335 std::cerr <<
"HTTP over SSL read : " << ec.message() << std::endl;
340 stream_.async_shutdown(
342 &HttpsClientSession::on_shutdown,
344 std::placeholders::_1));
348 on_shutdown(boost::system::error_code ec)
350 if (ec == boost::asio::error::eof)
354 ec.assign(0, ec.category());
365 const http::response<http::string_body>& getResponse()
const {