SHARE
TWEET

Untitled

ReallyMatrix May 25th, 2020 908 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2. #include "utilities.hpp"
  3. #include <boost/asio.hpp>
  4. #include <boost/beast.hpp>
  5. #include <optional>
  6.  
  7. namespace server {
  8. namespace net = boost::asio;
  9. namespace beast = boost::beast;
  10. namespace http = beast::http;
  11. namespace csock = net::detail::socket_ops;
  12.  
  13. using net::ip::tcp;
  14.  
  15. class custom_timed_socket_t {
  16.   net::io_context &io_context_;
  17.   net::ip::basic_resolver_results<tcp> &resolves_;
  18.   int http_status_code_ = -1;
  19.   bool data_read_error_ = false;
  20.  
  21. public:
  22.   bool data_read_error() const { return data_read_error_; }
  23.   int http_status_code() const { return http_status_code_; }
  24.  
  25.   custom_timed_socket_t(net::io_context &io_context,
  26.                         net::ip::basic_resolver_results<tcp> &resolves)
  27.       : io_context_{io_context}, resolves_{resolves} {}
  28.  
  29.   std::optional<std::string> get(std::string const &url,
  30.                                  int const connect_timeout_sec,
  31.                                  int const read_timeout_sec,
  32.                                  boost::system::error_code &ec) {
  33.  
  34.     utilities::uri const more_ip_uri_{url};
  35.     net::ip::basic_resolver_results<tcp>::iterator resolver_iter{};
  36.     bool is_ipv4 = true;
  37.     if (resolves_.empty()) {
  38.       net::ip::tcp::resolver resolver{io_context_};
  39.       resolves_ =
  40.           resolver.resolve(more_ip_uri_.host(), more_ip_uri_.protocol());
  41.     }
  42.     resolver_iter =
  43.         std::find_if(resolves_.begin(), resolves_.end(), [](auto const &ep) {
  44.           return ep.endpoint().address().is_v4();
  45.         });
  46.     is_ipv4 = resolver_iter != resolves_.end();
  47.     if (!is_ipv4) {
  48.       resolver_iter = std::find_if(
  49.           resolves_.begin(), resolves_.end(),
  50.           [](net::ip::basic_resolver_entry<net::ip::tcp> const &ep) {
  51.             return ep.endpoint().address().is_v6();
  52.           });
  53.       if (resolver_iter == resolves_.end()) {
  54.         return std::nullopt;
  55.       }
  56.     }
  57.  
  58.     tcp::socket http_tcp_socket(net::make_strand(io_context_));
  59.  
  60.     if (is_ipv4) {
  61.       http_tcp_socket.open(net::ip::tcp::v4(), ec);
  62.     } else {
  63.       http_tcp_socket.open(net::ip::tcp::v6(), ec);
  64.     }
  65.     if (ec) {
  66.       return std::nullopt;
  67.     }
  68.     ec = {};
  69.     auto socket_nhandle = http_tcp_socket.native_handle();
  70.     if (!http_tcp_socket.native_non_blocking())
  71.       http_tcp_socket.native_non_blocking(true, ec);
  72.  
  73.     if (ec) {
  74.       return std::nullopt;
  75.     }
  76.  
  77.     http_tcp_socket.connect(*resolver_iter);
  78.  
  79.     ec = {};
  80.     int const connect_time_ms = connect_timeout_sec * 1'000;
  81.    auto result = csock::poll_connect(socket_nhandle, connect_time_ms, ec);
  82.    if (ec || result < 0) {
  83.      return std::nullopt;
  84.    }
  85.    int connect_error = 0;
  86.    std::size_t connect_error_len = sizeof(connect_error);
  87.    auto const get_sock_result =
  88.        csock::getsockopt(socket_nhandle, 0, SOL_SOCKET, SO_ERROR,
  89.                          &connect_error, &connect_error_len, ec);
  90.    if (get_sock_result != 0 || ec) {
  91.      return std::nullopt;
  92.    }
  93.    ec = {};
  94.    if (http_tcp_socket.native_non_blocking()) {
  95.      http_tcp_socket.native_non_blocking(false, ec);
  96.    }
  97.    if (ec) {
  98.      return std::nullopt;
  99.    }
  100.  
  101.    http::request<http::empty_body> http_request{};
  102.    http_request.method(http::verb::get);
  103.    http_request.target(more_ip_uri_.target());
  104.    http_request.version(11);
  105.    http_request.set(http::field::host, more_ip_uri_.host());
  106.    http_request.set(http::field::user_agent, utilities::get_random_agent());
  107.  
  108.    http::write(http_tcp_socket, http_request, ec);
  109.    beast::flat_buffer buffer{};
  110.    http::response<http::string_body> server_response{};
  111.  
  112.    if (!http_tcp_socket.native_non_blocking())
  113.      http_tcp_socket.native_non_blocking(true, ec);
  114.  
  115.    if (ec) {
  116.      return std::nullopt;
  117.    }
  118.  
  119.    http::read(http_tcp_socket, buffer, server_response, ec);
  120.    ec = {};
  121.  
  122.    int const read_time_ms = read_timeout_sec * 1'000;
  123.     result = csock::poll_read(socket_nhandle, 0, read_time_ms, ec);
  124.     if (ec || result < 0) {
  125.       // would like to know if the error obtained is due to timeout on read
  126.       data_read_error_ = true;
  127.       return std::nullopt;
  128.     }
  129.  
  130.     ec = {};
  131.     if (http_tcp_socket.native_non_blocking())
  132.       http_tcp_socket.native_non_blocking(false, ec);
  133.  
  134.     http_tcp_socket.shutdown(tcp::socket::shutdown_both, ec);
  135.     http_status_code_ = server_response.result_int();
  136.     return server_response.body();
  137.   }
  138. };
  139.  
  140. } // namespace server
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top