#ifndef XRPL_SERVER_SSLHTTPPEER_H_INCLUDED #define XRPL_SERVER_SSLHTTPPEER_H_INCLUDED #include #include #include #include #include #include #include #include namespace ripple { 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 stream_ptr_; stream_type& stream_; socket_type& socket_; public: template 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 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 template SSLHTTPPeer::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( port, handler, ioc.get_executor(), journal, remote_address, buffers) , stream_ptr_(std::make_unique( middle_type(std::move(stream)), *port.context)) , stream_(*stream_ptr_) , socket_(stream_.next_layer().socket()) { } // Called when the acceptor accepts our socket. template void SSLHTTPPeer::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 std::shared_ptr SSLHTTPPeer::websocketUpgrade() { auto ws = this->ios().template emplace>( this->port_, this->handler_, this->remote_address_, std::move(this->message_), std::move(this->stream_ptr_), this->journal_); return ws; } template void SSLHTTPPeer::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 void SSLHTTPPeer::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 void SSLHTTPPeer::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 void SSLHTTPPeer::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