mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Split HTTP::Server to its own module
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,263 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_FRAME_HTTPSERVER_H_INCLUDED
|
||||
#define RIPPLE_FRAME_HTTPSERVER_H_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
/** Multi-threaded, asynchronous HTTP server. */
|
||||
class HTTPServer
|
||||
{
|
||||
public:
|
||||
/** Configuration information for a listening port. */
|
||||
struct Port
|
||||
{
|
||||
enum Security
|
||||
{
|
||||
no_ssl,
|
||||
allow_ssl,
|
||||
require_ssl
|
||||
};
|
||||
|
||||
Port ();
|
||||
Port (Port const& other);
|
||||
Port& operator= (Port const& other);
|
||||
Port (uint16 port_, IPEndpoint const& addr_,
|
||||
Security security_, SSLContext* context_);
|
||||
|
||||
uint16 port;
|
||||
IPEndpoint addr;
|
||||
Security security;
|
||||
SSLContext* context;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class Session;
|
||||
|
||||
/** Scoped ostream-based RAII container for building the HTTP response. */
|
||||
class ScopedStream
|
||||
{
|
||||
public:
|
||||
explicit ScopedStream (Session& session);
|
||||
ScopedStream (ScopedStream const& other);
|
||||
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
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,
|
||||
and all only become defined during specific callbacks.
|
||||
*/
|
||||
class Session : public Uncopyable
|
||||
{
|
||||
public:
|
||||
Session ();
|
||||
|
||||
/** Input: The Journal the HTTPServer is using. */
|
||||
Journal journal;
|
||||
|
||||
/** Input: The remote address of the connection. */
|
||||
IPEndpoint remoteAddress;
|
||||
|
||||
/** Input: `true` if all the headers have been received. */
|
||||
bool headersComplete;
|
||||
|
||||
/** Input: The currently known set of HTTP headers. */
|
||||
HTTPHeaders headers;
|
||||
|
||||
/** Input: The full HTTPRequest when it is known. */
|
||||
SharedPtr <HTTPRequest> request;
|
||||
|
||||
/** Input: The Content-Body as a linear buffer if we have the HTTPRequest. */
|
||||
std::string content;
|
||||
|
||||
/** Output: The buffer to send back as a reply.
|
||||
Upon each entry into the callback, reply.size() will be zero.
|
||||
If reply.size() is zero when the callback returns, no data is
|
||||
sent.
|
||||
*/
|
||||
std::string reply;
|
||||
|
||||
/** A user-definable pointer.
|
||||
The initial value is always zero.
|
||||
Changes to the value are persisted between calls.
|
||||
*/
|
||||
void* tag;
|
||||
|
||||
|
||||
|
||||
/** Send a copy of data asynchronously. */
|
||||
/** @{ */
|
||||
void write (std::string const& s)
|
||||
{
|
||||
if (! s.empty())
|
||||
write (&s.front(),
|
||||
std::distance (s.begin(), s.end()));
|
||||
}
|
||||
|
||||
template <typename BufferSequence>
|
||||
void write (BufferSequence const& buffers)
|
||||
{
|
||||
for (typename BufferSequence::const_iterator iter (buffers.begin());
|
||||
iter != buffers.end(); ++iter)
|
||||
{
|
||||
typename BufferSequence::value_type const& buffer (*iter);
|
||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
||||
boost::asio::buffer_size (buffer));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void write (void const* buffer, std::size_t bytes) = 0;
|
||||
/** @} */
|
||||
|
||||
/** Output support using ostream. */
|
||||
/** @{ */
|
||||
ScopedStream operator<< (std::ostream& manip (std::ostream&));
|
||||
|
||||
template <typename T>
|
||||
ScopedStream operator<< (T const& t)
|
||||
{
|
||||
return ScopedStream (*this, t);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Detach the session.
|
||||
This holds the session open so that the response can be sent
|
||||
asynchronously. Calls to io_service::run made by the HTTPServer
|
||||
will not return until all detached sessions are closed.
|
||||
*/
|
||||
virtual void detach() = 0;
|
||||
|
||||
/** Close the session.
|
||||
This will be performed asynchronously. The session will be
|
||||
closed gracefully after all pending writes have completed.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
virtual void onClose (Session& session) = 0;
|
||||
|
||||
/** Called when the HTTPServer has finished its stop. */
|
||||
virtual void onStopped (HTTPServer& server) = 0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** A set of listening ports settings. */
|
||||
typedef std::vector <Port> Ports;
|
||||
|
||||
/** Create the server using the specified handler. */
|
||||
HTTPServer (Handler& handler, Journal journal);
|
||||
|
||||
/** Destroy the server.
|
||||
This blocks until the server stops.
|
||||
*/
|
||||
virtual ~HTTPServer ();
|
||||
|
||||
/** Returns the Journal associated with the server. */
|
||||
Journal const& 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;
|
||||
|
||||
/** Set the listening ports settings.
|
||||
These take effect immediately. Any current ports that are not in the
|
||||
new set will be closed. Established connections will not be disturbed.
|
||||
Thread safety:
|
||||
Cannot be called concurrently.
|
||||
*/
|
||||
void setPorts (Ports const& ports);
|
||||
|
||||
/** Notify the server to stop, without blocking.
|
||||
Thread safety:
|
||||
Safe to call concurrently from any thread.
|
||||
*/
|
||||
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.
|
||||
Thread safety:
|
||||
Cannot be called concurrently.
|
||||
Cannot be called from the thread of execution of any Handler functions.
|
||||
*/
|
||||
void stop ();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
ScopedPointer <Impl> m_impl;
|
||||
};
|
||||
|
||||
int compare (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator== (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator!= (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator< (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator<= (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator> (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
bool operator>= (HTTPServer::Port const& lhs, HTTPServer::Port const& rhs);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
47
src/ripple/http/api/Handler.h
Normal file
47
src/ripple/http/api/Handler.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_HANDLER_H_INCLUDED
|
||||
#define RIPPLE_HTTP_HANDLER_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
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.
|
||||
*/
|
||||
virtual void onClose (Session& session) = 0;
|
||||
|
||||
/** Called when the server has finished its stop. */
|
||||
virtual void onStopped (Server& server) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
51
src/ripple/http/api/Port.h
Normal file
51
src/ripple/http/api/Port.h
Normal file
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_PORT_H_INCLUDED
|
||||
#define RIPPLE_HTTP_PORT_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
/** 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 (uint16 port_, IPEndpoint const& addr_,
|
||||
Security security_, SSLContext* context_);
|
||||
|
||||
uint16 port;
|
||||
IPEndpoint addr;
|
||||
Security security;
|
||||
SSLContext* context;
|
||||
};
|
||||
|
||||
int compare (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);
|
||||
bool operator>= (Port const& lhs, Port const& rhs);
|
||||
|
||||
/** A set of listening ports settings. */
|
||||
typedef std::vector <Port> Ports;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
57
src/ripple/http/api/ScopedStream.h
Normal file
57
src/ripple/http/api/ScopedStream.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_SCOPEDSTREAM_H_INCLUDED
|
||||
#define RIPPLE_HTTP_SCOPEDSTREAM_H_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
class Session;
|
||||
|
||||
/** Scoped ostream-based RAII container for building the HTTP response. */
|
||||
class ScopedStream
|
||||
{
|
||||
public:
|
||||
explicit ScopedStream (Session& session);
|
||||
ScopedStream (ScopedStream const& other);
|
||||
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
70
src/ripple/http/api/Server.h
Normal file
70
src/ripple/http/api/Server.h
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_SERVER_H_INCLUDED
|
||||
#define RIPPLE_HTTP_SERVER_H_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
class ServerImpl;
|
||||
|
||||
/** Multi-threaded, asynchronous HTTP server. */
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
/** Create the server using the specified handler. */
|
||||
Server (Handler& handler, Journal journal);
|
||||
|
||||
/** Destroy the server.
|
||||
This blocks until the server stops.
|
||||
*/
|
||||
virtual ~Server ();
|
||||
|
||||
/** Returns the Journal associated with the server. */
|
||||
Journal const& 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;
|
||||
|
||||
/** Set the listening ports settings.
|
||||
These take effect immediately. Any current ports that are not in the
|
||||
new set will be closed. Established connections will not be disturbed.
|
||||
Thread safety:
|
||||
Cannot be called concurrently.
|
||||
*/
|
||||
void setPorts (Ports const& ports);
|
||||
|
||||
/** Notify the server to stop, without blocking.
|
||||
Thread safety:
|
||||
Safe to call concurrently from any thread.
|
||||
*/
|
||||
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.
|
||||
Thread safety:
|
||||
Cannot be called concurrently.
|
||||
Cannot be called from the thread of execution of any Handler functions.
|
||||
*/
|
||||
void stop ();
|
||||
|
||||
private:
|
||||
ScopedPointer <ServerImpl> m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
112
src/ripple/http/api/Session.h
Normal file
112
src/ripple/http/api/Session.h
Normal file
@@ -0,0 +1,112 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_SESSION_H_INCLUDED
|
||||
#define RIPPLE_HTTP_SESSION_H_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
/** Persistent state information for a connection session.
|
||||
These values are preserved between calls for efficiency.
|
||||
Some fields are input parameters, some are output parameters,
|
||||
and all only become defined during specific callbacks.
|
||||
*/
|
||||
class Session : public Uncopyable
|
||||
{
|
||||
public:
|
||||
Session ();
|
||||
|
||||
/** Input: The Journal the server is using. */
|
||||
Journal journal;
|
||||
|
||||
/** Input: The remote address of the connection. */
|
||||
IPEndpoint remoteAddress;
|
||||
|
||||
/** Input: `true` if all the headers have been received. */
|
||||
bool headersComplete;
|
||||
|
||||
/** Input: The currently known set of HTTP headers. */
|
||||
HTTPHeaders headers;
|
||||
|
||||
/** Input: The full HTTPRequest when it is known. */
|
||||
SharedPtr <HTTPRequest> request;
|
||||
|
||||
/** Input: The Content-Body as a linear buffer if we have the HTTPRequest. */
|
||||
std::string content;
|
||||
|
||||
/** Output: The buffer to send back as a reply.
|
||||
Upon each entry into the callback, reply.size() will be zero.
|
||||
If reply.size() is zero when the callback returns, no data is
|
||||
sent.
|
||||
*/
|
||||
std::string reply;
|
||||
|
||||
/** A user-definable pointer.
|
||||
The initial value is always zero.
|
||||
Changes to the value are persisted between calls.
|
||||
*/
|
||||
void* tag;
|
||||
|
||||
|
||||
|
||||
/** Send a copy of data asynchronously. */
|
||||
/** @{ */
|
||||
void write (std::string const& s)
|
||||
{
|
||||
if (! s.empty())
|
||||
write (&s.front(),
|
||||
std::distance (s.begin(), s.end()));
|
||||
}
|
||||
|
||||
template <typename BufferSequence>
|
||||
void write (BufferSequence const& buffers)
|
||||
{
|
||||
for (typename BufferSequence::const_iterator iter (buffers.begin());
|
||||
iter != buffers.end(); ++iter)
|
||||
{
|
||||
typename BufferSequence::value_type const& buffer (*iter);
|
||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
||||
boost::asio::buffer_size (buffer));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void write (void const* buffer, std::size_t bytes) = 0;
|
||||
/** @} */
|
||||
|
||||
/** Output support using ostream. */
|
||||
/** @{ */
|
||||
ScopedStream operator<< (std::ostream& manip (std::ostream&));
|
||||
|
||||
template <typename T>
|
||||
ScopedStream operator<< (T const& t)
|
||||
{
|
||||
return ScopedStream (*this, t);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Detach the session.
|
||||
This holds the session open so that the response can be sent
|
||||
asynchronously. Calls to io_service::run made by the server
|
||||
will not return until all detached sessions are closed.
|
||||
*/
|
||||
virtual void detach() = 0;
|
||||
|
||||
/** Close the session.
|
||||
This will be performed asynchronously. The session will be
|
||||
closed gracefully after all pending writes have completed.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
102
src/ripple/http/impl/Door.cpp
Normal file
102
src/ripple/http/impl/Door.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
Door::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);
|
||||
|
||||
error_code ec;
|
||||
|
||||
m_acceptor.set_option (acceptor::reuse_address (true), ec);
|
||||
if (ec)
|
||||
{
|
||||
m_impl.journal().error <<
|
||||
"Error setting acceptor socket option: " << ec.message();
|
||||
}
|
||||
|
||||
if (! ec)
|
||||
{
|
||||
m_impl.journal().info << "Bound to endpoint " <<
|
||||
to_string (m_acceptor.local_endpoint());
|
||||
|
||||
async_accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_impl.journal().error << "Error binding to endpoint " <<
|
||||
to_string (m_acceptor.local_endpoint()) <<
|
||||
", '" << ec.message() << "'";
|
||||
}
|
||||
}
|
||||
|
||||
Door::~Door ()
|
||||
{
|
||||
m_impl.remove (*this);
|
||||
}
|
||||
|
||||
Port const& Door::port () const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
void Door::cancel ()
|
||||
{
|
||||
m_acceptor.cancel();
|
||||
}
|
||||
|
||||
void Door::failed (error_code ec)
|
||||
{
|
||||
}
|
||||
|
||||
void Door::asyncHandlersComplete ()
|
||||
{
|
||||
}
|
||||
|
||||
void Door::async_accept ()
|
||||
{
|
||||
Peer* peer (new Peer (m_impl, m_port));
|
||||
m_acceptor.async_accept (peer->get_socket(), boost::bind (
|
||||
&Door::handle_accept, Ptr(this),
|
||||
boost::asio::placeholders::error,
|
||||
Peer::Ptr (peer), CompletionCounter (this)));
|
||||
}
|
||||
|
||||
void Door::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();
|
||||
|
||||
// Save remote address in session
|
||||
peer->session().remoteAddress = from_asio (
|
||||
peer->get_socket().remote_endpoint()).withPort (0);
|
||||
m_impl.handler().onAccept (peer->session());
|
||||
|
||||
if (peer->session().closed())
|
||||
{
|
||||
peer->cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
peer->handle_accept();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
42
src/ripple/http/impl/Door.h
Normal file
42
src/ripple/http/impl/Door.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_DOOR_H_INCLUDED
|
||||
#define RIPPLE_HTTP_DOOR_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
/** A listening socket. */
|
||||
class Door
|
||||
: public SharedObject
|
||||
, public AsyncObject <Door>
|
||||
, public List <Door>::Node
|
||||
, public LeakChecked <Door>
|
||||
{
|
||||
public:
|
||||
typedef SharedPtr <Door> Ptr;
|
||||
|
||||
ServerImpl& m_impl;
|
||||
acceptor m_acceptor;
|
||||
Port m_port;
|
||||
|
||||
Door (ServerImpl& impl, Port const& port);
|
||||
~Door ();
|
||||
Port const& port () const;
|
||||
void cancel ();
|
||||
void failed (error_code ec);
|
||||
void asyncHandlersComplete ();
|
||||
void async_accept ();
|
||||
void handle_accept (error_code ec, Peer::Ptr peer, CompletionCounter);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
362
src/ripple/http/impl/Peer.cpp
Normal file
362
src/ripple/http/impl/Peer.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
Peer::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_parser (HTTPParser::typeRequest)
|
||||
, m_session (*this)
|
||||
, m_writesPending (0)
|
||||
, m_callClose (false)
|
||||
{
|
||||
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 = MultiSocket::New (m_impl.get_io_service(), port.context->get(), flags);
|
||||
|
||||
m_impl.add (*this);
|
||||
}
|
||||
|
||||
Peer::~Peer ()
|
||||
{
|
||||
if (m_callClose)
|
||||
m_impl.handler().onClose (m_session);
|
||||
|
||||
m_impl.remove (*this);
|
||||
}
|
||||
|
||||
// Returns the asio socket for the peer.
|
||||
//
|
||||
socket& Peer::get_socket()
|
||||
{
|
||||
return m_socket->this_layer<socket>();
|
||||
}
|
||||
|
||||
// Return the Session associated with this peer's session.
|
||||
//
|
||||
SessionImpl& Peer::session ()
|
||||
{
|
||||
return m_session;
|
||||
}
|
||||
|
||||
// Cancels all pending i/o and timers and sends tcp shutdown.
|
||||
//
|
||||
void Peer::cancel ()
|
||||
{
|
||||
error_code ec;
|
||||
m_data_timer.cancel (ec);
|
||||
m_request_timer.cancel (ec);
|
||||
m_socket->cancel (ec);
|
||||
m_socket->shutdown (socket::shutdown_both);
|
||||
}
|
||||
|
||||
// Called when I/O completes with an error that is not eof or aborted.
|
||||
//
|
||||
void Peer::failed (error_code ec)
|
||||
{
|
||||
cancel ();
|
||||
}
|
||||
|
||||
// Called when there are no more completion handlers pending.
|
||||
//
|
||||
void Peer::asyncHandlersComplete ()
|
||||
{
|
||||
}
|
||||
|
||||
// Send a copy of the data.
|
||||
//
|
||||
void Peer::write (void const* buffer, std::size_t bytes)
|
||||
{
|
||||
SharedBuffer buf (static_cast <char const*> (buffer), bytes);
|
||||
// Make sure this happens on an i/o service thread.
|
||||
m_impl.get_io_service().dispatch (m_strand.wrap (
|
||||
boost::bind (&Peer::handle_write, Ptr (this),
|
||||
buf, CompletionCounter (this))));
|
||||
}
|
||||
|
||||
// Called from an io_service thread to write the shared buffer.
|
||||
//
|
||||
void Peer::handle_write (SharedBuffer const& buf, CompletionCounter)
|
||||
{
|
||||
async_write (buf);
|
||||
}
|
||||
|
||||
// Send a shared buffer
|
||||
//
|
||||
void Peer::async_write (SharedBuffer const& buf)
|
||||
{
|
||||
bassert (buf.get().size() > 0);
|
||||
|
||||
++m_writesPending;
|
||||
|
||||
// Send the copy. We pass the SharedArg 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->front(), buf->size()),
|
||||
m_strand.wrap (boost::bind (&Peer::handle_write,
|
||||
Ptr (this), boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
buf, CompletionCounter (this))));
|
||||
}
|
||||
|
||||
// Calls the async_read_some initiating function.
|
||||
//
|
||||
void Peer::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));
|
||||
|
||||
m_data_timer.async_wait (m_strand.wrap (boost::bind (
|
||||
&Peer::handle_data_timer, Ptr(this),
|
||||
boost::asio::placeholders::error,
|
||||
CompletionCounter (this))));
|
||||
|
||||
// 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))));
|
||||
}
|
||||
|
||||
// Sends a copy of the reply in the session if it is not empty.
|
||||
// Returns `true` if m_session.closed is `true`
|
||||
// On return, reply.empty() will return `true`.
|
||||
//
|
||||
void Peer::maybe_send_reply ()
|
||||
{
|
||||
if (! m_session.reply.empty())
|
||||
{
|
||||
async_write (boost::asio::const_buffers_1 (
|
||||
&m_session.reply.front(), m_session.reply.size()));
|
||||
m_session.reply.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the acceptor gives us the connection.
|
||||
//
|
||||
void Peer::handle_accept ()
|
||||
{
|
||||
m_callClose = true;
|
||||
|
||||
m_request_timer.expires_from_now (
|
||||
boost::posix_time::seconds (
|
||||
requestTimeoutSeconds));
|
||||
|
||||
m_request_timer.async_wait (m_strand.wrap (boost::bind (
|
||||
&Peer::handle_request_timer, Ptr(this),
|
||||
boost::asio::placeholders::error,
|
||||
CompletionCounter (this))));
|
||||
|
||||
if (m_socket->needs_handshake ())
|
||||
{
|
||||
m_socket->async_handshake (Socket::server, m_strand.wrap (
|
||||
boost::bind (&Peer::handle_handshake, Ptr(this),
|
||||
boost::asio::placeholders::error,
|
||||
CompletionCounter (this))));
|
||||
}
|
||||
else
|
||||
{
|
||||
async_read_some();
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the handshake completes
|
||||
//
|
||||
void Peer::handle_handshake (error_code ec, CompletionCounter)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
if (ec != 0)
|
||||
{
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
|
||||
async_read_some();
|
||||
}
|
||||
|
||||
// Called when the data timer expires
|
||||
//
|
||||
void Peer::handle_data_timer (error_code ec, CompletionCounter)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
if (ec != 0)
|
||||
{
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
|
||||
// They took too long to send any bytes
|
||||
cancel();
|
||||
}
|
||||
|
||||
// Called when the request timer expires
|
||||
//
|
||||
void Peer::handle_request_timer (error_code ec, CompletionCounter)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
if (ec != 0)
|
||||
{
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
|
||||
// They took too long to complete the request
|
||||
cancel();
|
||||
}
|
||||
|
||||
// Called when async_write completes.
|
||||
//
|
||||
void Peer::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_session.closed())
|
||||
{
|
||||
m_socket->shutdown (socket::shutdown_send);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when async_read_some completes.
|
||||
//
|
||||
void Peer::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)
|
||||
{
|
||||
// set ec manually and call failed()
|
||||
return;
|
||||
}
|
||||
|
||||
if (ec == boost::asio::error::eof)
|
||||
{
|
||||
m_parser.process_eof();
|
||||
ec = error_code();
|
||||
}
|
||||
|
||||
if (m_parser.error())
|
||||
{
|
||||
// set ec manually and call failed()
|
||||
return;
|
||||
}
|
||||
|
||||
if (! m_parser.finished())
|
||||
{
|
||||
// Feed some headers to the callback
|
||||
if (m_parser.fields().size() > 0)
|
||||
{
|
||||
handle_headers ();
|
||||
if (m_session.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 Peer::handle_headers ()
|
||||
{
|
||||
m_session.headersComplete = m_parser.headersComplete();
|
||||
m_session.headers = HTTPHeaders (m_parser.fields());
|
||||
m_impl.handler().onHeaders (m_session);
|
||||
|
||||
maybe_send_reply ();
|
||||
}
|
||||
|
||||
// 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 (m_session.closed())
|
||||
return;
|
||||
|
||||
m_session.request = m_parser.request();
|
||||
|
||||
// Turn the Content-Body into a linear buffer.
|
||||
ContentBodyBuffer const& body (m_session.request->body ());
|
||||
m_session.content.resize (body.size ());
|
||||
boost::asio::buffer_copy (
|
||||
boost::asio::buffer (&m_session.content.front(),
|
||||
m_session.content.size()), body.data());
|
||||
|
||||
// Process the HTTPRequest
|
||||
m_impl.handler().onRequest (m_session);
|
||||
|
||||
maybe_send_reply ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
101
src/ripple/http/impl/Peer.h
Normal file
101
src/ripple/http/impl/Peer.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_PEER_H_INCLUDED
|
||||
#define RIPPLE_HTTP_PEER_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
/** Represents an active connection. */
|
||||
class Peer
|
||||
: public SharedObject
|
||||
, public AsyncObject <Peer>
|
||||
, public List <Peer>::Node
|
||||
, public LeakChecked <Peer>
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
// Size of our receive buffer
|
||||
bufferSize = 8192,
|
||||
|
||||
// Largest HTTP request allowed
|
||||
maxRequestBytes = 32 * 1024,
|
||||
|
||||
// Max seconds without receiving a byte
|
||||
dataTimeoutSeconds = 10,
|
||||
|
||||
// Max seconds without completing the request
|
||||
requestTimeoutSeconds = 30
|
||||
|
||||
};
|
||||
|
||||
typedef SharedPtr <Peer> Ptr;
|
||||
|
||||
ServerImpl& m_impl;
|
||||
boost::asio::io_service::strand m_strand;
|
||||
boost::asio::deadline_timer m_data_timer;
|
||||
boost::asio::deadline_timer m_request_timer;
|
||||
ScopedPointer <MultiSocket> m_socket;
|
||||
MemoryBlock m_buffer;
|
||||
HTTPParser m_parser;
|
||||
SessionImpl m_session;
|
||||
int m_writesPending;
|
||||
bool m_callClose;
|
||||
|
||||
Peer (ServerImpl& impl, Port const& port);
|
||||
~Peer ();
|
||||
socket& get_socket();
|
||||
SessionImpl& session ();
|
||||
void cancel ();
|
||||
void failed (error_code ec);
|
||||
void asyncHandlersComplete ();
|
||||
void write (void const* buffer, std::size_t bytes);
|
||||
void handle_write (SharedBuffer const& buf, CompletionCounter);
|
||||
void async_write (SharedBuffer const& buf);
|
||||
|
||||
template <typename BufferSequence>
|
||||
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 <char const*> (buffer),
|
||||
boost::asio::buffer_size (buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
void async_read_some ();
|
||||
void maybe_send_reply ();
|
||||
void handle_accept ();
|
||||
void handle_handshake (error_code ec, CompletionCounter);
|
||||
void handle_data_timer (error_code ec, CompletionCounter);
|
||||
void handle_request_timer (error_code ec, CompletionCounter);
|
||||
|
||||
void handle_write (error_code ec, std::size_t bytes_transferred,
|
||||
SharedBuffer buf, CompletionCounter);
|
||||
|
||||
void handle_read (error_code ec, std::size_t bytes_transferred,
|
||||
CompletionCounter);
|
||||
|
||||
void handle_headers ();
|
||||
void handle_request ();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
77
src/ripple/http/impl/Port.cpp
Normal file
77
src/ripple/http/impl/Port.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
Port::Port ()
|
||||
: port (0)
|
||||
, security (no_ssl)
|
||||
, context (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Port::Port (Port const& other)
|
||||
: port (other.port)
|
||||
, addr (other.addr)
|
||||
, security (other.security)
|
||||
, context (other.context)
|
||||
{
|
||||
}
|
||||
|
||||
Port& Port::operator= (Port const& other)
|
||||
{
|
||||
port = other.port;
|
||||
addr = other.addr;
|
||||
security = other.security;
|
||||
context = other.context;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Port::Port (
|
||||
uint16 port_,
|
||||
IPEndpoint const& addr_,
|
||||
Security security_,
|
||||
SSLContext* context_)
|
||||
: port (port_)
|
||||
, addr (addr_)
|
||||
, security (security_)
|
||||
, context (context_)
|
||||
{
|
||||
}
|
||||
|
||||
int compare (Port const& lhs, Port const& rhs)
|
||||
{
|
||||
int comp;
|
||||
|
||||
comp = compare (lhs.addr, rhs.addr);
|
||||
if (comp != 0)
|
||||
return comp;
|
||||
|
||||
if (lhs.port < rhs.port)
|
||||
return -1;
|
||||
else if (lhs.port > rhs.port)
|
||||
return 1;
|
||||
|
||||
if (lhs.security < rhs.security)
|
||||
return -1;
|
||||
else if (lhs.security > rhs.security)
|
||||
return 1;
|
||||
|
||||
// 'context' does not participate in the comparison
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator== (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) == 0; }
|
||||
bool operator!= (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) != 0; }
|
||||
bool operator< (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) < 0; }
|
||||
bool operator<= (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) <= 0; }
|
||||
bool operator> (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) > 0; }
|
||||
bool operator>= (Port const& lhs, Port const& rhs) { return compare (lhs, rhs) >= 0; }
|
||||
|
||||
}
|
||||
}
|
||||
44
src/ripple/http/impl/ScopedStream.cpp
Normal file
44
src/ripple/http/impl/ScopedStream.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
ScopedStream::ScopedStream (Session& session)
|
||||
: m_session (session)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedStream::ScopedStream (ScopedStream const& other)
|
||||
: m_session (other.m_session)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedStream::ScopedStream (Session& session,
|
||||
std::ostream& manip (std::ostream&))
|
||||
: m_session (session)
|
||||
{
|
||||
m_ostream << manip;
|
||||
}
|
||||
|
||||
ScopedStream::~ScopedStream ()
|
||||
{
|
||||
if (! m_ostream.str().empty())
|
||||
m_session.write (m_ostream.str());
|
||||
}
|
||||
|
||||
std::ostream& ScopedStream::operator<< (std::ostream& manip (std::ostream&)) const
|
||||
{
|
||||
return m_ostream << manip;
|
||||
}
|
||||
|
||||
std::ostringstream& ScopedStream::ostream () const
|
||||
{
|
||||
return m_ostream;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
46
src/ripple/http/impl/Server.cpp
Normal file
46
src/ripple/http/impl/Server.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
Server::Server (Handler& handler, Journal journal)
|
||||
: m_impl (new ServerImpl (*this, handler, journal))
|
||||
{
|
||||
}
|
||||
|
||||
Server::~Server ()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
Journal const& Server::journal () const
|
||||
{
|
||||
return m_impl->journal();
|
||||
}
|
||||
|
||||
Ports const& Server::getPorts () const
|
||||
{
|
||||
return m_impl->getPorts();
|
||||
}
|
||||
|
||||
void Server::setPorts (Ports const& ports)
|
||||
{
|
||||
m_impl->setPorts (ports);
|
||||
}
|
||||
|
||||
void Server::stopAsync ()
|
||||
{
|
||||
m_impl->stop(false);
|
||||
}
|
||||
|
||||
void Server::stop ()
|
||||
{
|
||||
m_impl->stop(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
246
src/ripple/http/impl/ServerImpl.h
Normal file
246
src/ripple/http/impl/ServerImpl.h
Normal file
@@ -0,0 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_SERVERIMPL_H_INCLUDED
|
||||
#define RIPPLE_HTTP_SERVERIMPL_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
class ServerImpl : public Thread
|
||||
{
|
||||
public:
|
||||
struct State
|
||||
{
|
||||
// Attributes for our listening ports
|
||||
Ports ports;
|
||||
|
||||
// All allocated Peer objects
|
||||
List <Peer> peers;
|
||||
|
||||
// All allocated Door objects
|
||||
List <Door> doors;
|
||||
};
|
||||
|
||||
typedef SharedData <State> SharedState;
|
||||
typedef std::vector <Door::Ptr> Doors;
|
||||
|
||||
Server& m_server;
|
||||
Handler& m_handler;
|
||||
Journal m_journal;
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::io_service::strand m_strand;
|
||||
boost::optional <boost::asio::io_service::work> m_work;
|
||||
WaitableEvent m_stopped;
|
||||
SharedState m_state;
|
||||
Doors m_doors;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
ServerImpl (Server& server, Handler& handler, Journal journal)
|
||||
: Thread ("HTTP::Server")
|
||||
, m_server (server)
|
||||
, m_handler (handler)
|
||||
, m_journal (journal)
|
||||
, m_strand (m_io_service)
|
||||
, m_work (boost::in_place (boost::ref (m_io_service)))
|
||||
, m_stopped (true)
|
||||
{
|
||||
startThread ();
|
||||
}
|
||||
|
||||
~ServerImpl ()
|
||||
{
|
||||
stopThread ();
|
||||
}
|
||||
|
||||
Journal const& journal() const
|
||||
{
|
||||
return m_journal;
|
||||
}
|
||||
|
||||
Ports const& getPorts () const
|
||||
{
|
||||
SharedState::UnlockedAccess state (m_state);
|
||||
return state->ports;
|
||||
}
|
||||
|
||||
void setPorts (Ports const& ports)
|
||||
{
|
||||
SharedState::Access state (m_state);
|
||||
state->ports = ports;
|
||||
update();
|
||||
}
|
||||
|
||||
bool stopping () const
|
||||
{
|
||||
return ! m_work;
|
||||
}
|
||||
|
||||
void stop (bool wait)
|
||||
{
|
||||
if (! stopping())
|
||||
{
|
||||
m_work = boost::none;
|
||||
update();
|
||||
}
|
||||
|
||||
if (wait)
|
||||
m_stopped.wait();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Server
|
||||
//
|
||||
|
||||
Handler& handler()
|
||||
{
|
||||
return m_handler;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service()
|
||||
{
|
||||
return m_io_service;
|
||||
}
|
||||
|
||||
// Inserts the peer into our list of peers. We only remove it
|
||||
// from the list inside the destructor of the Peer object. This
|
||||
// way, the Peer can never outlive the server.
|
||||
//
|
||||
void add (Peer& peer)
|
||||
{
|
||||
SharedState::Access state (m_state);
|
||||
state->peers.push_back (peer);
|
||||
}
|
||||
|
||||
void add (Door& door)
|
||||
{
|
||||
SharedState::Access state (m_state);
|
||||
state->doors.push_back (door);
|
||||
}
|
||||
|
||||
// Removes the peer from our list of peers. This is only called from
|
||||
// the destructor of Peer. Essentially, the item in the list functions
|
||||
// as a weak_ptr.
|
||||
//
|
||||
void remove (Peer& peer)
|
||||
{
|
||||
SharedState::Access state (m_state);
|
||||
state->peers.erase (state->peers.iterator_to (peer));
|
||||
}
|
||||
|
||||
void remove (Door& door)
|
||||
{
|
||||
SharedState::Access state (m_state);
|
||||
state->doors.push_back (door);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Thread
|
||||
//
|
||||
|
||||
// Updates our Door list based on settings.
|
||||
//
|
||||
void handle_update ()
|
||||
{
|
||||
if (! stopping())
|
||||
{
|
||||
// Make a local copy to shorten the lock
|
||||
//
|
||||
Ports ports;
|
||||
{
|
||||
SharedState::ConstAccess state (m_state);
|
||||
ports = state->ports;
|
||||
}
|
||||
|
||||
std::sort (ports.begin(), ports.end());
|
||||
|
||||
// Walk the Door list and the Port list simultaneously and
|
||||
// build a replacement Door vector which we will then swap in.
|
||||
//
|
||||
Doors doors;
|
||||
Doors::iterator door (m_doors.begin());
|
||||
for (Ports::const_iterator port (ports.begin());
|
||||
port != ports.end(); ++port)
|
||||
{
|
||||
int comp;
|
||||
|
||||
while (door != m_doors.end() &&
|
||||
((comp = compare (*port, (*door)->port())) > 0))
|
||||
{
|
||||
(*door)->cancel();
|
||||
++door;
|
||||
}
|
||||
|
||||
if (door != m_doors.end())
|
||||
{
|
||||
if (comp < 0)
|
||||
{
|
||||
doors.push_back (new Door (*this, *port));
|
||||
}
|
||||
else
|
||||
{
|
||||
// old Port and new Port are the same
|
||||
doors.push_back (*door);
|
||||
++door;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doors.push_back (new Door (*this, *port));
|
||||
}
|
||||
}
|
||||
|
||||
// Any remaining Door objects are not in the new set, so cancel them.
|
||||
//
|
||||
for (;door != m_doors.end();)
|
||||
(*door)->cancel();
|
||||
|
||||
m_doors.swap (doors);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cancel pending I/O on all doors.
|
||||
//
|
||||
for (Doors::iterator iter (m_doors.begin());
|
||||
iter != m_doors.end(); ++iter)
|
||||
{
|
||||
(*iter)->cancel();
|
||||
}
|
||||
|
||||
// Remove our references to the old doors.
|
||||
//
|
||||
m_doors.resize (0);
|
||||
}
|
||||
}
|
||||
|
||||
// Causes handle_update to run on the io_service
|
||||
//
|
||||
void update ()
|
||||
{
|
||||
m_io_service.post (m_strand.wrap (boost::bind (
|
||||
&ServerImpl::handle_update, this)));
|
||||
}
|
||||
|
||||
// The main i/o processing loop.
|
||||
//
|
||||
void run ()
|
||||
{
|
||||
m_io_service.run ();
|
||||
|
||||
m_stopped.signal();
|
||||
m_handler.onStopped (m_server);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
25
src/ripple/http/impl/Session.cpp
Normal file
25
src/ripple/http/impl/Session.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
Session::Session ()
|
||||
: headersComplete (false)
|
||||
, tag (nullptr)
|
||||
{
|
||||
content.reserve (1000);
|
||||
reply.reserve (1000);
|
||||
}
|
||||
|
||||
ScopedStream Session::operator<< (
|
||||
std::ostream& manip (std::ostream&))
|
||||
{
|
||||
return ScopedStream (*this, manip);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
43
src/ripple/http/impl/SessionImpl.cpp
Normal file
43
src/ripple/http/impl/SessionImpl.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
SessionImpl::SessionImpl (Peer& peer)
|
||||
: m_peer (peer)
|
||||
, m_closed (false)
|
||||
{
|
||||
}
|
||||
|
||||
SessionImpl::~SessionImpl ()
|
||||
{
|
||||
}
|
||||
|
||||
bool SessionImpl::closed() const
|
||||
{
|
||||
return m_closed;
|
||||
}
|
||||
|
||||
void SessionImpl::write (void const* buffer, std::size_t bytes)
|
||||
{
|
||||
m_peer.write (buffer, bytes);
|
||||
}
|
||||
|
||||
void SessionImpl::close()
|
||||
{
|
||||
m_closed = true;
|
||||
}
|
||||
|
||||
void SessionImpl::detach()
|
||||
{
|
||||
if (! m_work)
|
||||
m_work = boost::in_place (boost::ref (
|
||||
m_peer.m_impl.get_io_service()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
38
src/ripple/http/impl/SessionImpl.h
Normal file
38
src/ripple/http/impl/SessionImpl.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_SESSIONIMPL_H_INCLUDED
|
||||
#define RIPPLE_HTTP_SESSIONIMPL_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
using namespace beast;
|
||||
|
||||
// Holds the copy of buffers being sent
|
||||
typedef SharedArg <std::string> SharedBuffer;
|
||||
|
||||
class Peer;
|
||||
|
||||
class SessionImpl : public Session
|
||||
{
|
||||
public:
|
||||
Peer& m_peer;
|
||||
bool m_closed;
|
||||
boost::optional <boost::asio::io_service::work> m_work;
|
||||
|
||||
explicit SessionImpl (Peer& peer);
|
||||
~SessionImpl ();
|
||||
bool closed() const;
|
||||
void write (void const* buffer, std::size_t bytes);
|
||||
void close();
|
||||
void detach();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
58
src/ripple/http/impl/Types.h
Normal file
58
src/ripple/http/impl/Types.h
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HTTP_TYPES_H_INCLUDED
|
||||
#define RIPPLE_HTTP_TYPES_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace HTTP {
|
||||
|
||||
typedef boost::system::error_code error_code;
|
||||
typedef boost::asio::ip::tcp Protocol;
|
||||
typedef boost::asio::ip::address address;
|
||||
typedef Protocol::endpoint endpoint_t;
|
||||
typedef Protocol::acceptor acceptor;
|
||||
typedef Protocol::socket socket;
|
||||
|
||||
inline std::string to_string (address const& addr)
|
||||
{
|
||||
return addr.to_string();
|
||||
}
|
||||
|
||||
inline std::string to_string (endpoint_t const& endpoint)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << to_string (endpoint.address());
|
||||
if (endpoint.port() != 0)
|
||||
ss << ":" << std::dec << endpoint.port();
|
||||
return std::string (ss.str());
|
||||
}
|
||||
|
||||
inline endpoint_t to_asio (Port const& port)
|
||||
{
|
||||
if (port.addr.isV4())
|
||||
{
|
||||
IPEndpoint::V4 v4 (port.addr.v4());
|
||||
std::string const& s (v4.to_string());
|
||||
return endpoint_t (address().from_string (s), port.port);
|
||||
}
|
||||
|
||||
//IPEndpoint::V6 v6 (ep.v6());
|
||||
return endpoint_t ();
|
||||
}
|
||||
|
||||
inline IPEndpoint from_asio (endpoint_t const& endpoint)
|
||||
{
|
||||
std::stringstream ss (to_string (endpoint));
|
||||
IPEndpoint ep;
|
||||
ss >> ep;
|
||||
return ep;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
29
src/ripple/http/ripple_http.cpp
Normal file
29
src/ripple/http/ripple_http.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "BeastConfig.h"
|
||||
|
||||
#include "ripple_http.h"
|
||||
|
||||
#include "../ripple_net/ripple_net.h"
|
||||
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "impl/Port.cpp"
|
||||
#include "impl/ScopedStream.cpp"
|
||||
#include "impl/Session.cpp"
|
||||
|
||||
# include "impl/Types.h"
|
||||
# include "impl/SessionImpl.h"
|
||||
# include "impl/Peer.h"
|
||||
# include "impl/Door.h"
|
||||
# include "impl/ServerImpl.h"
|
||||
#include "impl/Door.cpp"
|
||||
#include "impl/Peer.cpp"
|
||||
#include "impl/Server.cpp"
|
||||
#include "impl/SessionImpl.cpp"
|
||||
@@ -4,8 +4,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_FRAME_H_INCLUDED
|
||||
#define RIPPLE_FRAME_H_INCLUDED
|
||||
#ifndef RIPPLE_HTTP_H_INCLUDED
|
||||
#define RIPPLE_HTTP_H_INCLUDED
|
||||
|
||||
#include "beast/modules/beast_core/beast_core.h"
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
// just for HTTPMessage!!
|
||||
#include "beast/modules/beast_asio/beast_asio.h"
|
||||
|
||||
#include "../json/ripple_json.h"
|
||||
|
||||
#include "api/HTTPServer.h"
|
||||
#include "api/RPCService.h"
|
||||
# include "api/Port.h"
|
||||
# include "api/ScopedStream.h"
|
||||
# include "api/Session.h"
|
||||
# include "api/Handler.h"
|
||||
#include "api/Server.h"
|
||||
|
||||
#endif
|
||||
@@ -102,42 +102,6 @@ public:
|
||||
virtual std::pair <bool, Json::Value> call (
|
||||
std::string const& method, Json::Value const& args) = 0;
|
||||
|
||||
/** Execute an RPC command asynchronously.
|
||||
|
||||
If the method exists, the dispatcher is invoked to provide the
|
||||
context for calling the handler with the argument list and this
|
||||
function returns `true` immediately. The dispatcher calls the
|
||||
CompletionHandler when the operation is complete. If the method
|
||||
does not exist, `false` is returned.
|
||||
|
||||
Copies of the Dispatcher and CompletionHandler are made as needed.
|
||||
|
||||
CompletionHandler must be compatible with this signature:
|
||||
void (Json::Value const&)
|
||||
|
||||
Dispatcher is a functor compatible with this signature:
|
||||
void (Handler const& handler,
|
||||
Json::Value const& args,
|
||||
CompletionHandler completionHandler);
|
||||
|
||||
Thread safety:
|
||||
Safe to call from any thread.
|
||||
|
||||
@return `true` if a handler was found.
|
||||
*/
|
||||
template <class CompletionHandler, class Dispatcher>
|
||||
bool call_async (std::string const& method,
|
||||
Json::Value const& args,
|
||||
CompletionHandler completionHandler,
|
||||
Dispatcher dispatcher)
|
||||
{
|
||||
Handler const* handler (find (method));
|
||||
if (! handler)
|
||||
return false;
|
||||
dispatcher (*handler, args, completionHandler);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the Handler for the specified method, or nullptr.
|
||||
Thread safety:
|
||||
Safe to call from any threads.
|
||||
@@ -6,12 +6,9 @@
|
||||
|
||||
#include "BeastConfig.h"
|
||||
|
||||
#include "ripple_frame.h"
|
||||
#include "ripple_rpc.h"
|
||||
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "api/HTTPServer.cpp"
|
||||
#include "api/RPCService.cpp"
|
||||
16
src/ripple/rpc/ripple_rpc.h
Normal file
16
src/ripple/rpc/ripple_rpc.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_H_INCLUDED
|
||||
#define RIPPLE_RPC_H_INCLUDED
|
||||
|
||||
#include "beast/modules/beast_core/beast_core.h"
|
||||
|
||||
#include "../json/ripple_json.h"
|
||||
|
||||
#include "api/RPCService.h"
|
||||
|
||||
#endif
|
||||
@@ -17,8 +17,7 @@
|
||||
//
|
||||
#include "beast/modules/beast_asio/beast_asio.h"
|
||||
|
||||
#include "../ripple/frame/ripple_frame.h"
|
||||
//#include "../ripple_basics/ripple_basics.h"
|
||||
#include "../ripple/rpc/ripple_rpc.h"
|
||||
#include "../ripple_data/ripple_data.h"
|
||||
|
||||
namespace ripple
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
class RPCHTTPServerImp
|
||||
: public RPCHTTPServer
|
||||
, public LeakChecked <RPCHTTPServerImp>
|
||||
, public HTTPServer::Handler
|
||||
, public HTTP::Handler
|
||||
{
|
||||
public:
|
||||
NetworkOPs& m_networkOPs;
|
||||
RPCServerHandler m_deprecatedHandler;
|
||||
HTTPServer m_server;
|
||||
HTTP::Server m_server;
|
||||
ScopedPointer <RippleSSLContext> m_context;
|
||||
|
||||
RPCHTTPServerImp (Stoppable& parent,
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
IPEndpoint ep (IPEndpoint::from_string (getConfig().getRpcIP()));
|
||||
if (! ep.empty())
|
||||
{
|
||||
HTTPServer::Port port;
|
||||
HTTP::Port port;
|
||||
port.addr = ep.withPort(0);
|
||||
if (getConfig ().getRpcPort() != 0)
|
||||
port.port = getConfig ().getRpcPort();
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
port.port = ep.port();
|
||||
port.context = m_context;
|
||||
|
||||
HTTPServer::Ports ports;
|
||||
HTTP::Ports ports;
|
||||
ports.push_back (port);
|
||||
m_server.setPorts (ports);
|
||||
}
|
||||
@@ -84,10 +84,10 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// HTTPServer::Handler
|
||||
// HTTP::Handler
|
||||
//
|
||||
|
||||
void onAccept (HTTPServer::Session& session)
|
||||
void onAccept (HTTP::Session& session)
|
||||
{
|
||||
// Reject non-loopback connections if RPC_ALLOW_REMOTE is not set
|
||||
if (! getConfig().RPC_ALLOW_REMOTE &&
|
||||
@@ -97,11 +97,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void onHeaders (HTTPServer::Session& session)
|
||||
void onHeaders (HTTP::Session& session)
|
||||
{
|
||||
}
|
||||
|
||||
void onRequest (HTTPServer::Session& session)
|
||||
void onRequest (HTTP::Session& session)
|
||||
{
|
||||
session.write (m_deprecatedHandler.processRequest (
|
||||
session.content, session.remoteAddress.to_string()));
|
||||
@@ -109,11 +109,11 @@ public:
|
||||
session.close();
|
||||
}
|
||||
|
||||
void onClose (HTTPServer::Session& session)
|
||||
void onClose (HTTP::Session& session)
|
||||
{
|
||||
}
|
||||
|
||||
void onStopped (HTTPServer&)
|
||||
void onStopped (HTTP::Server&)
|
||||
{
|
||||
stopped();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
// This .cpp will end up including all of the public header
|
||||
// material in Ripple since it holds the Application object.
|
||||
|
||||
#include "../ripple/http/ripple_http.h"
|
||||
#include "../ripple/rpc/ripple_rpc.h"
|
||||
#include "../ripple/validators/ripple_validators.h"
|
||||
|
||||
namespace ripple
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "../ripple/frame/ripple_frame.h"
|
||||
#include "../ripple_basics/ripple_basics.h"
|
||||
#include "../ripple_core/ripple_core.h"
|
||||
#include "../ripple_data/ripple_data.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// VFALCO TODO For UniformResourceLocator, remove asap
|
||||
#include "beast/modules/beast_asio/beast_asio.h"
|
||||
|
||||
#include "../ripple/frame/ripple_frame.h"
|
||||
#include "../ripple/rpc/ripple_rpc.h"
|
||||
#include "../ripple_basics/ripple_basics.h"
|
||||
#include "../ripple_data/ripple_data.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user