Compare commits

...

5 Commits

Author SHA1 Message Date
Vinnie Falco
9a0e806f78 Set version to 0.26.1 2014-07-28 12:05:01 -07:00
Vinnie Falco
20c9632996 Enable asynchronous handling of HTTP-RPC (RIPD-390)
* Activate async code path
* Tidy up HTTP server code
* Use shared_ptr in HTTP server
* Remove check for unspecified IP
* Remove hairtrigger
* Fix missing HTTP authorization check
* Fix multisocket flags in RPC-HTTP server
* Fix authorization failure when no credentials required
* Addresses RIPD-159, RIPD-161, RIPD-390
2014-07-28 12:05:01 -07:00
Vinnie Falco
65a628ca88 Add HTTPHeaders::build_map 2014-07-28 12:05:00 -07:00
Vinnie Falco
d82dbba096 Make bind_handler variadic ctor explicit 2014-07-28 12:05:00 -07:00
Nik Bougalis
704d7451a0 Fix auth handling during OfferCreate (RIPD-414) 2014-07-25 11:42:42 -07:00
31 changed files with 920 additions and 854 deletions

View File

@@ -1898,18 +1898,18 @@
<ClCompile Include="..\..\src\ripple\common\tests\cross_offer.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\api\Handler.h">
<ClInclude Include="..\..\src\ripple\http\Server.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Port.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\ScopedStream.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Server.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Session.h">
<ClInclude Include="..\..\src\ripple\http\Session.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\http\impl\Door.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\impl\Door.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\http\impl\Peer.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\impl\Peer.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\http\impl\Port.cpp">
@@ -3448,8 +3448,6 @@
</ClInclude>
<ClCompile Include="..\..\src\ripple\unity\http.cpp">
</ClCompile>
<ClInclude Include="..\..\src\ripple\unity\http.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\unity\hyperleveldb.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

View File

@@ -334,9 +334,6 @@
<Filter Include="ripple\http">
<UniqueIdentifier>{8601C61D-413C-725E-C9E6-BD4F97E40032}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\http\api">
<UniqueIdentifier>{F98B3E94-4FB9-98FF-C625-533A969D1210}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\http\impl">
<UniqueIdentifier>{43D68742-4714-D103-EE00-EB10BD045FB6}</UniqueIdentifier>
</Filter>
@@ -2856,24 +2853,21 @@
<ClCompile Include="..\..\src\ripple\common\tests\cross_offer.test.cpp">
<Filter>ripple\common\tests</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\api\Handler.h">
<Filter>ripple\http\api</Filter>
<ClInclude Include="..\..\src\ripple\http\Server.h">
<Filter>ripple\http</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Port.h">
<Filter>ripple\http\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\ScopedStream.h">
<Filter>ripple\http\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Server.h">
<Filter>ripple\http\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\http\api\Session.h">
<Filter>ripple\http\api</Filter>
<ClInclude Include="..\..\src\ripple\http\Session.h">
<Filter>ripple\http</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\http\impl\Door.cpp">
<Filter>ripple\http\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\impl\Door.h">
<Filter>ripple\http\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\http\impl\Peer.cpp">
<Filter>ripple\http\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\http\impl\Peer.h">
<Filter>ripple\http\impl</Filter>
</ClInclude>
@@ -4740,9 +4734,6 @@
<ClCompile Include="..\..\src\ripple\unity\http.cpp">
<Filter>ripple\unity</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\unity\http.h">
<Filter>ripple\unity</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\unity\hyperleveldb.cpp">
<Filter>ripple\unity</Filter>
</ClCompile>

View File

@@ -1,5 +1,5 @@
Name: rippled
Version: 0.26.0
Version: 0.26.1
Release: 1%{?dist}
Summary: Ripple peer-to-peer network daemon

View File

@@ -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

View File

@@ -56,6 +56,7 @@ private:
public:
typedef void result_type;
explicit
bound_handler (DeducedHandler&& handler, Args&&... args)
: m_handler (std::forward <DeducedHandler> (handler))
, m_args (std::forward <Args> (args)...)

View File

@@ -20,6 +20,7 @@
#ifndef BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#define BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#include <beast/Uncopyable.h>
#include <boost/asio/ssl/context.hpp>
namespace beast {

View File

@@ -20,6 +20,8 @@
#ifndef BEAST_ASIO_SHAREDARG_H_INCLUDED
#define BEAST_ASIO_SHAREDARG_H_INCLUDED
#include <beast/smart_ptr/SharedPtr.h>
namespace beast {
namespace asio {

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <algorithm>
namespace beast {
HTTPHeaders::HTTPHeaders ()
@@ -86,4 +88,20 @@ String HTTPHeaders::toString () const
return s;
}
std::map <std::string, std::string>
HTTPHeaders::build_map() const
{
std::map <std::string, std::string> c;
auto const& k (m_fields.getAllKeys());
auto const& v (m_fields.getAllValues());
for (std::size_t i = 0; i < m_fields.size(); ++i)
{
auto key (k[i].toStdString());
auto const value (v[i].toStdString());
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
c[key] = value;
}
return c;
}
}

View File

@@ -21,8 +21,8 @@
#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED
#include <beast/module/asio/http/HTTPField.h>
#include <beast/module/core/text/StringPairArray.h>
#include <map>
namespace beast {
@@ -70,6 +70,10 @@ public:
/** Outputs all the headers into one string. */
String toString () const;
// VFALCO HACK to present the headers in a useful format
std::map <std::string, std::string>
build_map() const;
private:
StringPairArray m_fields;
};

View File

@@ -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;

View File

@@ -20,13 +20,80 @@
#ifndef RIPPLE_HTTP_SERVER_H_INCLUDED
#define RIPPLE_HTTP_SERVER_H_INCLUDED
#include <beast/net/IPEndpoint.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <beast/utility/Journal.h>
#include <cstdint>
#include <memory>
#include <ostream>
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 <Port> 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 <ServerImpl> m_impl;
};
} // namespace HTTP
} // namespace ripple
} // HTTP
} // ripple
#endif

View File

@@ -24,13 +24,52 @@
#include <beast/net/IPEndpoint.h>
#include <beast/utility/Journal.h>
#include <beast/module/asio/http/HTTPRequest.h>
#include <ostream>
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 <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,

View File

@@ -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

View File

@@ -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 <beast/net/IPEndpoint.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <cstdint>
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 <Port> Ports;
} // namespace HTTP
} // namespace ripple
#endif

View File

@@ -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 <ostream>
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 <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;
};
} // namespace HTTP
} // namespace ripple
#endif

View File

@@ -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 <ripple/http/impl/Door.h>
#include <ripple/http/impl/Peer.h>
#include <beast/asio/placeholders.h>
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 <Peer> (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 <Peer> const& peer)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec)
{
impl_.journal().error << "Accept failed: " << ec.message();
return;
}
async_accept();
peer->accept();
}
}
}

View File

@@ -20,6 +20,8 @@
#ifndef RIPPLE_HTTP_DOOR_H_INCLUDED
#define RIPPLE_HTTP_DOOR_H_INCLUDED
#include <ripple/http/impl/ServerImpl.h>
#include <ripple/http/impl/Types.h>
#include <beast/asio/placeholders.h>
namespace ripple {
@@ -28,95 +30,37 @@ namespace HTTP {
/** A listening socket. */
class Door
: public beast::SharedObject
, public beast::asio::AsyncObject <Door>
, public beast::List <Door>::Node
, public beast::LeakChecked <Door>
{
public:
private:
// VFALCO TODO Use shared_ptr
typedef beast::SharedPtr <Door> 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 <Peer> const& peer);
};
}

View File

@@ -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 <ripple/http/impl/Peer.h>
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 <boost::asio::const_buffer>());
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 <char const*> (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)));
}
}
}

View File

@@ -20,29 +20,34 @@
#ifndef RIPPLE_HTTP_PEER_H_INCLUDED
#define RIPPLE_HTTP_PEER_H_INCLUDED
#include <ripple/http/api/Session.h>
#include <ripple/http/Server.h>
#include <ripple/http/Session.h>
#include <ripple/http/impl/Types.h>
#include <ripple/http/impl/ServerImpl.h>
#include <ripple/common/MultiSocket.h>
#include <beast/module/asio/async/AsyncObject.h>
#include <beast/asio/placeholders.h>
#include <beast/module/core/core.h>
#include <beast/module/asio/basics/SharedArg.h>
#include <beast/module/asio/http/HTTPRequestParser.h>
#include <boost/bind.hpp>
#include <functional>
#include <memory>
namespace ripple {
namespace HTTP {
// Holds the copy of buffers being sent
// VFALCO TODO Replace with std::shared_ptr<std::string>
//
typedef beast::asio::SharedArg <std::string> SharedBuffer;
/** Represents an active connection. */
class Peer
: public beast::SharedObject
, public beast::asio::AsyncObject <Peer>
: public std::enable_shared_from_this <Peer>
, public Session
, public beast::List <Peer>::Node
, public beast::LeakChecked <Peer>
{
public:
private:
enum
{
// Size of our receive buffer
@@ -59,462 +64,138 @@ public:
};
typedef beast::SharedPtr <Peer> Ptr;
ServerImpl& impl_;
boost::asio::io_service::strand strand_;
boost::asio::deadline_timer data_timer_;
boost::asio::deadline_timer request_timer_;
std::unique_ptr <MultiSocket> 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 <MultiSocket> m_socket;
beast::MemoryBlock m_buffer;
beast::HTTPRequestParser m_parser;
int m_writesPending;
bool m_closed;
bool m_callClose;
beast::SharedPtr <Peer> m_detach_ref;
boost::optional <boost::asio::io_service::work> m_work;
int m_errorCode;
std::atomic <int> m_detached;
// VFALCO TODO Use c++11
beast::MemoryBlock buffer_;
beast::HTTPRequestParser parser_;
int writesPending_;
bool closed_;
bool callClose_;
std::shared_ptr <Peer> detach_ref_;
boost::optional <boost::asio::io_service::work> work_;
int errorCode_;
std::atomic <int> 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 <beast::HTTPRequest> const& request()
beast::SharedPtr <beast::HTTPRequest> 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 <boost::asio::const_buffer>());
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 <char const*> (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<socket>();
return socket_->this_layer<socket>();
}
// 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 <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_write (SharedBuffer const& buf);
};
}

View File

@@ -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); }
}
}

View File

@@ -17,11 +17,15 @@
*/
//==============================================================================
#include <ripple/http/Server.h>
#include <ripple/http/impl/ServerImpl.h>
#include <beast/cxx14/memory.h> // <memory>
namespace ripple {
namespace HTTP {
Server::Server (Handler& handler, beast::Journal journal)
: m_impl (new ServerImpl (*this, handler, journal))
: m_impl (std::make_unique <ServerImpl> (*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);
}

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <ripple/http/impl/ServerImpl.h>
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;
}

View File

@@ -20,8 +20,14 @@
#ifndef RIPPLE_HTTP_SERVERIMPL_H_INCLUDED
#define RIPPLE_HTTP_SERVERIMPL_H_INCLUDED
#include <ripple/http/Server.h>
#include <beast/intrusive/List.h>
#include <beast/threads/SharedData.h>
#include <beast/threads/Thread.h>
#include <beast/module/asio/basics/SharedArg.h>
#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include <thread>
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 <boost::asio::io_service::work> 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);
};

View File

@@ -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.

View File

@@ -18,6 +18,7 @@
//==============================================================================
#include <ripple/common/RippleSSLContext.h>
#include <ripple/http/Session.h>
#include <ripple/module/app/main/RPCHTTPServer.h>
#include <ripple/module/rpc/RPCHandler.h>
#include <ripple/module/rpc/RPCServerHandler.h>
@@ -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 <std::string, std::string> 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;

View File

@@ -77,10 +77,10 @@ CreateOffer::checkAcceptAsset(IssueRef issue) const
// ordering. Determine which entry we need to access.
bool const canonical_gt (mTxnAccountID > issue.account);
bool const need_auth (trustLine->getFieldU32 (sfFlags) &
bool const is_authorized (trustLine->getFieldU32 (sfFlags) &
(canonical_gt ? lsfLowAuth : lsfHighAuth));
if (need_auth)
if (!is_authorized)
{
if (m_journal.debug) m_journal.debug <<
"delay: can't receive IOUs from issuer without auth.";

View File

@@ -31,7 +31,7 @@ char const* BuildInfo::getRawVersionString ()
//
// The build version number (edit this for each release)
//
"0.26.0"
"0.26.1"
//
// Must follow the format described here:
//

View File

@@ -262,10 +262,14 @@ std::string DecodeBase64 (std::string s)
bool HTTPAuthorized (const std::map<std::string, std::string>& mapHeaders)
{
std::map<std::string, std::string>::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);

View File

@@ -23,11 +23,12 @@
#include <ripple/unity/net.h>
#include <ripple/unity/rpcx.h>
#include <ripple/unity/websocket.h>
#include <ripple/unity/http.h>
#include <ripple/unity/resource.h>
#include <ripple/unity/sitefiles.h>
#include <ripple/unity/validators.h>
#include <ripple/http/Server.h>
#include <ripple/module/app/main/CollectorManager.cpp>
#include <ripple/module/app/main/NodeStoreScheduler.cpp>
#include <ripple/module/app/main/IoServicePool.cpp>

View File

@@ -19,19 +19,9 @@
#include <BeastConfig.h>
#include <ripple/unity/http.h>
#include <ripple/unity/net.h>
#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include <ripple/http/impl/Door.cpp>
#include <ripple/http/impl/Peer.cpp>
#include <ripple/http/impl/Port.cpp>
#include <ripple/http/impl/ScopedStream.cpp>
#include <ripple/http/impl/Types.h>
#include <ripple/http/impl/ServerImpl.h>
#include <ripple/http/impl/Peer.h>
#include <ripple/http/impl/Door.h>
#include <ripple/http/impl/ServerImpl.cpp>
#include <ripple/http/impl/Server.cpp>

View File

@@ -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 <beast/module/asio/asio.h>
#include <ripple/http/api/Port.h>
#include <ripple/http/api/ScopedStream.h>
#include <ripple/http/api/Session.h>
#include <ripple/http/api/Handler.h>
#include <ripple/http/api/Server.h>
#endif