diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj
index f0916e7e2..f9fcc44d0 100644
--- a/Builds/VisualStudio2012/beast.vcxproj
+++ b/Builds/VisualStudio2012/beast.vcxproj
@@ -144,8 +144,10 @@
+
+
diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters
index 7afce30be..77c34968d 100644
--- a/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -38,40 +38,40 @@
_meta
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
beast_core
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
@@ -198,15 +198,6 @@
{bf498396-2e1f-4903-be68-3053ba439af5}
-
- {92d1bb42-289a-4444-85c7-cb87540f2fff}
-
-
- {8832eb52-53f9-4850-8dc9-1d579a386a0e}
-
-
- {5904368f-a0f2-4d26-a031-8cbe4448dc3f}
-
{c0724499-ab69-40c3-90e2-65242dbd2eaa}
@@ -216,52 +207,61 @@
{27052a76-e315-4725-9d9a-1233c7d71aba}
-
+
+ {92d1bb42-289a-4444-85c7-cb87540f2fff}
+
+
+ {8832eb52-53f9-4850-8dc9-1d579a386a0e}
+
+
+ {5904368f-a0f2-4d26-a031-8cbe4448dc3f}
+
+
{5faa76ea-5691-4e63-8833-577f92991356}
-
+
{93670bc9-a748-42bd-8118-8de30c468b16}
-
+
{85158eb2-9340-4b3d-a136-f7631c7f1b7c}
-
+
{56d34c67-7027-44ba-9f09-4591ce4afb36}
-
+
{775ab0d6-aa5f-43d7-ab3b-3c01652a9ef1}
-
+
{da8084c0-491b-4eb0-b750-97182a9deed4}
-
+
{56ef157f-ad92-4da7-8fbf-00723f769732}
-
+
{565f012b-42b7-42c9-81b7-9e93aa378000}
-
+
{7eead15d-f9dc-4b4d-a653-57d9c090e697}
-
+
{233e3c4d-e398-4c11-a42c-3483107eb8e9}
-
+
{8d80e304-a42d-411a-9528-811eddff3191}
-
+
{eabf472c-e198-409a-a65b-7c087ae911d0}
-
+
{1fff3bd8-44ae-41df-8dd4-8bb6f07b2908}
-
+
{9c1ef4c4-5623-4500-859f-12d6ce5ae362}
-
+
{fc3d3f14-9ba1-43e4-b086-cbbd2f63b944}
-
+
{44489531-f44a-439a-a6ea-d32c252b1e8b}
@@ -825,28 +825,28 @@
beast_core\containers
- beast\intrusive
+ beast_asio\async\beast\intrusive
- beast\intrusive
+ beast_asio\async\beast\intrusive
- beast\mpl
+ beast_asio\async\beast\mpl
- beast\mpl
+ beast_asio\async\beast\mpl
- beast\mpl
+ beast_asio\async\beast\mpl
- beast\mpl
+ beast_asio\async\beast\mpl
- beast\mpl
+ beast_asio\async\beast\mpl
- beast\mpl
+ beast_asio\async\beast\mpl
beast_core\memory
@@ -972,7 +972,7 @@
beast_asio\http
- beast\mpl
+ beast_asio\async\beast\mpl
beast_asio\basics
@@ -1011,64 +1011,64 @@
beast_core\memory
- beast\net
+ beast_asio\async\beast\net
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast\type_traits
+ beast_asio\async\beast\type_traits
- beast\type_traits
+ beast_asio\async\beast\type_traits
- beast\type_traits
+ beast_asio\async\beast\type_traits
- beast\type_traits
+ beast_asio\async\beast\type_traits
- beast\utility
+ beast_asio\async\beast\utility
- beast\utility
+ beast_asio\async\beast\utility
- beast
+ beast_asio\async\beast
- beast\mpl
+ beast_asio\async\beast\mpl
- beast
+ beast_asio\async\beast
- beast\thread
+ beast_asio\async\beast\thread
- beast\thread
+ beast_asio\async\beast\thread
- beast\thread
+ beast_asio\async\beast\thread
- beast\thread
+ beast_asio\async\beast\thread
- beast
+ beast_asio\async\beast
beast_asio\http
@@ -1080,116 +1080,122 @@
beast_asio\basics
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast\intrusive
+ beast_asio\async\beast\intrusive
- beast\intrusive
+ beast_asio\async\beast\intrusive
- beast\mpl
+ beast_asio\async\beast\mpl
beast_core\thread
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast
+ beast_asio\async\beast
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast\strings
+ beast_asio\async\beast\strings
- beast
+ beast_asio\async\beast
- beast\config
+ beast_asio\async\beast\config
- beast\config
+ beast_asio\async\beast\config
- beast\config
+ beast_asio\async\beast\config
- beast
+ beast_asio\async\beast
- beast\config
+ beast_asio\async\beast\config
- beast\config
+ beast_asio\async\beast\config
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
- beast
+ beast_asio\async\beast
beast_core\system
- beast\http
+ beast_asio\async\beast\http
- beast\http
+ beast_asio\async\beast\http
- beast
+ beast_asio\async\beast
- beast\intrusive
+ beast_asio\async\beast\intrusive
- beast
+ beast_asio\async\beast
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
- beast\crypto
+ beast_asio\async\beast\crypto
+
+
+ beast_asio\async
+
+
+ beast_asio\async
@@ -1692,16 +1698,16 @@
beast_extras
- beast\net\impl
+ beast_asio\async\beast\net\impl
- beast\net
+ beast_asio\async\beast\net
- beast\utility
+ beast_asio\async\beast\utility
- beast\utility\impl
+ beast_asio\async\beast\utility\impl
beast_asio\http
@@ -1710,52 +1716,52 @@
beast_core\thread
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser
+ beast_asio\async\beast\http\impl\http-parser
- beast\http\impl\http-parser\contrib
+ beast_asio\async\beast\http\impl\http-parser\contrib
- beast\http\impl\http-parser\contrib
+ beast_asio\async\beast\http\impl\http-parser\contrib
- beast\http
+ beast_asio\async\beast\http
- beast\http\impl
+ beast_asio\async\beast\http\impl
- beast\strings\impl
+ beast_asio\async\beast\strings\impl
- beast\strings\impl
+ beast_asio\async\beast\strings\impl
- beast\strings
+ beast_asio\async\beast\strings
- beast\http\impl
+ beast_asio\async\beast\http\impl
- beast\http\impl
+ beast_asio\async\beast\http\impl
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
- beast\crypto\impl\sha2
+ beast_asio\async\beast\crypto\impl\sha2
- beast\crypto
+ beast_asio\async\beast\crypto
- beast\crypto\impl
+ beast_asio\async\beast\crypto\impl
diff --git a/modules/beast_asio/async/AbstractHandler.h b/modules/beast_asio/async/AbstractHandler.h
new file mode 100644
index 000000000..e732324e5
--- /dev/null
+++ b/modules/beast_asio/async/AbstractHandler.h
@@ -0,0 +1,706 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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_ABSTRACTHANDLER_H_INCLUDED
+#define BEAST_ASIO_ABSTRACTHANDLER_H_INCLUDED
+
+namespace beast {
+
+namespace detail {
+
+struct AbstractHandlerCallBase : SharedObject
+{
+ //typedef SharedFunction > invoked_type;
+
+ typedef SharedFunction invoked_type;
+
+ virtual void* allocate (std::size_t size) = 0;
+ virtual void deallocate (void* p, std::size_t size) = 0;
+ virtual bool is_continuation () = 0;
+ virtual void invoke (invoked_type& invoked) = 0;
+
+ template
+ void invoke (BEAST_MOVE_ARG(Function) f)
+ {
+ invoked_type invoked (BEAST_MOVE_CAST(Function)(f)
+ //, AbstractHandlerAllocator(this)
+ );
+ invoke (invoked);
+ }
+};
+
+/*
+template
+struct AbstractHandlerAllocator
+{
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef T const* const_pointer;
+ typedef T const& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ AbstractHandlerAllocator (AbstractHandler* handler) noexcept
+ : m_ptr (handler)
+ {
+ }
+
+ AbstractHandlerAllocator (SharedPtr const& ptr) noexcept
+ : m_ptr (ptr)
+ {
+ }
+
+ template
+ AbstractHandlerAllocator (AbstractHandlerAllocator const& other)
+ : m_ptr (other.m_ptr)
+ {
+ }
+
+ template
+ struct rebind
+ {
+ typedef AbstractHandlerAllocator other;
+ };
+
+ pointer address (reference x) const
+ {
+ return &x;
+ }
+
+ const_pointer address (const_reference x) const
+ {
+ return &x;
+ }
+
+ pointer allocate (size_type n) const
+ {
+ size_type const bytes = n * sizeof (value_type);
+ return static_cast (m_ptr->allocate (bytes));
+ }
+
+ void deallocate (pointer p, size_type n) const
+ {
+ size_type const bytes = n * sizeof (value_type);
+ m_ptr->deallocate (p, bytes);
+ }
+
+ size_type max_size () const noexcept
+ {
+ return std::numeric_limits ::max () / sizeof (value_type);
+ }
+
+ void construct (pointer p, const_reference val) const
+ {
+ new ((void *)p) value_type (val);
+ }
+
+ void destroy (pointer p) const
+ {
+ p->~value_type ();
+ }
+
+private:
+ template
+ friend struct AbstractHandlerAllocator;
+ friend class AbstractHandler;
+
+ SharedPtr m_ptr;
+};
+*/
+
+}
+
+/** A reference counted, abstract completion handler. */
+template >
+class AbstractHandler;
+
+//------------------------------------------------------------------------------
+
+// arity 0
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() () = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_h (BEAST_MOVE_CAST(H)(h)), m_alloc (a)
+ { }
+ R operator()()
+ { return (m_h)(); }
+ R operator()() const
+ { return (m_h)(); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (BEAST_MOVE_CAST(H)(h), a))
+ { }
+ R operator() ()
+ { return (*m_call)(); }
+ R operator() () const
+ { return (*m_call)(); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+//------------------------------------------------------------------------------
+
+// arity 1
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() (P1) = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (H h, A a = A ())
+ : m_h (h)
+ , m_alloc (a)
+ {
+ }
+
+ R operator()(P1 p1)
+ { return (m_h)(p1); }
+ R operator()(P1 p1) const
+ { return (m_h)(p1); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (H h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (h, a))
+ {
+ }
+
+ R operator() (P1 p1)
+ { return (*m_call)(p1); }
+ R operator() (P1 p1) const
+ { return (*m_call)(p1); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+//------------------------------------------------------------------------------
+
+// arity 2
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() (P1, P2) = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_h (BEAST_MOVE_CAST(H)(h)), m_alloc (a)
+ { }
+ R operator()(P1 p1, P2 p2)
+ { return (m_h)(p1, p2); }
+ R operator()(P1 p1, P2 p2) const
+ { return (m_h)(p1, p2); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (BEAST_MOVE_CAST(H)(h), a))
+ { }
+ R operator() (P1 p1, P2 p2)
+ { return (*m_call)(p1, p2); }
+ R operator() (P1 p1, P2 p2) const
+ { return (*m_call)(p1, p2); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+//------------------------------------------------------------------------------
+
+// arity 3
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() (P1, P2, P3) = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_h (BEAST_MOVE_CAST(H)(h)), m_alloc (a)
+ { }
+ R operator()(P1 p1, P2 p2, P3 p3)
+ { return (m_h)(p1, p2, p3); }
+ R operator()(P1 p1, P2 p2, P3 p3) const
+ { return (m_h)(p1, p2, p3); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (BEAST_MOVE_CAST(H)(h), a))
+ { }
+ R operator() (P1 p1, P2 p2, P3 p3)
+ { return (*m_call)(p1, p2, p3); }
+ R operator() (P1 p1, P2 p2, P3 p3) const
+ { return (*m_call)(p1, p2, p3); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+//------------------------------------------------------------------------------
+
+// arity 4
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() (P1, P2, P3, P4) = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_h (BEAST_MOVE_CAST(H)(h)), m_alloc (a)
+ { }
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4)
+ { return (m_h)(p1, p2, p3, p4); }
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4) const
+ { return (m_h)(p1, p2, p3, p4); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (BEAST_MOVE_CAST(H)(h), a))
+ { }
+ R operator() (P1 p1, P2 p2, P3 p3, P4 p4)
+ { return (*m_call)(p1, p2, p3, p4); }
+ R operator() (P1 p1, P2 p2, P3 p3, P4 p4) const
+ { return (*m_call)(p1, p2, p3, p4); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+//------------------------------------------------------------------------------
+
+// arity 5
+template
+struct AbstractHandler
+{
+ typedef R result_type;
+ struct Call : detail::AbstractHandlerCallBase
+ { virtual R operator() (P1, P2, P3, P4, P5) = 0; };
+
+ template
+ struct CallType : public Call
+ {
+ typedef typename A:: template rebind >::other Allocator;
+ CallType (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_h (BEAST_MOVE_CAST(H)(h)), m_alloc (a)
+ { }
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+ { return (m_h)(p1, p2, p3, p4, p5); }
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const
+ { return (m_h)(p1, p2, p3, p4, p5); }
+ void* allocate (std::size_t size)
+ { return boost_asio_handler_alloc_helpers::allocate(size, m_h); }
+ void deallocate (void* pointer, std::size_t size)
+ { boost_asio_handler_alloc_helpers::deallocate( pointer, size, m_h); }
+ bool is_continuation ()
+#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
+ { return boost_asio_handler_cont_helpers::is_continuation(m_h); }
+#else
+ { return false; }
+#endif
+ void invoke (invoked_type& invoked)
+ { boost_asio_handler_invoke_helpers::invoke (invoked, m_h); }
+ private:
+ H m_h;
+ Allocator m_alloc;
+ };
+
+ template
+ AbstractHandler (BEAST_MOVE_ARG(H) h, A a = A ())
+ : m_call (new (
+ typename A:: template rebind >::other (a)
+ .allocate (1)) CallType (BEAST_MOVE_CAST(H)(h), a))
+ { }
+ R operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+ { return (*m_call)(p1, p2, p3, p4, p5); }
+ R operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const
+ { return (*m_call)(p1, p2, p3, p4, p5); }
+ void* allocate (std::size_t size) const { return m_call->allocate(size); }
+ void deallocate (void* pointer, std::size_t size) const { m_call->deallocate(pointer,size); }
+ bool is_continuation () const { return m_call->is_continuation(); }
+ template
+ void invoke (Function& function) const
+ {
+ m_call->invoke(function);
+ }
+ template
+ void invoke (Function const& function) const
+ {
+ m_call->invoke(function);
+ }
+
+private:
+ SharedPtr m_call;
+};
+
+template
+void* asio_handler_allocate (std::size_t size,
+ AbstractHandler * handler)
+{
+ return handler->allocate (size);
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ AbstractHandler * handler)
+{
+ handler->deallocate (pointer, size);
+}
+
+template
+bool asio_handler_is_continuation(
+ AbstractHandler * handler)
+{
+ return handler->is_continuation();
+}
+
+template
+void asio_handler_invoke (BEAST_MOVE_ARG(Function) function,
+ AbstractHandler * handler)
+{
+ handler->invoke (BEAST_MOVE_CAST(Function)(function));
+}
+
+}
+
+#endif
diff --git a/modules/beast_asio/async/SharedHandler.h b/modules/beast_asio/async/SharedHandler.h
index cd6543c9f..9a1c58ed1 100644
--- a/modules/beast_asio/async/SharedHandler.h
+++ b/modules/beast_asio/async/SharedHandler.h
@@ -45,11 +45,9 @@ class SharedHandler : public SharedObject
{
protected:
typedef boost::system::error_code error_code;
-#if 0
- typedef boost::function invoked_type;
-#else
- typedef SharedFunction > invoked_type;
-#endif
+
+ typedef SharedFunction > invoked_type;
SharedHandler () noexcept { }
@@ -65,9 +63,6 @@ public:
template
void invoke (BOOST_ASIO_MOVE_ARG(Function) f)
-#if 0
- ;
-#else
{
// The allocator will hold a reference to the SharedHandler
// so that we can safely destroy the function object.
@@ -75,7 +70,6 @@ public:
SharedHandlerAllocator (this));
invoke (invoked);
}
-#endif
virtual void invoke (invoked_type& invoked) = 0;
virtual void* allocate (std::size_t size) = 0;
diff --git a/modules/beast_asio/async/SharedHandlerPtr.h b/modules/beast_asio/async/SharedHandlerPtr.h
index d864ca8cc..b2ef86e44 100644
--- a/modules/beast_asio/async/SharedHandlerPtr.h
+++ b/modules/beast_asio/async/SharedHandlerPtr.h
@@ -43,7 +43,7 @@ public:
@see isNull, isNotNull
*/
- inline SharedHandlerPtr () noexcept
+ inline SharedHandlerPtr ()
{
}
@@ -55,15 +55,14 @@ public:
{
}
- /** Construct a reference from an existing container.
- */
- inline SharedHandlerPtr (SharedHandlerPtr const& other) noexcept
+ /** Construct a reference from an existing container. */
+ inline SharedHandlerPtr (SharedHandlerPtr const& other)
: m_ptr (other.m_ptr)
{
}
/** Assign a reference from an existing container. */
- inline SharedHandlerPtr& operator= (SharedHandlerPtr const& other) noexcept
+ inline SharedHandlerPtr& operator= (SharedHandlerPtr const& other)
{
m_ptr = other.m_ptr;
return *this;
@@ -73,7 +72,7 @@ public:
/** Move-construct a reference from an existing container.
The other container is set to a null handler.
*/
- inline SharedHandlerPtr (SharedHandlerPtr&& other) noexcept
+ inline SharedHandlerPtr (SharedHandlerPtr&& other)
: m_ptr (other.m_ptr)
{
other.m_ptr = nullptr;
@@ -82,7 +81,7 @@ public:
/** Move-assign a reference from an existing container.
The other container is set to a null handler.
*/
- inline SharedHandlerPtr& operator= (SharedHandlerPtr&& other) noexcept
+ inline SharedHandlerPtr& operator= (SharedHandlerPtr&& other)
{
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
@@ -91,13 +90,13 @@ public:
#endif
/** Returns true if the handler is a null handler. */
- inline bool isNull () const noexcept
+ inline bool isNull () const
{
return m_ptr == nullptr;
}
/** Returns true if the handler is not a null handler. */
- inline bool isNotNull () const noexcept
+ inline bool isNotNull () const
{
return m_ptr != nullptr;
}
@@ -105,7 +104,7 @@ public:
/** Dereference the container.
This returns a reference to the underlying SharedHandler object.
*/
- inline SharedHandler& operator* () const noexcept
+ inline SharedHandler& operator* () const
{
return *m_ptr;
}
@@ -113,7 +112,7 @@ public:
/** SharedHandler member access.
This lets you call functions directly on the SharedHandler.
*/
- inline SharedHandler* operator-> () const noexcept
+ inline SharedHandler* operator-> () const
{
return m_ptr.get ();
}
@@ -132,7 +131,7 @@ public:
@endcode
*/
- inline SharedHandler* get () const noexcept
+ inline SharedHandler* get () const
{
return m_ptr.get ();
}
@@ -144,7 +143,7 @@ public:
{
(*m_ptr)();
}
-
+
/** Invoke the SharedHandler with signature void(error_code)
Normally this is called by a dispatcher, you shouldn't call it directly.
*/
@@ -180,7 +179,7 @@ private:
//
template
-inline void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandlerPtr* ptr)
+void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandlerPtr* ptr)
{
boost_asio_handler_invoke_helpers::
invoke
diff --git a/modules/beast_asio/async/SharedHandlerType.h b/modules/beast_asio/async/SharedHandlerType.h
index 77961ce2c..7ff937962 100644
--- a/modules/beast_asio/async/SharedHandlerType.h
+++ b/modules/beast_asio/async/SharedHandlerType.h
@@ -21,7 +21,6 @@
#define BEAST_ASIO_ASYNC_SHAREDHANDLERTYPE_H_INCLUDED
/** An instance of SharedHandler that wraps an existing Handler.
-
The wrapped handler will meet all the execution guarantees of
the original Handler object.
*/
diff --git a/modules/beast_asio/async/WrapHandler.h b/modules/beast_asio/async/WrapHandler.h
new file mode 100644
index 000000000..7d28934fe
--- /dev/null
+++ b/modules/beast_asio/async/WrapHandler.h
@@ -0,0 +1,205 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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_WRAPHANDLER_H_INCLUDED
+#define BEAST_ASIO_WRAPHANDLER_H_INCLUDED
+
+namespace beast {
+namespace detail {
+
+// Wrapper returned by wrapHandler, calls the Handler in the given Context
+//
+template
+class WrappedHandler
+{
+public:
+ typedef void result_type; // for result_of
+
+ WrappedHandler (Handler& handler, Context const& context)
+ : m_handler (handler)
+ , m_context (context)
+ {
+ }
+
+ WrappedHandler (Handler const& handler, Context const& context)
+ : m_handler (handler)
+ , m_context (context)
+ {
+ }
+
+#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
+ WrappedHandler (WrappedHandler const& other)
+ : m_handler (other.m_handler)
+ , m_context (other.m_context)
+ {
+ }
+
+ WrappedHandler (BEAST_MOVE_ARG(WrappedHandler) other)
+ : m_handler (BEAST_MOVE_CAST(Handler)(other.m_handler))
+ , m_context (BEAST_MOVE_CAST(Context)(other.m_context))
+ {
+ }
+#endif
+
+ Handler& handler()
+ { return m_handler; }
+
+ Handler const& handler() const
+ { return m_handler; }
+
+ Context& context()
+ { return m_context; }
+
+ Context const& context() const
+ { return m_context; }
+
+ void operator() ()
+ { m_handler(); }
+
+ void operator() () const
+ { m_handler(); }
+
+ template
+ void operator() (P1 const& p1)
+ { m_handler(p1); }
+
+ template
+ void operator() (P1 const& p1) const
+ { m_handler(p1); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2)
+ { m_handler(p1, p2); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2) const
+ { m_handler(p1, p2); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3)
+ { m_handler(p1, p2, p3); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3) const
+ { m_handler(p1, p2, p3); }
+
+ template
+ void operator()
+ (P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4)
+ { m_handler(p1, p2, p3, p4); }
+
+ template
+ void operator()
+ (P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4) const
+ { m_handler(p1, p2, p3, p4); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3,
+ P4 const& p4, P5 const& p5)
+ { m_handler(p1, p2, p3, p4, p5); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3,
+ P4 const& p4, P5 const& p5) const
+ { m_handler(p1, p2, p3, p4, p5); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3,
+ P4 const& p4, P5 const& p5, P6 const& p6)
+ { m_handler(p1, p2, p3, p4, p5, p6); }
+
+ template
+ void operator() (P1 const& p1, P2 const& p2, P3 const& p3,
+ P4 const& p4, P5 const& p5, P6 const& p6) const
+ { m_handler(p1, p2, p3, p4, p5, p6); }
+
+private:
+ Handler m_handler;
+ Context m_context;
+};
+
+//------------------------------------------------------------------------------
+
+template
+void* asio_handler_allocate (std::size_t size,
+ WrappedHandler * this_handler)
+{
+ return boost_asio_handler_alloc_helpers::allocate(
+ size, this_handler->context());
+}
+
+template
+void asio_handler_deallocate (void* pointer, std::size_t size,
+ WrappedHandler * this_handler)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->context());
+}
+
+template
+bool asio_handler_is_continuation(
+ WrappedHandler * this_handler)
+{
+ return boost_asio_handler_cont_helpers::is_continuation(
+ this_handler->handler());
+}
+
+template
+void asio_handler_invoke (Function& function,
+ WrappedHandler * handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, handler->context());
+}
+
+template
+void asio_handler_invoke (Function const& function,
+ WrappedHandler * handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, handler->context());
+}
+
+}
+
+//------------------------------------------------------------------------------
+
+/** Returns a handler that calls Handler using Context hooks.
+ This is useful when implementing composed asynchronous operations that
+ need to call their own intermediate handlers before issuing the final
+ completion to the original handler.
+*/
+template
+detail::WrappedHandler
+ wrapHandler (
+ BEAST_MOVE_ARG(Handler) handler,
+ BEAST_MOVE_ARG(Context) context)
+{
+ return detail::WrappedHandler (
+ BEAST_MOVE_CAST(Handler)(handler),
+ BEAST_MOVE_CAST(Context)(context));
+}
+
+}
+
+#endif
diff --git a/modules/beast_asio/beast_asio.h b/modules/beast_asio/beast_asio.h
index ecf7efda8..3ca6fa4f1 100644
--- a/modules/beast_asio/beast_asio.h
+++ b/modules/beast_asio/beast_asio.h
@@ -57,8 +57,10 @@
#include "../../beast/Utility.h"
#include "../../beast/HTTP.h"
-namespace beast
-{
+#include "async/AbstractHandler.h"
+#include "async/WrapHandler.h"
+
+namespace beast {
// Order matters
# include "async/SharedHandler.h"
@@ -88,8 +90,13 @@ namespace beast
# include "http/HTTPRequest.h"
# include "http/HTTPResponse.h"
# include "http/HTTPParser.h"
+
+}
+
#include "http/HTTPClientType.h"
+namespace beast {
+
# include "protocol/InputParser.h"
# include "protocol/HandshakeDetectLogic.h"
#include "protocol/HandshakeDetectLogicPROXY.h"
diff --git a/modules/beast_asio/http/HTTPClientType.cpp b/modules/beast_asio/http/HTTPClientType.cpp
index c35c1a12c..5c9328140 100644
--- a/modules/beast_asio/http/HTTPClientType.cpp
+++ b/modules/beast_asio/http/HTTPClientType.cpp
@@ -19,120 +19,108 @@
class HTTPClientType : public HTTPClientBase, public Uncopyable
{
-private:
- using HTTPClientBase::Listener;
+public:
+ class Session;
- typedef boost::system::error_code error_code;
-
- class ListenerHandler
+ struct State
{
- public:
- ListenerHandler ()
- : m_owner (nullptr)
- , m_listener (nullptr)
- {
- }
-
- ListenerHandler (HTTPClientType* owner, Listener* listener = nullptr)
- : m_owner (owner)
- , m_listener (listener)
- {
- }
-
- ListenerHandler (ListenerHandler const& other)
- : m_owner (other.m_owner)
- , m_listener (other.m_listener)
- {
- }
-
- ListenerHandler& operator= (ListenerHandler const& other)
- {
- m_owner = other.m_owner;
- m_listener = other.m_listener;
- return *this;
- }
-
- void operator() (error_code)
- {
- if (m_listener != nullptr)
- m_listener->onHTTPRequestComplete (
- *m_owner, m_owner->result ());
- }
-
- private:
- HTTPClientType* m_owner;
- Listener* m_listener;
+ List list;
};
-public:
+ typedef SharedData 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_timeoutSeconds (timeoutSeconds)
+ : m_journal (journal)
+ , m_timeoutSeconds (timeoutSeconds)
, m_messageLimitBytes (messageLimitBytes)
, m_bufferSize (bufferSize)
+ , m_stopped (true, true) // manual reset, initially signaled
{
}
~HTTPClientType ()
{
- m_async_op = nullptr;
+ cancel();
+ wait();
}
- Result const& result () const
- {
- return m_result;
- }
-
- Result const& get (URL const& url)
+ result_type get (URL const& url)
{
+ result_type result;
boost::asio::io_service io_service;
- async_get (io_service, nullptr, url);
+ async_get (io_service, url, bind (
+ &HTTPClientType::handle_get, placeholders::_1, &result));
io_service.run ();
- return result ();
+ return result;
}
- //--------------------------------------------------------------------------
-
- void async_get (boost::asio::io_service& io_service, Listener* listener,
- URL const& url)
+ void abstract_async_get (boost::asio::io_service& io_service, URL const& url,
+ AbstractHandler handler)
{
- async_get (io_service, url, ListenerHandler (this, listener));
- }
-
- // Handler signature is void(error_code)
- //
- template
- void async_get (boost::asio::io_service& io_service,
- URL const& url,
- BOOST_ASIO_MOVE_ARG(Handler) handler)
- {
- async_get (io_service, url, newErrorHandler (
- BOOST_ASIO_MOVE_CAST(Handler)(handler)));
- }
-
- void async_get (boost::asio::io_service& io_service,
- URL const& url, SharedHandlerPtr handler)
- {
- // This automatically dispatches
- m_async_op = new AsyncGetOp (
- *this, io_service, url, handler,
- m_timeoutSeconds, m_messageLimitBytes, m_bufferSize);
+ new Session (*this, io_service, url,
+ handler, m_timeoutSeconds, m_messageLimitBytes, m_bufferSize);
}
void cancel ()
{
- if (m_async_op != nullptr)
- {
- m_async_op->cancel ();
- m_async_op = nullptr;
- }
+ SharedState::Access state (m_state);
+ for (List ::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;
}
-private:
//--------------------------------------------------------------------------
/** Helper function to get a const_buffer from a String. */
@@ -160,75 +148,83 @@ private:
//--------------------------------------------------------------------------
- class AsyncGetOp : public ComposedAsyncOperation
+ class Session
+ : public SharedObject
+ , public AsyncObject
+ , public List ::Node
{
- private:
- typedef boost::asio::ip::tcp Protocol;
- typedef boost::system::error_code error_code;
-
- typedef Protocol::resolver resolver;
- typedef resolver::query query;
- typedef resolver::iterator iterator;
- typedef iterator::value_type resolver_entry;
- typedef Protocol::socket socket;
-
- //----------------------------------------------------------------------
-
- enum State
- {
- stateStart,
- stateResolveComplete,
- stateConnectComplete,
- stateHandshakeComplete,
- stateWriteComplete,
- stateShutdownComplete
- };
-
- //----------------------------------------------------------------------
-
- struct TimerHandler : SharedHandlerPtr
- {
- explicit TimerHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
- void operator() (error_code const& ec)
- {
- m_owner->timerCompletion (ec);
- }
-
- AsyncGetOp* m_owner;
- };
-
- //----------------------------------------------------------------------
-
public:
- AsyncGetOp (HTTPClientType& owner,
- boost::asio::io_service& io_service,
- URL const& url,
- SharedHandlerPtr const& handler,
- double timeoutSeconds,
- std::size_t messageLimitBytes,
- std::size_t bufferSize)
- : ComposedAsyncOperation (sizeof (*this), handler)
- , m_owner (owner)
+ typedef SharedPtr 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;
+ AbstractHandler m_handler;
+
+ URL m_url;
+ boost::asio::ssl::context m_context;
+ MemoryBlock m_buffer;
+ HTTPParser m_parser;
+ std::size_t m_messageLimitBytes;
+ std::size_t m_bytesReceived;
+
+ String m_get_string;
+ WaitableEvent m_done;
+ ScopedPointer m_stream;
+
+ struct State
+ {
+ State () : complete (false)
+ {
+ }
+
+ bool complete;
+ error_code error;
+ SharedPtr response;
+ };
+ typedef SharedData SharedState;
+ SharedState m_state;
+
+ //----------------------------------------------------------------------
+
+ Session (HTTPClientType& owner,
+ boost::asio::io_service& io_service,
+ URL const& url,
+ AbstractHandler const& handler,
+ double timeoutSeconds,
+ std::size_t messageLimitBytes,
+ std::size_t bufferSize)
+ : m_owner (owner)
, m_io_service (io_service)
- , m_strand (m_io_service)
- , m_url (url)
- , m_handler (handler)
+ , 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_parser (HTTPParser::typeResponse)
- , m_timer_set (false)
- , m_timer_canceled (false)
- , m_timer_expired (false)
, 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 |
@@ -236,342 +232,163 @@ private:
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_set = true;
- ++m_io_pending;
- m_timer.async_wait (TimerHandler (this));
+ m_timer.async_wait (m_strand.wrap (wrapHandler (
+ boost::bind (&Session::handle_timer, Ptr(this),
+ boost::asio::placeholders::error,
+ CompletionCounter(this)), m_handler)));
}
- // Count as pending i/o
- ++m_io_pending;
- m_io_service.dispatch (
- m_strand.wrap (StartHandler (this)));
+ // Start the operation on an io_service thread
+ io_service.dispatch (m_strand.wrap (wrapHandler (
+ boost::bind (&Session::handle_start, Ptr(this),
+ CompletionCounter(this)), m_handler)));
}
- ~AsyncGetOp ()
+ ~Session ()
{
+ State result;
+ {
+ SharedState::ConstAccess state (m_state);
+ result = *state;
+ }
+
+ m_io_service.wrap (m_handler) (std::make_pair (
+ result.error, result.response));
+
+ m_owner.remove (*this);
}
- // Cancel all pending I/O, if any, and block until
- // there are no more completion handler calls pending.
- //
+ //----------------------------------------------------------------------
+
+ // Called by the owner to cancel pending i/o.
void cancel ()
{
- cancel_timer ();
- m_resolver.cancel ();
- error_code ec;
- m_socket.close (ec);
-
- m_done.wait ();
- }
-
- private:
- //----------------------------------------------------------------------
-
- // Counts a pending i/o as canceled
- //
- void io_canceled ()
- {
- bassert (m_io_pending.get () > 0);
- if (--m_io_pending == 0)
- m_done.signal ();
- }
-
- // Cancels the deadline timer.
- //
- void cancel_timer ()
- {
- // Make sure the timer was set (versus infinite timeout)
- if (m_timer_set)
{
- // See if it was already canceled.
- if (! m_timer_canceled)
+ SharedState::Access state (m_state);
+ if (! state->complete)
{
- m_timer_canceled = true;
- error_code ec;
- m_timer.cancel (ec);
-
- // At this point, there will either be a pending completion
- // or a pending abort for the handler. If its a completion,
- // they will see that the timer was canceled (since we're on
- // a strand, everything is serialized). If its an abort it
- // counts as a cancellation anyway. Either way, we will deduct
- // one i/o from the pending i/o count.
+ state->complete = true;
+ state->error = boost::asio::error::operation_aborted;
}
}
+
+ cancel_all();
}
- // Called to notify the original handler the operation is complete.
- //
- void complete (error_code const& ec)
+ // Cancel all pending I/O
+ void cancel_all ()
{
- // Set the error code in the result.
- m_owner.m_result.error = ec;
-
- // Cancel the deadline timer. This ensures that
- // we will not return 'timeout' to the caller later.
- //
- cancel_timer ();
-
- bassert (m_io_pending.get () > 0);
-
- io_canceled ();
-
- // We call the handler directly since we know
- // we are already in the right context, and
- // because we need to do some things afterwards.
- //
- m_handler->operator() (ec);
- }
-
- // Called every time an async operation completes.
- // The return value indicates if the handler should
- // stop additional activity and return immediately.
- //
- bool io_complete (error_code const& ec)
- {
- if (m_timer_expired ||
- ec == boost::asio::error::operation_aborted)
- {
- // Timer expired, or the operation was aborted due to
- // cancel, so we deduct one i/o and return immediately.
- //
- io_canceled ();
- return true;
- }
-
- if (ec != 0 && ec != boost::asio::error::eof)
- {
- // A real error happened, and the timer didn't expire, so
- // notify the original handler that the operation is complete.
- //
- complete (ec);
- return true;
- }
-
- // Process the completion as usual. If the caller does not
- // call another initiating function, it is their responsibility
- // to call io_canceled() to deduce one pending i/o.
- //
- return false;
- }
-
- // Called when the deadline timer expires or is canceled.
- //
- void timerCompletion (error_code ec)
- {
- bassert (m_timer_set);
-
- if (m_timer_canceled || ec == boost::asio::error::operation_aborted)
- {
- // If the cancel flag is set or the operation was aborted it
- // means we canceled the timer so deduct one i/o and return.
- //
- io_canceled ();
- return;
- }
-
- bassert (ec == 0);
-
- // The timer expired, so this is a real timeout scenario.
- // We want to set the error code, notify the handler, and cancel
- // all other pending i/o.
- //
- m_timer_expired = true;
-
- ec = error_code (boost::asio::error::timed_out,
- boost::asio::error::get_system_category ());
-
- // Cancel pending name resolution
+ error_code ec;
+ m_timer.cancel (ec);
m_resolver.cancel ();
-
- // Close the socket. This will cancel up to 2 pending i/o
- m_socket.close (ec);
-
- // Notify the original handler of a timeout error.
- // The call to complete() consumes one pending i/o, which
- // we need since this function counts as one completion.
- //
- complete (ec);
+ m_socket.cancel (ec);
+ m_socket.shutdown (socket::shutdown_both);
}
- //----------------------------------------------------------------------
-
- struct StartHandler : SharedHandlerPtr
+ // Called by a completion handler when error is not eof or aborted.
+ void failed (error_code ec)
{
- explicit StartHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
{
+ SharedState::Access state (m_state);
+ if (! state->complete)
+ {
+ state->complete = true;
+ state->error = ec;
+ state->response = nullptr;
+ }
}
- void operator() ()
- {
- m_owner->start_complete ();
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct ResolveHandler : SharedHandlerPtr
- {
- explicit ResolveHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec, iterator iter)
- {
- m_owner->resolve_complete (ec, iter);
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct ConnectHandler : SharedHandlerPtr
- {
- explicit ConnectHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec)
- {
- m_owner->connect_complete (ec);
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct HandshakeHandler : SharedHandlerPtr
- {
- explicit HandshakeHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec)
- {
- m_owner->handshake_complete (ec);
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct WriteHandler : SharedHandlerPtr
- {
- explicit WriteHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec, std::size_t bytes_transferred)
- {
- m_owner->write_complete (ec, bytes_transferred);
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct ReadHandler : SharedHandlerPtr
- {
- explicit ReadHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec, std::size_t bytes_transferred)
- {
- m_owner->read_complete (ec, bytes_transferred);
- }
-
- AsyncGetOp* m_owner;
- };
-
- struct ShutdownHandler : SharedHandlerPtr
- {
- explicit ShutdownHandler (AsyncGetOp* owner)
- : SharedHandlerPtr (owner)
- , m_owner (owner)
- {
- }
-
- void operator() (error_code const& ec)
- {
- m_owner->shutdown_complete (ec);
- }
-
- AsyncGetOp* m_owner;
- };
-
- //----------------------------------------------------------------------
+ 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 (ReadHandler (this)));
- }
-
- // Called when the HTTP parser returns an error
- void parse_error ()
- {
- //unsigned char const http_errno (m_parser.error ());
- String const http_errmsg (m_parser.message ());
-
- // VFALCO TODO put the parser error in ec
- error_code ec (
- boost::system::errc::invalid_argument,
- boost::system::system_category ());
-
- complete (ec);
- }
-
- // Called to create an error when the message is over the limit
- error_code message_limit_error ()
- {
- // VFALCO TODO Make a suitable error code
- return error_code (
- boost::system::errc::invalid_argument,
- boost::system::system_category ());
+ m_stream->async_read_some (buf, m_strand.wrap (
+ wrapHandler (boost::bind (&Session::handle_read,
+ Ptr(this), boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred,
+ CompletionCounter(this)), m_handler)));
}
//----------------------------------------------------------------------
+ //
+ // Completion handlers
+ //
- void start_complete ()
+ // Called when there are no more pending i/o completions
+ void asyncHandlersComplete()
+ {
+ }
+
+ // Called when the operation starts
+ void handle_start (CompletionCounter)
{
query q (queryFromURL (m_url));
- m_resolver.async_resolve (q,
- m_strand.wrap (ResolveHandler (this)));
+
+ m_resolver.async_resolve (q, m_strand.wrap (
+ wrapHandler (boost::bind (&Session::handle_resolve,
+ Ptr(this), boost::asio::placeholders::error,
+ boost::asio::placeholders::iterator,
+ CompletionCounter(this)), m_handler)));
}
- void resolve_complete (error_code ec, iterator iter)
+ // Called when the timer completes
+ void handle_timer (error_code ec, CompletionCounter)
{
- if (io_complete (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, CompletionCounter)
+ {
+ 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 (ConnectHandler (this)));
+ m_socket.async_connect (entry.endpoint (), m_strand.wrap (
+ wrapHandler (boost::bind (&Session::handle_connect,
+ Ptr(this), boost::asio::placeholders::error,
+ CompletionCounter(this)), m_handler)));
}
- void connect_complete (error_code ec)
+ // Called when the connection attempt completes
+ void handle_connect (error_code ec, CompletionCounter)
{
- if (io_complete (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 ssl_stream;
@@ -581,154 +398,160 @@ private:
boost::asio::ssl::verify_peer |
boost::asio::ssl::verify_fail_if_no_peer_cert);
*/
- m_stream->async_handshake (
- Socket::client, HandshakeHandler (this));
+ m_stream->async_handshake (Socket::client, m_strand.wrap (
+ wrapHandler (boost::bind (&Session::handle_handshake,
+ Ptr(this), boost::asio::placeholders::error,
+ CompletionCounter(this)), m_handler)));
return;
}
m_stream = new SocketWrapper (m_socket);
- handshake_complete (ec);
+ handle_handshake (ec, CompletionCounter(this));
}
- void handshake_complete (error_code ec)
+ // Called when the SSL handshake completes
+ void handle_handshake (error_code ec, CompletionCounter)
{
- if (io_complete (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 (WriteHandler (this)));
- ++m_io_pending;
+ boost::asio::async_write (*m_stream, stringBuffer (
+ m_get_string), m_strand.wrap (wrapHandler (
+ boost::bind (&Session::handle_write, Ptr(this),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred,
+ CompletionCounter(this)), m_handler)));
async_read_some ();
}
- void write_complete (error_code ec, std::size_t)
+ // Called when the write operation completes
+ void handle_write (error_code ec, std::size_t, CompletionCounter)
{
- if (io_complete (ec))
+ if (ec == boost::asio::error::operation_aborted)
return;
- if (! m_stream->needs_handshake ())
+ if (ec != 0)
{
- m_socket.shutdown (socket::shutdown_send, ec);
- if (ec != 0)
- return complete (ec);
+ failed (ec);
+ return;
}
- // deduct one i/o since we aren't issuing any new one
- io_canceled ();
+ if (! m_stream->needs_handshake ())
+ m_socket.shutdown (socket::shutdown_send, ec);
}
- void read_complete (error_code ec, std::size_t bytes_transferred)
+ void handle_read (error_code ec,
+ std::size_t bytes_transferred, CompletionCounter)
{
+ if (ec == boost::asio::error::operation_aborted)
+ return;
+
+ if (ec != 0)
+ {
+ failed (ec);
+ return;
+ }
+
m_bytesReceived += bytes_transferred;
if (m_bytesReceived > m_messageLimitBytes)
- ec = message_limit_error ();
-
- if (io_complete (ec))
+ {
+ 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 ())
{
- parse_error ();
+ failed (error_code (
+ boost::system::errc::invalid_argument,
+ boost::system::system_category ()));
return;
}
if (bytes_parsed != bytes_transferred)
{
- // VFALCO TODO put an appropriate error in ec
- ec = error_code (
+ failed (error_code (
boost::system::errc::invalid_argument,
- boost::system::system_category ());
- return complete (ec);
+ boost::system::system_category ()));
+ return;
}
if (ec == boost::asio::error::eof)
- {
m_parser.process_eof ();
- }
if (m_parser.finished ())
{
- m_state = stateShutdownComplete;
if (m_stream->needs_handshake ())
- m_stream->async_shutdown (ShutdownHandler (this));
+ {
+ m_stream->async_shutdown (m_strand.wrap (wrapHandler (
+ boost::bind (&Session::handle_shutdown, Ptr(this),
+ boost::asio::placeholders::error,
+ CompletionCounter(this)), m_handler)));
+ }
else
- shutdown_complete (error_code ());
+ {
+ handle_shutdown (error_code (), CompletionCounter(this));
+ }
return;
}
async_read_some ();
}
- void shutdown_complete (error_code ec)
+ void handle_shutdown (error_code ec, CompletionCounter)
{
- if (io_complete (ec))
+ if (ec == boost::asio::error::operation_aborted)
return;
- m_owner.m_result.response = m_parser.response ();
- if (ec == boost::asio::error::eof)
- ec = error_code ();
+ if (ec != 0)
+ {
+ failed (ec);
+ return;
+ }
- return complete (ec);
+ {
+ SharedState::Access state (m_state);
+ if (! state->complete)
+ {
+ state->complete = true;
+ state->response = m_parser.response();
+ }
+ }
+
+ cancel_all();
}
-
- private:
- WaitableEvent m_done;
- Atomic m_io_pending;
- HTTPClientType& m_owner;
- boost::asio::io_service& m_io_service;
- boost::asio::io_service& m_strand;
- URL m_url;
- SharedHandlerPtr m_handler;
- boost::asio::deadline_timer m_timer;
- resolver m_resolver;
- socket m_socket;
- ScopedPointer m_stream;
- boost::asio::ssl::context m_context;
- MemoryBlock m_buffer;
- State m_state;
- HTTPParser m_parser;
- String m_get_string;
- bool m_timer_set;
- bool m_timer_canceled;
- bool m_timer_expired;
- std::size_t m_messageLimitBytes;
- std::size_t m_bytesReceived;
};
-
- double m_timeoutSeconds;
- std::size_t m_messageLimitBytes;
- std::size_t m_bufferSize;
- boost::asio::io_service m_io_service;
- SharedPtr m_async_op;
- Result m_result;
};
//------------------------------------------------------------------------------
-HTTPClientBase* HTTPClientBase::New (
+HTTPClientBase* HTTPClientBase::New (Journal journal,
double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
{
- ScopedPointer object (new HTTPClientType
- (timeoutSeconds, messageLimitBytes, bufferSize));
- return object.release ();
+ return new HTTPClientType (
+ journal, timeoutSeconds, messageLimitBytes, bufferSize);
}
//------------------------------------------------------------------------------
-class HTTPClientTests
- : public UnitTest
- , public HTTPClientBase::Listener
+class HTTPClientTests : public UnitTest
{
public:
typedef boost::system::error_code error_code;
@@ -787,19 +610,19 @@ public:
}
}
- void log (HTTPClientBase::Result const& result)
+ void log (HTTPClientBase::error_type error, HTTPClientBase::value_type const& response)
{
- if (result.error != 0)
+ if (error != 0)
{
logMessage (String (
- "HTTPClient error: '" + result.error.message() + "'"));
+ "HTTPClient error: '" + error.message() + "'"));
}
- else if (! result.response.empty ())
+ else if (! response.empty ())
{
logMessage (String ("Status: ") +
- String::fromNumber (result.response->status()));
-
- log (*result.response);
+ String::fromNumber (response->status()));
+
+ log (*response);
}
else
{
@@ -809,28 +632,31 @@ public:
//--------------------------------------------------------------------------
- void onHTTPRequestComplete (
- HTTPClientBase const&, HTTPClientBase::Result const& result)
+ void handle_get (HTTPClientBase::result_type result)
{
- log (result);
+ log (result.first, result.second);
}
void testSync (String const& s, double timeoutSeconds)
{
ScopedPointer client (
- HTTPClientBase::New (timeoutSeconds));
+ HTTPClientBase::New (Journal(), timeoutSeconds));
- log (client->get (ParsedURL (s).url ()));
+ HTTPClientBase::result_type const& result (
+ client->get (ParsedURL (s).url ()));
+
+ log (result.first, result.second);
}
void testAsync (String const& s, double timeoutSeconds)
{
IoServiceThread t;
ScopedPointer client (
- HTTPClientBase::New (timeoutSeconds));
+ HTTPClientBase::New (Journal(), timeoutSeconds));
- client->async_get (t.get_io_service (), this,
- ParsedURL (s).url ());
+ client->async_get (t.get_io_service (), ParsedURL (s).url (),
+ beast::bind (&HTTPClientTests::handle_get, this,
+ beast::_1));
t.start ();
t.join ();
diff --git a/modules/beast_asio/http/HTTPClientType.h b/modules/beast_asio/http/HTTPClientType.h
index db7982ae0..894bbbc6a 100644
--- a/modules/beast_asio/http/HTTPClientType.h
+++ b/modules/beast_asio/http/HTTPClientType.h
@@ -20,46 +20,49 @@
#ifndef BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
+#include
+
+namespace beast {
+
class HTTPClientBase
{
public:
- struct Result
- {
- boost::system::error_code error;
- SharedPtr response;
- };
-
- class Listener
- {
- public:
- virtual void onHTTPRequestComplete (
- HTTPClientBase const& client,
- Result const& result) = 0;
- };
+ typedef boost::system::error_code error_type;
+ typedef SharedPtr value_type;
+ typedef std::pair 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 const& result () const = 0;
+ virtual result_type get (URL const& url) = 0;
- virtual Result const& get (
- URL const& url) = 0;
+ template
+ void async_get (boost::asio::io_service& io_service,
+ URL const& url, GetHandler handler)
+ {
+ abstract_async_get (io_service, url,
+ AbstractHandler (handler));
+ }
- virtual void async_get (boost::asio::io_service& io_service,
- Listener* listener,
- URL const& url) = 0;
+ virtual void abstract_async_get (boost::asio::io_service& io_service,
+ URL const& url, AbstractHandler handler) = 0;
- /** Cancel any pending asynchronous operations.
- This must be called before destroying the container if there are
- any pending asynchronous operations. This routine does nothing if
- there are no pending operations. The call will block until all
- pending i/o is canceled.
- */
- virtual void cancel () = 0;
+ /** Cancel any pending asynchronous operations. */
+ virtual void cancel() = 0;
+
+ /** Block until all asynchronous i/o completes. */
+ virtual void wait() = 0;
};
+}
+
#endif