Files
rippled/include/xrpl/server/detail/PlainHTTPPeer.h
2025-11-10 11:49:19 -05:00

160 lines
3.9 KiB
C++

#ifndef XRPL_SERVER_PLAINHTTPPEER_H_INCLUDED
#define XRPL_SERVER_PLAINHTTPPEER_H_INCLUDED
#include <xrpl/beast/rfc2616.h>
#include <xrpl/server/detail/BaseHTTPPeer.h>
#include <xrpl/server/detail/PlainWSPeer.h>
#include <boost/beast/core/tcp_stream.hpp>
#include <memory>
namespace xrpl {
template <class Handler>
class PlainHTTPPeer
: public BaseHTTPPeer<Handler, PlainHTTPPeer<Handler>>,
public std::enable_shared_from_this<PlainHTTPPeer<Handler>>
{
private:
friend class BaseHTTPPeer<Handler, PlainHTTPPeer>;
using socket_type = boost::asio::ip::tcp::socket;
using stream_type = boost::beast::tcp_stream;
using endpoint_type = boost::asio::ip::tcp::endpoint;
stream_type stream_;
socket_type& socket_;
public:
template <class ConstBufferSequence>
PlainHTTPPeer(
Port const& port,
Handler& handler,
boost::asio::io_context& ioc,
beast::Journal journal,
endpoint_type remote_address,
ConstBufferSequence const& buffers,
stream_type&& stream);
void
run();
std::shared_ptr<WSSession>
websocketUpgrade() override;
private:
void
do_request() override;
void
do_close() override;
};
//------------------------------------------------------------------------------
template <class Handler>
template <class ConstBufferSequence>
PlainHTTPPeer<Handler>::PlainHTTPPeer(
Port const& port,
Handler& handler,
boost::asio::io_context& ioc,
beast::Journal journal,
endpoint_type remote_endpoint,
ConstBufferSequence const& buffers,
stream_type&& stream)
: BaseHTTPPeer<Handler, PlainHTTPPeer>(
port,
handler,
ioc.get_executor(),
journal,
remote_endpoint,
buffers)
, stream_(std::move(stream))
, socket_(stream_.socket())
{
// Set TCP_NODELAY on loopback interfaces,
// otherwise Nagle's algorithm makes Env
// tests run slower on Linux systems.
//
if (remote_endpoint.address().is_loopback())
socket_.set_option(boost::asio::ip::tcp::no_delay{true});
}
template <class Handler>
void
PlainHTTPPeer<Handler>::run()
{
if (!this->handler_.onAccept(this->session(), this->remote_address_))
{
util::spawn(
this->strand_,
std::bind(&PlainHTTPPeer::do_close, this->shared_from_this()));
return;
}
if (!socket_.is_open())
return;
util::spawn(
this->strand_,
std::bind(
&PlainHTTPPeer::do_read,
this->shared_from_this(),
std::placeholders::_1));
}
template <class Handler>
std::shared_ptr<WSSession>
PlainHTTPPeer<Handler>::websocketUpgrade()
{
auto ws = this->ios().template emplace<PlainWSPeer<Handler>>(
this->port_,
this->handler_,
this->remote_address_,
std::move(this->message_),
std::move(stream_),
this->journal_);
return ws;
}
template <class Handler>
void
PlainHTTPPeer<Handler>::do_request()
{
++this->request_count_;
auto const what = this->handler_.onHandoff(
this->session(), std::move(this->message_), this->remote_address_);
if (what.moved)
return;
boost::system::error_code ec;
if (what.response)
{
// half-close on Connection: close
if (!what.keep_alive)
socket_.shutdown(socket_type::shutdown_receive, ec);
if (ec)
return this->fail(ec, "request");
return this->write(what.response, what.keep_alive);
}
// Perform half-close when Connection: close and not SSL
if (!beast::rfc2616::is_keep_alive(this->message_))
socket_.shutdown(socket_type::shutdown_receive, ec);
if (ec)
return this->fail(ec, "request");
// legacy
this->handler_.onRequest(this->session());
}
template <class Handler>
void
PlainHTTPPeer<Handler>::do_close()
{
boost::system::error_code ec;
socket_.shutdown(socket_type::shutdown_send, ec);
}
} // namespace xrpl
#endif