Remove unused and obsolete classes and tidy up:

Many classes required to support type-erasure of handlers and boost::asio
types are now obsolete, so these classes and files are removed:
HTTPClientType, FixedInputBuffer, PeerRole, socket_wrapper,
client_session, basic_url, abstract_socket, buffer_sequence, memory_buffer,
enable_wait_for_async, shared_handler, wrap_handler, streambuf,
ContentBodyBuffer, SSLContext, completion-handler based handshake detectors.
These structural changes are made:
* Some missing includes added to headers
* asio module directory flattened
This commit is contained in:
Vinnie Falco
2014-10-25 17:59:04 -07:00
parent 3cd391daa6
commit fefdb32d08
83 changed files with 48 additions and 10042 deletions

View File

@@ -22,11 +22,5 @@
#endif
#include <beast/asio/impl/IPAddressConversion.cpp>
#include <beast/asio/tests/wrap_handler.test.cpp>
#include <beast/asio/tests/bind_handler.test.cpp>
#include <beast/asio/tests/enable_wait_for_async.test.cpp>
#include <beast/asio/tests/shared_handler.test.cpp>
#include <beast/asio/abstract_socket.cpp> // TEMPORARY!

View File

@@ -1,217 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/asio/abstract_socket.h>
#include <beast/asio/bind_handler.h>
namespace beast {
namespace asio {
#if ! BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
//------------------------------------------------------------------------------
//
// Socket
//
//------------------------------------------------------------------------------
void* abstract_socket::this_layer_ptr (char const*) const
{
pure_virtual_called ();
return nullptr;
}
//------------------------------------------------------------------------------
//
// native_handle
//
//------------------------------------------------------------------------------
bool abstract_socket::native_handle (char const*, void*)
{
pure_virtual_called ();
return false;
}
//------------------------------------------------------------------------------
//
// basic_io_object
//
//------------------------------------------------------------------------------
boost::asio::io_service& abstract_socket::get_io_service ()
{
pure_virtual_called ();
return *static_cast <boost::asio::io_service*>(nullptr);
}
//------------------------------------------------------------------------------
//
// basic_socket
//
//------------------------------------------------------------------------------
void*
abstract_socket::lowest_layer_ptr (char const*) const
{
pure_virtual_called ();
return nullptr;
}
auto
abstract_socket::cancel (boost::system::error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
auto
abstract_socket::shutdown (shutdown_type, boost::system::error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
auto
abstract_socket::close (boost::system::error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
//------------------------------------------------------------------------------
//
// basic_socket_acceptor
//
//------------------------------------------------------------------------------
auto
abstract_socket::accept (abstract_socket&, error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
void
abstract_socket::async_accept (abstract_socket&, error_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
//------------------------------------------------------------------------------
//
// basic_stream_socket
//
//------------------------------------------------------------------------------
std::size_t
abstract_socket::read_some (mutable_buffers, error_code& ec)
{
ec = pure_virtual_error ();
return 0;
}
std::size_t
abstract_socket::write_some (const_buffers, error_code& ec)
{
ec = pure_virtual_error ();
return 0;
}
void
abstract_socket::async_read_some (mutable_buffers, transfer_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
void
abstract_socket::async_write_some (const_buffers, transfer_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
//------------------------------------------------------------------------------
//
// ssl::stream
//
//------------------------------------------------------------------------------
void*
abstract_socket::next_layer_ptr (char const*) const
{
pure_virtual_called ();
return nullptr;
}
bool
abstract_socket::needs_handshake ()
{
return false;
}
void
abstract_socket::set_verify_mode (int)
{
pure_virtual_called ();
}
auto
abstract_socket::handshake (handshake_type, error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
void
abstract_socket::async_handshake (handshake_type, error_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
auto
abstract_socket::handshake (handshake_type, const_buffers, error_code& ec) ->
error_code
{
return pure_virtual_error (ec);
}
void
abstract_socket::async_handshake (handshake_type, const_buffers,
transfer_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
auto
abstract_socket::shutdown (error_code& ec) -> error_code
{
return pure_virtual_error (ec);
}
void
abstract_socket::async_shutdown (error_handler handler)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
#endif
}
}

View File

@@ -1,404 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_ABSTRACT_SOCKET_H_INCLUDED
#define BEAST_ASIO_ABSTRACT_SOCKET_H_INCLUDED
#include <beast/asio/buffer_sequence.h>
#include <beast/asio/shared_handler.h>
#include <boost/asio/io_service.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/ssl/stream_base.hpp>
// Checking overrides replaces unimplemented stubs with pure virtuals
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
# define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 1
#endif
#if BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
# define BEAST_SOCKET_VIRTUAL = 0
#else
# define BEAST_SOCKET_VIRTUAL
#endif
namespace beast {
namespace asio {
/** A high level socket abstraction.
This combines the capabilities of multiple socket interfaces such
as listening, connecting, streaming, and handshaking. It brings
everything together into a single abstract interface.
When member functions are called and the underlying implementation does
not support the operation, a fatal error is generated.
*/
class abstract_socket
: public boost::asio::ssl::stream_base
, public boost::asio::socket_base
{
protected:
typedef boost::system::error_code error_code;
typedef asio::shared_handler <void (void)> post_handler;
typedef asio::shared_handler <void (error_code)> error_handler;
typedef asio::shared_handler <
void (error_code, std::size_t)> transfer_handler;
static
void
pure_virtual_called()
{
throw std::runtime_error ("pure virtual called");
}
static
error_code
pure_virtual_error ()
{
pure_virtual_called();
return boost::system::errc::make_error_code (
boost::system::errc::function_not_supported);
}
static
error_code
pure_virtual_error (error_code& ec)
{
return ec = pure_virtual_error();
}
static
void
throw_if (error_code const& ec)
{
if (ec)
throw boost::system::system_error (ec);
}
public:
virtual ~abstract_socket ()
{
}
//--------------------------------------------------------------------------
//
// abstract_socket
//
//--------------------------------------------------------------------------
/** Retrieve the underlying object.
@note If the type doesn't match, nullptr is returned or an
exception is thrown if trying to acquire a reference.
*/
/** @{ */
template <class Object>
Object& this_layer ()
{
Object* object (this->this_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object const& this_layer () const
{
Object const* object (this->this_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object* this_layer_ptr ()
{
return static_cast <Object*> (
this->this_layer_ptr (typeid (Object).name ()));
}
template <class Object>
Object const* this_layer_ptr () const
{
return static_cast <Object const*> (
this->this_layer_ptr (typeid (Object).name ()));
}
/** @} */
virtual void* this_layer_ptr (char const* type_name) const
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// native_handle
//
//--------------------------------------------------------------------------
/** Retrieve the native representation of the object.
Since we dont know the return type, and because almost every
asio implementation passes the result by value, you need to provide
a pointer to a default-constructed object of the matching type.
@note If the type doesn't match, an exception is thrown.
*/
template <typename Handle>
void native_handle (Handle* dest)
{
if (! native_handle (typeid (Handle).name (), dest))
throw std::bad_cast ();
}
virtual bool native_handle (char const* type_name, void* dest)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// basic_io_object
//
//--------------------------------------------------------------------------
virtual boost::asio::io_service& get_io_service ()
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// basic_socket
//
//--------------------------------------------------------------------------
/** Retrieve the lowest layer object.
@note If the type doesn't match, nullptr is returned or an
exception is thrown if trying to acquire a reference.
*/
/** @{ */
template <class Object>
Object& lowest_layer ()
{
Object* object (this->lowest_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object const& lowest_layer () const
{
Object const* object (this->lowest_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object* lowest_layer_ptr ()
{
return static_cast <Object*> (
this->lowest_layer_ptr (typeid (Object).name ()));
}
template <class Object>
Object const* lowest_layer_ptr () const
{
return static_cast <Object const*> (
this->lowest_layer_ptr (typeid (Object).name ()));
}
/** @} */
virtual void* lowest_layer_ptr (char const* type_name) const
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
void cancel ()
{
error_code ec;
cancel (ec);
throw_if (ec);
}
virtual error_code cancel (error_code& ec)
BEAST_SOCKET_VIRTUAL;
void shutdown (shutdown_type what)
{
error_code ec;
shutdown (what, ec);
throw_if (ec);
}
virtual error_code shutdown (shutdown_type what,
error_code& ec)
BEAST_SOCKET_VIRTUAL;
void close ()
{
error_code ec;
close (ec);
throw_if (ec);
}
virtual error_code close (error_code& ec)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// basic_socket_acceptor
//
//--------------------------------------------------------------------------
virtual error_code accept (abstract_socket& peer, error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual void async_accept (abstract_socket& peer, error_handler handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// basic_stream_socket
//
//--------------------------------------------------------------------------
virtual std::size_t read_some (mutable_buffers buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual std::size_t write_some (const_buffers buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual void async_read_some (mutable_buffers buffers,
transfer_handler handler)
BEAST_SOCKET_VIRTUAL;
virtual void async_write_some (const_buffers buffers,
transfer_handler handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// ssl::stream
//
//--------------------------------------------------------------------------
/** Retrieve the next layer object.
@note If the type doesn't match, nullptr is returned or an
exception is thrown if trying to acquire a reference.
*/
/** @{ */
template <class Object>
Object& next_layer ()
{
Object* object (this->next_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object const& next_layer () const
{
Object const* object (this->next_layer_ptr <Object> ());
if (object == nullptr)
throw std::bad_cast ();
return *object;
}
template <class Object>
Object* next_layer_ptr ()
{
return static_cast <Object*> (
this->next_layer_ptr (typeid (Object).name ()));
}
template <class Object>
Object const* next_layer_ptr () const
{
return static_cast <Object const*> (
this->next_layer_ptr (typeid (Object).name ()));
}
/** @} */
virtual void* next_layer_ptr (char const* type_name) const
BEAST_SOCKET_VIRTUAL;
/** Determines if the underlying stream requires a handshake.
If needs_handshake is true, it will be necessary to call handshake or
async_handshake after the connection is established. Furthermore it
will be necessary to call the shutdown member from the
HandshakeInterface to close the connection. Do not close the underlying
socket or else the closure will not be graceful. Only one side should
initiate the handshaking shutdon. The other side should observe it.
Which side does what is up to the user.
The default version returns false.
*/
virtual bool needs_handshake ()
BEAST_SOCKET_VIRTUAL;
virtual void set_verify_mode (int verify_mode)
BEAST_SOCKET_VIRTUAL;
void handshake (handshake_type type)
{
error_code ec;
handshake (type, ec);
throw_if (ec);
}
virtual error_code handshake (handshake_type type, error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual void async_handshake (handshake_type type, error_handler handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
virtual error_code handshake (handshake_type type,
const_buffers buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual void async_handshake (handshake_type type,
const_buffers buffers, transfer_handler handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
void shutdown ()
{
error_code ec;
shutdown (ec);
throw_if (ec);
}
virtual error_code shutdown (error_code& ec)
BEAST_SOCKET_VIRTUAL;
virtual void async_shutdown (error_handler handler)
BEAST_SOCKET_VIRTUAL;
};
}
}
#endif

View File

@@ -1,126 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BUFFER_SEQUENCE_H_INCLUDED
#define BEAST_ASIO_BUFFER_SEQUENCE_H_INCLUDED
#include <boost/asio/buffer.hpp>
#include <beast/utility/noexcept.h>
#include <algorithm>
#include <iterator>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <vector>
namespace beast {
namespace asio {
template <class Buffer>
class buffer_sequence
{
private:
typedef std::vector <Buffer> sequence_type;
public:
typedef Buffer value_type;
typedef typename sequence_type::const_iterator const_iterator;
private:
sequence_type m_buffers;
template <class FwdIter>
void assign (FwdIter first, FwdIter last)
{
m_buffers.clear();
m_buffers.reserve (std::distance (first, last));
for (;first != last; ++first)
m_buffers.push_back (*first);
}
public:
buffer_sequence ()
{
}
template <
class BufferSequence,
class = std::enable_if_t <std::is_constructible <
Buffer, typename BufferSequence::value_type>::value>
>
buffer_sequence (BufferSequence const& s)
{
assign (std::begin (s), std::end (s));
}
template <
class FwdIter,
class = std::enable_if_t <std::is_constructible <
Buffer, typename std::iterator_traits <
FwdIter>::value_type>::value>
>
buffer_sequence (FwdIter first, FwdIter last)
{
assign (first, last);
}
template <class BufferSequence>
std::enable_if_t <std::is_constructible <
Buffer, typename BufferSequence::value_type>::value,
buffer_sequence&
>
operator= (BufferSequence const& s)
{
return assign (s);
}
const_iterator
begin () const noexcept
{
return m_buffers.begin ();
}
const_iterator
end () const noexcept
{
return m_buffers.end ();
}
#if 0
template <class ConstBufferSequence>
void
assign (ConstBufferSequence const& buffers)
{
auto const n (std::distance (
std::begin (buffers), std::end (buffers)));
for (int i = 0, auto iter (std::begin (buffers));
iter != std::end (buffers); ++iter, ++i)
m_buffers[i] = Buffer (boost::asio::buffer_cast <void*> (
*iter), boost::asio::buffer_size (*iter));
}
#endif
};
typedef buffer_sequence <boost::asio::const_buffer> const_buffers;
typedef buffer_sequence <boost::asio::mutable_buffer> mutable_buffers;
}
}
#endif

View File

@@ -1,369 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_ENABLE_WAIT_FOR_ASYNC_H_INCLUDED
#define BEAST_ASIO_ENABLE_WAIT_FOR_ASYNC_H_INCLUDED
#include <beast/asio/wrap_handler.h>
#include <beast/utility/is_call_possible.h>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <atomic>
#include <cassert>
#include <condition_variable>
#include <mutex>
#include <beast/cxx14/type_traits.h> // <type_traits>
namespace beast {
namespace asio {
namespace detail {
template <class Owner, class Handler>
class ref_counted_wrapped_handler
{
private:
static_assert (std::is_same <std::decay_t <Owner>, Owner>::value,
"Owner cannot be a const or reference type");
Handler m_handler;
std::reference_wrapper <Owner> m_owner;
bool m_continuation;
public:
~ref_counted_wrapped_handler();
ref_counted_wrapped_handler (Owner& owner,
Handler&& handler, bool continuation);
ref_counted_wrapped_handler (Owner& owner,
Handler const& handler, bool continuation);
ref_counted_wrapped_handler (
ref_counted_wrapped_handler const& other);
ref_counted_wrapped_handler (
ref_counted_wrapped_handler&& other);
ref_counted_wrapped_handler& operator= (
ref_counted_wrapped_handler const&) = delete;
template <class... Args>
void
operator() (Args&&... args)
{
m_handler (std::forward <Args> (args)...);
}
template <class... Args>
void
operator() (Args&&... args) const
{
m_handler (std::forward <Args> (args)...);
}
template <class Function>
friend
void
asio_handler_invoke (Function& f,
ref_counted_wrapped_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke (f, h->m_handler);
}
template <class Function>
friend
void
asio_handler_invoke (Function const& f,
ref_counted_wrapped_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke (f, h->m_handler);
}
friend
void*
asio_handler_allocate (std::size_t size,
ref_counted_wrapped_handler* h)
{
return boost_asio_handler_alloc_helpers::
allocate (size, h->m_handler);
}
friend
void
asio_handler_deallocate (void* p, std::size_t size,
ref_counted_wrapped_handler* h)
{
boost_asio_handler_alloc_helpers::
deallocate (p, size, h->m_handler);
}
friend
bool
asio_handler_is_continuation (ref_counted_wrapped_handler* h)
{
return h->m_continuation;
}
};
template <class Owner, class Handler>
ref_counted_wrapped_handler<Owner, Handler>::~ref_counted_wrapped_handler()
{
m_owner.get().decrement();
}
template <class Owner, class Handler>
ref_counted_wrapped_handler<Owner, Handler>::ref_counted_wrapped_handler (
Owner& owner, Handler&& handler, bool continuation)
: m_handler (std::move (handler))
, m_owner (owner)
, m_continuation (continuation ? true :
boost_asio_handler_cont_helpers::is_continuation (m_handler))
{
m_owner.get().increment();
}
template <class Owner, class Handler>
ref_counted_wrapped_handler<Owner, Handler>::ref_counted_wrapped_handler (
Owner& owner, Handler const& handler, bool continuation)
: m_handler (handler)
, m_owner (owner)
, m_continuation (continuation ? true :
boost_asio_handler_cont_helpers::is_continuation (m_handler))
{
m_owner.get().increment();
}
template <class Owner, class Handler>
ref_counted_wrapped_handler<Owner, Handler>::ref_counted_wrapped_handler (
ref_counted_wrapped_handler const& other)
: m_handler (other.m_handler)
, m_owner (other.m_owner)
, m_continuation (other.m_continuation)
{
m_owner.get().increment();
}
template <class Owner, class Handler>
ref_counted_wrapped_handler<Owner, Handler>::ref_counted_wrapped_handler (
ref_counted_wrapped_handler&& other)
: m_handler (std::move (other.m_handler))
, m_owner (other.m_owner)
, m_continuation (other.m_continuation)
{
m_owner.get().increment();
}
}
//------------------------------------------------------------------------------
/** Facilitates blocking until no completion handlers are remaining.
If Derived has this member function:
@code
void on_wait_for_async (void)
@endcode
Then it will be called every time the number of pending completion
handlers transitions to zero from a non-zero value. The call is made
while holding the internal mutex.
*/
template <class Derived>
class enable_wait_for_async
{
private:
BEAST_DEFINE_IS_CALL_POSSIBLE(
has_on_wait_for_async,on_wait_for_async);
void increment()
{
std::lock_guard <decltype(m_mutex)> lock (m_mutex);
++m_count;
}
void notify (std::true_type)
{
static_cast <Derived*> (this)->on_wait_for_async();
}
void notify (std::false_type)
{
}
void decrement()
{
std::lock_guard <decltype(m_mutex)> lock (m_mutex);
--m_count;
if (m_count == 0)
{
m_cond.notify_all();
notify (std::integral_constant <bool,
has_on_wait_for_async<Derived, void(void)>::value>());
}
}
template <class Owner, class Handler>
friend class detail::ref_counted_wrapped_handler;
std::mutex m_mutex;
std::condition_variable m_cond;
std::size_t m_count;
public:
/** Blocks if there are any pending completion handlers. */
void
wait_for_async()
{
std::unique_lock <decltype (m_mutex)> lock (m_mutex);
while (m_count != 0)
m_cond.wait (lock);
}
protected:
enable_wait_for_async()
: m_count (0)
{
}
~enable_wait_for_async()
{
assert (m_count == 0);
}
/** Wraps the specified handler so it can be counted. */
/** @{ */
template <class Handler>
detail::ref_counted_wrapped_handler <
enable_wait_for_async,
std::remove_reference_t <Handler>
>
wrap_with_counter (Handler&& handler, bool continuation = false)
{
return detail::ref_counted_wrapped_handler <enable_wait_for_async,
std::remove_reference_t <Handler>> (*this,
std::forward <Handler> (handler), continuation);
}
template <class Handler>
detail::ref_counted_wrapped_handler <
enable_wait_for_async,
std::remove_reference_t <Handler>
>
wrap_with_counter (continuation_t, Handler&& handler)
{
return detail::ref_counted_wrapped_handler <enable_wait_for_async,
std::remove_reference_t <Handler>> (*this,
std::forward <Handler> (handler), true);
}
/** @} */
};
//------------------------------------------------------------------------------
/** A waitable event object that blocks when handlers are pending. */
class pending_handlers
{
private:
std::size_t count_ = 0;
std::mutex mutex_;
std::condition_variable cond_;
template <class Owner, class Handler>
friend class detail::ref_counted_wrapped_handler;
template <class = void>
void
increment();
template <class = void>
void
decrement();
public:
~pending_handlers()
{
assert (count_ == 0);
}
template <class = void>
void
wait();
/** Returns a handler that causes wait to block until completed.
The returned handler provides the same execution
guarantees as the passed handler.
*/
/** @{ */
template <class Handler>
detail::ref_counted_wrapped_handler <pending_handlers,
std::remove_reference_t<Handler>>
wrap (Handler&& handler,
bool continuation = false)
{
return detail::ref_counted_wrapped_handler <pending_handlers,
std::remove_reference_t<Handler>> (*this,
std::forward<Handler>(handler), continuation);
}
template <class Handler>
detail::ref_counted_wrapped_handler <pending_handlers,
std::remove_reference_t<Handler>>
wrap (continuation_t, Handler&& handler)
{
return detail::ref_counted_wrapped_handler <pending_handlers,
std::remove_reference_t<Handler>> (*this,
std::forward<Handler>(handler), true);
}
/** @} */
};
template <class>
void
pending_handlers::increment()
{
std::lock_guard <std::mutex> lock (mutex_);
++count_;
}
template <class>
void
pending_handlers::decrement()
{
std::lock_guard <std::mutex> lock (mutex_);
if (--count_ == 0)
cond_.notify_all();
}
template <class>
void
pending_handlers::wait()
{
std::unique_lock <std::mutex> lock (mutex_);
while (count_ != 0)
cond_.wait (lock);
}
}
}
#endif

View File

@@ -1,426 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_MEMORY_BUFFER_H_INCLUDED
#define BEAST_ASIO_MEMORY_BUFFER_H_INCLUDED
#include <beast/utility/empty_base_optimization.h>
#include <boost/asio/buffer.hpp>
#include <beast/utility/noexcept.h>
#include <cstddef>
#include <memory>
#include <type_traits>
namespace beast {
namespace asio {
template <
class T,
class Alloc = std::allocator <T>
>
class memory_buffer
: private empty_base_optimization <Alloc>
{
private:
static_assert (std::is_same <char, T>::value ||
std::is_same <unsigned char, T>::value,
"memory_buffer only works with char and unsigned char");
typedef empty_base_optimization <Alloc> Base;
using AllocTraits = std::allocator_traits <Alloc>;
T* m_base;
std::size_t m_size;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T& reference;
typedef T const& const_reference;
typedef T* pointer;
typedef T const* const_pointer;
typedef Alloc allocator_type;
typedef T* iterator;
typedef T const* const_iterator;
typedef std::reverse_iterator <iterator> reverse_iterator;
typedef std::reverse_iterator <const_iterator> const_reverse_iterator;
memory_buffer ()
: m_base (nullptr)
, m_size (0)
{
}
memory_buffer (memory_buffer&& other)
: Base (std::move (other))
, m_base (other.m_base)
, m_size (other.m_size)
{
other.m_base = nullptr;
other.m_size = 0;
}
explicit memory_buffer (size_type n)
: m_base (AllocTraits::allocate (Base::member(), n))
, m_size (n)
{
}
explicit memory_buffer (Alloc const& alloc)
: Base (alloc)
, m_base (nullptr)
, m_size (0)
{
}
memory_buffer (size_type n, Alloc const& alloc)
: Base (alloc)
, m_base (AllocTraits::allocate (Base::member(), n))
, m_size (n)
{
}
~memory_buffer()
{
if (m_base != nullptr)
AllocTraits::deallocate (Base::member(), m_base, m_size);
}
memory_buffer& operator= (memory_buffer const&) = delete;
allocator_type
get_allocator() const
{
return Base::member;
}
//
// asio support
//
boost::asio::mutable_buffer
buffer()
{
return boost::asio::mutable_buffer (
data(), bytes());
}
boost::asio::const_buffer
buffer() const
{
return boost::asio::const_buffer (
data(), bytes());
}
boost::asio::mutable_buffers_1
buffers()
{
return boost::asio::mutable_buffers_1 (
data(), bytes());
}
boost::asio::const_buffers_1
buffers() const
{
return boost::asio::const_buffers_1 (
data(), bytes());
}
operator boost::asio::mutable_buffer()
{
return buffer();
}
operator boost::asio::const_buffer() const
{
return buffer();
}
operator boost::asio::mutable_buffers_1()
{
return buffers();
}
operator boost::asio::const_buffers_1() const
{
return buffers();
}
//
// Element access
//
reference
at (size_type pos)
{
if (! (pos < size()))
throw std::out_of_range ("bad array index");
return m_base [pos];
}
const_reference
at (size_type pos) const
{
if (! (pos < size()))
throw std::out_of_range ("bad array index");
return m_base [pos];
}
reference
operator[] (size_type pos) noexcept
{
return m_base [pos];
}
const_reference
operator[] (size_type pos) const noexcept
{
return m_base [pos];
}
reference
back() noexcept
{
return m_base [m_size - 1];
}
const_reference
back() const noexcept
{
return m_base [m_size - 1];
}
reference
front() noexcept
{
return *m_base;
}
const_reference
front() const noexcept
{
return *m_base;
}
pointer
data() noexcept
{
return m_base;
}
const_pointer
data() const noexcept
{
return m_base;
}
//
// Iterators
//
iterator
begin() noexcept
{
return m_base;
}
const_iterator
begin() const noexcept
{
return m_base;
}
const_iterator
cbegin() const noexcept
{
return m_base;
}
iterator
end() noexcept
{
return m_base + m_size;
}
const_iterator
end() const noexcept
{
return m_base + m_size;
}
const_iterator
cend() const noexcept
{
return m_base + m_size;
}
reverse_iterator
rbegin() noexcept
{
return reverse_iterator (end());
}
const_reverse_iterator
rbegin() const noexcept
{
return const_reverse_iterator (cend());
}
const_reverse_iterator
crbegin() const noexcept
{
return const_reverse_iterator (cend());
}
reverse_iterator
rend() noexcept
{
return reverse_iterator (begin());
}
const_reverse_iterator
rend() const noexcept
{
return const_reverse_iterator (cbegin());
}
const_reverse_iterator
crend() const noexcept
{
return const_reverse_iterator (cbegin());
}
//
// Capacity
//
bool
empty() const noexcept
{
return m_size == 0;
}
size_type
size() const noexcept
{
return m_size;
}
size_type
max_size() const noexcept
{
return size();
}
size_type
capacity() const noexcept
{
return size();
}
size_type bytes() const
{
return m_size * sizeof(T);
}
//
// Modifiers
//
template <class U, class A>
friend
void
swap (memory_buffer <U, A>& lhs,
memory_buffer <U, A>& rhs) noexcept;
};
//------------------------------------------------------------------------------
template <class T, class Alloc>
void
swap (memory_buffer <T, Alloc>& lhs,
memory_buffer <T, Alloc>& rhs) noexcept
{
std::swap (lhs.m_base, rhs.m_base);
std::swap (lhs.m_size, rhs.m_size);
}
template <class T, class A1, class A2>
inline
bool
operator== (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return std::equal (lhs.cbegin(), lhs.cend(),
rhs.cbegin(), rhs.cend());
}
template <class T, class A1, class A2>
inline
bool
operator!= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (lhs == rhs);
}
template <class T, class A1, class A2>
inline
bool
operator< (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return std::lexicographical_compare (
lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
}
template <class T, class A1, class A2>
inline
bool
operator>= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (lhs < rhs);
}
template <class T, class A1, class A2>
inline
bool
operator> (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return rhs < lhs;
}
template <class T, class A1, class A2>
inline
bool
operator<= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (rhs < lhs);
}
}
}
#endif

View File

@@ -1,475 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_SHARED_HANDLER_H_INCLUDED
#define BEAST_ASIO_SHARED_HANDLER_H_INCLUDED
#include <beast/Config.h>
#include <beast/utility/is_call_possible.h>
#include <boost/utility/base_from_member.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <beast/utility/noexcept.h>
#include <functional>
#include <memory>
#include <beast/cxx14/type_traits.h> // <type_traits>
#ifndef BEAST_ASIO_NO_ALLOCATE_SHARED
#define BEAST_ASIO_NO_ALLOCATE_SHARED 0
#endif
#ifndef BEAST_ASIO_NO_HANDLER_RESULT_OF
#define BEAST_ASIO_NO_HANDLER_RESULT_OF 1
#endif
namespace beast {
namespace asio {
class shared_handler_wrapper_base
{
public:
virtual ~shared_handler_wrapper_base()
{
}
virtual void invoke (std::function <void (void)> f) = 0;
virtual void* allocate (std::size_t size) = 0;
virtual void deallocate (void* p, std::size_t size) = 0;
virtual bool is_continuation () = 0;
};
//------------------------------------------------------------------------------
template <class Signature>
class shared_handler_wrapper_func
: public shared_handler_wrapper_base
{
private:
std::function <Signature> m_func;
public:
template <class Handler>
explicit shared_handler_wrapper_func (Handler&& handler)
: m_func (std::ref (std::forward <Handler> (handler)))
{
}
template <class... Args>
#if BEAST_ASIO_NO_HANDLER_RESULT_OF
void
#else
std::result_of_t <std::function <Signature> (Args...)>
#endif
operator() (Args&&... args) const
{
return m_func (std::forward <Args> (args)...);
}
};
//------------------------------------------------------------------------------
namespace detail {
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4512) // assignment operator could not be generated
#endif
template <class Signature, class Handler>
class shared_handler_wrapper
: private boost::base_from_member <Handler>
, public shared_handler_wrapper_func <Signature>
{
private:
typedef boost::base_from_member <Handler> Base;
BEAST_DEFINE_IS_CALL_POSSIBLE(has_is_continuation, is_continuation);
public:
shared_handler_wrapper (Handler&& handler)
: boost::base_from_member <Handler> (std::move (handler))
, shared_handler_wrapper_func <Signature> (Base::member)
{
}
shared_handler_wrapper (Handler const& handler)
: boost::base_from_member <Handler> (handler)
, shared_handler_wrapper_func <Signature> (Base::member)
{
}
private:
void
invoke (std::function <void (void)> f) override
{
return boost_asio_handler_invoke_helpers::
invoke (f, Base::member);
}
void*
allocate (std::size_t size) override
{
return boost_asio_handler_alloc_helpers::
allocate (size, Base::member);
}
void
deallocate (void* p, std::size_t size) override
{
boost_asio_handler_alloc_helpers::
deallocate (p, size, Base::member);
}
bool
is_continuation () override
{
return is_continuation (std::integral_constant <bool,
has_is_continuation <Handler, bool(void)>::value>());
}
bool
is_continuation (std::true_type)
{
return Base::member.is_continuation();
}
bool
is_continuation (std::false_type)
{
return boost_asio_handler_cont_helpers::
is_continuation (Base::member);
}
};
#ifdef _MSC_VER
#pragma warning (pop)
#endif
template <class T>
struct is_shared_handler : public std::false_type
{
};
//------------------------------------------------------------------------------
template <class T, class Handler>
class handler_allocator
{
private:
// We want a partial template specialization as a friend
// but that isn't allowed so we friend all versions. This
// should produce a compile error if Handler is not constructible
// from H.
//
template <class U, class H>
friend class handler_allocator;
Handler m_handler;
public:
typedef T value_type;
typedef T* pointer;
template <class U>
struct rebind
{
public:
typedef handler_allocator <U, Handler> other;
};
handler_allocator() = delete;
handler_allocator (Handler const& handler)
: m_handler (handler)
{
}
template <class U>
handler_allocator (
handler_allocator <U, Handler> const& other)
: m_handler (other.m_handler)
{
}
handler_allocator&
operator= (handler_allocator const&) = delete;
pointer
allocate (std::ptrdiff_t n)
{
auto const size (n * sizeof (T));
return static_cast <pointer> (
boost_asio_handler_alloc_helpers::allocate (
size, m_handler));
}
void
deallocate (pointer p, std::ptrdiff_t n)
{
auto const size (n * sizeof (T));
boost_asio_handler_alloc_helpers::deallocate (
p, size, m_handler);
}
// Work-around for MSVC not using allocator_traits
// in the implementation of shared_ptr
//
#ifdef _MSC_VER
void
destroy (T* t)
{
t->~T();
}
#endif
friend
bool
operator== (handler_allocator const& lhs, handler_allocator const& rhs)
{
return true;
}
friend
bool
operator!= (handler_allocator const& lhs, handler_allocator const& rhs)
{
return ! (lhs == rhs);
}
};
}
//------------------------------------------------------------------------------
/** Handler shared reference that provides io_service execution guarantees. */
template <class Signature>
class shared_handler
{
private:
template <class T>
friend class shared_handler_allocator;
typedef shared_handler_wrapper_func <
Signature> wrapper_type;
typedef std::shared_ptr <wrapper_type> ptr_type;
ptr_type m_ptr;
public:
shared_handler()
{
}
template <
class DeducedHandler,
class = std::enable_if_t <
! detail::is_shared_handler <
std::decay_t <DeducedHandler>>::value &&
std::is_constructible <std::function <Signature>,
std::decay_t <DeducedHandler>>::value
>
>
shared_handler (DeducedHandler&& handler)
{
typedef std::remove_reference_t <DeducedHandler> Handler;
#if BEAST_ASIO_NO_ALLOCATE_SHARED
m_ptr = std::make_shared <detail::shared_handler_wrapper <
Signature, Handler>> (std::forward <DeducedHandler> (handler));
#else
m_ptr = std::allocate_shared <detail::shared_handler_wrapper <
Signature, Handler>> (detail::handler_allocator <char, Handler> (
handler), std::forward <DeducedHandler> (handler));
#endif
}
shared_handler (shared_handler&& other)
: m_ptr (std::move (other.m_ptr))
{
}
shared_handler (shared_handler const& other)
: m_ptr (other.m_ptr)
{
}
shared_handler&
operator= (std::nullptr_t)
{
m_ptr = nullptr;
return *this;
}
shared_handler&
operator= (shared_handler const& rhs)
{
m_ptr = rhs.m_ptr;
return *this;
}
shared_handler&
operator= (shared_handler&& rhs)
{
m_ptr = std::move (rhs.m_ptr);
return *this;
}
explicit
operator bool() const noexcept
{
return m_ptr.operator bool();
}
void
reset()
{
m_ptr.reset();
}
template <class... Args>
#if BEAST_ASIO_NO_HANDLER_RESULT_OF
void
#else
std::result_of_t <std::function <Signature> (Args...)>
#endif
operator() (Args&&... args) const
{
return (*m_ptr)(std::forward <Args> (args)...);
}
template <class Function>
friend
void
asio_handler_invoke (Function&& f, shared_handler* h)
{
return h->m_ptr->invoke (f);
}
friend
void*
asio_handler_allocate (
std::size_t size, shared_handler* h)
{
return h->m_ptr->allocate (size);
}
friend
void
asio_handler_deallocate (
void* p, std::size_t size, shared_handler* h)
{
return h->m_ptr->deallocate (p, size);
}
friend
bool
asio_handler_is_continuation (
shared_handler* h)
{
return h->m_ptr->is_continuation ();
}
};
//------------------------------------------------------------------------------
namespace detail {
template <
class Signature
>
struct is_shared_handler <
shared_handler <Signature>
> : public std::true_type
{
};
}
//------------------------------------------------------------------------------
template <class T>
class shared_handler_allocator
{
private:
template <class U>
friend class shared_handler_allocator;
std::shared_ptr <shared_handler_wrapper_base> m_ptr;
public:
typedef T value_type;
typedef T* pointer;
shared_handler_allocator() = delete;
template <class Signature>
shared_handler_allocator (
shared_handler <Signature> const& handler)
: m_ptr (handler.m_ptr)
{
}
template <class U>
shared_handler_allocator (
shared_handler_allocator <U> const& other)
: m_ptr (other.m_ptr)
{
}
pointer
allocate (std::ptrdiff_t n)
{
auto const size (n * sizeof (T));
return static_cast <pointer> (
m_ptr->allocate (size));
}
void
deallocate (pointer p, std::ptrdiff_t n)
{
auto const size (n * sizeof (T));
m_ptr->deallocate (p, size);
}
friend
bool
operator== (shared_handler_allocator const& lhs,
shared_handler_allocator const& rhs)
{
return lhs.m_ptr == rhs.m_ptr;
}
friend
bool
operator!= (shared_handler_allocator const& lhs,
shared_handler_allocator const& rhs)
{
return ! (lhs == rhs);
}
};
}
}
#endif

View File

@@ -1,826 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_SOCKET_WRAPPER_H_INCLUDED
#define BEAST_ASIO_SOCKET_WRAPPER_H_INCLUDED
#include <beast/asio/abstract_socket.h>
#include <beast/asio/bind_handler.h>
#include <beast/utility/noexcept.h>
namespace beast {
namespace asio {
/** Wraps a reference to any object and exports all availble interfaces.
If the object does not support an interface, calling those
member functions will behave as if a pure virtual was called.
Note that only a reference to the underlying is stored. Management
of the lifetime of the object is controlled by the caller.
Examples of the type of Object:
asio::ip::tcp::socket
asio::ip::tcp::socket&
asio::ssl::stream <asio::ip::tcp::socket>
asio::ssl::stream <asio::ip::tcp::socket&>
explain arg must be an io_context
explain socket_wrapper will create and take ownership of the tcp::socket
explain this_layer_type will be tcp::socket
explain next_layer () returns a asio::ip::tcp::socket&
explain lowest_layer () returns a asio::ip::tcp::socket&
asio::ssl::stream <asio::buffered_stream <asio::ip::tcp::socket> > >
This makes my head explode
*/
template <typename Object>
class socket_wrapper : public abstract_socket
{
private:
Object m_object;
public:
template <class... Args>
explicit socket_wrapper (Args&&... args)
: m_object (std::forward <Args> (args)...)
{
}
socket_wrapper (socket_wrapper const&) = delete;
socket_wrapper& operator= (socket_wrapper const&) = delete;
//--------------------------------------------------------------------------
//
// socket_wrapper
//
//--------------------------------------------------------------------------
/** The type of the object being wrapped. */
typedef typename boost::remove_reference <Object>::type this_layer_type;
/** Get a reference to this layer. */
this_layer_type& this_layer () noexcept
{
return m_object;
}
/** Get a const reference to this layer. */
this_layer_type const& this_layer () const noexcept
{
return m_object;
}
//--------------------------------------------------------------------------
//
// abstract_socket
//
//--------------------------------------------------------------------------
void* this_layer_ptr (char const* type_name) const override
{
char const* const name (typeid (this_layer_type).name ());
if (strcmp (name, type_name) == 0)
return const_cast <void*> (static_cast <void const*> (&m_object));
return nullptr;
}
private:
BEAST_DEFINE_IS_CALL_POSSIBLE(has_get_io_service, get_io_service);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_lowest_layer, lowest_layer);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_cancel, cancel);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_shutdown, shutdown);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_close, close);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_accept, accept);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_accept, async_accept);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_read_some, read_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_write_some, write_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_read_some, async_read_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_write_some, async_write_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_set_verify_mode, set_verify_mode);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_handshake, handshake);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_handshake, async_handshake);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_shutdown, async_shutdown);
//--------------------------------------------------------------------------
//
// Implementation
//
//--------------------------------------------------------------------------
template <class Cond>
struct Enabled : public std::integral_constant <bool, Cond::value>
{
};
//--------------------------------------------------------------------------
//
// native_handle
//
//--------------------------------------------------------------------------
#if 0
// This is a potential work-around for the problem with
// the has_type_native_handle_type template, but requires
// Boost 1.54 or later.
//
// This include will be needed:
//
// boost/tti/has_type.hpp
//
//
BOOST_TTI_HAS_TYPE(native_handle_type)
#else
template <class T>
struct has_type_native_handle_type
{
typedef char yes;
typedef struct {char dummy[2];} no;
template <class C> static yes f(typename C::native_handle_type*);
template <class C> static no f(...);
#ifdef _MSC_VER
static bool const value = sizeof(f<T>(0)) == 1;
#else
// This line fails to compile under Visual Studio 2012
static bool const value = sizeof(
has_type_native_handle_type<T>::f<T>(0)) == 1;
#endif
};
#endif
template <typename T,
bool Exists = has_type_native_handle_type <T>::value
>
struct extract_native_handle_type
{
typedef typename T::native_handle_type type;
};
template <typename T>
struct extract_native_handle_type <T, false>
{
typedef void type;
};
// This will be void if native_handle_type doesn't exist in Object
typedef typename extract_native_handle_type <
this_layer_type>::type native_handle_type;
//--------------------------------------------------------------------------
bool native_handle (char const* type_name, void* dest) override
{
return native_handle (type_name, dest,
Enabled <has_type_native_handle_type <this_layer_type> > ());
}
bool native_handle (char const* type_name, void* dest,
std::true_type)
{
char const* const name (typeid (
typename this_layer_type::native_handle_type).name ());
if (strcmp (name, type_name) == 0)
{
native_handle_type* const p (reinterpret_cast <
native_handle_type*> (dest));
*p = m_object.native_handle ();
return true;
}
return false;
}
bool native_handle (char const*, void*,
std::false_type)
{
pure_virtual_called();
return false;
}
//--------------------------------------------------------------------------
//
// basic_io_object
//
//--------------------------------------------------------------------------
boost::asio::io_service& get_io_service () override
{
return get_io_service (
Enabled <has_get_io_service <this_layer_type,
boost::asio::io_service&()> > ());
}
boost::asio::io_service& get_io_service (
std::true_type)
{
return m_object.get_io_service ();
}
boost::asio::io_service& get_io_service (
std::false_type)
{
pure_virtual_called();
return *static_cast <boost::asio::io_service*>(nullptr);
}
//--------------------------------------------------------------------------
//
// basic_socket
//
//--------------------------------------------------------------------------
/*
To forward the lowest_layer_type type, we need to make sure it
exists in Object. This is a little more tricky than just figuring
out if Object has a particular member function.
The problem is boost::asio::basic_socket_acceptor, which doesn't
have lowest_layer () or lowest_layer_type ().
*/
template <class T>
struct has_type_lowest_layer_type
{
typedef char yes;
typedef struct {char dummy[2];} no;
template <class C> static yes f(typename C::lowest_layer_type*);
template <class C> static no f(...);
#ifdef _MSC_VER
static bool const value = sizeof(f<T>(0)) == 1;
#else
// This line fails to compile under Visual Studio 2012
static bool const value = sizeof(has_type_lowest_layer_type<T>::f<T>(0)) == 1;
#endif
};
template <typename T, bool Exists = has_type_lowest_layer_type <T>::value >
struct extract_lowest_layer_type
{
typedef typename T::lowest_layer_type type;
};
template <typename T>
struct extract_lowest_layer_type <T, false>
{
typedef void type;
};
// This will be void if lowest_layer_type doesn't exist in Object
typedef typename extract_lowest_layer_type <this_layer_type>::type lowest_layer_type;
//--------------------------------------------------------------------------
void* lowest_layer_ptr (char const* type_name) const override
{
return lowest_layer_ptr (type_name,
Enabled <has_type_lowest_layer_type <this_layer_type> > ());
}
void* lowest_layer_ptr (char const* type_name,
std::true_type) const
{
char const* const name (typeid (typename this_layer_type::lowest_layer_type).name ());
if (strcmp (name, type_name) == 0)
return const_cast <void*> (static_cast <void const*> (&m_object.lowest_layer ()));
return nullptr;
}
void* lowest_layer_ptr (char const*,
std::false_type) const
{
pure_virtual_called();
return nullptr;
}
//--------------------------------------------------------------------------
error_code cancel (error_code& ec) override
{
return cancel (ec,
Enabled <has_cancel <this_layer_type,
error_code (error_code&)> > ());
}
error_code cancel (error_code& ec,
std::true_type)
{
return m_object.cancel (ec);
}
error_code cancel (error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
error_code shutdown (shutdown_type what, error_code& ec) override
{
return shutdown (what, ec,
Enabled <has_shutdown <this_layer_type,
error_code (shutdown_type, error_code&)> > ());
}
error_code shutdown (shutdown_type what, error_code& ec,
std::true_type)
{
return m_object.shutdown (what, ec);
}
error_code shutdown (shutdown_type, error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
error_code close (error_code& ec) override
{
return close (ec,
Enabled <has_close <this_layer_type,
error_code (error_code&)> > ());
}
error_code close (error_code& ec,
std::true_type)
{
return m_object.close (ec);
}
error_code close (error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
//
// basic_socket_acceptor
//
//--------------------------------------------------------------------------
// Extracts the underlying socket type from the protocol of another asio object
template <typename T, typename Enable = void>
struct native_socket
{
typedef void* socket_type;
inline native_socket (abstract_socket&)
: m_socket (nullptr)
{
abstract_socket::pure_virtual_called();
}
inline socket_type& get ()
{
abstract_socket::pure_virtual_called();
return m_socket;
}
inline socket_type& operator-> ()
{
return get ();
}
private:
socket_type m_socket;
};
// Enabled if T::protocol_type::socket exists as a type
template <typename T>
struct native_socket <T, typename boost::enable_if <boost::is_class <
typename T::protocol_type::socket> >::type>
{
typedef typename T::protocol_type::socket socket_type;
inline native_socket (abstract_socket& peer)
: m_socket_ptr (&peer.this_layer <socket_type> ())
{
}
inline socket_type& get () noexcept
{
return *m_socket_ptr;
}
inline socket_type& operator-> () noexcept
{
return get ();
}
private:
socket_type* m_socket_ptr;
};
//--------------------------------------------------------------------------
error_code accept (abstract_socket& peer, error_code& ec) override
{
typedef typename native_socket <this_layer_type>::socket_type socket_type;
return accept (peer, ec,
Enabled <has_accept <this_layer_type,
error_code (socket_type&, error_code&)> > ());
}
error_code accept (abstract_socket& peer, error_code& ec,
std::true_type)
{
return m_object.accept (
native_socket <this_layer_type> (peer).get (), ec);
}
error_code accept (abstract_socket&, error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
void async_accept (abstract_socket& peer, error_handler handler) override
{
typedef typename native_socket <this_layer_type>::socket_type socket_type;
async_accept (peer, handler,
Enabled <has_async_accept <this_layer_type,
void (socket_type&, error_handler)> > ());
}
void async_accept (abstract_socket& peer, error_handler const& handler,
std::true_type)
{
m_object.async_accept (
native_socket <this_layer_type> (peer).get (), handler);
}
void async_accept (abstract_socket&, error_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
//--------------------------------------------------------------------------
//
// basic_stream_socket
//
//--------------------------------------------------------------------------
std::size_t
read_some (mutable_buffers buffers, error_code& ec) override
{
return read_some (buffers, ec,
Enabled <has_read_some <this_layer_type,
std::size_t (mutable_buffers const&, error_code&)> > ());
}
std::size_t
read_some (mutable_buffers const& buffers, error_code& ec,
std::true_type)
{
return m_object.read_some (buffers, ec);
}
std::size_t read_some (mutable_buffers const&, error_code& ec,
std::false_type)
{
ec = pure_virtual_error ();
return 0;
}
//--------------------------------------------------------------------------
std::size_t
write_some (const_buffers buffers, error_code& ec) override
{
return write_some (buffers, ec,
Enabled <has_write_some <this_layer_type,
std::size_t (const_buffers const&, error_code&)> > ());
}
std::size_t
write_some (const_buffers const& buffers, error_code& ec,
std::true_type)
{
return m_object.write_some (buffers, ec);
}
std::size_t
write_some (const_buffers const&, error_code& ec,
std::false_type)
{
ec = pure_virtual_error ();
return 0;
}
//--------------------------------------------------------------------------
void async_read_some (mutable_buffers buffers,
transfer_handler handler) override
{
async_read_some (buffers, handler,
Enabled <has_async_read_some <this_layer_type,
void (mutable_buffers const&, transfer_handler const&)> > ());
}
void
async_read_some (mutable_buffers const& buffers,
transfer_handler const& handler,
std::true_type)
{
m_object.async_read_some (buffers, handler);
}
void
async_read_some (mutable_buffers const&,
transfer_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
//--------------------------------------------------------------------------
void
async_write_some (const_buffers buffers,
transfer_handler handler) override
{
async_write_some (buffers, handler,
Enabled <has_async_write_some <this_layer_type,
void (const_buffers const&, transfer_handler const&)> > ());
}
void
async_write_some (const_buffers const& buffers,
transfer_handler const& handler,
std::true_type)
{
m_object.async_write_some (buffers, handler);
}
void
async_write_some (const_buffers const&,
transfer_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
//--------------------------------------------------------------------------
//
// ssl::stream
//
//--------------------------------------------------------------------------
template <class T>
struct has_type_next_layer_type
{
typedef char yes;
typedef struct {char dummy[2];} no;
template <class C> static yes f(typename C::next_layer_type*);
template <class C> static no f(...);
#ifdef _MSC_VER
static bool const value = sizeof(f<T>(0)) == 1;
#else
// This line fails to compile under Visual Studio 2012
static bool const value = sizeof(has_type_next_layer_type<T>::f<T>(0)) == 1;
#endif
};
template <typename T, bool Exists = has_type_next_layer_type <T>::value >
struct extract_next_layer_type
{
typedef typename T::next_layer_type type;
};
template <typename T>
struct extract_next_layer_type <T, false>
{
typedef void type;
};
// This will be void if next_layer_type doesn't exist in Object
typedef typename extract_next_layer_type <this_layer_type>::type next_layer_type;
//--------------------------------------------------------------------------
void* next_layer_ptr (char const* type_name) const override
{
return next_layer_ptr (type_name,
Enabled <has_type_next_layer_type <this_layer_type> > ());
}
void* next_layer_ptr (char const* type_name,
std::true_type) const
{
char const* const name (typeid (typename this_layer_type::next_layer_type).name ());
if (strcmp (name, type_name) == 0)
return const_cast <void*> (static_cast <void const*> (&m_object.next_layer ()));
return nullptr;
}
void* next_layer_ptr (char const*,
std::false_type) const
{
pure_virtual_called();
return nullptr;
}
//--------------------------------------------------------------------------
bool needs_handshake () override
{
return
has_handshake <this_layer_type,
error_code (handshake_type, error_code&)>::value ||
has_async_handshake <this_layer_type,
void (handshake_type, error_handler)>::value;
}
//--------------------------------------------------------------------------
void set_verify_mode (int verify_mode) override
{
set_verify_mode (verify_mode,
Enabled <has_set_verify_mode <this_layer_type,
void (int)> > ());
}
void set_verify_mode (int verify_mode,
std::true_type)
{
m_object.set_verify_mode (verify_mode);
}
void set_verify_mode (int,
std::false_type)
{
pure_virtual_called();
}
//--------------------------------------------------------------------------
error_code
handshake (handshake_type type, error_code& ec) override
{
return handshake (type, ec,
Enabled <has_handshake <this_layer_type,
error_code (handshake_type, error_code&)> > ());
}
error_code
handshake (handshake_type type, error_code& ec,
std::true_type)
{
return m_object.handshake (type, ec);
}
error_code
handshake (handshake_type, error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
void async_handshake (handshake_type type, error_handler handler) override
{
async_handshake (type, handler,
Enabled <has_async_handshake <this_layer_type,
void (handshake_type, error_handler)> > ());
}
void async_handshake (handshake_type type, error_handler const& handler,
std::true_type)
{
m_object.async_handshake (type, handler);
}
void async_handshake (handshake_type, error_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
//--------------------------------------------------------------------------
error_code
handshake (handshake_type type, const_buffers buffers,
error_code& ec) override
{
return handshake (type, buffers, ec,
Enabled <has_handshake <this_layer_type,
error_code (handshake_type, const_buffers const&, error_code&)> > ());
}
error_code
handshake (handshake_type type, const_buffers const& buffers,
error_code& ec,
std::true_type)
{
return m_object.handshake (type, buffers, ec);
}
error_code
handshake (handshake_type, const_buffers const&,
error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
void async_handshake (handshake_type type,
const_buffers buffers, transfer_handler handler) override
{
async_handshake (type, buffers, handler,
Enabled <has_async_handshake <this_layer_type,
void (handshake_type, const_buffers const&,
transfer_handler)> > ());
}
void async_handshake (handshake_type type, const_buffers const& buffers,
transfer_handler const& handler,
std::true_type)
{
m_object.async_handshake (type, buffers, handler);
}
void async_handshake (handshake_type, const_buffers const&,
transfer_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error(), 0));
}
//--------------------------------------------------------------------------
error_code shutdown (error_code& ec) override
{
return shutdown (ec,
Enabled <has_shutdown <this_layer_type,
error_code (error_code&)> > ());
}
error_code shutdown (error_code& ec,
std::true_type)
{
return m_object.shutdown (ec);
}
error_code shutdown (error_code& ec,
std::false_type)
{
return pure_virtual_error (ec);
}
//--------------------------------------------------------------------------
void async_shutdown (error_handler handler) override
{
async_shutdown (handler,
Enabled <has_async_shutdown <this_layer_type,
void (error_handler)> > ());
}
void async_shutdown (error_handler const& handler,
std::true_type)
{
m_object.async_shutdown (handler);
}
void async_shutdown (error_handler const& handler,
std::false_type)
{
get_io_service ().post (bind_handler (
handler, pure_virtual_error()));
}
};
}
}
#endif

View File

@@ -1,49 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BASIC_STREAMBUF_H_INCLUDED
#define BEAST_ASIO_BASIC_STREAMBUF_H_INCLUDED
#include <boost/asio/buffer.hpp>
#include <memory>
#include <vector>
namespace beast {
namespace asio {
template <class Alloc = std::allocator <char>>
class basic_streambuf : private Alloc
{
private:
typedef std::allocator_traits <Alloc> alloc_traits;
std::vector <boost::asio::mutable_buffer> bufs_;
public:
~basic_streambuf()
{
for (auto const& buf : bufs_)
alloc_traits::deallocate (
boost::asio::buffer_cast<char const*>(buf));
}
}
} // asio
} // beast
#endif

View File

@@ -1,105 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
#include <beast/unit_test/suite.h>
#include <beast/asio/bind_handler.h>
#include <beast/asio/enable_wait_for_async.h>
#include <boost/asio/io_service.hpp>
namespace beast {
class enable_wait_for_async_test : public unit_test::suite
{
public:
typedef boost::system::error_code error_code;
void test()
{
struct handler
{
void operator()(error_code)
{
}
};
struct owner : asio::enable_wait_for_async <owner>
{
bool notified;
owner()
: notified (false)
{
}
void operator()()
{
{
boost::asio::io_service ios;
ios.post (asio::bind_handler (handler(),
error_code()));
ios.run();
ios.reset();
wait_for_async();
}
{
boost::asio::io_service ios;
ios.post (wrap_with_counter (asio::bind_handler (
handler(), error_code())));
ios.run();
wait_for_async();
}
{
boost::asio::io_service ios;
handler h;
ios.post (wrap_with_counter (std::bind (
&handler::operator(), &h,
error_code())));
ios.run();
wait_for_async();
}
}
void on_wait_for_async()
{
notified = true;
}
};
owner o;
o();
expect (o.notified);
}
void run()
{
test();
}
};
BEAST_DEFINE_TESTSUITE(enable_wait_for_async,asio,beast);
}

View File

@@ -1,235 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
#include <beast/unit_test/suite.h>
#include <beast/asio/shared_handler.h>
// Disables is_constructible tests for std::function
// Visual Studio std::function fails the is_constructible tests
#ifndef BEAST_NO_STD_FUNCTION_CONSTRUCTIBLE
# ifdef _MSC_VER
# define BEAST_NO_STD_FUNCTION_CONSTRUCTIBLE 1
# else
# define BEAST_NO_STD_FUNCTION_CONSTRUCTIBLE 0
# endif
#endif
namespace beast {
class shared_handler_test : public unit_test::suite
{
public:
struct test_results
{
bool call;
bool invoke;
bool alloc;
bool dealloc;
bool cont;
test_results ()
: call (false)
, invoke (false)
, alloc (false)
, dealloc (false)
, cont (false)
{
}
};
struct test_handler
{
std::reference_wrapper <test_results> results;
explicit test_handler (test_results& results_)
: results (results_)
{
}
void operator() ()
{
results.get().call = true;
}
template <class Function>
friend void asio_handler_invoke (
Function& f, test_handler* h)
{
h->results.get().invoke = true;
f();
}
template <class Function>
friend void asio_handler_invoke (
Function const& f, test_handler* h)
{
h->results.get().invoke = true;
f();
}
friend void* asio_handler_allocate (
std::size_t size, test_handler* h)
{
h->results.get().alloc = true;
return boost::asio::asio_handler_allocate (size);
}
friend void asio_handler_deallocate (
void* p, std::size_t size, test_handler* h)
{
h->results.get().dealloc = true;
boost::asio::asio_handler_deallocate (p, size);
}
friend bool asio_handler_is_continuation (
test_handler* h)
{
h->results.get().cont = true;
return true;
}
};
struct test_invokable
{
bool call;
test_invokable ()
: call (false)
{
}
void operator() ()
{
call = true;
}
};
template <class Handler>
bool async_op (Handler&& handler)
{
void* const p (boost_asio_handler_alloc_helpers::allocate (32, handler));
handler();
boost_asio_handler_alloc_helpers::deallocate (p, 32, handler);
return boost_asio_handler_cont_helpers::is_continuation (handler);
}
void virtual_async_op (asio::shared_handler <void(void)> handler)
{
async_op (handler);
}
void run()
{
#if ! BEAST_NO_STD_FUNCTION_CONSTRUCTIBLE
static_assert (! std::is_constructible <
std::function <void(void)>, int&&>::value,
"Cannot construct std::function from int&&");
static_assert (! std::is_constructible <
std::function <void(void)>, int>::value,
"Cannot construct std::function from int");
static_assert (! std::is_constructible <
asio::shared_handler <void(void)>, int>::value,
"Cannot construct shared_handler from int");
#endif
static_assert (std::is_constructible <
asio::shared_handler <void(int)>,
asio::shared_handler <void(int)>>::value,
"Should construct <void(int)> from <void(int)>");
static_assert (! std::is_constructible <
asio::shared_handler <void(int)>,
asio::shared_handler <void(void)>>::value,
"Can't construct <void(int)> from <void(void)>");
// Hooks called when using the raw handler
{
test_results r;
test_handler h (r);
async_op (h);
expect (r.call);
expect (r.alloc);
expect (r.dealloc);
expect (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), h);
expect (r.invoke);
expect (f.call);
}
// Use of std::function shows the hooks not getting called
{
test_results r;
std::function <void(void)> fh ((test_handler) (r));
async_op (fh);
expect (r.call);
unexpected (r.alloc);
unexpected (r.dealloc);
unexpected (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), fh);
unexpected (r.invoke);
expect (f.call);
}
// Make sure shared_handler calls the hooks
{
test_results r;
asio::shared_handler <void(void)> sh ((test_handler)(r));
async_op (sh);
expect (r.call);
expect (r.alloc);
expect (r.dealloc);
expect (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), sh);
expect (r.invoke);
expect (f.call);
}
// Make sure shared_handler via implicit conversion calls hooks
{
test_results r;
test_handler h (r);
virtual_async_op ((test_handler) (r));
expect (r.call);
expect (r.alloc);
expect (r.dealloc);
expect (r.cont);
}
}
};
BEAST_DEFINE_TESTSUITE(shared_handler,asio,beast);
}

View File

@@ -1,280 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
#include <beast/unit_test/suite.h>
#include <beast/asio/wrap_handler.h>
#include <boost/version.hpp>
#include <boost/bind.hpp>
#include <functional>
#include <memory>
namespace beast {
namespace asio {
//------------------------------------------------------------------------------
// Displays the order of destruction of parameters in the bind wrapper
//
class boost_bind_test : public unit_test::suite
{
public:
struct Result
{
std::string text;
void push_back (std::string const& s)
{
if (! text.empty())
text += ", ";
text += s;
}
};
struct Payload
{
std::reference_wrapper <Result> m_result;
std::string m_name;
explicit Payload (Result& result, std::string const& name)
: m_result (result)
, m_name (name)
{
}
~Payload ()
{
m_result.get().push_back (m_name);
}
};
struct Arg
{
std::shared_ptr <Payload> m_payload;
Arg (Result& result, std::string const& name)
: m_payload (std::make_shared <Payload> (result, name))
{
}
};
static void foo (Arg const&, Arg const&, Arg const&)
{
}
void run()
{
{
Result r;
{
boost::bind (&foo,
Arg (r, "one"),
Arg (r, "two"),
Arg (r, "three"));
}
log <<
std::string ("boost::bind (") + r.text + ")";
}
{
Result r;
{
std::bind (&foo,
Arg (r, "one"),
Arg (r, "two"),
Arg (r, "three"));
}
log <<
std::string ("std::bind (") + r.text + ")";
}
pass();
}
};
BEAST_DEFINE_TESTSUITE(boost_bind,asio,beast);
//------------------------------------------------------------------------------
class wrap_handler_test : public unit_test::suite
{
public:
struct test_results
{
bool call;
bool invoke;
bool alloc;
bool dealloc;
bool cont;
test_results ()
: call (false)
, invoke (false)
, alloc (false)
, dealloc (false)
, cont (false)
{
}
};
struct test_handler
{
std::reference_wrapper <test_results> results;
explicit test_handler (test_results& results_)
: results (results_)
{
}
void operator() ()
{
results.get().call = true;
}
template <class Function>
friend void asio_handler_invoke (
Function& f, test_handler* h)
{
h->results.get().invoke = true;
f();
}
template <class Function>
friend void asio_handler_invoke (
Function const& f, test_handler* h)
{
h->results.get().invoke = true;
f();
}
friend void* asio_handler_allocate (
std::size_t, test_handler* h)
{
h->results.get().alloc = true;
return nullptr;
}
friend void asio_handler_deallocate (
void*, std::size_t, test_handler* h)
{
h->results.get().dealloc = true;
}
friend bool asio_handler_is_continuation (
test_handler* h)
{
h->results.get().cont = true;
return true;
}
};
struct test_invokable
{
bool call;
test_invokable ()
: call (false)
{
}
void operator() ()
{
call = true;
}
};
template <class Handler>
bool async_op (Handler&& handler)
{
void* const p (boost_asio_handler_alloc_helpers::allocate (32, handler));
(handler)();
boost_asio_handler_alloc_helpers::deallocate (p, 32, handler);
return boost_asio_handler_cont_helpers::is_continuation (handler);
}
void run()
{
// Hooks called when using the raw handler
{
test_results r;
test_handler h (r);
async_op (h);
expect (r.call);
expect (r.alloc);
expect (r.dealloc);
expect (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), h);
expect (r.invoke);
expect (f.call);
}
// Use of boost::bind shows the hooks not getting called
{
test_results r;
test_handler h (r);
auto b (std::bind (&test_handler::operator(), &h));
async_op (b);
expect (r.call);
unexpected (r.alloc);
unexpected (r.dealloc);
unexpected (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), b);
unexpected (r.invoke);
expect (f.call);
}
// Make sure the wrapped handler calls the hooks
{
test_results r;
test_handler h (r);
auto w (wrap_handler (
std::bind (&test_handler::operator(), test_handler(r)), h));
async_op (w);
expect (r.call);
expect (r.alloc);
expect (r.dealloc);
expect (r.cont);
test_invokable f;
boost_asio_handler_invoke_helpers::invoke (std::ref (f), w);
expect (r.invoke);
expect (f.call);
}
}
};
BEAST_DEFINE_TESTSUITE(wrap_handler,asio,beast);
}
}

View File

@@ -1,176 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_WRAP_HANDLER_H_INCLUDED
#define BEAST_ASIO_WRAP_HANDLER_H_INCLUDED
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <utility>
namespace beast {
namespace asio {
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4512) // assignment operator could not be generated
#endif
namespace detail {
/** A handler which wraps another handler using a specfic context.
The handler is invoked with the same io_service execution guarantees
as the provided context.
@note A copy of Context is made.
*/
template <class Handler, class Context>
class wrapped_handler
{
private:
Handler m_handler;
Context m_context;
bool m_continuation;
// If this goes off, consider carefully what the intent is.
static_assert (! std::is_reference <Handler>::value,
"Handler should not be a reference type");
public:
wrapped_handler (bool continuation, Handler&& handler, Context context)
: m_handler (std::move (handler))
, m_context (context)
, m_continuation (continuation ? true :
boost_asio_handler_cont_helpers::is_continuation (context))
{
}
wrapped_handler (bool continuation, Handler const& handler, Context context)
: m_handler (handler)
, m_context (context)
, m_continuation (continuation ? true :
boost_asio_handler_cont_helpers::is_continuation (context))
{
}
template <class... Args>
void
operator() (Args&&... args)
{
m_handler (std::forward <Args> (args)...);
}
template <class... Args>
void
operator() (Args&&... args) const
{
m_handler (std::forward <Args> (args)...);
}
template <class Function>
friend
void
asio_handler_invoke (Function& f, wrapped_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke (f, h->m_context);
}
template <class Function>
friend
void
asio_handler_invoke (Function const& f, wrapped_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke (f, h->m_context);
}
friend
void*
asio_handler_allocate (std::size_t size, wrapped_handler* h)
{
return boost_asio_handler_alloc_helpers::
allocate (size, h->m_context);
}
friend
void
asio_handler_deallocate (void* p, std::size_t size, wrapped_handler* h)
{
boost_asio_handler_alloc_helpers::
deallocate (p, size, h->m_context);
}
friend
bool
asio_handler_is_continuation (wrapped_handler* h)
{
return h->m_continuation;
}
};
}
//------------------------------------------------------------------------------
// Tag for dispatching wrap_handler with is_continuation == true
enum continuation_t
{
continuation
};
/** Returns a wrapped handler so it executes within another context.
The handler is invoked with the same io_service execution guarantees
as the provided context. The handler will be copied if necessary.
@note A copy of Context is made.
*/
/** @{ */
template <class DeducedHandler, class Context>
detail::wrapped_handler <
std::remove_reference_t <DeducedHandler>,
Context
>
wrap_handler (DeducedHandler&& handler, Context const& context,
bool continuation = false)
{
typedef std::remove_reference_t <DeducedHandler> Handler;
return detail::wrapped_handler <Handler, Context> (continuation,
std::forward <DeducedHandler> (handler), context);
}
template <class DeducedHandler, class Context>
detail::wrapped_handler <
std::remove_reference_t <DeducedHandler>,
Context
>
wrap_handler (continuation_t, DeducedHandler&& handler,
Context const& context)
{
typedef std::remove_reference_t <DeducedHandler> Handler;
return detail::wrapped_handler <Handler, Context> (true,
std::forward <DeducedHandler> (handler), context);
}
/** @} */
}
}
#endif

View File

@@ -22,14 +22,11 @@
#endif
#include <beast/http/impl/basic_parser.cpp>
#include <beast/http/impl/basic_url.cpp>
#include <beast/http/impl/joyent_parser.cpp>
#include <beast/http/impl/method.cpp>
#include <beast/http/impl/raw_parser.cpp>
#include <beast/http/impl/URL.cpp>
#include <beast/http/tests/basic_url.test.cpp>
#include <beast/http/tests/client_session.test.cpp>
#include <beast/http/tests/parser.test.cpp>
#include <beast/http/tests/rfc2616.test.cpp>
#include <beast/http/tests/URL.test.cpp>

View File

@@ -1,174 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_HTTP_BASIC_URL_H_INCLUDED
#define BEAST_HTTP_BASIC_URL_H_INCLUDED
#include <boost/system/error_code.hpp>
#include <boost/utility/string_ref.hpp>
#include <beast/utility/noexcept.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
namespace beast {
namespace http {
namespace detail {
class basic_url_base
{
public:
typedef char value_type;
typedef std::char_traits <value_type> traits_type;
typedef boost::basic_string_ref <
value_type, traits_type> string_ref;
string_ref
scheme () const noexcept
{
return m_scheme;
}
string_ref
host () const noexcept
{
return m_host;
}
std::uint16_t
port () const noexcept
{
return m_port;
}
string_ref
port_string () const noexcept
{
return m_port_string;
}
string_ref
path () const noexcept
{
return m_path;
}
string_ref
query () const noexcept
{
return m_query;
}
string_ref
fragment () const noexcept
{
return m_fragment;
}
string_ref
userinfo () const noexcept
{
return m_userinfo;
}
protected:
void
parse_impl (string_ref s, boost::system::error_code& ec);
string_ref m_string_ref;
string_ref m_scheme;
string_ref m_host;
std::uint16_t m_port;
string_ref m_port_string;
string_ref m_path;
string_ref m_query;
string_ref m_fragment;
string_ref m_userinfo;
};
}
/** A URL. */
template <
class Alloc = std::allocator <char>
>
class basic_url : public detail::basic_url_base
{
public:
typedef std::basic_string <
value_type, traits_type, Alloc> string_type;
basic_url() = default;
explicit basic_url (Alloc const& alloc)
: m_string (alloc)
{
}
void
parse (string_ref s)
{
boost::system::error_code ec;
parse (s, ec);
if (ec)
throw std::invalid_argument ("invalid url string");
}
boost::system::error_code
parse (string_ref s,
boost::system::error_code& ec)
{
parse_impl (s, ec);
if (!ec)
{
m_string = string_type (s.begin(), s.end());
m_string_ref = m_string;
}
return ec;
}
bool
empty () const noexcept
{
return m_string.empty();
}
template <class Alloc1, class Alloc2>
friend
int
compare (basic_url const& lhs,
basic_url const& rhs) noexcept
{
return lhs.m_buf.compare (rhs.m_buf);
}
private:
string_type m_string;
};
using url = basic_url <std::allocator <char>>;
}
}
#endif

View File

@@ -1,727 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HTTP_BASIC_SESSION_H_INCLUDED
#define BEAST_ASIO_HTTP_BASIC_SESSION_H_INCLUDED
#include <beast/http/basic_url.h>
#include <beast/http/raw_parser.h>
#include <beast/http/detail/header_traits.h>
#include <beast/asio/bind_handler.h>
#include <beast/asio/enable_wait_for_async.h>
#include <beast/asio/placeholders.h>
#include <beast/asio/shared_handler.h>
#include <beast/utility/is_call_possible.h>
#include <beast/utility/ci_char_traits.h>
#include <boost/asio/buffer.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/streambuf.hpp>
//#include <boost/optional.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/logic/tribool.hpp>
#include <beast/cxx14/memory.h> // <memory>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <sstream> // REMOVE ASAP!
namespace beast {
namespace http {
template <class T, class Alloc>
boost::asio::basic_streambuf <Alloc>&
operator<< (boost::asio::basic_streambuf <Alloc>& stream, T const& t)
{
std::stringstream ss;
ss << t;
std::string const s (ss.str());
auto const b (boost::asio::buffer (s));
auto const len (boost::asio::buffer_size (b));
boost::asio::buffer_copy (stream.prepare (len), b);
stream.commit (len);
return stream;
}
template <class Alloc>
boost::asio::basic_streambuf <Alloc>&
operator<< (boost::asio::basic_streambuf <Alloc>& stream,
std::string const& s)
{
auto const b (boost::asio::buffer (s));
auto const len (boost::asio::buffer_size (b));
boost::asio::buffer_copy (stream.prepare (len), b);
stream.commit (len);
return stream;
}
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4100) // unreferenced formal parameter
#endif
/** Provides asynchronous HTTP client service on a socket. */
template <class Socket>
class client_session
: public asio::enable_wait_for_async <client_session <Socket>>
, private raw_parser::callback
{
private:
BOOST_TRIBOOL_THIRD_STATE(unspecified);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_keep_alive, keep_alive);
template <class Cond>
struct Enabled : public std::integral_constant <bool, Cond::value>
{
};
static_assert (! std::is_const <Socket>::value,
"Socket cannot be const");
typedef boost::system::error_code error_code;
typedef boost::asio::streambuf write_buffers;
typedef boost::basic_string_ref <
char, ci_char_traits> ci_string_ref;
class abstract_request;
class abstract_response;
Socket m_socket;
boost::asio::io_service::strand m_strand;
boost::asio::deadline_timer m_timer;
asio::shared_handler <void(error_code)> m_handler;
std::unique_ptr <abstract_request> m_request;
std::unique_ptr <abstract_response> m_response;
raw_parser m_parser;
write_buffers m_write_buffer;
boost::asio::mutable_buffer m_read_buffer;
std::string m_field;
std::string m_value;
bool m_complete : 1;
bool m_keep_alive : 1;
public:
typedef Socket stream_type;
client_session& operator= (client_session const&) = delete;
template <class... Args>
explicit client_session (Args&&... args)
: m_socket (std::forward <Args> (args)...)
, m_strand (m_socket.get_io_service())
, m_timer (m_socket.get_io_service())
, m_parser (*this)
{
}
~client_session() = default;
/** Returns the stream associated with the session. */
/** @{ */
stream_type&
stream()
{
return m_socket;
}
stream_type const&
stream() const
{
return m_socket;
}
/** @} */
void
cancel()
{
error_code ec;
m_socket.cancel(ec);
}
/** Fetch a resource asynchronously. */
template <
class Request,
class Response,
class Handler
>
void
async_get (Request request, Response response, Handler&& handler)
{
m_handler = std::forward <Handler> (handler);
m_request = std::make_unique <
wrapped_request <Request>> (request);
m_response = std::make_unique <
wrapped_response <Response>> (response);
start();
}
template <
class Handler
>
void
async_get (std::string const&) noexcept
{
}
private:
class abstract_request
{
public:
virtual
~abstract_request()
{
}
virtual
boost::tribool
keep_alive () = 0;
virtual
void
headers (write_buffers& buffer) = 0;
};
template <class Request>
class wrapped_request : public abstract_request
{
private:
typedef std::remove_reference_t <Request> request_type;
Request m_request;
public:
explicit wrapped_request (Request request)
: m_request (request)
{
}
wrapped_request (wrapped_request const&) = delete;
private:
boost::tribool
keep_alive() override
{
return keep_alive (Enabled <has_keep_alive <
request_type, bool ()>>());
}
boost::tribool
keep_alive (std::true_type)
{
return m_request.keep_alive();
}
boost::tribool
keep_alive (std::false_type)
{
return unspecified;
}
class submit
{
private:
write_buffers& m_buffer;
public:
explicit submit (write_buffers& buffer)
: m_buffer (buffer)
{
}
// Throws if an invalid request field is specified.
// Invalid fields are ones that the client_session inserts
// itself, such as keep-alive.
//
static void check_request_field (std::string const& field)
{
static std::vector <std::string> reserved =
{
"Content-Length",
"Connection"
};
if (std::any_of (reserved.cbegin(), reserved.cend(),
[&](typename decltype(reserved)::value_type const& s)
{
return detail::field_eq (field, s);
}))
throw std::invalid_argument (
"Reserved HTTP header in request");
}
template <class F, class V>
void
operator() (F const& f, V const& v)
{
check_request_field (f);
auto const fb (boost::asio::buffer (f));
m_buffer.commit (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (fb)), fb));
m_buffer << ": ";
auto const vb (boost::asio::buffer (v));
m_buffer.commit (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (vb)), vb));
m_buffer << "\r\n";
}
};
void
headers (write_buffers& buffer) override
{
submit f (buffer);
m_request.template headers <
std::add_lvalue_reference_t <submit>> (f);
}
};
class abstract_response
{
public:
abstract_response() = default;
abstract_response (abstract_response const&) = default;
abstract_response& operator= (abstract_response const&) = default;
virtual
~abstract_response() = default;
virtual
boost::asio::mutable_buffer
buffer () = 0;
virtual
error_code
header (std::string const& field,
std::string const& value) = 0;
virtual
error_code
body (boost::asio::const_buffer in) = 0;
};
template <class Response>
class wrapped_response : public abstract_response
{
private:
Response m_response;
public:
explicit wrapped_response (Response response)
: m_response (response)
{
}
wrapped_response (wrapped_response const&) = delete;
boost::asio::mutable_buffer
buffer() override
{
return m_response.buffer();
}
error_code
header (std::string const& field,
std::string const& value) override
{
return m_response.header (field, value);
}
virtual
error_code
body (boost::asio::const_buffer in)
{
return m_response.body (in);
}
};
void upcall (error_code const& ec, bool continuation = true)
{
if (m_handler)
{
// TODO cancel all pending i/o here?
if (continuation)
{
m_handler (ec);
m_handler = nullptr;
}
else
{
m_socket.get_io_service().post (
asio::bind_handler (
std::move (m_handler), ec));
assert (! m_handler);
}
}
}
void start()
{
// reset and setup state
m_parser.reset (raw_parser::response);
m_write_buffer.consume (m_write_buffer.size());
m_write_buffer <<
"GET / HTTP/1.0\r\n";
m_request->headers (m_write_buffer);
m_write_buffer <<
"Content-Length: 0\r\n"
"\r\n";
m_read_buffer = m_response->buffer();
m_field = std::string();
m_value = std::string();
m_complete = false;
m_keep_alive = false;
async_write_some (false);
}
//
// request
//
bool
async_write_some (bool continuation = true)
{
auto const& data (m_write_buffer.data());
auto const size (boost::asio::buffer_size (
m_write_buffer.data()));
if (size > 0)
{
m_socket.async_write_some (data, this->wrap_with_counter (
m_strand.wrap (asio::wrap_handler (std::bind (
&client_session::handle_write, this,
asio::placeholders::error,
asio::placeholders::bytes_transferred),
continuation))));
return true;
}
return false;
}
void
handle_write (error_code ec, std::size_t bytes_transferred)
{
if (ec)
return upcall (ec);
m_write_buffer.consume (bytes_transferred);
if (async_write_some())
return;
// write finished
//if (! keep_alive)
{
m_socket.shutdown (
boost::asio::socket_base::shutdown_send, ec);
// VFALCO What do we do with ec?
}
// now read
async_read_some (true);
}
//
// response
//
void
async_read_some (bool continuation = true)
{
m_socket.async_read_some (boost::asio::mutable_buffers_1 (
m_read_buffer), this->wrap_with_counter (
m_strand.wrap (asio::wrap_handler (std::bind (
&client_session::handle_read, this,
asio::placeholders::error,
asio::placeholders::bytes_transferred),
continuation))));
};
void
handle_read (error_code ec, std::size_t bytes_transferred)
{
if (ec != boost::asio::error::eof)
{
if (ec)
return upcall (ec);
std::size_t bytes_consumed;
std::tie (ec, bytes_consumed) = m_parser.process_data (
boost::asio::buffer_cast <void const*> (m_read_buffer),
bytes_transferred);
// TODO Handle leftover bytes
//assert (ec || bytes_consumed == bytes_transferred);
if (ec)
return upcall (ec);
if (! m_complete)
return async_read_some();
}
else
{
// This is here for when we expect keep-alive but
// the server ends up closing the connection erroneously.
if (m_keep_alive)
{
m_keep_alive = false;
// warning: Got EOF on keep-alive
}
ec = m_parser.process_eof();
}
if (! m_complete)
{
// custom error
ec = error_code (boost::system::errc::no_message_available,
boost::system::generic_category());
}
if (ec)
return upcall (ec);
// We have a complete response
if (! m_keep_alive)
{
// VFALCO NOTE This is surely wrong for ssl::stream
{
error_code ec_;
m_socket.shutdown (
boost::asio::socket_base::shutdown_receive, ec_);
}
{
error_code ec_;
m_socket.close (ec_);
assert (! ec_);
}
}
m_request.reset();
m_response.reset();
m_handler (ec);
// done
}
//
// parser
//
error_code
do_header()
{
error_code ec;
if (! m_value.empty())
{
ec = m_response->header (m_field, m_value);
m_field.clear();
m_value.clear();
}
return ec;
}
error_code
on_response () override
{
m_field = decltype(m_field)();
m_value = decltype(m_value)();
return error_code();
}
error_code
on_url (
void const* in, std::size_t bytes) override
{
// Shouldn't be called for HTTP responses
assert (false);
return error_code();
}
error_code
on_status (int status_code,
void const* in, std::size_t bytes) override
{
return error_code();
}
error_code
on_header_field (
void const* in, std::size_t bytes) override
{
do_header();
m_field.append (static_cast <char const*> (in), bytes);
return error_code();
}
error_code
on_header_value (
void const* in, std::size_t bytes) override
{
m_value.append (static_cast <char const*> (in), bytes);
return error_code();
}
error_code
on_headers_done (
bool keep_alive) override
{
do_header();
return error_code();
}
error_code
on_body (bool,
void const* in, std::size_t bytes) override
{
m_response->body (
boost::asio::const_buffer (in, bytes));
return error_code();
}
error_code
on_message_complete (bool keep_alive) override
{
m_keep_alive = keep_alive;
m_complete = true;
return error_code();
}
};
#ifdef _MSC_VER
#pragma warning (pop)
#endif
//------------------------------------------------------------------------------
/** Synchronous HTTP client session. */
template <class Socket>
class sync_client_session
{
private:
typedef boost::system::error_code error_code;
boost::asio::io_service m_ios;
Socket m_socket;
error_code m_ec;
static_assert (std::is_same <Socket, std::decay_t <Socket>>::value,
"Socket cannot be a reference or const type");
struct sync_handler
{
std::reference_wrapper <sync_client_session> m_session;
sync_handler (sync_client_session& session)
: m_session (session)
{
}
void operator() (boost::system::error_code ec)
{
m_session.get().m_ec = ec;
}
};
public:
typedef std::remove_reference_t <Socket> next_layer_type;
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
sync_client_session()
: m_socket (m_ios)
{
}
sync_client_session (sync_client_session const&) = delete;
// VFALCO We might be able to get away with having move ctor/assign
~sync_client_session() = default;
next_layer_type&
next_layer() noexcept
{
return m_socket;
}
next_layer_type const&
next_layer() const noexcept
{
}
lowest_layer_type&
lowest_layer() noexcept
{
return m_socket.lowest_layer();
}
lowest_layer_type const&
lowest_layer() const noexcept
{
return m_socket.lowest_layer();
}
template <class Request, class Response>
error_code
get (Request& request, Response& response)
{
client_session <Socket&> session (m_socket);
session.template async_get <
std::add_lvalue_reference_t <Request>,
std::add_lvalue_reference_t <Response>,
sync_handler> (
request, response, sync_handler (*this));
m_ios.run();
m_ios.reset();
return m_ec;
}
};
}
}
#endif

View File

@@ -1,56 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/http/basic_url.h>
#include <beast/unit_test/suite.h>
namespace beast {
class basic_url_test : public unit_test::suite
{
public:
void
run ()
{
std::vector <char const*> const urls {
"http://www.example.com/#%c2%a9",
"http://127.0.0.1:443",
"http://192.168.0.1 hello.urltest.lookout.net/",
"http://\\uff10\\uff38\\uff43\\uff10\\uff0e\\uff10\\uff12\\uff15\\uff10\\uff0e\\uff10\\uff11.urltest.lookout.net/"
};
http::url url;
for (auto const& s : urls)
{
try
{
url.parse (s);
pass();
}
catch(...)
{
fail();
}
}
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(basic_url,http,beast);
}

View File

@@ -1,376 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
// LIBS: pthread
// MODULES: urls_large_data.cpp ../impl/raw_parser.cpp ../impl/joyent_parser.cpp
#if BEAST_INCLUDE_BEASTCONFIG
#include "../../BeastConfig.h"
#endif
#include <beast/unit_test/suite.h>
#include <beast/http/tests/urls_large_data.h>
#include <beast/http/client_session.h>
#include <beast/asio/bind_handler.h>
#include <beast/asio/memory_buffer.h>
#include <beast/utility/ci_char_traits.h>
#include <boost/asio.hpp>
#include <thread>
#include <unordered_map>
namespace beast {
namespace http {
/** Allows thread-safe forward traversal of a sequence.
Each time the shared_iterator is dereferenced it provides an element in
the sequence or the one-past-the-end iterator if there are no elements
remaining in the sequence. Access to the shared iterator is thread safe:
multiple threads of execution can request iterators from the sequence,
and no two threads will see the same iterator.
Any operations on the underlying container which would invalidate
iterators or change the sequence of elements pointed to by the range
of iterators referenced by the shared_iterator, results in undefined
behavior.
*/
template <class Iterator>
class shared_iterator
{
public:
static_assert (std::is_same <Iterator, std::decay_t <Iterator>>::value,
"Iterator may not be a reference or const type");
typedef Iterator value_type;
private:
std::mutex m_mutex;
Iterator m_iter;
Iterator m_end;
public:
/** Construct the iteration from the range [first, last) */
shared_iterator (Iterator first, Iterator last)
: m_iter (first)
, m_end (last)
{
}
/** Obtains the next iterator in the sequence.
Post-condition
Current shared position in the sequence is advanced by one.
Thread safety:
Can be called from any thread at any time.
*/
Iterator
operator* ()
{
std::lock_guard <decltype(m_mutex)> lock (m_mutex);
if (m_iter == m_end)
return m_iter;
return m_iter++;
}
/** Returns the one-past-the end iterator for the sequence.
Thread safety:
Can be called from any thread at any time.
*/
Iterator
end() const
{
return m_end;
}
};
//------------------------------------------------------------------------------
class client_session_test : public unit_test::suite
{
public:
typedef boost::system::error_code error_code;
//--------------------------------------------------------------------------
/** Used to submit HTTP requests. */
class Request
{
private:
typedef std::string value_type;
typedef std::string string_type;
std::unordered_map <std::string, string_type> m_headers;
// This also works, for allowing header values to
// span multiple discontiguous memory buffers.
//
std::unordered_map <std::string,
std::vector <std::string>> m_headers_plus;
class vector_proxy
{
private:
std::reference_wrapper <std::vector <string_type>> m_vec;
public:
explicit vector_proxy (std::vector <string_type>& vec)
: m_vec (vec)
{
}
vector_proxy& operator= (string_type const& s)
{
m_vec.get().emplace_back (s);
return *this;
}
};
public:
bool keep_alive()
{
return false;
}
// Use this to set the fields
std::string&
operator[] (std::string const& field)
{
return m_headers[field];
}
/** Calls Function for each header.
Requirements:
`X` The type `Function`
`Y` A type meeting this requirement:
ConvertibleToConstBuffer
`Z` A type meeting either requirement:
ConstBufferSequence
ConvertibleToConstBuffer
`f` A value of type `X`
`n` A value of type `Y`
`v` A value of type `Z`
The expression
f (n, v);
must be well formed.
*/
template <class Function>
void
headers (Function f)
{
for (auto const& h : m_headers)
f (h.first, h.second);
}
};
//--------------------------------------------------------------------------
class Response
{
private:
typedef boost::system::error_code error_code;
asio::memory_buffer <std::uint8_t> m_buffer;
boost::asio::streambuf m_body;
public:
enum
{
buffer_bytes = 4192
};
typedef std::vector <std::pair <
std::string, std::string>> headers_type;
headers_type headers;
Response()
: m_buffer (buffer_bytes)
{
}
boost::asio::mutable_buffer
buffer()
{
return boost::asio::mutable_buffer (
m_buffer.data(), m_buffer.size());
}
template <class FieldString, class ValueString>
error_code
header (FieldString const& field, ValueString const& value)
{
headers.push_back (std::make_pair (field, value));
return error_code();
}
error_code
body (boost::asio::const_buffer in)
{
m_body.commit (boost::asio::buffer_copy (
m_body.prepare (boost::asio::buffer_size (in)),
boost::asio::buffer (in)));
return error_code();
}
std::size_t
size() const
{
return m_body.size();
}
std::string
data() const
{
std::string s;
s.resize (m_body.size());
boost::asio::buffer_copy (boost::asio::buffer (
&s[0], s.size()), m_body.data());
return s;
}
};
//--------------------------------------------------------------------------
template <class Session>
error_code
visit (Session& session, std::string const& url)
{
error_code ec;
typedef boost::asio::ip::tcp::resolver resolver_t;
boost::asio::io_service ios;
resolver_t r (ios);
auto iter (r.resolve (resolver_t::query (
url, "80", resolver_t::query::numeric_service), ec));
if (ec)
return ec;
if (iter != resolver_t::iterator())
{
session.next_layer().connect (iter->endpoint(), ec);
if (ec)
return ec;
Request req;
req ["User-Agent"] = "rippled-http-client/1.0";
req ["Host"] = url + ":80";
req ["Content-Type"] = "application/text";
req ["Accept"] = "application/text";
//req ["Content-length"] = "0";
//req.prepare ("GET / HTTP/1.0");
Response resp;
ec = session.get (req, resp);
if (ec)
{
// hack
session.next_layer().close();
}
log <<
"GET " << url << " " << ec.message();
for (auto const& h : resp.headers)
log << h.first << ": " << h.second;
log << resp.data();
log << " ";
}
return ec;
}
//--------------------------------------------------------------------------
template <class Iterator>
void
concurrent_get (shared_iterator <Iterator>& iter)
{
typedef boost::asio::ip::tcp::socket socket_type;
for (auto cur (*iter); cur != iter.end(); cur = *iter)
{
sync_client_session <socket_type> session;
std::string const base (*cur);
std::string url;
url = "www." + base;
visit (session, url);
}
}
// Perform HTTP get on a sequence of URLs in parallel
// Requirements
// Sequence must me
// Sequence::value_type must be convertible to std::string
template <class Iterator>
void test_concurrent_get (Iterator first, Iterator last)
{
#if 0
last = first;
std::advance (last, 3000);
#endif
shared_iterator <Iterator> iter (first, last);
std::vector <std::thread> pool;
#if 0
std::size_t const hardware_concurrency (
std::max (std::thread::hardware_concurrency(),
2u
));
#else
std::size_t const hardware_concurrency (1);
#endif
for (std::size_t n (hardware_concurrency); n--;)
pool.emplace_back (std::bind (
&client_session_test::concurrent_get <Iterator>, this,
std::ref (iter)));
for (auto& t : pool)
t.join();
pass();
}
template <class Sequence>
void test_concurrent_get (Sequence const& sequence)
{
auto last (std::begin(sequence));
std::advance (last, std::min (std::size_t(1), sequence.size()));
test_concurrent_get (std::begin (sequence), last);
}
void run()
{
test_concurrent_get (urls_large_data());
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(client_session,http,beast);
}
}

View File

@@ -20,6 +20,9 @@
#ifndef BEAST_ASIO_ASYNCOBJECT_H_INCLUDED
#define BEAST_ASIO_ASYNCOBJECT_H_INCLUDED
#include <beast/Atomic.h>
#include <cassert>
namespace beast {
namespace asio {
@@ -34,7 +37,7 @@ public:
~AsyncObject ()
{
// Destroying the object with I/O pending? Not a clean exit!
bassert (m_pending.get() == 0);
assert (m_pending.get() == 0);
}
/** RAII container that maintains the count of pending I/O.

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPField.h>
namespace beast {
HTTPField::HTTPField ()

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPHeaders.h>
#include <algorithm>
namespace beast {

View File

@@ -20,7 +20,7 @@
#ifndef BEAST_ASIO_HTTPHEADERS_H_INCLUDED
#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED
#include <beast/module/asio/http/HTTPField.h>
#include <beast/module/asio/HTTPField.h>
#include <beast/module/core/text/StringPairArray.h>
#include <map>

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPMessage.h>
namespace beast {
HTTPMessage::HTTPMessage (HTTPVersion const& version_,

View File

@@ -20,8 +20,8 @@
#ifndef BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
#define BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
#include <beast/module/asio/http/HTTPHeaders.h>
#include <beast/module/asio/http/HTTPVersion.h>
#include <beast/module/asio/HTTPHeaders.h>
#include <beast/module/asio/HTTPVersion.h>
#include <beast/smart_ptr/SharedObject.h>
#include <beast/net/DynamicBuffer.h>

View File

@@ -17,6 +17,9 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPParser.h>
#include <beast/module/asio/HTTPParserImpl.h>
namespace beast {
HTTPParser::HTTPParser (Type type)

View File

@@ -20,8 +20,8 @@
#ifndef BEAST_ASIO_HTTPPARSER_H_INCLUDED
#define BEAST_ASIO_HTTPPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPRequest.h>
#include <beast/module/asio/http/HTTPResponse.h>
#include <beast/module/asio/HTTPRequest.h>
#include <beast/module/asio/HTTPResponse.h>
namespace beast {

View File

@@ -20,6 +20,9 @@
#ifndef BEAST_HTTPPARSERIMPL_H_INCLUDED
#define BEAST_HTTPPARSERIMPL_H_INCLUDED
#include <beast/http/impl/joyent_parser.h>
#include <boost/asio/buffer.hpp>
namespace beast {
class HTTPParserImpl

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPRequest.h>
namespace beast {
HTTPRequest::HTTPRequest (

View File

@@ -20,7 +20,7 @@
#ifndef BEAST_ASIO_HTTPREQUEST_H_INCLUDED
#define BEAST_ASIO_HTTPREQUEST_H_INCLUDED
#include <beast/module/asio/http/HTTPMessage.h>
#include <beast/module/asio/HTTPMessage.h>
namespace beast {

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
//#include "HTTPRequestParser.h"
#include <beast/module/asio/HTTPRequestParser.h>
namespace beast {

View File

@@ -20,7 +20,7 @@
#ifndef BEAST_HTTP_REQUESTPARSER_H_INCLUDED
#define BEAST_HTTP_REQUESTPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPParser.h>
#include <beast/module/asio/HTTPParser.h>
namespace beast {

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include <beast/module/asio/HTTPResponse.h>
namespace beast {
HTTPResponse::HTTPResponse (

View File

@@ -20,6 +20,8 @@
#ifndef BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
#define BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
#include <beast/module/asio/HTTPMessage.h>
namespace beast {
class HTTPResponse : public HTTPMessage

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
//#include "HTTPResponseParser.h"
#include <beast/module/asio/HTTPResponseParser.h>
namespace beast {

View File

@@ -20,7 +20,7 @@
#ifndef BEAST_HTTP_RESPONSEPARSER_H_INCLUDED
#define BEAST_HTTP_RESPONSEPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPParser.h>
#include <beast/module/asio/HTTPParser.h>
namespace beast {

View File

@@ -1,75 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_MODULE_H_INCLUDED
#define BEAST_ASIO_MODULE_H_INCLUDED
// Must come before boost includes to fix the bost placeholders.
#include <beast/module/core/core.h>
// This module requires boost and possibly OpenSSL
#include <beast/module/asio/system/BoostIncludes.h>
#include <beast/http/URL.h>
#include <beast/asio/IPAddressConversion.h>
// Order matters
#include <beast/module/asio/async/AsyncObject.h>
#include <beast/module/asio/basics/FixedInputBuffer.h>
#include <beast/module/asio/basics/PeerRole.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <beast/module/asio/http/HTTPVersion.h>
#include <beast/module/asio/http/HTTPField.h>
#include <beast/module/asio/http/HTTPHeaders.h>
#include <beast/module/asio/http/HTTPMessage.h>
#include <beast/module/asio/http/HTTPRequest.h>
#include <beast/module/asio/http/HTTPResponse.h>
#include <beast/module/asio/http/HTTPParser.h>
#include <beast/module/asio/http/HTTPRequestParser.h>
#include <beast/module/asio/http/HTTPResponseParser.h>
#include <beast/module/asio/http/HTTPClientType.h>
#include <beast/module/asio/protocol/InputParser.h>
#include <beast/module/asio/protocol/HandshakeDetectLogic.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicPROXY.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicSSL2.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicSSL3.h>
#include <beast/module/asio/protocol/HandshakeDetector.h>
#include <beast/module/asio/protocol/PrefilledReadStream.h>
#include <beast/module/asio/tests/TestPeerBasics.h>
#include <beast/module/asio/tests/TestPeer.h>
#include <beast/module/asio/tests/TestPeerDetails.h>
#include <beast/module/asio/tests/TestPeerLogic.h>
#include <beast/module/asio/tests/TestPeerLogicSyncServer.h>
#include <beast/module/asio/tests/TestPeerLogicSyncClient.h>
#include <beast/module/asio/tests/TestPeerLogicProxyClient.h>
#include <beast/module/asio/tests/TestPeerLogicAsyncServer.h>
#include <beast/module/asio/tests/TestPeerLogicAsyncClient.h>
#include <beast/module/asio/tests/TestPeerType.h>
#include <beast/module/asio/tests/TestPeerDetailsTcp.h>
#include <beast/module/asio/tests/PeerTest.h>
#endif

View File

@@ -21,36 +21,12 @@
#include <BeastConfig.h>
#endif
#include <beast/module/asio/system/OpenSSLIncludes.h>
#include <beast/module/asio/asio.h>
#include <beast/http/impl/joyent_parser.h>
#include <beast/module/asio/basics/PeerRole.cpp>
#include <beast/module/asio/basics/SSLContext.cpp>
#include <beast/module/asio/protocol/HandshakeDetectLogicPROXY.cpp>
#include <beast/module/asio/http/HTTPParserImpl.h>
#include <beast/module/asio/http/HTTPClientType.cpp>
#include <beast/module/asio/http/HTTPField.cpp>
#include <beast/module/asio/http/HTTPHeaders.cpp>
#include <beast/module/asio/http/HTTPMessage.cpp>
#include <beast/module/asio/http/HTTPRequest.cpp>
#include <beast/module/asio/http/HTTPResponse.cpp>
#include <beast/module/asio/http/HTTPVersion.cpp>
#include <beast/module/asio/tests/PeerTest.cpp>
#include <beast/module/asio/tests/TestPeerBasics.cpp>
#include <beast/module/asio/tests/TestPeerLogic.cpp>
#include <beast/module/asio/tests/TestPeerLogicProxyClient.cpp>
#include <beast/module/asio/tests/TestPeerLogicSyncServer.cpp>
#include <beast/module/asio/tests/TestPeerLogicSyncClient.cpp>
#include <beast/module/asio/tests/TestPeerLogicAsyncServer.cpp>
#include <beast/module/asio/tests/TestPeerLogicAsyncClient.cpp>
#include <beast/module/asio/tests/TestPeerUnitTests.cpp>
#include <beast/module/asio/http/HTTPParser.cpp>
#include <beast/module/asio/http/HTTPRequestParser.cpp>
#include <beast/module/asio/http/HTTPResponseParser.cpp>
#include <beast/module/asio/HTTPField.cpp>
#include <beast/module/asio/HTTPHeaders.cpp>
#include <beast/module/asio/HTTPMessage.cpp>
#include <beast/module/asio/HTTPRequest.cpp>
#include <beast/module/asio/HTTPResponse.cpp>
#include <beast/module/asio/HTTPVersion.cpp>
#include <beast/module/asio/HTTPParser.cpp>
#include <beast/module/asio/HTTPRequestParser.cpp>
#include <beast/module/asio/HTTPResponseParser.cpp>

View File

@@ -1,101 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
ContentBodyBuffer::ContentBodyBuffer (size_type blocksize)
: m_blocksize (blocksize)
, m_size (0)
{
}
ContentBodyBuffer::~ContentBodyBuffer ()
{
for (Handles::iterator iter (m_handles.begin());
iter != m_handles.end(); ++iter)
{
void* const buffer (*iter);
std::free (buffer);
}
}
void ContentBodyBuffer::swapWith (ContentBodyBuffer& other)
{
std::swap (m_blocksize, other.m_blocksize);
std::swap (m_size, other.m_size);
m_handles.swap (other.m_handles);
}
void ContentBodyBuffer::commit (size_type n)
{
m_size += n;
bassert (m_size <= m_handles.size () * m_blocksize);
}
ConstBuffers ContentBodyBuffer::data () const
{
size_type n (m_size);
std::vector <ConstBuffer> v;
v.reserve ((m_size + m_blocksize - 1) / m_blocksize);
for (Handles::const_iterator iter (m_handles.begin());
iter != m_handles.end() && n > 0; ++iter)
{
size_type const amount (std::min (n, m_blocksize));
v.push_back (MutableBuffer (*iter, amount));
n -= amount;
}
return ConstBuffers (v);
}
ContentBodyBuffer::size_type ContentBodyBuffer::size () const
{
return m_size;
}
MutableBuffers ContentBodyBuffer::prepare (size_type n)
{
reserve (n);
std::vector <MutableBuffer> v;
size_type offset (m_size % m_blocksize);
for (Handles::iterator iter = m_handles.begin () + (m_size / m_blocksize);
iter != m_handles.end () && n > 0; ++iter)
{
size_type const amount (std::min (n, m_blocksize - offset));
v.push_back (MutableBuffer (*iter, amount));
n -= amount;
offset = 0;
}
return MutableBuffers (v);
}
void ContentBodyBuffer::reserve (size_type n)
{
size_type count ((m_size + n + m_blocksize - 1) / m_blocksize);
if (count > m_handles.size ())
for (count -= m_handles.size (); count-- > 0;)
m_handles.push_back (std::malloc (m_blocksize));
}
void ContentBodyBuffer::shrink_to_fit ()
{
size_type const count ((m_size + m_blocksize - 1) / m_blocksize);
while (m_handles.size () > count)
{
std::free (m_handles.back ());
m_handles.erase (m_handles.end () - 1);
}
}

View File

@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
#define BEAST_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
/** Dynamic storage optimized for a large Content-Body of unknown size.
This comes at the expense of discontiguous storage of the segments.
We derive from SharedObject to make transfer of ownership inexpensive.
*/
class ContentBodyBuffer
{
public:
enum
{
defaultBlocksize = 32 * 1024
};
typedef std::size_t size_type;
typedef ConstBuffers const_buffers_tyoe;
typedef MutableBuffers mutable_buffers_type;
explicit ContentBodyBuffer (size_type blocksize = defaultBlocksize);
~ContentBodyBuffer ();
/** Swap the contents of this buffer with another.
This is the preferred way to transfer ownership.
*/
void swapWith (ContentBodyBuffer& other);
/** Move bytes from the output to the input sequence.
This will invalidate references to buffers.
*/
void commit (size_type n);
/** Returns a buffer to the input sequence. */
ConstBuffers data () const;
/** Returns the size of the input sequence. */
size_type size () const;
/** Reserve space in the output sequence.
This also returns a buffer suitable for writing.
*/
MutableBuffers prepare (size_type n);
/** Reserve space in the output sequence. */
void reserve (size_type n);
/** Release memory while preserving the input sequence. */
void shrink_to_fit ();
private:
typedef std::vector <void*> Handles;
size_type m_blocksize;
size_type m_size;
Handles m_handles;
};
#endif

View File

@@ -1,202 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
#define BEAST_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
#include <beast/asio/buffer_sequence.h>
#include <array>
namespace beast {
namespace asio {
/** Represents a small, fixed size buffer.
This provides a convenient interface for doing a bytewise
verification/reject test on a handshake protocol.
*/
/** @{ */
class FixedInputBuffer
{
protected:
struct CtorParams
{
CtorParams (std::uint8_t const* begin_, std::size_t bytes_)
: begin (begin_)
, bytes (bytes_)
{
}
std::uint8_t const* begin;
std::size_t bytes;
};
FixedInputBuffer (CtorParams const& params)
: m_begin (params.begin)
, m_iter (m_begin)
, m_end (m_begin + params.bytes)
{
}
public:
FixedInputBuffer (FixedInputBuffer const& other)
: m_begin (other.m_begin)
, m_iter (other.m_iter)
, m_end (other.m_end)
{
}
FixedInputBuffer& operator= (FixedInputBuffer const& other)
{
m_begin = other.m_begin;
m_iter = other.m_iter;
m_end = other.m_end;
return *this;
}
// Returns the number of bytes consumed
std::size_t used () const noexcept
{
return m_iter - m_begin;
}
// Returns the size of what's remaining
std::size_t size () const noexcept
{
return m_end - m_iter;
}
void const* peek (std::size_t bytes)
{
return peek_impl (bytes, nullptr);
}
template <typename T>
bool peek (T* t) const noexcept
{
return peek_impl (sizeof (T), t) != nullptr;
}
bool consume (std::size_t bytes) noexcept
{
return read_impl (bytes, nullptr) != nullptr;
}
bool read (std::size_t bytes) noexcept
{
return read_impl (bytes, nullptr) != nullptr;
}
template <typename T>
bool read (T* t) noexcept
{
return read_impl (sizeof (T), t) != nullptr;
}
std::uint8_t operator[] (std::size_t index) const noexcept
{
bassert (index >= 0 && index < size ());
return m_iter [index];
}
// Reads an integraltype in network byte order
template <typename IntegerType>
bool readNetworkInteger (IntegerType* value)
{
// Must be an integral type!
// not available in all versions of std:: unfortunately
//static_bassert (std::is_integral <IntegerType>::value);
IntegerType networkValue;
if (! read (&networkValue))
return false;
*value = fromNetworkByteOrder (networkValue);
return true;
}
protected:
void const* peek_impl (std::size_t bytes, void* buffer) const noexcept
{
if (size () >= bytes)
{
if (buffer != nullptr)
memcpy (buffer, m_iter, bytes);
return m_iter;
}
return nullptr;
}
void const* read_impl (std::size_t bytes, void* buffer) noexcept
{
if (size () >= bytes)
{
if (buffer != nullptr)
memcpy (buffer, m_iter, bytes);
void const* data = m_iter;
m_iter += bytes;
return data;
}
return nullptr;
}
private:
std::uint8_t const* m_begin;
std::uint8_t const* m_iter;
std::uint8_t const* m_end;
};
//------------------------------------------------------------------------------
template <int Bytes>
class FixedInputBufferSize : public FixedInputBuffer
{
protected:
struct SizedCtorParams
{
template <typename ConstBufferSequence, typename Storage>
SizedCtorParams (ConstBufferSequence const& buffers, Storage& storage)
{
boost::asio::mutable_buffer buffer (boost::asio::buffer (storage));
data = boost::asio::buffer_cast <std::uint8_t const*> (buffer);
bytes = boost::asio::buffer_copy (buffer, buffers);
}
operator CtorParams () const noexcept
{
return CtorParams (data, bytes);
}
std::uint8_t const* data;
std::size_t bytes;
};
public:
template <typename ConstBufferSequence>
explicit FixedInputBufferSize (ConstBufferSequence const& buffers)
: FixedInputBuffer (SizedCtorParams (buffers, m_storage))
{
}
private:
std::array <std::uint8_t, Bytes> m_storage;
boost::asio::mutable_buffer m_buffer;
};
}
}
#endif

View File

@@ -1,50 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
PeerRole::PeerRole (role_t role)
: m_role (role)
{
}
String PeerRole::name () const noexcept
{
if (m_role == server)
return "server";
return "client";
}
bool PeerRole::operator== (role_t role) const noexcept
{
return m_role == role;
}
#if 0
PeerRole::operator abstract_socket::handshake_type () const noexcept
{
if (m_role == server)
return abstract_socket::server;
return abstract_socket::client;
}
#endif
}
}

View File

@@ -1,46 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BASICS_PEERROLE_H_INCLUDED
#define BEAST_ASIO_BASICS_PEERROLE_H_INCLUDED
namespace beast {
namespace asio {
/** Identifies if the peer is a client or a server. */
struct PeerRole
{
enum role_t
{
client,
server
};
PeerRole (role_t role);
String name () const noexcept;
bool operator== (role_t role) const noexcept;
private:
role_t m_role;
};
}
}
#endif

View File

@@ -1,33 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
SSLContext::SSLContext (ContextType& context)
: m_context (context)
{
}
SSLContext::~SSLContext ()
{
}
}
}

View File

@@ -1,72 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#define BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#include <boost/asio/ssl/context.hpp>
namespace beast {
namespace asio {
/** Simple base class for passing a context around.
This lets derived classes hide their implementation from the headers.
*/
class SSLContext
{
public:
virtual ~SSLContext ();
// Saves typing
typedef boost::asio::ssl::context ContextType;
inline ContextType& get () noexcept
{
return m_context;
}
inline ContextType const& get () const noexcept
{
return m_context;
}
// implicit conversion
inline operator ContextType& () noexcept
{
return get ();
}
inline operator ContextType const& () const noexcept
{
return get ();
}
protected:
explicit SSLContext (ContextType& context);
SSLContext(SSLContext const&) = delete;
SSLContext& operator= (SSLContext const&) = delete;
ContextType& m_context;
};
}
}
#endif

View File

@@ -1,693 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/asio/wrap_handler.h>
#include <beast/asio/placeholders.h>
#include <beast/unit_test/suite.h>
#include <boost/asio/ssl/stream.hpp>
#include <beast/cxx14/memory.h> // <memory>
namespace beast {
namespace asio {
class HTTPClientType : public HTTPClientBase
{
public:
class Session;
struct State
{
List <Session> list;
};
typedef SharedData <State> SharedState;
SharedState m_state;
Journal m_journal;
double m_timeoutSeconds;
std::size_t m_messageLimitBytes;
std::size_t m_bufferSize;
boost::asio::io_service m_io_service;
WaitableEvent m_stopped;
//--------------------------------------------------------------------------
HTTPClientType (
Journal journal,
double timeoutSeconds,
std::size_t messageLimitBytes,
std::size_t bufferSize)
: m_journal (journal)
, m_timeoutSeconds (timeoutSeconds)
, m_messageLimitBytes (messageLimitBytes)
, m_bufferSize (bufferSize)
, m_stopped (true, true) // manual reset, initially signaled
{
}
HTTPClientType(HTTPClientType const&) = delete;
HTTPClientType& operator= (HTTPClientType const&) = delete;
~HTTPClientType ()
{
cancel();
wait();
}
result_type get (URL const& url)
{
result_type result;
boost::asio::io_service io_service;
async_get (io_service, url, std::bind (
&HTTPClientType::handle_get, std::placeholders::_1, &result));
io_service.run ();
return result;
}
void async_get (boost::asio::io_service& io_service, URL const& url,
asio::shared_handler <void (result_type)> handler)
{
new Session (*this, io_service, url,
handler, m_timeoutSeconds, m_messageLimitBytes, m_bufferSize);
}
void cancel ()
{
SharedState::Access state (m_state);
for (List <Session>::iterator iter (state->list.begin());
iter != state->list.end(); ++iter)
iter->cancel();
}
void wait()
{
m_stopped.wait();
}
//--------------------------------------------------------------------------
void add (Session& session)
{
SharedState::Access state (m_state);
if (state->list.empty())
m_stopped.reset();
state->list.push_back (session);
}
void remove (Session& session)
{
SharedState::Access state (m_state);
state->list.erase (state->list.iterator_to (session));
if (state->list.empty())
m_stopped.signal();
}
static void handle_get (result_type const& result, result_type* dest)
{
*dest = result;
}
Journal journal() const
{
return m_journal;
}
boost::asio::io_service& get_io_service()
{
return m_io_service;
}
//--------------------------------------------------------------------------
/** Helper function to get a const_buffer from a String. */
static boost::asio::const_buffers_1 stringBuffer (String const& s)
{
return boost::asio::const_buffers_1 (s.getCharPointer (), s.length ());
}
/** Helper function to fill out a Query from a URL. */
template <typename Query>
static Query queryFromURL (URL const& url)
{
if (url.port () != 0)
{
return Query (
url.host(),
url.port_string(),
Query::numeric_service);
}
return Query (
url.host(),
url.scheme());
}
//--------------------------------------------------------------------------
class Session
: public SharedObject
, public List <Session>::Node
{
public:
typedef SharedPtr <Session> Ptr;
typedef boost::asio::ip::tcp Protocol;
typedef boost::system::error_code error_code;
typedef HTTPClientBase::error_type error_type;
typedef HTTPClientBase::value_type value_type;
typedef HTTPClientBase::result_type result_type;
typedef Protocol::resolver resolver;
typedef Protocol::socket socket;
typedef resolver::query query;
typedef resolver::iterator iterator;
typedef iterator::value_type resolver_entry;
HTTPClientType& m_owner;
boost::asio::io_service& m_io_service;
boost::asio::io_service::strand m_strand;
boost::asio::deadline_timer m_timer;
resolver m_resolver;
socket m_socket;
asio::shared_handler <void (result_type)> m_handler;
URL m_url;
boost::asio::ssl::context m_context;
MemoryBlock m_buffer;
HTTPResponseParser m_parser;
std::size_t m_messageLimitBytes;
std::size_t m_bytesReceived;
String m_get_string;
WaitableEvent m_done;
std::unique_ptr <abstract_socket> m_stream;
struct State
{
State () : complete (false)
{
}
bool complete;
error_code error;
SharedPtr <HTTPResponse> response;
};
typedef SharedData <State> SharedState;
SharedState m_state;
//----------------------------------------------------------------------
Session (HTTPClientType& owner,
boost::asio::io_service& io_service,
URL const& url,
asio::shared_handler <void (result_type)> const& handler,
double timeoutSeconds,
std::size_t messageLimitBytes,
std::size_t bufferSize)
: m_owner (owner)
, m_io_service (io_service)
, m_strand (io_service)
, m_timer (io_service)
, m_resolver (io_service)
, m_socket (io_service)
, m_handler (handler)
, m_url (url)
, m_context (boost::asio::ssl::context::sslv23)
, m_buffer (bufferSize)
, m_messageLimitBytes (messageLimitBytes)
, m_bytesReceived (0)
{
m_owner.add (*this);
// Configure the SSL context for certificate verification
m_context.set_default_verify_paths ();
m_context.set_options (
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use |
boost::asio::ssl::context::default_workarounds);
//m_context.set_verify_mode (boost::asio::ssl::verify_peer);
// Set the timer if a timeout is requested
if (timeoutSeconds > 0)
{
m_timer.expires_from_now (
boost::posix_time::milliseconds (
long (timeoutSeconds * 1000)));
m_timer.async_wait (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_timer, Ptr(this),
asio::placeholders::error), m_handler)));
}
// Start the operation on an io_service thread
io_service.dispatch (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_start, Ptr(this)), m_handler)));
}
~Session ()
{
State result;
{
SharedState::ConstAccess state (m_state);
result = *state;
}
m_io_service.post (bind_handler (m_handler,
std::make_pair (result.error, result.response)));
m_owner.remove (*this);
}
//----------------------------------------------------------------------
// Called by the owner to cancel pending i/o.
void cancel ()
{
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->error = boost::asio::error::operation_aborted;
}
}
cancel_all();
}
// Cancel all pending I/O
void cancel_all ()
{
error_code ec;
m_timer.cancel (ec);
m_resolver.cancel ();
m_socket.cancel (ec);
m_socket.shutdown (socket::shutdown_both, ec);
}
// Called by a completion handler when error is not eof or aborted.
void failed (error_code ec)
{
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->error = ec;
state->response = nullptr;
}
}
cancel_all();
}
void async_read_some ()
{
boost::asio::mutable_buffers_1 buf (
m_buffer.getData (), m_buffer.getSize ());
m_stream->async_read_some (buf, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_read,
Ptr(this), asio::placeholders::error,
asio::placeholders::bytes_transferred), m_handler)));
}
//----------------------------------------------------------------------
//
// Completion handlers
//
// Called when the operation starts
void handle_start ()
{
query q (queryFromURL <query> (m_url));
m_resolver.async_resolve (q, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_resolve,
Ptr(this), asio::placeholders::error,
asio::placeholders::iterator), m_handler)));
}
// Called when the timer completes
void handle_timer (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
failed (boost::system::errc::make_error_code (
boost::system::errc::timed_out));
}
// Called when the resolver completes
void handle_resolve (error_code ec, iterator iter)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
resolver_entry const entry (*iter);
m_socket.async_connect (entry.endpoint (), m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_connect,
Ptr(this), asio::placeholders::error), m_handler)));
}
// Called when the connection attempt completes
void handle_connect (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
if (m_url.scheme () == "https")
{
typedef boost::asio::ssl::stream <socket&> ssl_stream;
m_stream = std::make_unique <
socket_wrapper <ssl_stream>> (m_socket, m_context);
/*
m_stream->set_verify_mode (
boost::asio::ssl::verify_peer |
boost::asio::ssl::verify_fail_if_no_peer_cert);
*/
m_stream->async_handshake (abstract_socket::client, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_handshake,
Ptr(this), asio::placeholders::error), m_handler)));
return;
}
m_stream = std::make_unique <socket_wrapper <socket&>> (m_socket);
handle_handshake (ec);
}
// Called when the SSL handshake completes
void handle_handshake (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
m_get_string =
"GET " + m_url.path() + " HTTP/1.1\r\n" +
"Host: " + m_url.host() + "\r\n" +
"Accept: */*\r\n" +
"Connection: close\r\n\r\n";
boost::asio::async_write (*m_stream, stringBuffer (
m_get_string), m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_write, Ptr(this),
asio::placeholders::error,
asio::placeholders::bytes_transferred), m_handler)));
async_read_some ();
}
// Called when the write operation completes
void handle_write (error_code ec, std::size_t)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
if (! m_stream->needs_handshake ())
m_socket.shutdown (socket::shutdown_send, ec);
}
void handle_read (error_code ec,
std::size_t bytes_transferred)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
m_bytesReceived += bytes_transferred;
if (m_bytesReceived > m_messageLimitBytes)
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
std::size_t const bytes_parsed (m_parser.process (
m_buffer.getData (), bytes_transferred));
if (m_parser.error ())
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
if (bytes_parsed != bytes_transferred)
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
if (ec == boost::asio::error::eof)
m_parser.process_eof ();
if (m_parser.finished ())
{
if (m_stream->needs_handshake ())
{
m_stream->async_shutdown (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_shutdown,
Ptr(this), asio::placeholders::error), m_handler)));
}
else
{
handle_shutdown (error_code ());
}
return;
}
async_read_some ();
}
void handle_shutdown (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec == boost::asio::error::eof)
ec = error_code();
if (ec != 0)
{
failed (ec);
return;
}
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->response = m_parser.response();
}
}
cancel_all();
}
};
};
//------------------------------------------------------------------------------
HTTPClientBase* HTTPClientBase::New (Journal journal,
double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
{
return new HTTPClientType (
journal, timeoutSeconds, messageLimitBytes, bufferSize);
}
//------------------------------------------------------------------------------
class HTTPClient_test : public unit_test::suite
{
public:
typedef boost::system::error_code error_code;
//--------------------------------------------------------------------------
class IoServiceThread : protected Thread
{
public:
explicit IoServiceThread (String name = "io_service")
: Thread (name)
{
}
~IoServiceThread ()
{
join ();
}
boost::asio::io_service& get_io_service ()
{
return m_service;
}
void start ()
{
startThread ();
}
void join ()
{
this->waitForThreadToExit ();
}
private:
void run ()
{
m_service.run ();
}
private:
boost::asio::io_service m_service;
};
//--------------------------------------------------------------------------
void print (HTTPMessage const& m)
{
for (int i = 0; i < m.headers().size(); ++i)
{
HTTPField const f (m.headers()[i]);
std::stringstream ss;
log <<
"[ '" << f.name() <<
"' , '" << f.value() + "' ]";
}
}
void print (HTTPClientBase::error_type error,
HTTPClientBase::value_type const& response)
{
if (error != 0)
{
log <<
"HTTPClient error: '" + error.message() << "'";
}
else if (! response.empty ())
{
log <<
"Status: " <<
String::fromNumber (response->status()).toStdString();
print (*response);
}
else
{
log <<
"HTTPClient: no response";
}
}
//--------------------------------------------------------------------------
void handle_get (HTTPClientBase::result_type result)
{
print (result.first, result.second);
}
void testSync (String const& s, double timeoutSeconds)
{
std::unique_ptr <HTTPClientBase> client (
HTTPClientBase::New (Journal(), timeoutSeconds));
HTTPClientBase::result_type const& result (
client->get (parse_URL (s.toStdString ()).second));
print (result.first, result.second);
}
void testAsync (String const& s, double timeoutSeconds)
{
IoServiceThread t;
std::unique_ptr <HTTPClientBase> client (
HTTPClientBase::New (Journal(), timeoutSeconds));
client->async_get (t.get_io_service (), parse_URL (s.toStdString ()).second,
std::bind (&HTTPClient_test::handle_get, this,
std::placeholders::_1));
t.start ();
t.join ();
}
//--------------------------------------------------------------------------
void run ()
{
testSync (
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
testAsync (
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
testAsync (
"https://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
pass ();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(HTTPClient,beast_asio,beast);
}
}

View File

@@ -1,68 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#include <beast/asio/shared_handler.h>
#include <utility>
namespace beast {
namespace asio {
class HTTPClientBase
{
public:
typedef boost::system::error_code error_type;
typedef SharedPtr <HTTPResponse> value_type;
typedef std::pair <error_type, value_type> result_type;
static HTTPClientBase* New (
Journal journal = Journal(),
double timeoutSeconds = 30,
std::size_t messageLimitBytes = 256 * 1024,
std::size_t bufferSize = 16 * 1024);
/** Destroy the client.
This will cancel any pending i/o and block until all completion
handlers have been called.
*/
virtual ~HTTPClientBase () { }
virtual result_type get (URL const& url) = 0;
/** Perform an asynchronous get on the specified URL.
Handler will be called with this signature:
void (result_type)
*/
virtual void async_get (boost::asio::io_service& io_service,
URL const& url, asio::shared_handler <void (result_type)> handler) = 0;
/** Cancel all pending asynchronous operations. */
virtual void cancel() = 0;
/** Block until all asynchronous i/o completes. */
virtual void wait() = 0;
};
}
}
#endif

View File

@@ -1,147 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
namespace beast {
namespace asio {
class HandshakeDetectLogic
{
public:
HandshakeDetectLogic ()
: m_finished (false)
, m_success (false)
{
}
/** How many bytes maximum we might need.
This is the largest number of bytes that the detector
might need in order to come to a conclusion about
whether or not the handshake is a match. Depending
on the data, it could come to that conclusion sooner
though.
Use read_some instead of read so that the detect logic
can reject the handshake sooner if possible.
*/
virtual std::size_t max_needed () = 0;
/** How many bytes the handshake consumes.
If the detector processes the entire handshake this will
be non zero. The SSL detector would return 0, since we
want all the existing bytes to be passed on.
*/
virtual std::size_t bytes_consumed () = 0;
/** Return true if we have enough data to form a conclusion.
*/
bool finished () const noexcept
{
return m_finished;
}
/** Return true if we came to a conclusion and the data matched.
*/
bool success () const noexcept
{
return m_finished && m_success;
}
protected:
void conclude (bool success = true)
{
m_finished = true;
m_success = success;
}
void fail ()
{
conclude (false);
}
private:
bool m_finished;
bool m_success;
};
//------------------------------------------------------------------------------
/** Wraps the logic and exports it as an abstract interface.
*/
template <typename Logic>
class HandshakeDetectLogicType
{
public:
typedef Logic LogicType;
typedef typename Logic::arg_type arg_type;
explicit HandshakeDetectLogicType (arg_type const& arg = arg_type ())
: m_logic (arg)
{
}
LogicType& get ()
{
return m_logic;
}
std::size_t max_needed ()
{
return m_logic.max_needed ();
}
std::size_t bytes_consumed ()
{
return m_logic.bytes_consumed ();
}
bool finished ()
{
return m_logic.finished ();
}
/** If finished is true, this tells us if the handshake was detected.
*/
bool success ()
{
return m_logic.success ();
}
/** Analyze the buffer to match the Handshake.
Returns `true` if the analysis is complete.
*/
template <typename ConstBufferSequence>
bool analyze (ConstBufferSequence const& buffer)
{
bassert (! m_logic.finished ());
m_logic.analyze (buffer);
return m_logic.finished ();
}
private:
Logic m_logic;
};
}
}
#endif

View File

@@ -1,24 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
}
}

View File

@@ -1,168 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
#include <beast/module/asio/protocol/HandshakeDetectLogic.h>
#include <beast/module/asio/protocol/InputParser.h>
namespace beast {
namespace asio {
/** Handshake detector for the PROXY protcol
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
*/
class HandshakeDetectLogicPROXY : public HandshakeDetectLogic
{
public:
typedef int arg_type;
enum
{
// This is for version 1. The largest number of bytes
// that we could possibly need to parse a valid handshake.
// We will reject it much sooner if there's an illegal value.
//
maxBytesNeeded = 107 // including CRLF, no null term
};
struct ProxyInfo
{
typedef InputParser::IPv4Address IPv4Address;
String protocol; // "TCP4", "TCP6", "UNKNOWN"
IPv4Address sourceAddress;
IPv4Address destAddress;
std::uint16_t sourcePort;
std::uint16_t destPort;
};
explicit HandshakeDetectLogicPROXY (arg_type const&)
: m_consumed (0)
{
}
ProxyInfo const& getInfo () const noexcept
{
return m_info;
}
std::size_t max_needed ()
{
return maxBytesNeeded;
}
std::size_t bytes_consumed ()
{
return m_consumed;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <maxBytesNeeded> in (buffer);
InputParser::State state;
analyze_input (in, state);
if (state.passed ())
{
m_consumed = in.used ();
conclude (true);
}
else if (state.failed ())
{
conclude (false);
}
}
void analyze_input (FixedInputBuffer& in, InputParser::State& state)
{
using namespace InputParser;
if (! match (in, "PROXY ", state))
return;
if (match (in, "TCP4 "))
{
m_info.protocol = "TCP4";
if (! read (in, m_info.sourceAddress, state))
return;
if (! match (in, " ", state))
return;
if (! read (in, m_info.destAddress, state))
return;
if (! match (in, " ", state))
return;
UInt16Str sourcePort;
if (! read (in, sourcePort, state))
return;
m_info.sourcePort = sourcePort.value;
if (! match (in, " ", state))
return;
UInt16Str destPort;
if (! read (in, destPort, state))
return;
m_info.destPort = destPort.value;
if (! match (in, "\r\n", state))
return;
state = State::pass;
return;
}
else if (match (in, "TCP6 "))
{
m_info.protocol = "TCP6";
state = State::fail;
return;
}
else if (match (in, "UNKNOWN "))
{
m_info.protocol = "UNKNOWN";
state = State::fail;
return;
}
state = State::fail;
}
private:
std::size_t m_consumed;
ProxyInfo m_info;
};
}
}
#endif

View File

@@ -1,114 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
namespace beast {
namespace asio {
// Handshake for SSL 2
//
// http://tools.ietf.org/html/rfc5246#appendix-E.2
//
// std::uint8_t V2CipherSpec[3];
// struct {
// std::uint16_t msg_length;
// std::uint8_t msg_type;
// Version version; Should be 'ProtocolVersion'?
// std::uint16_t cipher_spec_length;
// std::uint16_t session_id_length;
// std::uint16_t challenge_length;
// ...
//
class HandshakeDetectLogicSSL2 : public HandshakeDetectLogic
{
public:
typedef int arg_type;
explicit HandshakeDetectLogicSSL2 (arg_type const&)
{
}
enum
{
bytesNeeded = 3
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <bytesNeeded> in (buffer);
{
std::uint8_t byte;
if (! in.peek (&byte))
return;
// First byte must have the high bit set
//
if((byte & 0x80) != 0x80)
return fail ();
}
// The remaining bits contain the
// length of the following data in bytes.
//
std::uint16_t msg_length;
if (! in.readNetworkInteger(&msg_length))
return;
// sizeof (msg_type +
// Version (ProtcolVersion?) +
// cipher_spec_length +
// session_id_length +
// challenge_length)
//
// Should be 9 or greater.
//
if (msg_length < 9)
return fail ();
std::uint8_t msg_type;
if (! in.read (&msg_type))
return;
// The msg_type must be 0x01 for a version 2 ClientHello
//
if (msg_type != 0x01)
return fail ();
conclude ();
}
};
}
}
#endif

View File

@@ -1,90 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
#include <beast/ByteOrder.h>
namespace beast {
namespace asio {
// Handshake for SSL 3 (Also TLS 1.0 and 1.1)
//
// http://www.ietf.org/rfc/rfc2246.txt
//
// Section 7.4. Handshake protocol
//
class HandshakeDetectLogicSSL3 : public HandshakeDetectLogic
{
public:
typedef int arg_type; // dummy
explicit HandshakeDetectLogicSSL3 (arg_type const&)
{
}
enum
{
bytesNeeded = 6
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
std::uint16_t version;
FixedInputBufferSize <bytesNeeded> in (buffer);
std::uint8_t msg_type;
if (! in.read (&msg_type))
return;
// msg_type must be 0x16 = "SSL Handshake"
//
if (msg_type != 0x16)
return fail ();
if (! in.read (&version))
return;
version = fromNetworkByteOrder (version);
std::uint16_t length;
if (! in.read (&length))
return;
length = fromNetworkByteOrder (length);
conclude ();
}
};
}
}
#endif

View File

@@ -1,220 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
#include <beast/boost/get_pointer.h>
#include <beast/asio/bind_handler.h>
#include <beast/asio/wrap_handler.h>
#include <beast/asio/placeholders.h>
#include <beast/asio/shared_handler.h>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/streambuf.hpp>
namespace beast {
namespace asio {
/** A wrapper to decode the handshake data on a Stream.
Stream must meet these requirements
For detect:
SyncReadStream
For async_detect:
AsyncReadStream
Logic must meet this requirement:
HandshakeDetectLogic
*/
template <typename Stream, typename Logic>
class HandshakeDetectorType
{
protected:
typedef boost::system::error_code error_code;
public:
Logic& getLogic ()
{
return m_logic.get ();
}
//--------------------------------------------------------------------------
/** Synchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
*/
template <typename Allocator>
error_code detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer)
{
typedef boost::asio::basic_streambuf <Allocator> BuffersType;
error_code ec;
do
{
m_logic.analyze (buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= buffer.size ());
buffer.consume (consumed);
break;
}
std::size_t const available = buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BuffersType::mutable_buffers_type buffers (
buffer.prepare (needed - available));
buffer.commit (stream.read_some (buffers, ec));
}
}
while (! ec);
return ec;
}
//--------------------------------------------------------------------------
/** Asynchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
DetectHandler must have this signature:
void(error_code)
*/
template <typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
asio::shared_handler <void(error_code)> handler)
{
typedef AsyncOp <Allocator> Op;
auto const op (std::make_shared <Op> (std::ref (m_logic),
std::ref (stream), std::ref (buffer), std::cref (handler)));
//op->start();
stream.get_io_service().post (asio::wrap_handler (std::bind (
&Op::start, op), handler));
}
private:
template <typename Allocator>
class AsyncOp
: public std::enable_shared_from_this <AsyncOp <Allocator>>
{
public:
typedef boost::asio::basic_streambuf <Allocator> BuffersType;
AsyncOp (HandshakeDetectLogicType <Logic>& logic, Stream& stream,
BuffersType& buffer, asio::shared_handler <
void(error_code)> const& handler)
: m_logic (logic)
, m_stream (stream)
, m_buffer (buffer)
, m_handler (handler)
, m_continuation (false)
{
}
// Set breakpoint to prove it gets destroyed
~AsyncOp ()
{
}
void start()
{
async_read_some (error_code(), 0);
}
void on_read (error_code ec, size_t bytes_transferred)
{
m_continuation = true;
async_read_some (ec, bytes_transferred);
}
void async_read_some (error_code ec, size_t bytes_transferred)
{
if (! ec)
{
m_buffer.commit (bytes_transferred);
m_logic.analyze (m_buffer.data ());
if (!m_logic.finished ())
{
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BuffersType::mutable_buffers_type buffers (
m_buffer.prepare (needed - available));
m_stream.async_read_some (buffers, asio::wrap_handler (
std::bind (&AsyncOp <Allocator>::on_read,
this->shared_from_this(), asio::placeholders::error,
asio::placeholders::bytes_transferred),
m_handler, m_continuation));
}
return;
}
std::size_t const consumed = m_logic.bytes_consumed ();
m_buffer.consume (consumed);
}
// Finalize with a call to the original handler.
if (m_continuation)
{
m_handler (ec);
return;
}
// Post, otherwise we would call the
// handler from the initiating function.
m_stream.get_io_service ().post (asio::bind_handler (
m_handler, ec));
}
private:
HandshakeDetectLogicType <Logic>& m_logic;
Stream& m_stream;
BuffersType& m_buffer;
asio::shared_handler <void(error_code)> m_handler;
bool m_continuation;
};
private:
HandshakeDetectLogicType <Logic> m_logic;
};
}
}
#endif

View File

@@ -1,395 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
#include <beast/module/asio/basics/FixedInputBuffer.h>
#include <beast/strings/String.h>
#include <cctype>
namespace beast {
namespace asio {
namespace InputParser {
/** Tri-valued parsing state.
This is convertible to bool which means continue.
Or you can use stop() to decide if you should return.
After a stop you can use failed () to determine if parsing failed.
*/
struct State
{
enum State_t
{
pass, // passed the parse
fail, // failed the parse
more // didn't fail but need more bytes
};
State () : m_state (more) { }
State (State_t state) : m_state (state) { }
/** Implicit construction from bool.
If condition is true then the parse passes, else need more.
*/
State (bool condition) : m_state (condition ? pass : more) { }
State& operator= (State_t state) { m_state = state; return *this; }
bool eof () const noexcept { return m_state == more; }
bool stop () const noexcept { return m_state != pass; }
bool passed () const noexcept { return m_state == pass; }
bool failed () const noexcept { return m_state == fail; }
explicit operator bool() const noexcept { return m_state == pass; }
private:
State_t m_state;
};
//------------------------------------------------------------------------------
// Shortcut to save typing.
typedef FixedInputBuffer& Input;
/** Specializations implement the get() function. */
template <class T>
struct Get;
/** Specializations implement the match() function.
Default implementation of match tries to read it into a local.
*/
template <class T>
struct Match
{
static State func (Input in, T other)
{
T t;
State state = Get <T>::func (in, t);
if (state.passed ())
{
if (t == other)
return State::pass;
return State::fail;
}
return state;
}
};
/** Specializations implement the peek() function.
Default implementation of peek reads and rewinds.
*/
template <class T>
struct Peek
{
static State func (Input in, T& t)
{
Input dup (in);
return Get <T>::func (dup, t);
}
};
//------------------------------------------------------------------------------
//
// Free Functions
//
//------------------------------------------------------------------------------
// match a block of data in memory
//
static State match_buffer (Input in, void const* buffer, std::size_t bytes)
{
bassert (bytes > 0);
if (in.size () <= 0)
return State::more;
std::size_t const have = std::min (in.size (), bytes);
void const* data = in.peek (have);
bassert (data != nullptr);
int const compare = memcmp (data, buffer, have);
if (compare != 0)
return State::fail;
in.consume (have);
return have == bytes;
}
//------------------------------------------------------------------------------
//
// match
//
// Returns the state
template <class T>
State match (Input in, T t)
{
return Match <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool match (Input in, T t, State& state)
{
return (state = match (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// peek
//
// Returns the state
template <class T>
State peek (Input in, T& t)
{
return Peek <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool peek (Input in, T& t, State& state)
{
return (state = peek (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// read
//
// Returns the state
template <class T>
State read (Input in, T& t)
{
return Get <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool read (Input in, T& t, State& state)
{
return (state = read (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// Specializations for basic types
//
template <>
struct Match <char const*>
{
static State func (Input in, char const* text)
{
return InputParser::match_buffer (in, text, strlen (text));
}
};
//------------------------------------------------------------------------------
//
// Special types and their specializations
//
struct Digit
{
int value;
};
template <>
struct Get <Digit>
{
static State func (Input in, Digit& t)
{
char c;
if (! in.peek (&c))
return State::more;
if (! std::isdigit (c))
return State::fail;
in.consume (1);
t.value = c - '0';
return State::pass;
}
};
//------------------------------------------------------------------------------
// An unsigned 32 bit number expressed as a string
struct UInt32Str
{
std::uint32_t value;
};
template <>
struct Get <UInt32Str>
{
static State func (Input in, UInt32Str& t)
{
State state;
std::uint32_t value (0);
Digit digit;
// have to have at least one digit
if (! read (in, digit, state))
return state;
value = digit.value;
for (;;)
{
state = peek (in, digit);
if (state.failed ())
{
t.value = value;
return State::pass;
}
else if (state.eof ())
{
t.value = value;
return state;
}
// can't have a digit following a zero
if (value == 0)
return State::fail;
std::uint32_t newValue = (value * 10) + digit.value;
// overflow
if (newValue < value)
return State::fail;
value = newValue;
}
return State::fail;
}
};
//------------------------------------------------------------------------------
// An unsigned 16 bit number expressed as a string
struct UInt16Str
{
std::uint16_t value;
};
template <>
struct Get <UInt16Str>
{
static State func (Input in, UInt16Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 65535)
{
t.value = std::uint16_t(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An unsigned 8 bit number expressed as a string
struct UInt8Str
{
std::uint8_t value;
};
template <>
struct Get <UInt8Str>
{
static State func (Input in, UInt8Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 255)
{
t.value = std::uint8_t(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An dotted IPv4 address
struct IPv4Address
{
std::uint8_t value [4];
String toString () const
{
return String::fromNumber <int> (value [0]) + "." +
String::fromNumber <int> (value [1]) + "." +
String::fromNumber <int> (value [2]) + "." +
String::fromNumber <int> (value [3]);
}
};
template <>
struct Get <IPv4Address>
{
static State func (Input in, IPv4Address& t)
{
State state;
UInt8Str digit [4];
if (! read (in, digit [0], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [1], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [2], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [3], state))
return state;
t.value [0] = digit [0].value;
t.value [1] = digit [1].value;
t.value [2] = digit [2].value;
t.value [3] = digit [3].value;
return State::pass;
}
};
}
}
}
#endif

View File

@@ -1,207 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <utility>
namespace beast {
namespace asio {
/** Front-ends a stream with a provided block of data.
When read operations are performed on this object, bytes will first be
returned from the buffer provided on construction. When those bytes
are exhausted, read operations will then pass through to the underlying
stream.
Write operations are all simply passed through.
*/
template <class Stream>
class PrefilledReadStream
{
protected:
typedef boost::system::error_code error_code;
static void throw_if (error_code const& ec)
{
throw boost::system::system_error (ec);
}
public:
PrefilledReadStream (PrefilledReadStream const&) = delete;
PrefilledReadStream& operator= (PrefilledReadStream const&) = delete;
typedef std::remove_reference_t <Stream> next_layer_type;
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/** Single argument constructor for when we are wrapped in something.
arg is passed through to the next layer's constructor.
*/
template <class Arg>
explicit PrefilledReadStream (Arg& arg)
: m_next_layer (arg)
{
}
/** Construct with the buffer, and argument passed through.
This creates a copy of the data. The argument is passed through
to the constructor of Stream.
*/
template <class Arg, class ConstBufferSequence>
PrefilledReadStream (Arg& arg, ConstBufferSequence const& buffers)
: m_next_layer (arg)
{
fill (buffers);
}
/** Place some input into the prefilled buffer.
Note that this is in no way thread safe. The only reason this function
is here is for the case when you can't pass the buffer through the
constructor because there is another object wrapping this stream.
*/
template <class ConstBufferSequence>
void fill (ConstBufferSequence const& buffers)
{
// We don't assume the caller's buffers will
// remain valid for the lifetime of this object.
//
m_buffer.commit (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (buffers)),
buffers));
}
next_layer_type& next_layer()
{
return m_next_layer;
}
next_layer_type const& next_layer() const
{
return m_next_layer;
}
lowest_layer_type& lowest_layer()
{
return m_next_layer.lowest_layer();
}
const lowest_layer_type& lowest_layer() const
{
return m_next_layer.lowest_layer();
}
boost::asio::io_service& get_io_service()
{
return m_next_layer.get_io_service();
}
void close()
{
error_code ec;
close (ec);
throw_if (ec);
}
error_code close (error_code& ec)
{
// VFALCO NOTE This is questionable. We can't
// call m_next_layer.close() because Stream might not
// support that function. For example, ssl::stream has no close()
//
return lowest_layer ().close(ec);
}
template <class MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers)
{
error_code ec;
std::size_t const amount = read_some (buffers, ec);
throw_if (ec);
return amount;
}
template <class MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers,
error_code& ec)
{
if (m_buffer.size () > 0)
{
ec = error_code ();
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
return bytes_transferred;
}
return m_next_layer.read_some (buffers, ec);
}
template <class ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers)
{
error_code ec;
auto const amount (write_some (buffers, ec));
throw_if (ec);
return amount;
}
template <class ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers,
error_code& ec)
{
return m_next_layer.write_some (buffers, ec);
}
template <class MutableBufferSequence, class ReadHandler>
void async_read_some (MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
if (m_buffer.size () > 0)
{
auto const bytes_transferred (boost::asio::buffer_copy (
buffers, m_buffer.data ()));
m_buffer.consume (bytes_transferred);
get_io_service ().post (bind_handler (
std::forward <ReadHandler> (handler),
error_code (), bytes_transferred));
return;
}
m_next_layer.async_read_some (buffers,
std::forward <ReadHandler> (handler));
}
template <class ConstBufferSequence, class WriteHandler>
void async_write_some (ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
m_next_layer.async_write_some (buffers,
std::forward <WriteHandler> (handler));
}
private:
Stream m_next_layer;
boost::asio::streambuf m_buffer;
};
}
}
#endif

View File

@@ -1,110 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
PeerTest::Result::Result ()
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::skipped))
, m_message (m_ec.message ())
{
}
PeerTest::Result::Result (boost::system::error_code const& ec, String const& prefix)
: m_ec (ec)
, m_message ((prefix == String::empty) ? ec.message ()
: prefix + ": " + ec.message ())
{
}
PeerTest::Result::Result (std::exception const& e, String const& prefix)
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::exceptioned))
, m_message ((prefix == String::empty) ? e.what ()
: prefix + ": " + e.what ())
{
}
bool PeerTest::Result::operator== (Result const& other) const noexcept
{
return m_ec == other.m_ec;
}
bool PeerTest::Result::operator!= (Result const& other) const noexcept
{
return m_ec != other.m_ec;
}
bool PeerTest::Result::failed () const noexcept
{
return TestPeerBasics::failure (m_ec);
}
bool PeerTest::Result::timedout () const noexcept
{
return m_ec == TestPeerBasics::make_error (TestPeerBasics::errc::timeout);
}
String PeerTest::Result::message () const noexcept
{
return m_message;
}
bool PeerTest::Result::report (unit_test::suite& suite,
bool reportPassingTests) const
{
bool const success = suite.expect (! failed (),
message ().toStdString());
if (reportPassingTests && success)
suite.log <<
"pass " + message().toStdString();
return success;
}
//------------------------------------------------------------------------------
PeerTest::Results::Results ()
: name ("unknown")
{
}
bool PeerTest::Results::operator== (Results const& other) const noexcept
{
return (client == other.client) && (server == other.server);
}
bool PeerTest::Results::operator!= (Results const& other) const noexcept
{
return (client != other.client) || (server != other.server);
}
bool PeerTest::Results::report (unit_test::suite& suite,
bool beginTestCase) const
{
if (beginTestCase)
suite.testcase << name.toStdString();
bool success = true;
if (! client.report (suite))
success = false;
if (! server.report (suite))
success = false;
return success;
}
}
}

View File

@@ -1,247 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_PEERTEST_H_INCLUDED
#define BEAST_ASIO_TESTS_PEERTEST_H_INCLUDED
#include <beast/unit_test/suite.h>
namespace beast {
namespace asio {
/** Performs a test of two peers defined by template parameters. */
class PeerTest
{
public:
enum
{
/** How long to wait before aborting a peer and reporting a timeout.
@note Aborting synchronous logics may cause undefined behavior.
*/
defaultTimeoutSeconds = 30
};
//--------------------------------------------------------------------------
/** Holds the test results for one peer.
*/
class Result
{
public:
/** Default constructor indicates the test was skipped.
*/
Result ();
/** Construct from an error code.
The prefix is prepended to the error message.
*/
explicit Result (boost::system::error_code const& ec, String const& prefix = "");
explicit Result (std::exception const& e, String const& prefix = "");
/** Returns true if the error codes match (message is ignored).
*/
bool operator== (Result const& other) const noexcept;
bool operator!= (Result const& other) const noexcept;
/** Returns true if the peer failed.
*/
bool failed () const noexcept;
/** Convenience for determining if the peer timed out.
*/
bool timedout () const noexcept;
/** Provides a descriptive message.
This is suitable to pass to suite::fail.
*/
String message () const noexcept;
/** Report the result to a testsuite.
A return value of true indicates success.
*/
bool report (unit_test::suite& suite,
bool reportPassingTests = false) const;
private:
boost::system::error_code m_ec;
String m_message;
};
//--------------------------------------------------------------------------
/** Holds the results for both peers in a test.
*/
struct Results
{
String name; // A descriptive name for this test case.
Result client;
Result server;
Results ();
/** Determines if client and server results match. */
bool operator== (Results const& other) const noexcept;
bool operator!= (Results const& other) const noexcept;
/** Report the results to a suite object.
A return value of true indicates success.
@param beginTestCase `true` to call test.beginTestCase for you
*/
bool report (unit_test::suite& suite, bool beginTestCase = true) const;
};
//--------------------------------------------------------------------------
/** Test two peers and return the results.
*/
template <class Details, class ClientLogic, class ServerLogic,
class ClientArg, class ServerArg>
static Results run (ClientArg const& clientArg, ServerArg const& serverArg,
int timeoutSeconds = defaultTimeoutSeconds)
{
Results results;
if (Process::isRunningUnderDebugger ())
timeoutSeconds = -1;
try
{
TestPeerType <ServerLogic, Details> server (serverArg);
results.name = server.name () + Details::getArgName (serverArg);
try
{
TestPeerType <ClientLogic, Details> client (clientArg);
results.name << " / " + client.name () + Details::getArgName (clientArg);
try
{
server.start (timeoutSeconds);
try
{
client.start (timeoutSeconds);
boost::system::error_code const ec = client.join ();
results.client = Result (ec, client.name ());
try
{
boost::system::error_code const ec = server.join ();
results.server = Result (ec, server.name ());
}
catch (std::exception& e)
{
results.server = Result (e, server.name ());
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), server.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, client.name ());
}
catch (...)
{
results.client = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), client.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, server.name ());
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), server.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, "client");
}
catch (...)
{
results.client = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), "client");
}
}
catch (std::exception& e)
{
results.server = Result (e, "server");
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), "server");
}
return results;
}
template <class Details, class ClientLogic, class ServerLogic, class Arg>
static Results run (Arg const& arg, int timeoutSeconds = defaultTimeoutSeconds)
{
return run <Details, ClientLogic, ServerLogic, Arg, Arg> (
arg, arg, timeoutSeconds);
}
//--------------------------------------------------------------------------
template <class Details, class Arg>
static void report_async (unit_test::suite& suite, Arg const& arg,
int timeoutSeconds = defaultTimeoutSeconds,
bool beginTestCase = true)
{
run <Details, TestPeerLogicAsyncClient, TestPeerLogicAsyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
}
template <class Details, class Arg>
static
void
report (unit_test::suite& suite, Arg const& arg,
int timeoutSeconds = defaultTimeoutSeconds, bool beginTestCase = true)
{
run <Details, TestPeerLogicSyncClient, TestPeerLogicSyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
run <Details, TestPeerLogicAsyncClient, TestPeerLogicSyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
run <Details, TestPeerLogicSyncClient, TestPeerLogicAsyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
report_async <Details> (suite, arg, timeoutSeconds, beginTestCase);
}
};
}
}
#endif

View File

@@ -1,58 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEER_H_INCLUDED
namespace beast {
namespace asio {
/** An abstract peer for unit tests. */
class TestPeer : public TestPeerBasics
{
public:
enum
{
// This should be long enough to go about your business.
defaultTimeout = 10
};
virtual ~TestPeer () { }
/** Get the name of this peer. */
virtual String name () const = 0;
/** Start the peer.
If timeoutSeconds is 0 or less, the wait is infinite.
@param timeoutSeconds How long until the peer should be
considered timed out.
*/
virtual void start (int timeoutSeconds = defaultTimeout) = 0;
/** Wait for the peer to finish.
@return Any error code generated during the server operation.
*/
virtual boost::system::error_code join () = 0;
};
}
}
#endif

View File

@@ -1,161 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerBasics::Model::Model (model_t model)
: m_model (model)
{
}
String TestPeerBasics::Model::name () const noexcept
{
if (m_model == async)
return "async";
return "sync";
}
bool TestPeerBasics::Model::operator== (model_t model) const noexcept
{
return m_model == model;
}
boost::asio::ssl::stream_base::handshake_type
TestPeerBasics::to_handshake_type (PeerRole const& role)
{
if (role == PeerRole::client)
return boost::asio::ssl::stream_base::client;
return boost::asio::ssl::stream_base::server;
}
//------------------------------------------------------------------------------
boost::system::error_category const& TestPeerBasics::test_category () noexcept
{
struct test_category_type : boost::system::error_category
{
char const* name () const noexcept
{
return "TestPeer";
}
std::string message (int ev) const
{
switch (ev)
{
case errc::none: return "No error";
case errc::timeout: return "The timeout expired before the test could complete";
case errc::unexpected: return "An unexpected test result was encountered";
case errc::exceptioned: return "An unexpected exception was thrown";
case errc::skipped: return "The test was skipped because of previous errors";
default:
break;
};
return "An unknown error";
}
boost::system::error_condition default_error_condition (int ev) const noexcept
{
return boost::system::error_condition (ev, *this);
}
bool equivalent (int ev, boost::system::error_condition const& condition) const noexcept
{
return default_error_condition (ev) == condition;
}
bool equivalent (boost::system::error_code const& code, int ev) const noexcept
{
return *this == code.category() && code.value() == ev;
}
};
static test_category_type category;
return category;
}
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev) noexcept
{
return boost::system::error_code (ev, test_category ());
}
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev, boost::system::error_code& ec) noexcept
{
return ec = make_error (ev);
}
bool TestPeerBasics::success (boost::system::error_code const& ec, bool eofIsOkay) noexcept
{
if (eofIsOkay && ec == boost::asio::error::eof)
return true;
if (! ec)
return true;
breakpoint (ec);
return false;
}
bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOkay) noexcept
{
return ! success (ec, eofIsOkay);
}
bool TestPeerBasics::expected (bool condition, boost::system::error_code& ec) noexcept
{
if (condition)
{
ec = boost::system::error_code ();
}
else
{
make_error (errc::unexpected, ec);
breakpoint (ec);
}
return condition;
}
bool TestPeerBasics::unexpected (bool condition, boost::system::error_code& ec) noexcept
{
return ! expected (condition, ec);
}
bool TestPeerBasics::aborted (boost::system::error_code const& ec) noexcept
{
return ec == boost::asio::error::operation_aborted;
}
//------------------------------------------------------------------------------
void TestPeerBasics::breakpoint (boost::system::error_code const& ec)
{
// Set a breakpoint here to catch a failure
std::string const& message = ec.message ();
char const* const c_str = message.c_str ();
breakpoint (c_str);
}
void TestPeerBasics::breakpoint (char const* const)
{
}
}
}

View File

@@ -1,114 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
#include <boost/asio/ssl/stream_base.hpp>
namespace beast {
namespace asio {
/** Common declarations for TestPeer.
@see TestPeer
*/
class TestPeerBasics
{
public:
/** Selects between synchronous or asynchronous networking i/o usage. */
struct Model
{
enum model_t
{
sync,
async
};
Model (model_t model);
String name () const noexcept;
bool operator== (model_t model) const noexcept;
private:
model_t m_model;
};
//--------------------------------------------------------------------------
/** Convert a PeerRole to boost::asio::ssl::stream_base_handshake_type */
static boost::asio::ssl::stream_base::handshake_type to_handshake_type (PeerRole const& role);
//--------------------------------------------------------------------------
// Custom error codes for distinguishing test conditions
struct errc
{
enum errc_t
{
none = 0,
timeout, // The peer join timeout expired
unexpected, // An expected condition was false
exceptioned, // An exception occurred
skipped // Test skipped due to previous errors
};
};
/** Returns the category that represents TestPeer errors.
*/
static boost::system::error_category const& test_category () noexcept;
/** Creates a test error_code from the give code value.
*/
static boost::system::error_code make_error (errc::errc_t ev) noexcept;
/** Sets the passed error_code to a test error and returns it.
*/
static boost::system::error_code make_error (errc::errc_t ev,
boost::system::error_code& ec) noexcept;
/** Returns true if the error code indicates success.
*/
static bool success (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
/** Returns false if the error code indicates failure.
*/
static bool failure (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
/** Set the error based on a failed condition and return the success.
*/
static bool expected (bool condition, boost::system::error_code& ec) noexcept;
/** Set the error based on a passed condition and return the success.
*/
static bool unexpected (bool condition, boost::system::error_code& ec) noexcept;
/** Returns true if the error condition indicates an aborted I/O. */
static bool aborted (boost::system::error_code const& ec) noexcept;
/** Provides a place to set a breakpoint to catch a failed condition. */
static void breakpoint (boost::system::error_code const& ec);
/** Forces the variable to exist in the debugger. */
static void breakpoint (char const* const message);
};
}
}
#endif

View File

@@ -1,52 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
#include <beast/asio/abstract_socket.h>
namespace beast {
namespace asio {
/** Base class of all detail objects. */
class TestPeerDetails
{
public:
virtual ~TestPeerDetails () { }
virtual String name () const = 0;
virtual abstract_socket& get_socket () = 0;
virtual abstract_socket& get_acceptor () = 0;
boost::asio::io_service& get_io_service ()
{
return m_io_service;
}
private:
boost::asio::io_service m_io_service;
};
}
}
#endif

View File

@@ -1,115 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
#include <beast/asio/socket_wrapper.h>
namespace beast {
namespace asio {
/** Some predefined Detail classes for TestPeer */
struct TcpDetails : public TestPeerDetails
{
protected:
typedef boost::asio::ip::tcp protocol_type;
typedef protocol_type::socket socket_type;
typedef protocol_type::acceptor acceptor_type;
typedef protocol_type::endpoint endpoint_type;
typedef protocol_type::resolver resolver_type;
public:
typedef protocol_type arg_type;
typedef socket_type native_socket_type;
typedef acceptor_type native_acceptor_type;
explicit TcpDetails (arg_type protocol)
: m_protocol (protocol)
, m_socket (get_io_service ())
, m_acceptor (get_io_service ())
, m_socket_wrapper (m_socket)
, m_acceptor_wrapper (m_acceptor)
{
}
static String getArgName (arg_type arg)
{
if (arg == protocol_type::v4 ())
return ".tcpv4";
else if (arg == protocol_type::v6 ())
return ".tcpv6";
return ".tcp?";
}
String name () const
{
return getArgName (m_protocol);
}
abstract_socket& get_socket ()
{
return m_socket_wrapper;
}
abstract_socket& get_acceptor ()
{
return m_acceptor_wrapper;
}
socket_type& get_native_socket ()
{
return m_socket;
}
acceptor_type& get_native_acceptor ()
{
return m_acceptor;
}
endpoint_type get_endpoint (PeerRole role)
{
if (m_protocol == protocol_type::v4 ())
{
if (role == PeerRole::server)
return endpoint_type (m_protocol, 1053);
else
return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
}
else
{
if (role == PeerRole::server)
return endpoint_type (m_protocol, 1052);
else
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
}
}
protected:
protocol_type m_protocol;
socket_type m_socket;
acceptor_type m_acceptor;
socket_wrapper <socket_type&> m_socket_wrapper;
socket_wrapper <acceptor_type&> m_acceptor_wrapper;
};
}
}
#endif

View File

@@ -1,69 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogic::TestPeerLogic (abstract_socket& socket)
: m_socket (&socket)
{
}
TestPeerLogic::error_code& TestPeerLogic::error () noexcept
{
return m_ec;
}
TestPeerLogic::error_code const& TestPeerLogic::error () const noexcept
{
return m_ec;
}
TestPeerLogic::error_code const& TestPeerLogic::error (error_code const& ec) noexcept
{
return m_ec = ec;
}
abstract_socket& TestPeerLogic::socket () noexcept
{
return *m_socket;
}
void TestPeerLogic::on_connect ()
{
pure_virtual ();
}
void TestPeerLogic::on_connect_async (error_code const&)
{
pure_virtual ();
}
void TestPeerLogic::finished ()
{
pure_virtual ();
}
void TestPeerLogic::pure_virtual ()
{
fatal_error ("A TestPeerLogic function was called incorrectly");
}
}
}

View File

@@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
namespace beast {
namespace asio {
/** Interface for implementing the logic part of a peer test. */
class TestPeerLogic : public TestPeerBasics
{
public:
typedef boost::system::error_code error_code;
explicit TestPeerLogic (abstract_socket& socket);
error_code& error () noexcept;
error_code const& error () const noexcept;
error_code const& error (error_code const& ec) noexcept; // assigns to m_ec
abstract_socket& socket () noexcept;
virtual PeerRole get_role () const noexcept = 0;
virtual Model get_model () const noexcept = 0;
virtual void on_connect ();
virtual void on_connect_async (error_code const&);
// asynchronous logic classes
// must call this when they are done
virtual void finished ();
static void pure_virtual ();
private:
error_code m_ec;
abstract_socket* m_socket;
};
}
}
#endif

View File

@@ -1,164 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/asio/placeholders.h>
namespace beast {
namespace asio {
TestPeerLogicAsyncClient::TestPeerLogicAsyncClient (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicAsyncClient::get_role () const noexcept
{
return PeerRole::client;
}
TestPeerBasics::Model TestPeerLogicAsyncClient::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncClient::on_connect_async (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_handshake (abstract_socket::client,
std::bind (&TestPeerLogicAsyncClient::on_handshake, this,
beast::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncClient::on_handshake (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
boost::asio::async_write (socket (), boost::asio::buffer ("hello", 5),
std::bind (&TestPeerLogicAsyncClient::on_write, this,
beast::asio::placeholders::error,
beast::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 5, error ()))
return finished ();
boost::asio::async_read_until (socket (), m_buf, std::string ("goodbye"),
std::bind (&TestPeerLogicAsyncClient::on_read, this,
beast::asio::placeholders::error, beast::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 7, error ()))
return finished ();
// should check the data here?
m_buf.consume (bytes_transferred);
// Fire up a 1 byte read, to wait for the server to
// shut down its end of the connection.
boost::asio::async_read (socket (), m_buf.prepare (1),
std::bind (&TestPeerLogicAsyncClient::on_read_final, this,
beast::asio::placeholders::error, beast::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read_final (error_code const& ec, std::size_t)
{
if (aborted (ec))
return finished ();
// An eof is the normal case. The server should have closed shop.
//
if (ec == boost::asio::error::eof)
{
if (socket ().needs_handshake ())
{
socket ().async_shutdown (std::bind (&TestPeerLogicAsyncClient::on_shutdown, this,
beast::asio::placeholders::error));
}
else
{
// on_shutdown will call finished ()
error_code ec;
on_shutdown (socket ().shutdown (abstract_socket::shutdown_send, ec));
}
}
else
{
// If we don't get eof, then there should be some other
// error in there. We don't expect the server to send more bytes!
//
// This statement will do the following:
//
// error (ec) save ec into our error state
// success () return true if ec represents success
// unexpected () changes error() to 'unexpected' result if
// success() returned true
//
unexpected (success (error (ec)), error ());
return finished ();
}
}
void TestPeerLogicAsyncClient::on_shutdown (error_code const& ec)
{
if (! aborted (ec))
{
if (success (error (ec), true))
{
if (socket ().needs_handshake ())
{
socket ().shutdown (abstract_socket::shutdown_send, error ());
}
if (! error ())
{
if (success (socket ().close (error ())))
{
// doing nothing here is intended,
// as the calls to success() may set error()
}
}
}
}
finished ();
}
}
}

View File

@@ -1,45 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicAsyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncClient (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_read_final (error_code const& ec, std::size_t);
void on_shutdown (error_code const& ec);
private:
boost::asio::streambuf m_buf;
};
}
}
#endif

View File

@@ -1,126 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/asio/placeholders.h>
namespace beast {
namespace asio {
TestPeerLogicAsyncServer::TestPeerLogicAsyncServer (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicAsyncServer::get_role () const noexcept
{
return PeerRole::server;
}
TestPeerBasics::Model TestPeerLogicAsyncServer::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncServer::on_connect_async (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_handshake (abstract_socket::server,
std::bind (&TestPeerLogicAsyncServer::on_handshake, this,
beast::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncServer::on_handshake (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
boost::asio::async_read_until (socket (), m_buf, std::string ("hello"),
std::bind (&TestPeerLogicAsyncServer::on_read, this,
beast::asio::placeholders::error, beast::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 5, error ()))
return finished ();
boost::asio::async_write (socket (), boost::asio::buffer ("goodbye", 7),
std::bind (&TestPeerLogicAsyncServer::on_write, this,
beast::asio::placeholders::error, beast::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 7, error ()))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_shutdown (std::bind (&TestPeerLogicAsyncServer::on_shutdown, this,
beast::asio::placeholders::error));
}
else
{
// on_shutdown will call finished ()
// we need another instance of ec so we can call on_shutdown()
error_code ec;
on_shutdown (socket ().shutdown (abstract_socket::shutdown_receive, ec));
}
}
void TestPeerLogicAsyncServer::on_shutdown (error_code const& ec)
{
if (! aborted (ec))
{
if (success (error (ec), true))
{
if (socket ().needs_handshake ())
{
socket ().shutdown (abstract_socket::shutdown_receive, error ());
}
if (success (socket ().close (error ())))
{
// doing nothing here is intended,
// as the calls to success() may set error()
}
}
}
finished ();
}
}
}

View File

@@ -1,44 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicAsyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncServer (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_shutdown (error_code const& ec);
private:
boost::asio::streambuf m_buf;
};
}
}
#endif

View File

@@ -1,42 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicProxyClient::TestPeerLogicProxyClient (abstract_socket& socket)
: TestPeerLogicSyncClient (socket)
{
}
void TestPeerLogicProxyClient::on_pre_handshake ()
{
//ProxyHandshakeParser h;
static std::string line (
"PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"
// 56 chars
);
boost::asio::write (socket (), boost::asio::buffer (line), error ());
}
}
}

View File

@@ -1,37 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
namespace beast {
namespace asio {
/** A synchronous client logic that sends a PROXY protocol pre-handshake. */
class TestPeerLogicProxyClient : public TestPeerLogicSyncClient
{
public:
explicit TestPeerLogicProxyClient (abstract_socket& socket);
void on_pre_handshake ();
};
}
}
#endif

View File

@@ -1,115 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicSyncClient::TestPeerLogicSyncClient (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicSyncClient::get_role () const noexcept
{
return PeerRole::client;
}
TestPeerBasics::Model TestPeerLogicSyncClient::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncClient::on_connect ()
{
{
// pre-handshake hook is optional
on_pre_handshake ();
if (failure (error ()))
return ;
}
if (socket ().needs_handshake ())
{
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("hello", 5), error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
}
{
char data [7];
size_t const amount = boost::asio::read (
socket (), boost::asio::buffer (data, 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
if (unexpected (memcmp (&data, "goodbye", 7) == 0, error ()))
return;
}
// Wait for 1 byte which should never come. Instead,
// the server should close its end and we will get eof
{
char data [1];
boost::asio::read (socket (), boost::asio::buffer (data, 1), error ());
if (error () == boost::asio::error::eof)
{
error () = error_code ();
}
else if (unexpected (failure (error ()), error ()))
{
return;
}
}
if (socket ().needs_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
error () = error_code ();
}
if (failure (socket ().shutdown (abstract_socket::shutdown_send, error ())))
return;
if (failure (socket ().close (error ())))
return;
}
void TestPeerLogicSyncClient::on_pre_handshake ()
{
}
}
}

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicSyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncClient (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
virtual void on_pre_handshake ();
};
}
}
#endif

View File

@@ -1,86 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicSyncServer::TestPeerLogicSyncServer (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicSyncServer::get_role () const noexcept
{
return PeerRole::server;
}
TestPeerBasics::Model TestPeerLogicSyncServer::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncServer::on_connect ()
{
if (socket ().needs_handshake ())
{
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
return;
}
{
boost::asio::streambuf buf (5);
std::size_t const amount = boost::asio::read_until (
socket (), buf, "hello", error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
if (unexpected (buf.size () == 5, error ()))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("goodbye", 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
}
if (socket ().needs_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
}
if (failure (socket ().shutdown (abstract_socket::shutdown_send, error ())))
return;
if (failure (socket ().close (error ())))
return;
}
}
}

View File

@@ -1,38 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicSyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncServer (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
};
}
}
#endif

View File

@@ -1,404 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
#include <beast/asio/placeholders.h>
namespace beast {
namespace asio {
template <typename Logic, typename Details>
class TestPeerType
: public Details
, public Logic
, public TestPeer
, public Thread
{
protected:
// TestPeerDetails
using Details::get_socket;
using Details::get_acceptor;
using Details::get_io_service;
// Details
typedef typename Details::protocol_type protocol_type;
typedef typename Details::socket_type socket_type;
typedef typename Details::acceptor_type acceptor_type;
typedef typename Details::endpoint_type endpoint_type;
typedef typename Details::resolver_type resolver_type;
using Details::get_native_socket;
using Details::get_native_acceptor;
using Details::get_endpoint;
// TestPeerLogic
typedef typename Logic::error_code error_code;
using Logic::error;
using Logic::socket;
using Logic::get_role;
using Logic::get_model;
using Logic::on_connect;
using Logic::on_connect_async;
using Logic::pure_virtual;
typedef TestPeerType <Logic, Details> This;
public:
// Details
typedef typename Details::arg_type arg_type;
typedef typename Details::native_socket_type native_socket_type;
typedef typename Details::native_acceptor_type native_acceptor_type;
TestPeerType (arg_type const& arg)
: Details (arg)
, Logic (get_socket ())
, Thread (name ())
, m_timer (get_io_service ())
, m_timer_set (false)
, m_timed_out (false)
{
}
~TestPeerType ()
{
}
String name () const
{
return get_model ().name () + "_" + get_role ().name ();
}
bool is_async () const noexcept
{
return get_model () == Model::async;
}
void start (int timeoutSeconds)
{
if (is_async ())
{
if (timeoutSeconds > 0)
{
m_timer.expires_from_now (
boost::posix_time::seconds (timeoutSeconds));
m_timer.async_wait (std::bind (&This::on_deadline,
this, beast::asio::placeholders::error));
m_timer_set = true;
}
else
{
// Don't set the timer, so infinite wait.
}
}
else
{
// Save the value for when join() is called later.
//
m_timeoutSeconds = timeoutSeconds;
}
startThread ();
// For server roles block until the thread is litening.
//
if (get_role () == PeerRole::server)
m_listening.wait ();
}
error_code join ()
{
if (is_async ())
{
// If the timer expired, then all our i/o should be
// aborted and the thread will exit. So we will wait
// for the thread for an infinite amount of time to
// prevent undefined behavior. If an asynchronous logic
// fails to end when the deadline timer expires, it
// means there's a bug in the logic code.
//
m_join.wait ();
// The wait was satisfied but now the thread is still on
// it's way out of the thread function, so block until
// we know its done.
//
stopThread ();
// If we timed out then always report the custom error
if (m_timed_out)
return error (make_error (errc::timeout));
}
else
{
if (m_timeoutSeconds > 0)
{
// Wait for the thread to finish
//
if (! m_join.wait (m_timeoutSeconds * 1000))
{
// Uh oh, we timed out! This is bad.
// The synchronous model requires that the thread
// be forcibly killed, which can result in undefined
// behavior. It's best not to perform tests with
// synchronous Logic objects that are supposed to time out.
// Force the thread to be killed, without waiting.
stopThread (0);
error () = make_error (errc::timeout);
}
else
{
stopThread ();
}
}
else
{
// They requested an infinite wait.
//
m_join.wait ();
stopThread ();
}
}
return error ();
}
//--------------------------------------------------------------------------
void run ()
{
if (is_async ())
{
if (get_role () == PeerRole::server)
{
run_async_server ();
}
else if (get_role () == PeerRole::client)
{
run_async_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else if (get_model () == Model::sync)
{
if (get_role () == PeerRole::server)
{
run_sync_server ();
}
else if (get_role () == PeerRole::client)
{
run_sync_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else
{
error () = make_error (errc::unexpected);
}
get_io_service ().run ();
}
//--------------------------------------------------------------------------
void run_sync_server ()
{
do_listen ();
if (failure (error ()))
return finished ();
if (failure (get_acceptor ().accept (get_socket (), error ())))
return finished ();
if (failure (get_acceptor ().close (error ())))
return finished ();
this->on_connect ();
finished ();
}
//--------------------------------------------------------------------------
void on_accept (error_code const& ec)
{
if (failure (ec))
return finished ();
// Close the acceptor down so we don't block the io_service forever
//
// VFALCO NOTE what difference between cancel and close?
#if 0
if (failure (get_acceptor ().close (error ())))
return finished ();
#endif
this->on_connect_async (ec);
}
void run_async_server ()
{
do_listen ();
if (failure (error ()))
return finished ();
get_acceptor ().async_accept (get_socket (), std::bind (
&This::on_accept, this, beast::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void run_sync_client ()
{
if (failure (get_native_socket ().connect (get_endpoint (get_role ()), error ())))
return finished ();
this->on_connect ();
finished ();
}
void run_async_client ()
{
get_native_socket ().async_connect (get_endpoint (get_role ()),
std::bind (&Logic::on_connect_async, this,
beast::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void do_listen ()
{
if (failure (get_native_acceptor ().open (
get_endpoint (get_role ()).protocol (), error ())))
return;
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
if (failure (get_native_acceptor ().set_option (
boost::asio::socket_base::reuse_address (true), error ())))
return;
if (failure (get_native_acceptor ().bind (get_endpoint (get_role ()), error ())))
return;
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
if (failure (get_native_acceptor ().listen (
boost::asio::socket_base::max_connections, error ())))
return;
m_listening.signal ();
}
void on_deadline (error_code const& ec)
{
m_timer_set = false;
if (ec != boost::asio::error::operation_aborted)
{
// We expect that ec represents no error, since the
// timer expired and the operation wasn't aborted.
//
// If by some chance there is an error in ec we will
// report that as an unexpected test condition instead
// of a timeout.
//
if (expected (! ec, error ()))
m_timed_out = true;
}
else
{
// The timer was canceled because the Logic
// called finished(), so we do nothing here.
}
finished ();
}
void finished ()
{
// If the server errors out it will come through
// here so signal the listening event and unblock
// the main thread.
//
if (get_role () == PeerRole::server)
m_listening.signal ();
if (m_timer_set)
{
error_code ec;
std::size_t const amount = m_timer.cancel (ec);
// The Logic should not have any I/O pending when
// it calls finished, so amount should be zero.
//
unexpected (amount == 0, ec);
}
// The logic should close the socket at the end of
// its operations, unless it encounters an error.
// Therefore, we will clean everything up and squelch
// any errors, so that io_service::run() will return.
//
{
error_code ec;
this->get_socket ().close (ec);
}
// The acceptor will not have closed if the client
// never established the connection, so do it here.
{
error_code ec;
this->get_acceptor ().close (ec);
}
// Wake up the thread blocked on join()
m_join.signal ();
}
private:
WaitableEvent m_listening;
WaitableEvent m_join;
// for async peers
boost::asio::deadline_timer m_timer;
bool m_timer_set;
bool m_timed_out;
// for sync peers
int m_timeoutSeconds;
};
}
}
#endif

View File

@@ -1,54 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <beast/unit_test/suite.h>
namespace beast {
namespace asio {
/** Test suite for the TestPeer family of objects. */
class TestPeer_test : public unit_test::suite
{
public:
template <typename Details, typename Arg >
void testDetails (Arg const& arg = Arg ())
{
PeerTest::report <Details> (*this, arg, timeoutSeconds);
}
void run ()
{
typedef boost::asio::ip::tcp protocol;
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v4 ());
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v6 ());
}
//--------------------------------------------------------------------------
enum
{
timeoutSeconds = 10
};
};
BEAST_DEFINE_TESTSUITE(TestPeer,beast_asio,beast);
}
}

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include <beast/module/core/diagnostic/FatalError.h>
#include <beast/unit_test/suite.h>
namespace beast {

View File

@@ -20,6 +20,8 @@
#ifndef BEAST_CORE_FATALERROR_H_INCLUDED
#define BEAST_CORE_FATALERROR_H_INCLUDED
#include <beast/strings/String.h>
namespace beast
{
@@ -39,7 +41,7 @@ class FatalError
public:
struct Reporter
{
virtual ~Reporter () { }
virtual ~Reporter() = default;
/** Called when a fatal error is raised.

View File

@@ -60,7 +60,8 @@ public:
ConstBufferType (void const* buffer, size_type bytes);
*/
template <typename ConstBufferType>
std::vector <ConstBufferType> data () const
std::vector <ConstBufferType>
data () const
{
std::vector <ConstBufferType> buffers;
buffers.reserve (m_buffers.size());
@@ -81,7 +82,8 @@ public:
MutableBufferType (void* buffer, size_type bytes);
*/
template <typename MutableBufferType>
std::vector <MutableBufferType> prepare (size_type amount)
std::vector <MutableBufferType>
prepare (size_type amount)
{
std::vector <MutableBufferType> buffers;
buffers.reserve (m_buffers.size());