diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index bc892ce01c..c5163f5a2a 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -1898,18 +1898,18 @@ True - + - - - - - - - + + + True + + + True + @@ -3448,8 +3448,6 @@ - - ..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories) ..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories) diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index f31331d692..0282167f64 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -334,9 +334,6 @@ {8601C61D-413C-725E-C9E6-BD4F97E40032} - - {F98B3E94-4FB9-98FF-C625-533A969D1210} - {43D68742-4714-D103-EE00-EB10BD045FB6} @@ -2856,24 +2853,21 @@ ripple\common\tests - - ripple\http\api + + ripple\http - - ripple\http\api - - - ripple\http\api - - - ripple\http\api - - - ripple\http\api + + ripple\http + + ripple\http\impl + ripple\http\impl + + ripple\http\impl + ripple\http\impl @@ -4740,9 +4734,6 @@ ripple\unity - - ripple\unity - ripple\unity diff --git a/src/BeastConfig.h b/src/BeastConfig.h index 2ffdf48e5f..1b0a014a6b 100644 --- a/src/BeastConfig.h +++ b/src/BeastConfig.h @@ -227,4 +227,10 @@ #define RIPPLE_STRUCTURED_OVERLAY 0 #endif +/** Config: RIPPLE_ASYNC_RPC_HANDLER +*/ +#ifndef RIPPLE_ASYNC_RPC_HANDLER +#define RIPPLE_ASYNC_RPC_HANDLER 1 +#endif + #endif diff --git a/src/ripple/common/MultiSocket.h b/src/ripple/common/MultiSocket.h index d73c39a5e4..e116164d5c 100644 --- a/src/ripple/common/MultiSocket.h +++ b/src/ripple/common/MultiSocket.h @@ -96,15 +96,6 @@ public: private: int m_flags; }; - - enum Flags - { - none = 0, - client_ssl = 1, - server_ssl = 2, - server_ssl_required = 4, - server_proxy = 8 - }; typedef beast::asio::HandshakeDetectLogicPROXY::ProxyInfo ProxyInfo; diff --git a/src/ripple/http/api/Server.h b/src/ripple/http/Server.h similarity index 53% rename from src/ripple/http/api/Server.h rename to src/ripple/http/Server.h index a657d414e9..10de42c116 100644 --- a/src/ripple/http/api/Server.h +++ b/src/ripple/http/Server.h @@ -20,13 +20,80 @@ #ifndef RIPPLE_HTTP_SERVER_H_INCLUDED #define RIPPLE_HTTP_SERVER_H_INCLUDED +#include +#include +#include +#include #include #include namespace ripple { - namespace HTTP { +//------------------------------------------------------------------------------ + +/** Configuration information for a server listening port. */ +struct Port +{ + enum Security + { + no_ssl, + allow_ssl, + require_ssl + }; + + Security security; + std::uint16_t port; + beast::IP::Endpoint addr; + beast::asio::SSLContext* context; + + Port (); + Port (Port const& other); + Port& operator= (Port const& other); + Port (std::uint16_t port_, beast::IP::Endpoint const& addr_, + Security security_, beast::asio::SSLContext* context_); +}; + +bool operator== (Port const& lhs, Port const& rhs); +bool operator< (Port const& lhs, Port const& rhs); + +/** A set of listening ports settings. */ +typedef std::vector Ports; + +//------------------------------------------------------------------------------ + +class Server; +class Session; + +/** Processes all sessions. + Thread safety: + Must be safe to call concurrently from any number of foreign threads. +*/ +struct Handler +{ + /** Called when the connection is accepted and we know remoteAddress. */ + virtual void onAccept (Session& session) = 0; + + /** Called repeatedly as new HTTP headers are received. + Guaranteed to be called at least once. + */ + virtual void onHeaders (Session& session) = 0; + + /** Called when we have the full Content-Body. */ + virtual void onRequest (Session& session) = 0; + + /** Called when the session ends. + Guaranteed to be called once. + @param errorCode Non zero for a failed connection. + */ + virtual void onClose (Session& session, int errorCode) = 0; + + /** Called when the server has finished its stop. */ + virtual void onStopped (Server& server) = 0; +}; + +//------------------------------------------------------------------------------ + class ServerImpl; /** Multi-threaded, asynchronous HTTP server. */ @@ -39,17 +106,19 @@ public: /** Destroy the server. This blocks until the server stops. */ - virtual ~Server (); - + virtual + ~Server (); /** Returns the Journal associated with the server. */ - beast::Journal const& journal () const; + beast::Journal + journal () const; /** Returns the listening ports settings. Thread safety: Safe to call from any thread. Cannot be called concurrently with setPorts. */ - Ports const& getPorts () const; + Ports const& + getPorts () const; /** Set the listening ports settings. These take effect immediately. Any current ports that are not in the @@ -57,13 +126,15 @@ public: Thread safety: Cannot be called concurrently. */ - void setPorts (Ports const& ports); + void + setPorts (Ports const& ports); /** Notify the server to stop, without blocking. Thread safety: Safe to call concurrently from any thread. */ - void stopAsync (); + void + stopAsync (); /** Notify the server to stop, and block until the stop is complete. The handler's onStopped method will be called when the stop completes. @@ -71,13 +142,14 @@ public: Cannot be called concurrently. Cannot be called from the thread of execution of any Handler functions. */ - void stop (); + void + stop (); private: std::unique_ptr m_impl; }; -} // namespace HTTP -} // namespace ripple +} // HTTP +} // ripple #endif diff --git a/src/ripple/http/api/Session.h b/src/ripple/http/Session.h similarity index 81% rename from src/ripple/http/api/Session.h rename to src/ripple/http/Session.h index 92e3a97bb2..54542c5e61 100644 --- a/src/ripple/http/api/Session.h +++ b/src/ripple/http/Session.h @@ -24,13 +24,52 @@ #include #include #include - #include namespace ripple { namespace HTTP { +class Session; + +/** Scoped ostream-based RAII container for building the HTTP response. */ +// VFALCO TODO Use abstract_ostream +class ScopedStream +{ +public: + explicit ScopedStream (Session& session); + ScopedStream (ScopedStream const& other); + + template + ScopedStream (Session& session, T const& t) + : m_session (session) + { + m_ostream << t; + } + + ScopedStream (Session& session, std::ostream& manip (std::ostream&)); + + ~ScopedStream (); + + std::ostringstream& ostream () const; + + std::ostream& operator<< (std::ostream& manip (std::ostream&)) const; + + template + std::ostream& operator<< (T const& t) const + { + return m_ostream << t; + } + +private: + ScopedStream& operator= (ScopedStream const&); // disallowed + + Session& m_session; + std::ostringstream mutable m_ostream; +}; + +//------------------------------------------------------------------------------ + /** Persistent state information for a connection session. These values are preserved between calls for efficiency. Some fields are input parameters, some are output parameters, diff --git a/src/ripple/http/api/Handler.h b/src/ripple/http/api/Handler.h deleted file mode 100644 index d4155292f4..0000000000 --- a/src/ripple/http/api/Handler.h +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_HTTP_HANDLER_H_INCLUDED -#define RIPPLE_HTTP_HANDLER_H_INCLUDED - -namespace ripple { - -namespace HTTP { - -class Server; -class Session; - -/** Processes all sessions. - Thread safety: - Must be safe to call concurrently from any number of foreign threads. -*/ -struct Handler -{ - /** Called when the connection is accepted and we know remoteAddress. */ - virtual void onAccept (Session& session) = 0; - - /** Called repeatedly as new HTTP headers are received. - Guaranteed to be called at least once. - */ - virtual void onHeaders (Session& session) = 0; - - /** Called when we have the full Content-Body. */ - virtual void onRequest (Session& session) = 0; - - /** Called when the session ends. - Guaranteed to be called once. - @param errorCode Non zero for a failed connection. - */ - virtual void onClose (Session& session, int errorCode) = 0; - - /** Called when the server has finished its stop. */ - virtual void onStopped (Server& server) = 0; -}; - -} // namespace HTTP -} // namespace ripple - -#endif diff --git a/src/ripple/http/api/Port.h b/src/ripple/http/api/Port.h deleted file mode 100644 index 74b9b9fe4c..0000000000 --- a/src/ripple/http/api/Port.h +++ /dev/null @@ -1,67 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_HTTP_PORT_H_INCLUDED -#define RIPPLE_HTTP_PORT_H_INCLUDED - -#include -#include - -#include - -namespace ripple { - -namespace HTTP { - -/** Configuration information for a server listening port. */ -struct Port -{ - enum Security - { - no_ssl, - allow_ssl, - require_ssl - }; - - Port (); - Port (Port const& other); - Port& operator= (Port const& other); - Port (std::uint16_t port_, beast::IP::Endpoint const& addr_, - Security security_, beast::asio::SSLContext* context_); - - std::uint16_t port; - beast::IP::Endpoint addr; - Security security; - beast::asio::SSLContext* context; -}; - -bool operator== (Port const& lhs, Port const& rhs); -bool operator!= (Port const& lhs, Port const& rhs); -bool operator< (Port const& lhs, Port const& rhs); -bool operator<= (Port const& lhs, Port const& rhs); -bool operator> (Port const& lhs, Port const& rhs); -bool operator>= (Port const& lhs, Port const& rhs); - -/** A set of listening ports settings. */ -typedef std::vector Ports; - -} // namespace HTTP -} // namespace ripple - -#endif diff --git a/src/ripple/http/api/ScopedStream.h b/src/ripple/http/api/ScopedStream.h deleted file mode 100644 index fdeb088f40..0000000000 --- a/src/ripple/http/api/ScopedStream.h +++ /dev/null @@ -1,69 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_HTTP_SCOPEDSTREAM_H_INCLUDED -#define RIPPLE_HTTP_SCOPEDSTREAM_H_INCLUDED - -#include - -namespace ripple { - -namespace HTTP { - -class Session; - -/** Scoped ostream-based RAII container for building the HTTP response. */ -class ScopedStream -{ -public: - explicit ScopedStream (Session& session); - ScopedStream (ScopedStream const& other); - - template - ScopedStream (Session& session, T const& t) - : m_session (session) - { - m_ostream << t; - } - - ScopedStream (Session& session, std::ostream& manip (std::ostream&)); - - ~ScopedStream (); - - std::ostringstream& ostream () const; - - std::ostream& operator<< (std::ostream& manip (std::ostream&)) const; - - template - std::ostream& operator<< (T const& t) const - { - return m_ostream << t; - } - -private: - ScopedStream& operator= (ScopedStream const&); // disallowed - - Session& m_session; - std::ostringstream mutable m_ostream; -}; - -} // namespace HTTP -} // namespace ripple - -#endif diff --git a/src/ripple/http/impl/Door.cpp b/src/ripple/http/impl/Door.cpp new file mode 100644 index 0000000000..aa00157e0f --- /dev/null +++ b/src/ripple/http/impl/Door.cpp @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +namespace ripple { +namespace HTTP { + +Door::Door (ServerImpl& impl, Port const& port) + : impl_ (impl) + , acceptor_ (impl_.get_io_service(), to_asio (port)) + , port_ (port) +{ + impl_.add (*this); + + error_code ec; + + acceptor_.set_option (acceptor::reuse_address (true), ec); + if (ec) + { + impl_.journal().error << + "Error setting acceptor socket option: " << ec.message(); + } + + if (! ec) + { + impl_.journal().info << "Bound to endpoint " << + to_string (acceptor_.local_endpoint()); + + async_accept(); + } + else + { + impl_.journal().error << "Error binding to endpoint " << + to_string (acceptor_.local_endpoint()) << + ", '" << ec.message() << "'"; + } +} + +Door::~Door () +{ + impl_.remove (*this); +} + +Port const& +Door::port () const +{ + return port_; +} + +void +Door::cancel () +{ + acceptor_.cancel(); +} + +void +Door::failed (error_code ec) +{ +} + +void +Door::async_accept () +{ + auto const peer (std::make_shared (impl_, port_)); + acceptor_.async_accept (peer->get_socket(), std::bind ( + &Door::handle_accept, Ptr(this), + beast::asio::placeholders::error, peer)); +} + +void +Door::handle_accept (error_code ec, + std::shared_ptr const& peer) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + { + impl_.journal().error << "Accept failed: " << ec.message(); + return; + } + + async_accept(); + + peer->accept(); +} + +} +} diff --git a/src/ripple/http/impl/Door.h b/src/ripple/http/impl/Door.h index d5267b1262..35a8f645eb 100644 --- a/src/ripple/http/impl/Door.h +++ b/src/ripple/http/impl/Door.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_HTTP_DOOR_H_INCLUDED #define RIPPLE_HTTP_DOOR_H_INCLUDED +#include +#include #include namespace ripple { @@ -28,95 +30,37 @@ namespace HTTP { /** A listening socket. */ class Door : public beast::SharedObject - , public beast::asio::AsyncObject , public beast::List ::Node , public beast::LeakChecked { -public: +private: + // VFALCO TODO Use shared_ptr typedef beast::SharedPtr Ptr; - ServerImpl& m_impl; - acceptor m_acceptor; - Port m_port; + ServerImpl& impl_; + acceptor acceptor_; + Port port_; - Door (ServerImpl& impl, Port const& port) - : m_impl (impl) - , m_acceptor (m_impl.get_io_service(), to_asio (port)) - , m_port (port) - { - m_impl.add (*this); +public: + Door (ServerImpl& impl, Port const& port); - error_code ec; + ~Door (); - m_acceptor.set_option (acceptor::reuse_address (true), ec); - if (ec) - { - m_impl.journal().error << - "Error setting acceptor socket option: " << ec.message(); - } + Port const& + port () const; - if (! ec) - { - m_impl.journal().info << "Bound to endpoint " << - to_string (m_acceptor.local_endpoint()); + void + cancel (); - async_accept(); - } - else - { - m_impl.journal().error << "Error binding to endpoint " << - to_string (m_acceptor.local_endpoint()) << - ", '" << ec.message() << "'"; - } - } + void + failed (error_code ec); - ~Door () - { - m_impl.remove (*this); - } + void + async_accept (); - Port const& port () const - { - return m_port; - } - - void cancel () - { - m_acceptor.cancel(); - } - - void failed (error_code ec) - { - } - - void asyncHandlersComplete () - { - } - - void async_accept () - { - Peer* peer (new Peer (m_impl, m_port)); - m_acceptor.async_accept (peer->get_socket(), std::bind ( - &Door::handle_accept, Ptr(this), - beast::asio::placeholders::error, - Peer::Ptr (peer), CompletionCounter (this))); - } - - void handle_accept (error_code ec, Peer::Ptr peer, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec) - { - m_impl.journal().error << "Accept failed: " << ec.message(); - return; - } - - async_accept(); - - peer->handle_accept(); - } + void + handle_accept (error_code ec, + std::shared_ptr const& peer); }; } diff --git a/src/ripple/http/impl/Peer.cpp b/src/ripple/http/impl/Peer.cpp new file mode 100644 index 0000000000..9af4e62811 --- /dev/null +++ b/src/ripple/http/impl/Peer.cpp @@ -0,0 +1,409 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +namespace ripple { +namespace HTTP { + +Peer::Peer (ServerImpl& impl, Port const& port) + : impl_ (impl) + , strand_ (impl_.get_io_service()) + , data_timer_ (impl_.get_io_service()) + , request_timer_ (impl_.get_io_service()) + , buffer_ (bufferSize) + , writesPending_ (0) + , closed_ (false) + , callClose_ (false) + , errorCode_ (0) + , detached_ (0) +{ + tag = nullptr; + + int flags = MultiSocket::Flag::server_role; + switch (port.security) + { + default: + bassertfalse; + + case Port::no_ssl: + break; + + case Port::allow_ssl: + flags |= MultiSocket::Flag::ssl; + break; + + case Port::require_ssl: + flags |= MultiSocket::Flag::ssl_required; + break; + } + + socket_.reset (MultiSocket::New ( + impl_.get_io_service(), port.context->get(), flags)); + + impl_.add (*this); +} + +Peer::~Peer () +{ + if (callClose_) + impl_.handler().onClose (session(), errorCode_); + + impl_.remove (*this); +} + +//-------------------------------------------------------------------------- + +// Returns the Content-Body as a single buffer. +// VFALCO NOTE This is inefficient... +std::string +Peer::content() +{ + std::string s; + beast::DynamicBuffer const& body ( + parser_.request()->body ()); + s.resize (body.size ()); + boost::asio::buffer_copy ( + boost::asio::buffer (&s[0], + s.size()), body.data ()); + return s; +} + +// Send a copy of the data. +void +Peer::write (void const* buffer, std::size_t bytes) +{ + // Make sure this happens on an io_service thread. + impl_.get_io_service().dispatch (strand_.wrap ( + std::bind (&Peer::async_write, shared_from_this(), + SharedBuffer (static_cast (buffer), bytes)))); +} + +// Make the Session asynchronous +void +Peer::detach () +{ + if (detached_.exchange (1) == 0) + { + bassert (! work_); + bassert (detach_ref_ == nullptr); + + // Maintain an additional reference while detached + detach_ref_ = shared_from_this(); + + // Prevent the io_service from running out of work. + // The work object will be destroyed with the Peer + // after the Session is closed and handlers complete. + // + work_ = boost::in_place (std::ref ( + impl_.get_io_service())); + } +} + +// Called by the Handler to close the session. +void +Peer::close () +{ + // Make sure this happens on an io_service thread. + impl_.get_io_service().dispatch (strand_.wrap ( + std::bind (&Peer::handle_close, shared_from_this()))); +} + +//-------------------------------------------------------------------------- + +// Called when the handshake completes +// +void +Peer::handle_handshake (error_code ec) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec != 0) + { + failed (ec); + return; + } + + async_read_some(); +} + +// Called when the data timer expires +// +void +Peer::handle_data_timer (error_code ec) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (closed_) + return; + + if (ec != 0) + { + failed (ec); + return; + } + + failed (boost::system::errc::make_error_code ( + boost::system::errc::timed_out)); +} + +// Called when the request timer expires +// +void +Peer::handle_request_timer (error_code ec) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (closed_) + return; + + if (ec != 0) + { + failed (ec); + return; + } + + failed (boost::system::errc::make_error_code ( + boost::system::errc::timed_out)); +} + +// Called when async_write completes. +void +Peer::handle_write (error_code ec, std::size_t bytes_transferred, + SharedBuffer const& buf) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec != 0) + { + failed (ec); + return; + } + + bassert (writesPending_ > 0); + if (--writesPending_ == 0 && closed_) + socket_->shutdown (socket::shutdown_send); +} + +// Called when async_read_some completes. +void +Peer::handle_read (error_code ec, std::size_t bytes_transferred) +{ + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec != 0 && ec != boost::asio::error::eof) + { + failed (ec); + return; + } + + std::size_t const bytes_parsed (parser_.process ( + buffer_.getData(), bytes_transferred)); + + if (parser_.error() || + bytes_parsed != bytes_transferred) + { + failed (boost::system::errc::make_error_code ( + boost::system::errc::bad_message)); + return; + } + + if (ec == boost::asio::error::eof) + { + parser_.process_eof(); + ec = error_code(); + } + + if (parser_.error()) + { + failed (boost::system::errc::make_error_code ( + boost::system::errc::bad_message)); + return; + } + + if (! parser_.finished()) + { + // Feed some headers to the callback + if (parser_.fields().size() > 0) + { + handle_headers(); + if (closed_) + return; + } + } + + if (parser_.finished ()) + { + data_timer_.cancel(); + // VFALCO NOTE: Should we cancel this one? + request_timer_.cancel(); + + if (! socket_->needs_handshake()) + socket_->shutdown (socket::shutdown_receive); + + handle_request (); + return; + } + + async_read_some(); +} + +// Called when we have some new headers. +void +Peer::handle_headers () +{ + impl_.handler().onHeaders (session()); +} + +// Called when we have a complete http request. +void +Peer::handle_request () +{ + // This is to guarantee onHeaders is called at least once. + handle_headers(); + + if (closed_) + return; + + // Process the HTTPRequest + impl_.handler().onRequest (session()); +} + +// Called to close the session. +void +Peer::handle_close () +{ + closed_ = true; + + // Release our additional reference + detach_ref_.reset(); +} + +//-------------------------------------------------------------------------- +// +// Peer +// + +// Called when the acceptor accepts our socket. +void +Peer::accept () +{ + callClose_ = true; + + impl_.handler().onAccept (session()); + + if (closed_) + { + cancel(); + return; + } + + request_timer_.expires_from_now ( + boost::posix_time::seconds ( + requestTimeoutSeconds)); + + request_timer_.async_wait (strand_.wrap (std::bind ( + &Peer::handle_request_timer, shared_from_this(), + beast::asio::placeholders::error))); + + if (socket_->needs_handshake ()) + { + socket_->async_handshake (beast::asio::abstract_socket::server, + strand_.wrap (std::bind (&Peer::handle_handshake, shared_from_this(), + beast::asio::placeholders::error))); + } + else + { + async_read_some(); + } +} + +// Cancel all pending i/o and timers and send tcp shutdown. +void +Peer::cancel () +{ + error_code ec; + data_timer_.cancel (ec); + request_timer_.cancel (ec); + socket_->cancel (ec); + socket_->shutdown (socket::shutdown_both); +} + +// Called by a completion handler when error is not eof or aborted. +void +Peer::failed (error_code const& ec) +{ + errorCode_ = ec.value(); + bassert (errorCode_ != 0); + cancel (); +} + +// Call the async_read_some initiating function. +void +Peer::async_read_some () +{ + // re-arm the data timer + // (this cancels the previous wait, if any) + // + data_timer_.expires_from_now ( + boost::posix_time::seconds ( + dataTimeoutSeconds)); + + data_timer_.async_wait (strand_.wrap (std::bind ( + &Peer::handle_data_timer, shared_from_this(), + beast::asio::placeholders::error))); + + // issue the read + // + boost::asio::mutable_buffers_1 buf ( + buffer_.getData (), buffer_.getSize ()); + + socket_->async_read_some (buf, strand_.wrap ( + std::bind (&Peer::handle_read, shared_from_this(), + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred))); +} + +// Send a shared buffer +void +Peer::async_write (SharedBuffer const& buf) +{ + bassert (buf.get().size() > 0); + + ++writesPending_; + + // Send the copy. We pass the SharedBuffer in the last parameter + // so that a reference is maintained as the handler gets copied. + // When the final completion function returns, the reference + // count will drop to zero and the buffer will be freed. + // + boost::asio::async_write (*socket_, + boost::asio::const_buffers_1 (&(*buf)[0], buf->size()), + strand_.wrap (std::bind (&Peer::handle_write, + shared_from_this(), beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred, buf))); +} + +} +} diff --git a/src/ripple/http/impl/Peer.h b/src/ripple/http/impl/Peer.h index 2c56564c23..427aab4c8c 100644 --- a/src/ripple/http/impl/Peer.h +++ b/src/ripple/http/impl/Peer.h @@ -20,29 +20,34 @@ #ifndef RIPPLE_HTTP_PEER_H_INCLUDED #define RIPPLE_HTTP_PEER_H_INCLUDED -#include +#include +#include +#include +#include #include -#include +#include +#include #include #include -#include +#include #include namespace ripple { namespace HTTP { // Holds the copy of buffers being sent +// VFALCO TODO Replace with std::shared_ptr +// typedef beast::asio::SharedArg SharedBuffer; /** Represents an active connection. */ class Peer - : public beast::SharedObject - , public beast::asio::AsyncObject + : public std::enable_shared_from_this , public Session , public beast::List ::Node , public beast::LeakChecked { -public: +private: enum { // Size of our receive buffer @@ -59,462 +64,138 @@ public: }; - typedef beast::SharedPtr Ptr; + ServerImpl& impl_; + boost::asio::io_service::strand strand_; + boost::asio::deadline_timer data_timer_; + boost::asio::deadline_timer request_timer_; + std::unique_ptr socket_; - ServerImpl& m_impl; - boost::asio::io_service::strand m_strand; - boost::asio::deadline_timer m_data_timer; - boost::asio::deadline_timer m_request_timer; - std::unique_ptr m_socket; - beast::MemoryBlock m_buffer; - beast::HTTPRequestParser m_parser; - int m_writesPending; - bool m_closed; - bool m_callClose; - beast::SharedPtr m_detach_ref; - boost::optional m_work; - int m_errorCode; - std::atomic m_detached; + // VFALCO TODO Use c++11 + beast::MemoryBlock buffer_; + + beast::HTTPRequestParser parser_; + int writesPending_; + bool closed_; + bool callClose_; + std::shared_ptr detach_ref_; + boost::optional work_; + int errorCode_; + std::atomic detached_; //-------------------------------------------------------------------------- - Peer (ServerImpl& impl, Port const& port) - : m_impl (impl) - , m_strand (m_impl.get_io_service()) - , m_data_timer (m_impl.get_io_service()) - , m_request_timer (m_impl.get_io_service()) - , m_buffer (bufferSize) - , m_writesPending (0) - , m_closed (false) - , m_callClose (false) - , m_errorCode (0) - , m_detached (0) - { - tag = nullptr; - - int flags; - switch (port.security) - { - default: - bassertfalse; - case Port::no_ssl: flags = MultiSocket::none; break; - case Port::allow_ssl: flags = MultiSocket::server_ssl; break; - case Port::require_ssl: flags = MultiSocket::server_ssl_required; break; - } - - m_socket.reset (MultiSocket::New ( - m_impl.get_io_service(), port.context->get(), flags)); - - m_impl.add (*this); - } - - ~Peer () - { - if (m_callClose) - m_impl.handler().onClose (session(), m_errorCode); - - m_impl.remove (*this); - } +public: + Peer (ServerImpl& impl, Port const& port); + ~Peer (); +private: //-------------------------------------------------------------------------- // // Session // - beast::Journal journal() + beast::Journal + journal() { - return m_impl.journal(); + return impl_.journal(); } - beast::IP::Endpoint remoteAddress() + beast::IP::Endpoint + remoteAddress() { return from_asio (get_socket().remote_endpoint()); } - bool headersComplete() + bool + headersComplete() { - return m_parser.headersComplete(); + return parser_.headersComplete(); } - beast::HTTPHeaders headers() + beast::HTTPHeaders + headers() { - return beast::HTTPHeaders (m_parser.fields()); + return beast::HTTPHeaders (parser_.fields()); } - beast::SharedPtr const& request() + beast::SharedPtr const& + request() { - return m_parser.request(); + return parser_.request(); } - // Returns the Content-Body as a single buffer. - // VFALCO NOTE This is inefficient... - std::string content() - { - std::string s; - beast::DynamicBuffer const& body ( - m_parser.request()->body ()); - s.resize (body.size ()); - boost::asio::buffer_copy ( - boost::asio::buffer (&s[0], - s.size()), body.data ()); - return s; - } + std::string + content(); - // Send a copy of the data. - void write (void const* buffer, std::size_t bytes) - { - // Make sure this happens on an io_service thread. - m_impl.get_io_service().dispatch (m_strand.wrap ( - boost::bind (&Peer::handle_write, Ptr (this), - SharedBuffer (static_cast (buffer), bytes), - CompletionCounter (this)))); - } + void + write (void const* buffer, std::size_t bytes); - // Make the Session asynchronous - void detach () - { - if (m_detached.exchange (1) == 0) - { - bassert (! m_work); - bassert (m_detach_ref.empty()); + void + detach (); - // Maintain an additional reference while detached - m_detach_ref = this; - - // Prevent the io_service from running out of work. - // The work object will be destroyed with the Peer - // after the Session is closed and handlers complete. - // - m_work = boost::in_place (std::ref ( - m_impl.get_io_service())); - } - } - - // Called by the Handler to close the session. - void close () - { - // Make sure this happens on an io_service thread. - m_impl.get_io_service().dispatch (m_strand.wrap ( - boost::bind (&Peer::handle_close, Ptr (this), - CompletionCounter (this)))); - } + void + close (); //-------------------------------------------------------------------------- // // Completion Handlers // - // Called when the last pending completion handler returns. - void asyncHandlersComplete () - { - } + void + handle_handshake (error_code ec); - // Called when the acceptor accepts our socket. - void handle_accept () - { - m_callClose = true; + void + handle_data_timer (error_code ec); - m_impl.handler().onAccept (session()); + void + handle_request_timer (error_code ec); - if (m_closed) - { - cancel(); - return; - } + void + handle_write (error_code ec, std::size_t bytes_transferred, + SharedBuffer const& buf); - m_request_timer.expires_from_now ( - boost::posix_time::seconds ( - requestTimeoutSeconds)); + void + handle_read (error_code ec, std::size_t bytes_transferred); - m_request_timer.async_wait (m_strand.wrap (boost::bind ( - &Peer::handle_request_timer, Ptr(this), - boost::asio::placeholders::error, - CompletionCounter (this)))); + void + handle_headers (); - if (m_socket->needs_handshake ()) - { - m_socket->async_handshake (beast::asio::abstract_socket::server, - m_strand.wrap (boost::bind (&Peer::handle_handshake, Ptr(this), - boost::asio::placeholders::error, - CompletionCounter (this)))); - } - else - { - async_read_some(); - } - } + void + handle_request (); - // Called from an io_service thread to write the shared buffer. - void handle_write (SharedBuffer const& buf, CompletionCounter) - { - async_write (buf); - } - - // Called when the handshake completes - // - void handle_handshake (error_code ec, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec != 0) - { - failed (ec); - return; - } - - async_read_some(); - } - - // Called when the data timer expires - // - void handle_data_timer (error_code ec, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (m_closed) - return; - - if (ec != 0) - { - failed (ec); - return; - } - - failed (boost::system::errc::make_error_code ( - boost::system::errc::timed_out)); - } - - // Called when the request timer expires - // - void handle_request_timer (error_code ec, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (m_closed) - return; - - if (ec != 0) - { - failed (ec); - return; - } - - failed (boost::system::errc::make_error_code ( - boost::system::errc::timed_out)); - } - - // Called when async_write completes. - void handle_write (error_code ec, std::size_t bytes_transferred, - SharedBuffer buf, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec != 0) - { - failed (ec); - return; - } - - bassert (m_writesPending > 0); - if (--m_writesPending == 0 && m_closed) - m_socket->shutdown (socket::shutdown_send); - } - - // Called when async_read_some completes. - void handle_read (error_code ec, std::size_t bytes_transferred, CompletionCounter) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec != 0 && ec != boost::asio::error::eof) - { - failed (ec); - return; - } - - std::size_t const bytes_parsed (m_parser.process ( - m_buffer.getData(), bytes_transferred)); - - if (m_parser.error() || - bytes_parsed != bytes_transferred) - { - failed (boost::system::errc::make_error_code ( - boost::system::errc::bad_message)); - return; - } - - if (ec == boost::asio::error::eof) - { - m_parser.process_eof(); - ec = error_code(); - } - - if (m_parser.error()) - { - failed (boost::system::errc::make_error_code ( - boost::system::errc::bad_message)); - return; - } - - if (! m_parser.finished()) - { - // Feed some headers to the callback - if (m_parser.fields().size() > 0) - { - handle_headers(); - if (m_closed) - return; - } - } - - if (m_parser.finished ()) - { - m_data_timer.cancel(); - // VFALCO NOTE: Should we cancel this one? - m_request_timer.cancel(); - - if (! m_socket->needs_handshake()) - m_socket->shutdown (socket::shutdown_receive); - - handle_request (); - return; - } - - async_read_some(); - } - - // Called when we have some new headers. - void handle_headers () - { - m_impl.handler().onHeaders (session()); - } - - // Called when we have a complete http request. - void handle_request () - { - // This is to guarantee onHeaders is called at least once. - handle_headers(); - - if (m_closed) - return; - - // Process the HTTPRequest - m_impl.handler().onRequest (session()); - } - - // Called to close the session. - void handle_close (CompletionCounter) - { - m_closed = true; - - // Release our additional reference - m_detach_ref = nullptr; - } + void + handle_close (); +public: //-------------------------------------------------------------------------- // // Peer // - - // Returns the asio socket for the peer. - socket& get_socket() + socket& + get_socket() { - return m_socket->this_layer(); + return socket_->this_layer(); } - // Return the Session associated with this peer's session. - Session& session () + Session& + session () { return *this; } - // Cancel all pending i/o and timers and send tcp shutdown. - void cancel () - { - error_code ec; - m_data_timer.cancel (ec); - m_request_timer.cancel (ec); - m_socket->cancel (ec); - m_socket->shutdown (socket::shutdown_both); - } + void + accept (); - // Called by a completion handler when error is not eof or aborted. - void failed (error_code const& ec) - { - m_errorCode = ec.value(); - bassert (m_errorCode != 0); - cancel (); - } + void + cancel (); - // Call the async_read_some initiating function. - void async_read_some () - { - // re-arm the data timer - // (this cancels the previous wait, if any) - // - m_data_timer.expires_from_now ( - boost::posix_time::seconds ( - dataTimeoutSeconds)); + void + failed (error_code const& ec); - m_data_timer.async_wait (m_strand.wrap (boost::bind ( - &Peer::handle_data_timer, Ptr(this), - boost::asio::placeholders::error, - CompletionCounter (this)))); + void + async_read_some (); - // issue the read - // - boost::asio::mutable_buffers_1 buf ( - m_buffer.getData (), m_buffer.getSize ()); - - m_socket->async_read_some (buf, m_strand.wrap ( - boost::bind (&Peer::handle_read, Ptr (this), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred, - CompletionCounter (this)))); - } - - // Send a shared buffer - void async_write (SharedBuffer const& buf) - { - bassert (buf.get().size() > 0); - - ++m_writesPending; - - // Send the copy. We pass the SharedBuffer in the last parameter - // so that a reference is maintained as the handler gets copied. - // When the final completion function returns, the reference - // count will drop to zero and the buffer will be freed. - // - boost::asio::async_write (*m_socket, - boost::asio::const_buffers_1 (&(*buf)[0], buf->size()), - m_strand.wrap (boost::bind (&Peer::handle_write, - Ptr (this), boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred, - buf, CompletionCounter (this)))); - } - - // Send a copy of a BufferSequence - template - void async_write (BufferSequence const& buffers) - { - // Iterate over each linear vector in the BufferSequence. - for (typename BufferSequence::const_iterator iter (buffers.begin()); - iter != buffers.end(); ++iter) - { - typename BufferSequence::value_type const& buffer (*iter); - - // Put a copy of this section of the buffer sequence into - // a reference counted, shared container. - // - async_write (SharedBuffer ( - boost::asio::buffer_cast (buffer), - boost::asio::buffer_size (buffer))); - } - } + void async_write (SharedBuffer const& buf); }; } diff --git a/src/ripple/http/impl/Port.cpp b/src/ripple/http/impl/Port.cpp index 136727849d..629250ca1a 100644 --- a/src/ripple/http/impl/Port.cpp +++ b/src/ripple/http/impl/Port.cpp @@ -21,16 +21,16 @@ namespace ripple { namespace HTTP { Port::Port () - : port (0) - , security (no_ssl) + : security (no_ssl) + , port (0) , context (nullptr) { } Port::Port (Port const& other) - : port (other.port) + : security (other.security) + , port (other.port) , addr (other.addr) - , security (other.security) , context (other.context) { } @@ -44,14 +44,11 @@ Port& Port::operator= (Port const& other) return *this; } -Port::Port ( - std::uint16_t port_, - beast::IP::Endpoint const& addr_, - Security security_, - beast::asio::SSLContext* context_) - : port (port_) +Port::Port (std::uint16_t port_, beast::IP::Endpoint const& addr_, + Security security_, beast::asio::SSLContext* context_) + : security (security_) + , port (port_) , addr (addr_) - , security (security_) , context (context_) { } @@ -88,18 +85,5 @@ bool operator< (Port const& lhs, Port const& rhs) return true; } -bool operator!= (Port const& lhs, Port const& rhs) - { return ! (lhs == rhs); } - -bool operator> (Port const& lhs, Port const& rhs) - { return rhs < lhs; } - -bool operator<= (Port const& lhs, Port const& rhs) - { return ! (rhs < lhs); } - -bool operator>= (Port const& lhs, Port const& rhs) - { return ! (lhs < rhs); } - - } } diff --git a/src/ripple/http/impl/Server.cpp b/src/ripple/http/impl/Server.cpp index 79a2235f94..cbceaf7350 100644 --- a/src/ripple/http/impl/Server.cpp +++ b/src/ripple/http/impl/Server.cpp @@ -17,11 +17,15 @@ */ //============================================================================== +#include +#include +#include // + namespace ripple { namespace HTTP { Server::Server (Handler& handler, beast::Journal journal) - : m_impl (new ServerImpl (*this, handler, journal)) + : m_impl (std::make_unique (*this, handler, journal)) { } @@ -30,27 +34,32 @@ Server::~Server () stop(); } -beast::Journal const& Server::journal () const +beast::Journal +Server::journal () const { return m_impl->journal(); } -Ports const& Server::getPorts () const +Ports const& +Server::getPorts () const { return m_impl->getPorts(); } -void Server::setPorts (Ports const& ports) +void +Server::setPorts (Ports const& ports) { m_impl->setPorts (ports); } -void Server::stopAsync () +void +Server::stopAsync () { m_impl->stop(false); } -void Server::stop () +void +Server::stop () { m_impl->stop(true); } diff --git a/src/ripple/http/impl/ServerImpl.cpp b/src/ripple/http/impl/ServerImpl.cpp index 21cbc3beed..f77ff26d1f 100644 --- a/src/ripple/http/impl/ServerImpl.cpp +++ b/src/ripple/http/impl/ServerImpl.cpp @@ -17,6 +17,8 @@ */ //============================================================================== +#include + namespace ripple { namespace HTTP { @@ -24,7 +26,7 @@ ServerImpl::ServerImpl (Server& server, Handler& handler, beast::Journal journal : Thread ("HTTP::Server") , m_server (server) , m_handler (handler) - , m_journal (journal) + , journal_ (journal) , m_strand (m_io_service) , m_work (boost::in_place (std::ref (m_io_service))) , m_stopped (true) @@ -37,11 +39,6 @@ ServerImpl::~ServerImpl () stopThread (); } -beast::Journal const& ServerImpl::journal() const -{ - return m_journal; -} - Ports const& ServerImpl::getPorts () const { SharedState::ConstUnlockedAccess state (m_state); @@ -129,7 +126,7 @@ int ServerImpl::compare (Port const& lhs, Port const& rhs) { if (lhs < rhs) return -1; - else if (lhs > rhs) + else if (rhs < lhs) return 1; return 0; } diff --git a/src/ripple/http/impl/ServerImpl.h b/src/ripple/http/impl/ServerImpl.h index 8eaa6d7c74..0443b32215 100644 --- a/src/ripple/http/impl/ServerImpl.h +++ b/src/ripple/http/impl/ServerImpl.h @@ -20,8 +20,14 @@ #ifndef RIPPLE_HTTP_SERVERIMPL_H_INCLUDED #define RIPPLE_HTTP_SERVERIMPL_H_INCLUDED +#include +#include +#include #include #include +#include +#include +#include namespace ripple { namespace HTTP { @@ -31,7 +37,7 @@ class Peer; class ServerImpl : public beast::Thread { -public: +private: struct State { // Attributes for our listening ports @@ -49,7 +55,7 @@ public: Server& m_server; Handler& m_handler; - beast::Journal m_journal; + beast::Journal journal_; boost::asio::io_service m_io_service; boost::asio::io_service::strand m_strand; boost::optional m_work; @@ -57,24 +63,54 @@ public: SharedState m_state; Doors m_doors; +public: ServerImpl (Server& server, Handler& handler, beast::Journal journal); ~ServerImpl (); - beast::Journal const& journal() const; - Ports const& getPorts () const; - void setPorts (Ports const& ports); - bool stopping () const; - void stop (bool wait); - Handler& handler(); - boost::asio::io_service& get_io_service(); - void add (Peer& peer); - void add (Door& door); - void remove (Peer& peer); - void remove (Door& door); + beast::Journal + journal() const + { + return journal_; + } - void handle_update (); - void update (); - void run (); + Ports const& + getPorts () const; + + void + setPorts (Ports const& ports); + + bool + stopping () const; + + void + stop (bool wait); + + Handler& + handler(); + + boost::asio::io_service& + get_io_service(); + + void + add (Peer& peer); + + void + add (Door& door); + + void + remove (Peer& peer); + + void + remove (Door& door); + + void + handle_update (); + + void + update (); + + void + run (); static int compare (Port const& lhs, Port const& rhs); }; diff --git a/src/ripple/module/app/main/Application.cpp b/src/ripple/module/app/main/Application.cpp index 766f663463..30f1096caf 100644 --- a/src/ripple/module/app/main/Application.cpp +++ b/src/ripple/module/app/main/Application.cpp @@ -801,6 +801,10 @@ public: // // Allow RPC connections. // +#if RIPPLE_ASYNC_RPC_HANDLER + m_rpcHTTPServer->setup (m_journal); + +#else if (! getConfig ().getRpcIP().empty () && getConfig ().getRpcPort() != 0) { try @@ -820,6 +824,7 @@ public: { m_journal.info << "RPC interface: disabled"; } +#endif // // Begin connecting to network. diff --git a/src/ripple/module/app/main/RPCHTTPServer.cpp b/src/ripple/module/app/main/RPCHTTPServer.cpp index 5414224483..24759a2035 100644 --- a/src/ripple/module/app/main/RPCHTTPServer.cpp +++ b/src/ripple/module/app/main/RPCHTTPServer.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -75,9 +76,12 @@ public: getConfig ().getRpcPort() != 0) { beast::IP::Endpoint ep (beast::IP::Endpoint::from_string (getConfig().getRpcIP())); - if (! is_unspecified (ep)) + + // VFALCO TODO IP address should not have an "unspecified" state + //if (! is_unspecified (ep)) { HTTP::Port port; + port.security = HTTP::Port::allow_ssl; port.addr = ep.at_port(0); if (getConfig ().getRpcPort() != 0) port.port = getConfig ().getRpcPort(); @@ -131,16 +135,24 @@ public: void onRequest (HTTP::Session& session) { + // Check user/password authorization + auto const headers (session.request()->headers().build_map()); + if (! HTTPAuthorized (headers)) + { + session.write (HTTPReply (403, "Forbidden")); + session.close(); + return; + } + #if 0 + // Synchronous version that doesn't use job queue Job job; processSession (job, session); + #else session.detach(); - // The "boost::"'s are a workaround for broken versions of tr1::functional that - // require the reference wrapper to be callable. HTTP::Session has abstract functions - // and so references to it are not callable. - m_jobQueue.addJob (jtRPC, "RPC", std::bind ( + m_jobQueue.addJob (jtCLIENT, "RPC-Client", std::bind ( &RPCHTTPServerImp::processSession, this, std::placeholders::_1, std::ref (session))); #endif @@ -159,8 +171,14 @@ public: void processSession (Job& job, HTTP::Session& session) { +#if 0 + // Goes through the old code session.write (m_deprecatedHandler.processRequest ( session.content(), session.remoteAddress().at_port(0))); +#else + session.write (processRequest (session.content(), + session.remoteAddress().at_port(0))); +#endif session.close(); } @@ -172,14 +190,10 @@ public: return HTTPReply (statusCode, description); } - bool isAuthorized ( - std::map const& headers) - { - return HTTPAuthorized (headers); - } - // Stolen directly from RPCServerHandler - std::string processRequest (std::string const& request, beast::IP::Endpoint const& remoteIPAddress) + std::string + processRequest (std::string const& request, + beast::IP::Endpoint const& remoteIPAddress) { Json::Value jvRequest; { @@ -247,14 +261,6 @@ public: return HTTPReply (403, "Forbidden"); } - // This code does all the work on the io_service thread and - // has no rate-limiting based on source IP or anything. - // This is a temporary safety - if ((role != Config::ADMIN) && (getApp().getFeeTrack().isLoadedLocal())) - { - return HTTPReply (503, "Unable to service at this time"); - } - std::string response; m_journal.debug << "Query: " << strMethod << params; diff --git a/src/ripple/module/net/rpc/RPCUtil.cpp b/src/ripple/module/net/rpc/RPCUtil.cpp index f837c9affe..401a927551 100644 --- a/src/ripple/module/net/rpc/RPCUtil.cpp +++ b/src/ripple/module/net/rpc/RPCUtil.cpp @@ -262,10 +262,14 @@ std::string DecodeBase64 (std::string s) bool HTTPAuthorized (const std::map& mapHeaders) { - std::map::const_iterator it = mapHeaders.find ("authorization"); + bool const credentialsRequired (! getConfig().RPC_USER.empty() && + ! getConfig().RPC_PASSWORD.empty()); + if (! credentialsRequired) + return true; + auto const it = mapHeaders.find ("authorization"); if ((it == mapHeaders.end ()) || (it->second.substr (0, 6) != "Basic ")) - return getConfig ().RPC_USER.empty () && getConfig ().RPC_PASSWORD.empty (); + return false; std::string strUserPass64 = it->second.substr (6); boost::trim (strUserPass64); diff --git a/src/ripple/unity/app.cpp b/src/ripple/unity/app.cpp index 0542c45ea9..f6928ae9ee 100644 --- a/src/ripple/unity/app.cpp +++ b/src/ripple/unity/app.cpp @@ -23,11 +23,12 @@ #include #include #include -#include #include #include #include +#include + #include #include #include diff --git a/src/ripple/unity/http.cpp b/src/ripple/unity/http.cpp index d980419cbe..1ad92de1fe 100644 --- a/src/ripple/unity/http.cpp +++ b/src/ripple/unity/http.cpp @@ -19,19 +19,9 @@ #include -#include - -#include - -#include -#include - +#include +#include #include #include - -#include -#include -#include -#include #include #include diff --git a/src/ripple/unity/http.h b/src/ripple/unity/http.h deleted file mode 100644 index 12a900fbec..0000000000 --- a/src/ripple/unity/http.h +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_HTTP_H_INCLUDED -#define RIPPLE_HTTP_H_INCLUDED - -// VFALCO This entire file is deprecated now, I'm working on a replacement - -// VFALCO NOTE this sucks that we have to include asio in the header -// just for HTTPMessage!! -#include - -#include -#include -#include -#include -#include - -#endif