Skip to content
Snippets Groups Projects
session.cpp 3.45 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "session.hpp"
    
    using namespace mtx::client;
    
    Session::Session(boost::asio::io_service &ios,
                     boost::asio::ssl::context &ssl_ctx,
                     const std::string &host,
                     RequestID id,
                     SuccessCallback on_success,
                     FailureCallback on_failure)
      : socket(ios, ssl_ctx)
      , host(std::move(host))
      , id(std::move(id))
      , on_success(std::move(on_success))
      , on_failure(std::move(on_failure))
    {
            parser.header_limit(8192);
            parser.body_limit(1 * 1024 * 1024 * 1024); // 1 GiB
    }
    
    void
    Session::on_resolve(boost::system::error_code ec,
                        boost::asio::ip::tcp::resolver::results_type results)
    {
            if (ec) {
                    on_failure(id, ec);
                    shutdown();
                    return;
            }
    
            boost::asio::async_connect(
              socket.next_layer(),
              results,
              std::bind(&Session::on_connect, shared_from_this(), std::placeholders::_1));
    }
    
    void
    Session::on_close(boost::system::error_code ec)
    {
            if (ec == boost::asio::error::eof) {
                    // Rationale:
                    // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
                    ec.assign(0, ec.category());
            }
    
    // SSL_R_SHORT_READ is removed in openssl-1.1
    #if defined SSL_R_SHORT_READ
            if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ)
                    return;
    #else
            if (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated)
                    return;
    #endif
    
            if (ec)
                    // TODO: propagate the error.
                    std::cout << "shutdown: " << ec.message() << std::endl;
    }
    
    void
    Session::on_connect(const boost::system::error_code &ec)
    {
            if (ec) {
                    on_failure(id, ec);
                    shutdown();
                    return;
            }
    
            // Perform the SSL handshake
            socket.async_handshake(
              boost::asio::ssl::stream_base::client,
              std::bind(&Session::on_handshake, shared_from_this(), std::placeholders::_1));
    }
    
    void
    Session::shutdown()
    {
            socket.async_shutdown(
              std::bind(&Session::on_close, shared_from_this(), std::placeholders::_1));
    }
    
    void
    Session::on_request_complete()
    {
            boost::system::error_code ec(error_code);
            on_success(id, parser.get(), ec);
    
            shutdown();
    }
    
    void
    Session::on_handshake(const boost::system::error_code &ec)
    {
            if (ec) {
                    on_failure(id, ec);
                    shutdown();
                    return;
            }
    
            boost::beast::http::async_write(
              socket,
              request,
              std::bind(
                &Session::on_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
    }
    
    void
    Session::on_write(const boost::system::error_code &ec, std::size_t bytes_transferred)
    {
            boost::ignore_unused(bytes_transferred);
    
            if (ec) {
                    on_failure(id, ec);
                    shutdown();
                    return;
            }
    
            // Receive the HTTP response
            boost::beast::http::async_read(
              socket,
              output_buf,
              parser,
              std::bind(
                &Session::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
    }
    
    void
    Session::on_read(const boost::system::error_code &ec, std::size_t bytes_transferred)
    {
            boost::ignore_unused(bytes_transferred);
    
            if (ec)
                    error_code = ec;
    
            on_request_complete();
    }