3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/net/IPAddressConversion.h>
5#include <xrpl/beast/net/IPEndpoint.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/server/Handoff.h>
8#include <xrpl/server/Port.h>
9#include <xrpl/server/Session.h>
10#include <xrpl/server/Writer.h>
11#include <xrpl/server/detail/Spawn.h>
12#include <xrpl/server/detail/io_list.h>
14#include <boost/asio/ip/tcp.hpp>
15#include <boost/asio/spawn.hpp>
16#include <boost/asio/ssl/stream.hpp>
17#include <boost/asio/strand.hpp>
18#include <boost/asio/streambuf.hpp>
19#include <boost/beast/core/stream_traits.hpp>
20#include <boost/beast/http/dynamic_body.hpp>
21#include <boost/beast/http/message.hpp>
22#include <boost/beast/http/parser.hpp>
23#include <boost/beast/http/read.hpp>
41template <
class Handler,
class Impl>
58 memcpy(
data.get(), ptr, len);
68 boost::asio::executor_work_guard<boost::asio::executor>
work_;
69 boost::asio::strand<boost::asio::executor>
strand_;
83 boost::system::error_code
ec_;
92 template <
class ConstBufferSequence>
96 boost::asio::executor
const& executor,
99 ConstBufferSequence
const& buffers);
116 return *
static_cast<Impl*
>(
this);
185 close(
bool graceful)
override;
190template <
class Handler,
class Impl>
191template <
class ConstBufferSequence>
195 boost::asio::executor
const& executor,
198 ConstBufferSequence
const& buffers)
201 ,
work_(
boost::asio::make_work_guard(executor))
207 boost::asio::buffer_copy(
readBuf_.prepare(boost::asio::buffer_size(buffers)), buffers));
214template <
class Handler,
class Impl>
222template <
class Handler,
class Impl>
226 if (!
strand_.running_in_this_thread())
228 return post(
strand_, [self =
impl().shared_from_this()] { self->close(); });
230 boost::beast::get_lowest_layer(
impl().stream_).close();
235template <
class Handler,
class Impl>
239 if (!
ec_ && ec != boost::asio::error::operation_aborted)
243 boost::beast::get_lowest_layer(
impl().stream_).close();
247template <
class Handler,
class Impl>
251 boost::beast::get_lowest_layer(
impl().stream_)
258template <
class Handler,
class Impl>
262 boost::beast::get_lowest_layer(
impl().stream_).expires_never();
266template <
class Handler,
class Impl>
270 auto ec = boost::system::errc::make_error_code(boost::system::errc::timed_out);
276template <
class Handler,
class Impl>
285 if (ec == boost::beast::http::error::end_of_stream)
287 if (ec == boost::beast::error::timeout)
290 return fail(ec,
"http::read");
296template <
class Handler,
class Impl>
301 if (ec == boost::beast::error::timeout)
304 return fail(ec,
"write");
316 for (
auto const& b :
wq2_)
319 return boost::asio::async_write(
324 [self =
impl().shared_from_this()](
326 self->onWrite(ec, bytesTransferred);
334 self->doRead(doYield);
338template <
class Handler,
class Impl>
347 auto const p =
impl().shared_from_this();
350 p->doWriter(writer, keepAlive, doYield);
360 auto const bytesTransferred = boost::asio::async_write(
361 impl().stream_, writer->data(), boost::asio::transfer_at_least(1), doYield[ec]);
363 return fail(ec,
"writer");
364 writer->consume(bytesTransferred);
365 if (writer->complete())
373 self->doRead(doYield);
380template <
class Handler,
class Impl>
388 wq_.emplace_back(buf, bytes);
389 return wq_.size() == 1 &&
wq2_.empty();
392 if (!
strand_.running_in_this_thread())
401template <
class Handler,
class Impl>
407 self->doWriter(writer, keepAlive, doYield);
413template <
class Handler,
class Impl>
417 return impl().shared_from_this();
422template <
class Handler,
class Impl>
426 if (!
strand_.running_in_this_thread())
428 return post(
strand_, [self =
impl().shared_from_this()] { self->complete(); });
436 if (!
wq_.empty() && !
wq2_.empty())
442 self->doRead(doYield);
448template <
class Handler,
class Impl>
452 if (!
strand_.running_in_this_thread())
455 strand_, [self =
impl().shared_from_this(), graceful] { self->close(graceful); });
464 if (!
wq_.empty() || !
wq2_.empty())
470 boost::beast::get_lowest_layer(
impl().stream_).close();
A generic endpoint for log messages.
A version-independent IP address and port combination.
BaseHTTPPeer(Port const &port, Handler &handler, boost::asio::executor const &executor, beast::Journal journal, endpoint_type remoteAddress, ConstBufferSequence const &buffers)
endpoint_type remoteAddress_
http_request_type message_
void write(void const *buffer, std::size_t bytes) override
boost::asio::ip::tcp::endpoint endpoint_type
void onWrite(error_code const &ec, std::size_t bytesTransferred)
boost::system::error_code ec_
beast::ip::Endpoint remoteAddress() override
boost::system::error_code error_code
beast::Journal const journal_
void fail(error_code ec, char const *what)
void doWriter(std::shared_ptr< Writer > const &writer, bool keepAlive, yield_context doYield)
boost::asio::streambuf readBuf_
std::shared_ptr< Session > detach() override
Detach the session.
beast::Journal journal() override
boost::asio::strand< boost::asio::executor > strand_
static constexpr auto kTimeoutSecondsLocal
boost::asio::executor_work_guard< boost::asio::executor > work_
virtual void doRequest()=0
void complete() override
Indicate that the response is complete.
std::vector< Buffer > wq2_
std::chrono::system_clock clock_type
Port const & port() override
static constexpr auto kBufferSize
std::vector< Buffer > wq_
void doRead(yield_context doYield)
static constexpr auto kTimeoutSeconds
http_request_type & request() override
Returns the current HTTP request.
boost::asio::yield_context yield_context
T emplace_back(T... args)
void spawn(Ctx &&ctx, F &&func)
Spawns a coroutine using boost::asio::spawn.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
static ip::Endpoint fromAsio(boost::asio::ip::address const &address)
Buffer(void const *ptr, std::size_t len)
std::unique_ptr< char[]> data
Configuration information for a Server listening port.