10 #include <string_view> 13 #include <boost/asio/connect.hpp> 14 #include <boost/asio/ip/tcp.hpp> 15 #include <boost/asio/ssl/context.hpp> 16 #include <boost/asio/ssl/error.hpp> 17 #include <boost/asio/ssl/stream.hpp> 18 #include <boost/beast/http.hpp> 24 resolver_(io_context_),
25 ssl_ctx_(boost::asio::ssl::context::sslv23),
26 deadline_timer_(io_context_),
30 ssl_ctx_.set_verify_mode(boost::asio::ssl::verify_peer);
32 [log =
log_, wp = weak_from_this()](
33 bool preverified, boost::asio::ssl::verify_context &ctx) {
35 char subject_name[256];
36 X509 *cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
37 X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
39 "Verifying [{}] was {}",
41 preverified ?
"Successful" :
"Failed");
48 std::string_view uri_arg,
53 fmt::format(
"URI parsing was failed: {}",
uri_.
error().value());
63 if (
int port = std::stoi(std::string(
uri_.
Port));
96 request_.method(boost::beast::http::verb::post);
98 request_.method(boost::beast::http::verb::get);
103 request_.set(boost::beast::http::field::user_agent,
"KagomeOffchainWorker");
104 request_.set(boost::beast::http::field::connection,
"Close");
118 auto &stream = *boost::relaxed_get<SslStreamPtr>(
stream_);
121 if (!SSL_set_tlsext_host_name(stream.native_handle(),
123 boost::beast::error_code ec{
static_cast<int>(::ERR_get_error()),
124 boost::asio::error::get_ssl_category()};
126 "Can't resolve hostname {}: {}",
uri_.
Host, ec.message());
133 auto resolve_handler = [wp = weak_from_this()](
const auto &ec,
auto it) {
134 if (
auto self = wp.lock()) {
135 if (self->status_ != 0) {
137 self->log_,
"Result of resolving is ignored: {}", self->status_);
142 SL_TRACE(self->log_,
"Resolved hostname {}", self->uri_.Host);
143 self->resolver_iterator_ = it;
148 self->error_message_ = fmt::format(
149 "Can't resolve hostname {}: {}", self->uri_.Host, ec.message());
150 SL_ERROR(self->log_,
"{}", self->error_message_);
164 "Connect to `{}` (addr={}:{})",
169 auto &stream =
secure_ ? boost::beast::get_lowest_layer(
170 *boost::relaxed_get<SslStreamPtr>(
stream_))
171 : boost::beast::get_lowest_layer(
172 *boost::relaxed_get<TcpStreamPtr>(
stream_));
174 auto connect_handler = [wp = weak_from_this()](
const auto &ec,
auto it) {
175 if (
auto self = wp.lock()) {
176 if (self->status_ != 0) {
178 self->log_,
"Result of connecting is ignored: {}", self->status_);
183 SL_TRACE(self->log_,
"Connection established");
187 self->connected_ =
true;
193 SL_ERROR(self->log_,
"Connection failed: {}", ec.message());
196 if (++self->resolver_iterator_
197 != boost::asio::ip::tcp::resolver::iterator{}) {
198 SL_TRACE(self->log_,
"Trying next endpoint...");
201 self->error_message_ =
202 fmt::format(
"Connection failed: {}", ec.message());
218 auto &stream = *boost::relaxed_get<SslStreamPtr>(
stream_);
220 auto handshake_handler = [wp = weak_from_this()](
const auto &ec) {
221 if (
auto self = wp.lock()) {
222 if (self->status_ != 0) {
224 self->log_,
"Result of handshake is ignored: {}", self->status_);
229 SL_TRACE(self->log_,
"Handshake successful");
230 self->connected_ =
true;
235 self->error_message_ =
236 fmt::format(
"Handshake failed: {}", ec.message());
237 SL_ERROR(self->log_,
"{}", self->error_message_);
242 stream.async_handshake(boost::asio::ssl::stream_base::client,
243 std::move(handshake_handler));
252 SL_TRACE(
log_,
"Request not ready (body is not finalized)");
256 SL_TRACE(
log_,
"Request not ready (connection is not established)");
260 if (
request_.method() == boost::beast::http::verb::post) {
261 request_.set(boost::beast::http::field::content_length,
265 auto serializer = std::make_shared<boost::beast::http::request_serializer<
266 boost::beast::http::string_body>>(
request_);
268 auto write_handler = [wp = weak_from_this(), serializer](
const auto &ec,
270 if (
auto self = wp.lock()) {
271 if (self->status_ != 0) {
273 "Result of request sending is ignored: {}",
279 SL_TRACE(self->log_,
"Request has sent successful");
280 self->recvResponse();
284 self->error_message_ =
285 fmt::format(
"Request send was fail: {}", ec.message());
286 SL_ERROR(self->log_,
"{}", self->error_message_);
293 auto &stream = *boost::relaxed_get<SslStreamPtr>(
stream_);
294 boost::beast::http::async_write(
295 stream, *serializer, std::move(write_handler));
297 auto &stream = *boost::relaxed_get<TcpStreamPtr>(
stream_);
298 boost::beast::http::async_write(
299 stream, *serializer, std::move(write_handler));
308 SL_TRACE(
log_,
"Read response");
310 auto read_handler = [wp = weak_from_this()](
const auto &ec,
auto received) {
311 if (
auto self = wp.lock()) {
312 if (self->status_ != 0) {
314 "Result of response receiving is ignored: {}",
320 SL_TRACE(self->log_,
"Response has received successful", received);
325 self->error_message_ =
326 fmt::format(
"Response reception has failed: {}", ec.message());
327 SL_ERROR(self->log_,
"{}", self->error_message_);
333 auto &stream = *boost::relaxed_get<SslStreamPtr>(
stream_);
334 boost::system::error_code ec;
335 boost::beast::get_lowest_layer(stream).socket().shutdown(
336 boost::asio::ip::tcp::socket::shutdown_send, ec);
337 boost::beast::http::async_read(
340 auto &stream = *boost::relaxed_get<TcpStreamPtr>(
stream_);
341 boost::system::error_code ec;
342 boost::beast::get_lowest_layer(stream).socket().shutdown(
343 boost::asio::ip::tcp::socket::shutdown_send, ec);
344 boost::beast::http::async_read(
355 auto &stream = *boost::relaxed_get<SslStreamPtr>(
stream_);
356 boost::system::error_code ec;
357 boost::beast::get_lowest_layer(stream).socket().shutdown(
358 boost::asio::ip::tcp::socket::shutdown_both, ec);
360 auto &stream = *boost::relaxed_get<TcpStreamPtr>(
stream_);
361 boost::system::error_code ec;
362 boost::beast::get_lowest_layer(stream).socket().shutdown(
363 boost::asio::ip::tcp::socket::shutdown_both, ec);
380 std::string_view name, std::string_view value) {
387 request_.insert(boost::string_view(name.begin(), name.size()), value);
394 std::optional<std::chrono::milliseconds> deadline_opt) {
409 if (deadline_opt.has_value()) {
410 auto &deadline = deadline_opt.value();
421 request_.body().append(reinterpret_cast<const char *>(chunk.data()),
428 std::vector<std::pair<std::string, std::string>>
430 std::vector<std::pair<std::string, std::string>> result;
432 result.emplace_back(std::pair(header.name_string(), header.value()));
440 std::optional<std::chrono::milliseconds> deadline) {
453 auto amount = std::min(
response_.body().size(), chunk.size());
455 std::copy_n(
response_.body().begin(), amount, chunk.begin());
Class represents arbitrary (including empty) byte buffer.
boost::beast::http::response< boost::beast::http::string_body > response_
std::string to_string() const
std::string_view to_string(SlotType s)
The deadline was reached.
boost::beast::http::response_parser< boost::beast::http::string_body > parser_
HttpRequest(HttpRequest &&) noexcept=delete
HttpStatus status() const
bool init(HttpMethod method, std::string_view uri, common::Buffer meta)
std::string error_message_
boost::asio::io_context io_context_
uint16_t HttpStatus
HTTP status codes that can get returned by certain Offchain funcs. 0: the specified request identifie...
There was an IO error while processing the request.
bool adding_headers_is_allowed_
static Uri parse(std::string_view uri)
std::vector< std::pair< std::string, std::string > > getResponseHeaders() const
constexpr HttpStatus InvalidIdentifier(0)
boost::beast::flat_buffer buffer_
Result< Success, Failure > addRequestHeader(std::string_view name, std::string_view value)
Result< uint32_t, HttpError > readResponseBody(common::Buffer &chunk, std::optional< std::chrono::milliseconds > deadline)
constexpr HttpStatus ErrorHasOccurred(20)
boost::asio::ip::tcp::resolver resolver_
boost::asio::ip::tcp::resolver::iterator resolver_iterator_
The ID of the request is invalid.
Result< Success, HttpError > writeRequestBody(const common::Buffer &chunk, std::optional< std::chrono::milliseconds > deadline_opt)
const std::optional< std::string_view > & error() const
Logger createLogger(const std::string &tag)
boost::asio::ssl::context ssl_ctx_
boost::variant< TcpStreamPtr, SslStreamPtr > stream_
boost::beast::http::request< boost::beast::http::string_body > request_
constexpr HttpStatus DeadlineHasReached(10)