#pragma once #include #include #include #include #include #include #include #include namespace xrpl { template class SSLHTTPPeer : public BaseHTTPPeer>, public std::enable_shared_from_this> { private: friend class BaseHTTPPeer; using socket_type = boost::asio::ip::tcp::socket; using middle_type = boost::beast::tcp_stream; using stream_type = boost::beast::ssl_stream; 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 streamPtr_; stream_type& stream_; socket_type& socket_; public: template SSLHTTPPeer( Port const& port, Handler& handler, boost::asio::io_context& ioc, beast::Journal journal, endpoint_type remoteAddress, ConstBufferSequence const& buffers, middle_type&& stream); void run(); std::shared_ptr websocketUpgrade() override; private: void doHandshake(yield_context doYield); void doRequest() override; void doClose() override; void onShutdown(error_code ec); }; //------------------------------------------------------------------------------ template template SSLHTTPPeer::SSLHTTPPeer( Port const& port, Handler& handler, boost::asio::io_context& ioc, beast::Journal journal, endpoint_type remoteAddress, ConstBufferSequence const& buffers, middle_type&& stream) : BaseHTTPPeer( port, handler, ioc.get_executor(), journal, remoteAddress, buffers) , streamPtr_(std::make_unique(middle_type(std::move(stream)), *port.context)) , stream_(*streamPtr_) , socket_(stream_.next_layer().socket()) { } // Called when the acceptor accepts our socket. template void SSLHTTPPeer::run() { if (!this->handler_.onAccept(this->session(), this->remoteAddress_)) { util::spawn(this->strand_, std::bind(&SSLHTTPPeer::doClose, this->shared_from_this())); return; } if (!socket_.is_open()) return; util::spawn( this->strand_, std::bind(&SSLHTTPPeer::doHandshake, this->shared_from_this(), std::placeholders::_1)); } template std::shared_ptr SSLHTTPPeer::websocketUpgrade() { auto ws = this->ios().template emplace>( this->port_, this->handler_, this->remoteAddress_, std::move(this->message_), std::move(this->streamPtr_), this->journal_); return ws; } template void SSLHTTPPeer::doHandshake(yield_context doYield) { boost::system::error_code ec; stream_.set_verify_mode(boost::asio::ssl::verify_none); this->startTimer(); this->readBuf_.consume( stream_.async_handshake(stream_type::server, this->readBuf_.data(), doYield[ec])); this->cancelTimer(); if (ec == boost::beast::error::timeout) return this->onTimer(); 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::doRead, this->shared_from_this(), std::placeholders::_1)); return; } // `this` will be destroyed } template void SSLHTTPPeer::doRequest() { ++this->requestCount_; auto const what = this->handler_.onHandoff( this->session(), std::move(streamPtr_), std::move(this->message_), this->remoteAddress_); if (what.moved) return; if (what.response) return this->write(what.response, what.keepAlive); // legacy this->handler_.onRequest(this->session()); } template void SSLHTTPPeer::doClose() { this->startTimer(); stream_.async_shutdown(bind_executor( this->strand_, std::bind(&SSLHTTPPeer::onShutdown, this->shared_from_this(), std::placeholders::_1))); } template void SSLHTTPPeer::onShutdown(error_code ec) { this->cancelTimer(); 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 xrpl