Files
rippled/include/xrpl/server/detail/SSLHTTPPeer.h
2025-10-23 11:04:30 -04:00

210 lines
5.3 KiB
C++

#ifndef XRPL_SERVER_SSLHTTPPEER_H_INCLUDED
#define XRPL_SERVER_SSLHTTPPEER_H_INCLUDED
#include <xrpl/server/detail/BaseHTTPPeer.h>
#include <xrpl/server/detail/SSLWSPeer.h>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/ssl/ssl_stream.hpp>
#include <memory>
namespace ripple {
template <class Handler>
class SSLHTTPPeer : public BaseHTTPPeer<Handler, SSLHTTPPeer<Handler>>,
public std::enable_shared_from_this<SSLHTTPPeer<Handler>>
{
private:
friend class BaseHTTPPeer<Handler, SSLHTTPPeer>;
using socket_type = boost::asio::ip::tcp::socket;
using middle_type = boost::beast::tcp_stream;
using stream_type = boost::beast::ssl_stream<middle_type>;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using yield_context = boost::asio::yield_context;
using error_code = boost::system::error_code;
std::unique_ptr<stream_type> stream_ptr_;
stream_type& stream_;
socket_type& socket_;
public:
template <class ConstBufferSequence>
SSLHTTPPeer(
Port const& port,
Handler& handler,
boost::asio::io_context& ioc,
beast::Journal journal,
endpoint_type remote_address,
ConstBufferSequence const& buffers,
middle_type&& stream);
void
run();
std::shared_ptr<WSSession>
websocketUpgrade() override;
private:
void
do_handshake(yield_context do_yield);
void
do_request() override;
void
do_close() override;
void
on_shutdown(error_code ec);
};
//------------------------------------------------------------------------------
template <class Handler>
template <class ConstBufferSequence>
SSLHTTPPeer<Handler>::SSLHTTPPeer(
Port const& port,
Handler& handler,
boost::asio::io_context& ioc,
beast::Journal journal,
endpoint_type remote_address,
ConstBufferSequence const& buffers,
middle_type&& stream)
: BaseHTTPPeer<Handler, SSLHTTPPeer>(
port,
handler,
ioc.get_executor(),
journal,
remote_address,
buffers)
, stream_ptr_(std::make_unique<stream_type>(
middle_type(std::move(stream)),
*port.context))
, stream_(*stream_ptr_)
, socket_(stream_.next_layer().socket())
{
}
// Called when the acceptor accepts our socket.
template <class Handler>
void
SSLHTTPPeer<Handler>::run()
{
if (!this->handler_.onAccept(this->session(), this->remote_address_))
{
util::spawn(
this->strand_,
std::bind(&SSLHTTPPeer::do_close, this->shared_from_this()));
return;
}
if (!socket_.is_open())
return;
util::spawn(
this->strand_,
std::bind(
&SSLHTTPPeer::do_handshake,
this->shared_from_this(),
std::placeholders::_1));
}
template <class Handler>
std::shared_ptr<WSSession>
SSLHTTPPeer<Handler>::websocketUpgrade()
{
auto ws = this->ios().template emplace<SSLWSPeer<Handler>>(
this->port_,
this->handler_,
this->remote_address_,
std::move(this->message_),
std::move(this->stream_ptr_),
this->journal_);
return ws;
}
template <class Handler>
void
SSLHTTPPeer<Handler>::do_handshake(yield_context do_yield)
{
boost::system::error_code ec;
stream_.set_verify_mode(boost::asio::ssl::verify_none);
this->start_timer();
this->read_buf_.consume(stream_.async_handshake(
stream_type::server, this->read_buf_.data(), do_yield[ec]));
this->cancel_timer();
if (ec == boost::beast::error::timeout)
return this->on_timer();
if (ec)
return this->fail(ec, "handshake");
bool const http = this->port().protocol.count("peer") > 0 ||
this->port().protocol.count("wss") > 0 ||
this->port().protocol.count("wss2") > 0 ||
this->port().protocol.count("https") > 0;
if (http)
{
util::spawn(
this->strand_,
std::bind(
&SSLHTTPPeer::do_read,
this->shared_from_this(),
std::placeholders::_1));
return;
}
// `this` will be destroyed
}
template <class Handler>
void
SSLHTTPPeer<Handler>::do_request()
{
++this->request_count_;
auto const what = this->handler_.onHandoff(
this->session(),
std::move(stream_ptr_),
std::move(this->message_),
this->remote_address_);
if (what.moved)
return;
if (what.response)
return this->write(what.response, what.keep_alive);
// legacy
this->handler_.onRequest(this->session());
}
template <class Handler>
void
SSLHTTPPeer<Handler>::do_close()
{
this->start_timer();
stream_.async_shutdown(bind_executor(
this->strand_,
std::bind(
&SSLHTTPPeer::on_shutdown,
this->shared_from_this(),
std::placeholders::_1)));
}
template <class Handler>
void
SSLHTTPPeer<Handler>::on_shutdown(error_code ec)
{
this->cancel_timer();
if (ec == boost::asio::error::operation_aborted)
return;
if (ec)
{
JLOG(this->journal_.debug()) << "on_shutdown: " << ec.message();
}
// Close socket now in case this->destructor is delayed
stream_.next_layer().close();
}
} // namespace ripple
#endif