Add HTTPServer

This commit is contained in:
Vinnie Falco
2013-09-21 17:11:26 -07:00
parent ac1ebf403f
commit 0dc3cf07d0
11 changed files with 1492 additions and 5 deletions

View File

@@ -22,6 +22,12 @@
<ClCompile Include="..\..\build\proto\ripple.pb.cc" />
<ClCompile Include="..\..\src\ripple\beast\ripple_beast.cpp" />
<ClCompile Include="..\..\src\ripple\beast\ripple_beastc.c" />
<ClCompile Include="..\..\src\ripple\frame\api\HTTPServer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\frame\api\RPCService.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -285,6 +291,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\main\RPCHTTPServer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\misc\NetworkOPs.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -1493,6 +1505,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ripple\frame\api\HTTPServer.h" />
<ClInclude Include="..\..\src\ripple\frame\api\RPCService.h" />
<ClInclude Include="..\..\src\ripple\frame\ripple_frame.h" />
<ClInclude Include="..\..\src\ripple\json\api\json_config.h" />
@@ -1560,6 +1573,7 @@
<ClInclude Include="..\..\src\ripple_app\main\LoadManager.h" />
<ClInclude Include="..\..\src\ripple_app\main\LocalCredentials.h" />
<ClInclude Include="..\..\src\ripple_app\main\RippleMain.h" />
<ClInclude Include="..\..\src\ripple_app\main\RPCHTTPServer.h" />
<ClInclude Include="..\..\src\ripple_app\misc\NetworkOPs.h" />
<ClInclude Include="..\..\src\ripple_app\misc\PowResult.h" />
<ClInclude Include="..\..\src\ripple_app\misc\AccountItem.h" />

View File

@@ -984,6 +984,12 @@
<ClCompile Include="..\..\src\ripple_app\main\NodeStoreScheduler.cpp">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\frame\api\HTTPServer.cpp">
<Filter>[1] Ripple\frame\api</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\main\RPCHTTPServer.cpp">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ripple_basics\containers\KeyCache.h">
@@ -1944,6 +1950,12 @@
<ClInclude Include="..\..\src\ripple_app\main\NodeStoreScheduler.h">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\frame\api\HTTPServer.h">
<Filter>[1] Ripple\frame\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\main\RPCHTTPServer.h">
<Filter>[2] Old Ripple\ripple_app\main</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">

View File

@@ -3,6 +3,7 @@ RIPPLE TODO
--------------------------------------------------------------------------------
Vinnie's List: Changes day to day, descending priority
- Finish RPCAsyncServer, RPCService and RPCService::Manager
- Fix and tidy up broken beast classes
- Parse Validator line using cribbed code
- Parse ContentBodyBuffer from HTTPResponse

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
//------------------------------------------------------------------------------
/*
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

View File

@@ -6,11 +6,12 @@
#include "BeastConfig.h"
#include "beast/modules/beast_core/beast_core.h"
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
#include <boost/unordered_map.hpp>
#include "ripple_frame.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"

View File

@@ -9,8 +9,13 @@
#include "beast/modules/beast_core/beast_core.h"
// VFALCO NOTE this sucks that we have to include asio in the header
// just for HTTPMessage!!
#include "beast/modules/beast_asio/beast_asio.h"
#include "../json/ripple_json.h"
#include "api/HTTPServer.h"
#include "api/RPCService.h"
#endif

View File

@@ -24,6 +24,8 @@ class NetworkOPsLog;
template <> char const* LogPartition::getPartitionName <NetworkOPsLog> () { return "NetworkOPs"; }
class RPCServiceManagerLog;
template <> char const* LogPartition::getPartitionName <RPCServiceManagerLog> () { return "RPCServiceManager"; }
class HTTPServerLog;
template <> char const* LogPartition::getPartitionName <HTTPServerLog> () { return "RPCServer"; }
//
//------------------------------------------------------------------------------
@@ -82,6 +84,9 @@ public:
// VFALCO NOTE LocalCredentials starts the deprecated UNL service
, m_deprecatedUNL (UniqueNodeList::New (*m_jobQueue))
, m_rpcHTTPServer (RPCHTTPServer::New (*m_jobQueue,
LogJournal::get <HTTPServerLog> (), *m_networkOPs))
, m_rpcServerHandler (*m_networkOPs) // passive object, not a Service
, m_nodeStoreScheduler (*m_jobQueue, *m_jobQueue)
@@ -577,6 +582,10 @@ public:
//
// Allow RPC connections.
//
#if RIPPLE_USE_RPC_SERVICE_MANAGER
m_rpcHTTPServer->setup (m_journal);
#else
if (! getConfig ().getRpcIP().empty () && getConfig ().getRpcPort() != 0)
{
try
@@ -596,6 +605,7 @@ public:
{
m_journal.info << "RPC interface: disabled";
}
#endif
//
// Begin connecting to network.
@@ -797,6 +807,7 @@ private:
LedgerMaster m_ledgerMaster;
ScopedPointer <NetworkOPs> m_networkOPs;
ScopedPointer <UniqueNodeList> m_deprecatedUNL;
ScopedPointer <RPCHTTPServer> m_rpcHTTPServer;
RPCServerHandler m_rpcServerHandler;
NodeStoreScheduler m_nodeStoreScheduler;
ScopedPointer <NodeStore::Database> m_nodeStore;

View File

@@ -0,0 +1,137 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
class RPCHTTPServerImp
: public RPCHTTPServer
, public LeakChecked <RPCHTTPServerImp>
, public HTTPServer::Handler
{
public:
NetworkOPs& m_networkOPs;
RPCServerHandler m_deprecatedHandler;
HTTPServer m_server;
ScopedPointer <RippleSSLContext> m_context;
RPCHTTPServerImp (Stoppable& parent,
Journal journal,
NetworkOPs& networkOPs)
: RPCHTTPServer (parent)
, m_networkOPs (networkOPs)
, m_deprecatedHandler (networkOPs)
, m_server (*this, journal)
{
if (getConfig ().RPC_SECURE == 0)
{
m_context = RippleSSLContext::createBare ();
}
else
{
m_context = RippleSSLContext::createAuthenticated (
getConfig ().RPC_SSL_KEY,
getConfig ().RPC_SSL_CERT,
getConfig ().RPC_SSL_CHAIN);
}
}
~RPCHTTPServerImp ()
{
m_server.stop();
}
void setup (Journal journal)
{
if (! getConfig ().getRpcIP().empty () &&
getConfig ().getRpcPort() != 0)
{
IPEndpoint ep (IPEndpoint::from_string (getConfig().getRpcIP()));
if (! ep.empty())
{
HTTPServer::Port port;
port.addr = ep.withPort(0);
if (getConfig ().getRpcPort() != 0)
port.port = getConfig ().getRpcPort();
else
port.port = ep.port();
port.context = m_context;
HTTPServer::Ports ports;
ports.push_back (port);
m_server.setPorts (ports);
}
}
else
{
journal.info << "RPC interface: disabled";
}
}
//--------------------------------------------------------------------------
//
// Stoppable
//
void onStop()
{
m_server.stopAsync();
}
void onChildrenStopped()
{
}
//--------------------------------------------------------------------------
//
// HTTPServer::Handler
//
void onAccept (HTTPServer::Session& session)
{
// Reject non-loopback connections if RPC_ALLOW_REMOTE is not set
if (! getConfig().RPC_ALLOW_REMOTE &&
! session.remoteAddress.isLoopback())
{
session.close();
}
}
void onHeaders (HTTPServer::Session& session)
{
}
void onRequest (HTTPServer::Session& session)
{
session.write (m_deprecatedHandler.processRequest (
session.content, session.remoteAddress.to_string()));
session.close();
}
void onClose (HTTPServer::Session& session)
{
}
void onStopped (HTTPServer&)
{
stopped();
}
};
//------------------------------------------------------------------------------
RPCHTTPServer::RPCHTTPServer (Stoppable& parent)
: Stoppable ("RPCHTTPServer", parent)
{
}
//------------------------------------------------------------------------------
RPCHTTPServer* RPCHTTPServer::New (Stoppable& parent,
Journal journal,
NetworkOPs& networkOPs)
{
return new RPCHTTPServerImp (parent, journal, networkOPs);
}

View File

@@ -0,0 +1,25 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_APP_RPCHTTPSERVER_H_INCLUDED
#define RIPPLE_APP_RPCHTTPSERVER_H_INCLUDED
class RPCHTTPServer : public Stoppable
{
protected:
RPCHTTPServer (Stoppable& parent);
public:
static RPCHTTPServer* New (Stoppable& parent,
Journal journal, NetworkOPs& networkOPs);
virtual ~RPCHTTPServer () { }
/** Opens listening ports based on the Config settings. */
virtual void setup(Journal journal) = 0;
};
#endif

View File

@@ -49,6 +49,8 @@ namespace ripple
#include "rpc/RPCHandler.cpp"
# include "rpc/RPCServerHandler.h"
# include "main/RPCHTTPServer.h"
#include "main/RPCHTTPServer.cpp"
#include "rpc/RPCServerHandler.cpp"
#include "websocket/WSConnection.h"