Your server is not an HTTP server. You don't disclose what kind of proxy you're using but, if you just point e.g. Chrome at your server, it doesn't like being treated that way either.
Here's with the code made self-contained:

I'd suggest starting out with at least a valid HTTP response, e.g.:
void handle_read(error_code error, size_t bytes_transferred) {
    if (!error) {
        res_ = {http::status::ok, 10,
                std::string(data_.data(), bytes_transferred)};
        http::async_write(socket_, res_,
                          boost::bind(&session::handle_write, this,
                                      asio::placeholders::error));
    } else {
        delete this;
    }
}
This would echo minimal valid HTTP responses ignoring the request:
HTTP/1.0 200 OK
foo
bar
HTTP/1.0 200 OK
bar
qux
HTTP/1.0 200 OK
qux
We're ignoring the client's request, and we're not warning about content-length or keepalive. Le'ts improve that by going HTTP/1.1:
void handle_read(error_code error, size_t bytes_transferred) {
    if (!error) {
        res_ = {http::status::ok, 11,
                std::string(data_.data(), bytes_transferred)};
        res_.keep_alive(false);
        res_.prepare_payload();
        http::async_write(socket_, res_,
                          boost::bind(&session::handle_write, this,
                                      asio::placeholders::error));
    } else {
        delete this;
    }
}
Now we get responses like on openssl s_client -connect localhost:8989 -quiet -verify_quiet <<< "Hello world":
HTTP/1.1 200 OK
Connection: close
Content-Length: 12
Hello world
Does the browser like it better?
Curl doesn't complain:
curl -k https://localhost:8989/my/page
GET /my/page HTTP/1.1
Host: localhost:8989
User-Agent: curl/7.81.0
Accept: */*
My browser browser sends a load of cookies to the localhost domain:

Not shown in the browser are the actual response headers:
HTTP/1.1 200 OK
Connection: close
Content-Length: 1003
In fact, if the request is larger than 1024 bytes, the full request can't even be received before the server blurts out a partial "echo" and disconnects. Let's improve the situation by at least reading the entire request headers:
asio::async_read_until(
    socket_, asio::dynamic_buffer(data_), "\r\n\r\n",
    boost::bind(&session::handle_read, this,
                asio::placeholders::error,
                asio::placeholders::bytes_transferred));
See it In Full On Coliru
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <boost/beast.hpp>
namespace asio  = boost::asio;
namespace ssl   = asio::ssl;
namespace beast = boost::beast;
namespace http  = beast::http;
using asio::ip::tcp;
using boost::system::error_code;
using ssl_socket = ssl::stream<tcp::socket>;
using namespace std::chrono_literals;
class session {
  public:
    session(asio::io_service& io_service, ssl::context& context)
        : socket_(io_service, context) {}
    ssl_socket::lowest_layer_type& socket() {
        return socket_.lowest_layer();
    }
    void start() {
        socket_.async_handshake( //
            ssl_socket::server,
            boost::bind(&session::handle_handshake, this,
                        asio::placeholders::error));
    }
    void handle_handshake(error_code error) {
        if (!error) {
            std::cout << "handshake good" << std::endl;
            asio::async_read_until(
                socket_, asio::dynamic_buffer(data_), "\r\n\r\n",
                boost::bind(&session::handle_read, this,
                            asio::placeholders::error,
                            asio::placeholders::bytes_transferred));
        } else {
            std::cout << "handshake failed " + error.what() << std::endl;
            delete this;
        }
    }
    void handle_read(error_code error, size_t bytes_transferred) {
        if (!error) {
            res_ = {http::status::ok, 11,
                    std::string(data_.data(), bytes_transferred)};
            res_.keep_alive(false);
            res_.prepare_payload();
            http::async_write(socket_, res_,
                              boost::bind(&session::handle_write, this,
                                          asio::placeholders::error));
        } else {
            delete this;
        }
    }
    void handle_write(error_code error) {
        if (!error) {
            socket_.async_read_some( //
                asio::buffer(data_),
                boost::bind(&session::handle_read, this,
                            asio::placeholders::error,
                            asio::placeholders::bytes_transferred));
        } else {
            delete this;
        }
    }
  private:
    ssl_socket                        socket_;
    std::string                       data_;
    http::response<http::string_body> res_;
};
class server {
  public:
    using Ctx = ssl::context;
    server(asio::io_service& io_service, uint16_t port)
        : io_service_(io_service)
        , acceptor_(io_service, {tcp::v4(), port})
        , context_(Ctx::sslv23) //
    {
        acceptor_.set_option(tcp::acceptor::reuse_address(true));
        context_.set_options(Ctx::default_workarounds | Ctx::no_sslv2 |
                             Ctx::single_dh_use);
        context_.set_password_callback(&server::get_password);
        context_.use_certificate_chain_file("cert.pem");
        context_.use_private_key_file("key.pem", Ctx::pem);
        context_.use_tmp_dh_file("dh2048.pem");
        start_accept();
    }
  private:
    static std::string get_password(size_t, Ctx::password_purpose) {
        return "test";
    }
    void start_accept() {
        session* new_session = new session(io_service_, context_);
        acceptor_.async_accept(new_session->socket(),
                               boost::bind(&server::handle_accept, this,
                                           new_session,
                                           asio::placeholders::error));
    }
    void handle_accept(session* new_session, error_code error) {
        if (!error) {
            std::cout << "accept good" << std::endl;
            new_session->start();
        } else {
            delete new_session;
        }
        start_accept();
    }
  private:
    asio::io_service& io_service_;
    tcp::acceptor     acceptor_;
    ssl::context      context_;
};
int main() {
    asio::io_service ioc;
    server s(ioc, 8989);
    ioc.run_for(30s);
}
Further Work
In fact, you probably need to read the HTTP request anyways (since the context is browsers and HTTP proxies). So, perhaps use Beast again:
void do_receive() {
    http::async_read(
        socket_, buf_, req_,
        boost::bind(&session::handle_read, this,
                    asio::placeholders::error,
                    asio::placeholders::bytes_transferred));
}
Now we can get rid of the keep_alive(false) since we don't clobber our input.
Now, the delete this anti-pattern can be replaced by the enable_shared_from_this pattern.
If we now move the socket creation to the server and avoid passing io_service& references, we can also remove the violation of encapsulation that was socket() and stop depending on io_service which has been deprecated for several Asio versions.
The result is eerily close to the Beast HTTP server examples:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <boost/beast.hpp>
#include <boost/lexical_cast.hpp> // for the request echo
namespace asio  = boost::asio;
namespace ssl   = asio::ssl;
namespace beast = boost::beast;
namespace http  = beast::http;
using asio::ip::tcp;
using boost::system::error_code;
using ssl_socket = ssl::stream<tcp::socket>;
using namespace std::chrono_literals;
struct session : public std::enable_shared_from_this<session> {
    session(tcp::socket s, ssl::context& context)
        : socket_(std::move(s), context) {}
    void start() {
        socket_.async_handshake( //
            ssl_socket::server,
            boost::bind(&session::handle_handshake, shared_from_this(),
                        asio::placeholders::error));
    }
  private:
    void handle_handshake(error_code error) {
        if (!error) {
            std::cout << "handshake good" << std::endl;
            do_receive();
        } else {
            std::cout << "handshake failed " + error.what() << std::endl;
        }
    }
    void do_receive() {
        http::async_read(
            socket_, buf_, req_,
            boost::bind(&session::handle_read, shared_from_this(),
                        asio::placeholders::error,
                        asio::placeholders::bytes_transferred));
    }
    void handle_read(error_code error, size_t /*bytes_transferred*/) {
        if (!error) {
            res_ = {http::status::ok, 11,
                    boost::lexical_cast<std::string>(req_)};
            res_.keep_alive(false);
            res_.prepare_payload();
            http::async_write(socket_, res_,
                              boost::bind(&session::handle_write,
                                          shared_from_this(),
                                          asio::placeholders::error));
        }
    }
    void handle_write(error_code error) {
        if (!error) {
            do_receive();
        }
    }
  private:
    ssl_socket socket_;
    beast::flat_buffer                buf_;
    http::request<http::string_body>  req_;
    http::response<http::string_body> res_;
};
struct server {
    server(asio::any_io_executor ex, uint16_t port)
        : acceptor_(ex, {tcp::v4(), port})
        , context_(Ctx::sslv23) //
    {
        acceptor_.set_option(tcp::acceptor::reuse_address(true));
        context_.set_options(Ctx::default_workarounds | Ctx::no_sslv2 |
                             Ctx::single_dh_use);
        context_.set_password_callback(&server::get_password);
        context_.use_certificate_chain_file("cert.pem");
        context_.use_private_key_file("key.pem", Ctx::pem);
        context_.use_tmp_dh_file("dh2048.pem");
        start_accept();
    }
  private:
    using Ctx = ssl::context;
    tcp::acceptor acceptor_;
    Ctx           context_;
    static std::string get_password(size_t, Ctx::password_purpose) {
        return "test";
    }
    void start_accept() {
        acceptor_.async_accept(
            // make_strand(acceptor_.get_executor()), // for multi-threaded servers
            [this](error_code ec, tcp::socket s) {
                if (!ec) {
                    std::cout << "accept good" << std::endl;
                    auto sess = std::make_shared<session>(std::move(s),
                                                          context_);
                    sess->start();
                }
                start_accept();
            });
    }
};
int main() {
    asio::io_context ioc;
    server s(ioc.get_executor(), 8989);
    ioc.run_for(30s);
}
UPDATE
Saving information from the comments for the future:
Here's my review of your code, same but 100 lines of code less.
Adding back 50 lines I implemented the minimal CONNECT parsing and connect code: http://coliru.stacked-crooked.com/a/28fbdaf23ab00586 - See it working with
  curl -px http://localhost:8989
on my system, for both HTTP and HTTPS targets:

Listing: Full HTTTP CONNECT de,p supporting any protocol (HTTPS included)
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <boost/bind/bind.hpp>
#include <iomanip>
#include <iostream>
namespace Tcp {
    namespace asio    = boost::asio;
    namespace ph      = asio::placeholders;
    using tcp         = asio::ip::tcp;
    using socket_type = tcp::socket;
    using error_code  = boost::system::error_code;
    template <typename Session> struct Listener {
        Listener(asio::any_io_executor ex, uint16_t bind_port)
            : acceptor_(ex, tcp::endpoint({}, bind_port)) {}
        void do_accept() {
            acceptor_.async_accept( //
                make_strand(acceptor_.get_executor()), [this](error_code ec, tcp::socket s) {
                    std::cerr << "accepted " << s.remote_endpoint() << " (" << ec.message() << ")" << std::endl;
                    if (!ec) {
                        std::make_shared<Session>(std::move(s))->start();
                        do_accept();
                    } else {
                        std::cerr << "do_accept: " << ec.message() << std::endl;
                    }
                });
        }
      private:
        tcp::acceptor acceptor_;
    };
    namespace util {
        // Relay from from_ to to_ sockets
        // Lifetime shared with shared owner
        struct half_duplex {
            using Owner = std::weak_ptr<void>;
            half_duplex(socket_type& f, socket_type& t) : from_(f), to_(t) {}
            void start(Owner w) {
                owner_ = w;
                do_read();
            }
            // send previously received pending data first
            template <typename ConstBufferSequence> void start(Owner w, ConstBufferSequence pending) {
                owner_ = w;
                async_write(to_, pending, boost::bind(&half_duplex::on_written, owner_shared(), ph::error));
            }
          private:
            socket_type& from_;
            socket_type& to_;
            Owner        owner_;
            std::array<uint8_t, 8192> buf_;
            void do_read() {
                from_.async_read_some(
                    asio::buffer(buf_),
                    boost::bind(&half_duplex::on_read, owner_shared(), ph::error, ph::bytes_transferred));
            }
            void on_read(error_code ec, size_t xfer) {
                if (!ec)
                    async_write(to_, asio::buffer(buf_, xfer),
                                boost::bind(&half_duplex::on_written, owner_shared(), ph::error));
            }
            void on_written(error_code ec) {
                if (!ec)
                    do_read();
            }
            std::shared_ptr<half_duplex> owner_shared() {
                if (auto o = owner_.lock())
                    return std::shared_ptr<half_duplex>(o, this); // aliasing constructor
                else
                    throw std::bad_weak_ptr();
            }
        };
    } // namespace util
    namespace proxy {
        namespace http = boost::beast::http;
        struct Session : std::enable_shared_from_this<Session> {
            Session(socket_type s) : client_(std::move(s)), server_(s.get_executor()) {}
            void start() {
                http::async_read(
                    client_, lead_in_, req_,
                    boost::bind(&Session::on_connect_request, shared_from_this(), ph::error));
            }
          private:
            asio::streambuf                  lead_in_;
            http::request<http::empty_body>  req_;
            http::response<http::empty_body> res_;
            socket_type client_, server_;
            util::half_duplex down_stream_{server_, client_};
            util::half_duplex up_stream_{client_, server_};
            void on_connect_request(error_code ec) {
                if (ec.failed() || req_.method() != http::verb::connect)
                    return; // TODO error handling
                std::cerr << "Connect request: " << req_ << std::endl;
                // TODO handle headers?
                std::string upstream(req_.target());
                auto pos  = upstream.find_last_of(":");
                auto host = upstream.substr(0, pos);
                auto svc  = upstream.substr(pos + 1);
                if (svc.empty())
                    svc = "http";
                // TODO async resolve?
                auto eps = tcp::resolver(server_.get_executor()).resolve(host, svc);
                asio::async_connect(server_, eps,
                                    boost::bind(&Session::on_connect, shared_from_this(), ph::error));
            }
            void on_connect(error_code ec) {
                if (ec)
                    return; // TODO error handling
                std::cerr << "Connected to " << server_.remote_endpoint() << std::endl;
                res_ = {http::status::ok, req_.version()};
                res_.keep_alive(true);
                res_.prepare_payload();
                http::async_write(client_, res_,
                                  boost::bind(&Session::on_connect_response, shared_from_this(), ph::error));
            }
            void on_connect_response(error_code ec) {
                if (ec)
                    return; // TODO error handling
                up_stream_.start(shared_from_this());
                if (lead_in_.size())
                    down_stream_.start(shared_from_this(), lead_in_.data());
                else
                    down_stream_.start(shared_from_this());
            }
        };
    }
    using Proxy = Listener<proxy::Session>;
} // namespace Tcp
int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "usage: " << std::quoted(argv[0]) << " <bind port>\n";
        return 1;
    }
    auto bind_port = static_cast<uint16_t>(::atoi(argv[1]));
    try {
        boost::asio::io_context ioc;
        Tcp::Proxy p(ioc.get_executor(), bind_port);
        p.do_accept();
        ioc.run();
    } catch (std::exception const& e) {
        std::cerr << "main: " << e.what() << std::endl;
        return 1;
    }
}