diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj
index 1001acc0ec..3fab76e0d8 100644
--- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj
+++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj
@@ -84,11 +84,21 @@
+
+
+
+
+
+
+
+
+
+
@@ -97,7 +107,6 @@
-
@@ -350,6 +359,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -361,6 +376,54 @@
true
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
true
true
@@ -373,12 +436,6 @@
true
true
-
- true
- true
- true
- true
-
true
true
diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters
index 7c2f61e5db..a4a31b7aaa 100644
--- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -176,6 +176,9 @@
{c0724499-ab69-40c3-90e2-65242dbd2eaa}
+
+ {f7252567-a5bb-4be2-bbd0-c9d9b62298de}
+
@@ -989,12 +992,39 @@
beast_asio\protocol
-
- beast_asio\protocol
-
beast_core\functional
+
+ beast_asio\basics
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
@@ -1483,8 +1513,32 @@
beast_asio\protocol
-
- beast_asio\protocol
+
+ beast_asio\basics
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
+
+
+ beast_asio\http
diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.cpp b/Subtrees/beast/modules/beast_asio/beast_asio.cpp
index 4bb4c2b0d3..6301c1c2e6 100644
--- a/Subtrees/beast/modules/beast_asio/beast_asio.cpp
+++ b/Subtrees/beast/modules/beast_asio/beast_asio.cpp
@@ -28,6 +28,7 @@ namespace beast
#include "async/SharedHandler.cpp"
+#include "basics/ContentBodyBuffer.cpp"
#include "basics/PeerRole.cpp"
#include "basics/SSLContext.cpp"
@@ -37,7 +38,15 @@ namespace beast
#include "protocol/HandshakeDetectLogicPROXY.cpp"
# include "parsehttp/http_parser.h"
-#include "protocol/UniformResourceLocator.cpp"
+# include "http/HTTPParserImpl.h"
+#include "http/HTTPParser.cpp"
+#include "http/UniformResourceLocator.cpp"
+#include "http/HTTPClientType.cpp"
+#include "http/HTTPField.cpp"
+#include "http/HTTPHeaders.cpp"
+#include "http/HTTPMessage.cpp"
+#include "http/HTTPResponse.cpp"
+#include "http/HTTPVersion.cpp"
#include "tests/PeerTest.cpp"
#include "tests/TestPeerBasics.cpp"
diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.h b/Subtrees/beast/modules/beast_asio/beast_asio.h
index 5ce86e8cbb..3ff63dac6f 100644
--- a/Subtrees/beast/modules/beast_asio/beast_asio.h
+++ b/Subtrees/beast/modules/beast_asio/beast_asio.h
@@ -63,7 +63,8 @@ namespace beast
# include "async/ComposedAsyncOperation.h"
#include "async/SharedHandlerAllocator.h"
-#include "basics/BufferType.h"
+# include "basics/BufferType.h"
+#include "basics/ContentBodyBuffer.h"
#include "basics/FixedInputBuffer.h"
#include "basics/PeerRole.h"
#include "basics/SSLContext.h"
@@ -73,6 +74,15 @@ namespace beast
# include "sockets/SocketWrapper.h"
#include "sockets/SocketWrapperStrand.h"
+# include "http/HTTPVersion.h"
+# include "http/HTTPField.h"
+# include "http/HTTPHeaders.h"
+# include "http/HTTPMessage.h"
+# include "http/HTTPResponse.h"
+# include "http/HTTPParser.h"
+# include "http/UniformResourceLocator.h"
+#include "http/HTTPClientType.h"
+
# include "protocol/InputParser.h"
# include "protocol/HandshakeDetectLogic.h"
#include "protocol/HandshakeDetectLogicPROXY.h"
@@ -80,7 +90,6 @@ namespace beast
#include "protocol/HandshakeDetectLogicSSL3.h"
#include "protocol/HandshakeDetector.h"
#include "protocol/PrefilledReadStream.h"
-#include "protocol/UniformResourceLocator.h"
#include "tests/TestPeerBasics.h"
#include "tests/TestPeer.h"
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp
new file mode 100644
index 0000000000..143b19fdbe
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.cpp
@@ -0,0 +1,838 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+class HTTPClientType : public HTTPClientBase, public Uncopyable
+{
+private:
+ using HTTPClientBase::Listener;
+
+ typedef boost::system::error_code error_code;
+
+ class ListenerHandler
+ {
+ 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;
+ };
+
+public:
+ //--------------------------------------------------------------------------
+
+ HTTPClientType (
+ double timeoutSeconds,
+ std::size_t messageLimitBytes,
+ std::size_t bufferSize)
+ : m_timeoutSeconds (timeoutSeconds)
+ , m_messageLimitBytes (messageLimitBytes)
+ , m_bufferSize (bufferSize)
+ {
+ }
+
+ ~HTTPClientType ()
+ {
+ m_async_op = nullptr;
+ }
+
+ Result const& result () const
+ {
+ return m_result;
+ }
+
+ Result const& get (UniformResourceLocator const& url)
+ {
+ boost::asio::io_service io_service;
+ async_get (io_service, nullptr, url);
+ io_service.run ();
+ cancel ();
+ return result ();
+ }
+
+ //--------------------------------------------------------------------------
+
+ void async_get (boost::asio::io_service& io_service, Listener* listener,
+ UniformResourceLocator const& url)
+ {
+ async_get (io_service, url, ListenerHandler (this, listener));
+ }
+
+ // Handler signature is void(error_code)
+ //
+ template
+ void async_get (boost::asio::io_service& io_service,
+ UniformResourceLocator 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,
+ UniformResourceLocator const& url, SharedHandlerPtr handler)
+ {
+ // This automatically dispatches
+ m_async_op = new AsyncGetOp (
+ *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;
+ }
+ }
+
+private:
+ //--------------------------------------------------------------------------
+
+ /** 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
+ static Query queryFromURL (UniformResourceLocator const& url)
+ {
+ if (url.port () != 0)
+ {
+ return Query (
+ url.host().toStdString(),
+ url.port_string().toStdString(),
+ Query::numeric_service);
+ }
+
+ return Query (
+ url.host().toStdString(),
+ url.scheme().toStdString());
+ }
+
+ //--------------------------------------------------------------------------
+
+ class AsyncGetOp : public ComposedAsyncOperation
+ {
+ 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,
+ UniformResourceLocator const& url,
+ SharedHandlerPtr const& handler,
+ double timeoutSeconds,
+ std::size_t messageLimitBytes,
+ std::size_t bufferSize)
+ : ComposedAsyncOperation (sizeof (*this), handler)
+ , m_owner (owner)
+ , m_io_service (io_service)
+ , m_strand (m_io_service)
+ , m_url (url)
+ , m_handler (handler)
+ , m_timer (io_service)
+ , m_resolver (io_service)
+ , m_socket (io_service)
+ , m_context (boost::asio::ssl::context::sslv23)
+ , m_buffer (bufferSize)
+ , m_parser (HTTPParser::typeResponse)
+ , m_timer_canceled (false)
+ , m_timer_expired (false)
+ , m_messageLimitBytes (messageLimitBytes)
+ , m_bytesReceived (0)
+ {
+ m_context.set_default_verify_paths ();
+ m_context.set_options (
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::single_dh_use |
+ boost::asio::ssl::context::default_workarounds);
+ //m_context.set_verify_mode (boost::asio::ssl::verify_peer);
+
+ if (timeoutSeconds > 0)
+ {
+ m_timer.expires_from_now (
+ boost::posix_time::milliseconds (
+ long (timeoutSeconds * 1000)));
+
+ ++m_io_pending;
+ m_timer.async_wait (TimerHandler (this));
+ }
+
+ // Count as pending i/o
+ ++m_io_pending;
+ m_io_service.dispatch (
+ m_strand.wrap (StartHandler (this)));
+ }
+
+ ~AsyncGetOp ()
+ {
+ }
+
+ // Cancel all pending I/O, if any, and block until
+ // there are no more completion handler calls pending.
+ //
+ void cancel ()
+ {
+ cancel_all ();
+ m_done.wait ();
+ }
+
+ private:
+ //----------------------------------------------------------------------
+
+ // Counts a pending i/o as canceled
+ //
+ void cancel_io ()
+ {
+ bassert (m_io_pending.get () > 0);
+ if (--m_io_pending == 0)
+ m_done.signal ();
+ }
+
+ // Cancels the deadline timer.
+ //
+ void cancel_timer ()
+ {
+ m_timer_canceled = true;
+ error_code ec;
+ m_timer.cancel (ec);
+ }
+
+ // Called to notify the original handler the operation is complete.
+ //
+ void complete (error_code const& ec)
+ {
+ m_owner.m_result.error = ec;
+
+ cancel_timer ();
+
+ bassert (m_io_pending.get () > 0);
+
+ cancel_io ();
+
+ // 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)
+ {
+ cancel_io ();
+ return true;
+ }
+ else if (ec != 0 && ec != boost::asio::error::eof)
+ {
+ complete (ec);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Cancels/closes all i/o objects.
+ //
+ void cancel_all ()
+ {
+ cancel_timer ();
+ m_resolver.cancel ();
+ error_code ec;
+ m_socket.close (ec);
+ }
+
+ // Called when the deadline timer expires or is canceled.
+ //
+ void timerCompletion (error_code ec)
+ {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ bassert (m_timer_canceled);
+ return cancel_io ();
+ }
+
+ check_invariant (ec == 0);
+
+ // Handle the case where the timer completion has already
+ // been queued for dispatch but we have finished the operation
+ // and queued the completion handler for dispatch.
+ //
+ if (! m_timer_canceled)
+ {
+ m_timer_expired = true;
+
+ ec = error_code (boost::asio::error::timed_out,
+ boost::asio::error::get_system_category ());
+
+ complete (ec);
+
+ io_complete (ec);
+
+ m_resolver.cancel ();
+ m_socket.close (ec);
+ }
+ else
+ {
+ cancel_io ();
+ }
+ }
+
+ //----------------------------------------------------------------------
+
+ struct StartHandler : SharedHandlerPtr
+ {
+ explicit StartHandler (AsyncGetOp* owner)
+ : SharedHandlerPtr (owner)
+ , m_owner (owner)
+ {
+ }
+
+ 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;
+ };
+
+ //----------------------------------------------------------------------
+
+ 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 ());
+ }
+
+ //----------------------------------------------------------------------
+
+ void start_complete ()
+ {
+ query q (queryFromURL (m_url));
+ m_resolver.async_resolve (q,
+ m_strand.wrap (ResolveHandler (this)));
+ }
+
+ void resolve_complete (error_code ec, iterator iter)
+ {
+ if (io_complete (ec))
+ return;
+
+ resolver_entry const entry (*iter);
+ m_socket.async_connect (entry.endpoint (),
+ m_strand.wrap (ConnectHandler (this)));
+ }
+
+ void connect_complete (error_code ec)
+ {
+ if (io_complete (ec))
+ return;
+
+ if (m_url.scheme () == "https")
+ {
+ typedef boost::asio::ssl::stream ssl_stream;
+ m_stream = new SocketWrapper (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 (
+ Socket::client, HandshakeHandler (this));
+ return;
+ }
+
+ m_stream = new SocketWrapper (m_socket);
+ handshake_complete (ec);
+ }
+
+ void handshake_complete (error_code ec)
+ {
+ if (io_complete (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;
+
+ async_read_some ();
+ }
+
+ void write_complete (error_code ec, std::size_t)
+ {
+ if (io_complete (ec))
+ return;
+
+ if (! m_stream->needs_handshake ())
+ {
+ m_socket.shutdown (socket::shutdown_send, ec);
+ if (ec != 0)
+ return complete (ec);
+ }
+
+ // deduct one i/o since we aren't issuing any new one
+ cancel_io ();
+ }
+
+ void read_complete (error_code ec, std::size_t bytes_transferred)
+ {
+ m_bytesReceived += bytes_transferred;
+ if (m_bytesReceived > m_messageLimitBytes)
+ ec = message_limit_error ();
+
+ if (io_complete (ec))
+ return;
+
+ std::size_t const bytes_parsed (m_parser.process (
+ m_buffer.getData (), bytes_transferred));
+
+ if (m_parser.error ())
+ {
+ parse_error ();
+ return;
+ }
+
+ if (bytes_parsed != bytes_transferred)
+ {
+ // VFALCO TODO put an appropriate error in ec
+ ec = error_code (
+ boost::system::errc::invalid_argument,
+ boost::system::system_category ());
+ return complete (ec);
+ }
+
+ 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));
+ else
+ shutdown_complete (error_code ());
+ return;
+ }
+
+ async_read_some ();
+ }
+
+ void shutdown_complete (error_code ec)
+ {
+ if (io_complete (ec))
+ return;
+
+ m_owner.m_result.response = m_parser.response ();
+ if (ec == boost::asio::error::eof)
+ ec = error_code ();
+
+ return complete (ec);
+ }
+
+ private:
+ WaitableEvent m_done;
+ Atomic m_io_pending;
+ HTTPClientType& m_owner;
+ boost::asio::io_service& m_io_service;
+ boost::asio::io_service& m_strand;
+ UniformResourceLocator 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_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 (
+ double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
+{
+ ScopedPointer object (new HTTPClientType
+ (timeoutSeconds, messageLimitBytes, bufferSize));
+ return object.release ();
+}
+
+//------------------------------------------------------------------------------
+
+class HTTPClientTests
+ : public UnitTest
+ , public HTTPClientBase::Listener
+{
+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 log (HTTPMessage const& m)
+ {
+ for (std::size_t i = 0; i < m.headers().size(); ++i)
+ {
+ HTTPField const f (m.headers()[i]);
+ String s;
+ s = "[ '" + f.name() +
+ "' , '" + f.value() + "' ]";
+ logMessage (s);
+ }
+ }
+
+ void log (HTTPClientBase::Result const& result)
+ {
+ if (result.error != 0)
+ {
+ logMessage (String (
+ "HTTPClient error: '" + result.error.message() + "'"));
+ }
+ else if (! result.response.empty ())
+ {
+ logMessage (String ("Status: ") +
+ String::fromNumber (result.response->status()));
+
+ log (*result.response);
+ }
+ else
+ {
+ logMessage ("HTTPClient: no response");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+
+ void onHTTPRequestComplete (
+ HTTPClientBase const&, HTTPClientBase::Result const& result)
+ {
+ log (result);
+ }
+
+ void testSync (String const& s, double timeoutSeconds)
+ {
+ ScopedPointer client (
+ HTTPClientBase::New (timeoutSeconds));
+
+ log (client->get (ParsedURL (s).url ()));
+ }
+
+ void testAsync (String const& s, double timeoutSeconds)
+ {
+ IoServiceThread t;
+ ScopedPointer client (
+ HTTPClientBase::New (timeoutSeconds));
+
+ client->async_get (t.get_io_service (), this,
+ ParsedURL (s).url ());
+
+ t.start ();
+ t.join ();
+ }
+
+ //--------------------------------------------------------------------------
+
+ void runTest ()
+ {
+ beginTestCase ("HTTPClient::get");
+
+ 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 ();
+ }
+
+ HTTPClientTests () : UnitTest ("HttpClient", "beast", runManual)
+ {
+ }
+};
+
+static HTTPClientTests httpClientTests;
+
+
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h
new file mode 100644
index 0000000000..5922813f38
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPClientType.h
@@ -0,0 +1,65 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPCLIENTTYPE_H_INCLUDED
+#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
+
+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;
+ };
+
+ static HTTPClientBase* New (
+ double timeoutSeconds = 30,
+ std::size_t messageLimitBytes = 256 * 1024,
+ std::size_t bufferSize = 16 * 1024);
+
+ virtual ~HTTPClientBase () { }
+
+ virtual Result const& result () const = 0;
+
+ virtual Result const& get (
+ UniformResourceLocator const& url) = 0;
+
+ virtual void async_get (boost::asio::io_service& io_service,
+ Listener* listener,
+ UniformResourceLocator const& url) = 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;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp
new file mode 100644
index 0000000000..d026a55bcf
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPField.cpp
@@ -0,0 +1,51 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPField::HTTPField ()
+{
+}
+
+HTTPField::HTTPField (String name_, String value_)
+ : m_name (name_)
+ , m_value (value_)
+{
+}
+
+HTTPField::HTTPField (HTTPField const& other)
+ : m_name (other.m_name)
+ , m_value (other.m_value)
+{
+}
+
+HTTPField& HTTPField::operator= (HTTPField const& other)
+{
+ m_name = other.m_name;
+ m_value = other.m_value;
+ return *this;
+}
+
+String HTTPField::name () const
+{
+ return m_name;
+}
+
+String HTTPField::value () const
+{
+ return m_value;
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPField.h b/Subtrees/beast/modules/beast_asio/http/HTTPField.h
new file mode 100644
index 0000000000..048f71c1ea
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPField.h
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPFIELD_H_INCLUDED
+#define BEAST_ASIO_HTTPFIELD_H_INCLUDED
+
+/** A single header.
+ The header is a field/value pair.
+ Time complexity of copies is constant.
+*/
+class HTTPField
+{
+public:
+ HTTPField ();
+ HTTPField (String name_, String value_);
+ HTTPField (HTTPField const& other);
+ HTTPField& operator= (HTTPField const& other);
+ String name () const;
+ String value () const;
+
+private:
+ String m_name;
+ String m_value;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp
new file mode 100644
index 0000000000..f28f5113f2
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.cpp
@@ -0,0 +1,74 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPHeaders::HTTPHeaders ()
+{
+}
+
+HTTPHeaders::HTTPHeaders (StringPairArray& fields)
+{
+ m_fields.swapWith (fields);
+}
+
+HTTPHeaders::HTTPHeaders (StringPairArray const& fields)
+ : m_fields (fields)
+{
+}
+
+HTTPHeaders::HTTPHeaders (HTTPHeaders const& other)
+ : m_fields (other.m_fields)
+{
+}
+
+HTTPHeaders& HTTPHeaders::operator= (HTTPHeaders const& other)
+{
+ m_fields = other.m_fields;
+ return *this;
+}
+
+bool HTTPHeaders::empty () const
+{
+ return m_fields.size () == 0;
+}
+
+std::size_t HTTPHeaders::size () const
+{
+ return m_fields.size ();
+}
+
+HTTPField HTTPHeaders::at (std::size_t index) const
+{
+ return HTTPField (m_fields.getAllKeys () [index],
+ m_fields.getAllValues () [index]);
+}
+
+HTTPField HTTPHeaders::operator[] (std::size_t index) const
+{
+ return at (index);
+}
+
+String HTTPHeaders::get (String const& field) const
+{
+ return m_fields [field];
+}
+
+String HTTPHeaders::operator[] (String const& field) const
+{
+ return get (field);
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h
new file mode 100644
index 0000000000..d2a1a4cad1
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPHeaders.h
@@ -0,0 +1,68 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPHEADERS_H_INCLUDED
+#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED
+
+/** A set of HTTP headers. */
+class HTTPHeaders
+{
+public:
+ /** Construct an empty set of headers. */
+ HTTPHeaders ();
+
+ /** Construct headers taking ownership of a field array.
+ The callers value is overwritten.
+ */
+ HTTPHeaders (StringPairArray& fields);
+
+ /** Construct a copy of headers from an array.*/
+ HTTPHeaders (StringPairArray const& fields);
+
+ /** Construct a copy of headers. */
+ HTTPHeaders (HTTPHeaders const& other);
+
+ /** Assign a copy of headers. */
+ HTTPHeaders& operator= (HTTPHeaders const& other);
+
+ /** Returns `true` if the container is empty. */
+ bool empty () const;
+
+ /** Returns the number of fields in the container. */
+ std::size_t size () const;
+
+ /** Random access to fields by index. */
+ /** @{ */
+ HTTPField at (std::size_t index) const;
+ HTTPField operator[] (std::size_t index) const;
+ /** @} */
+
+ /** Associative access to fields by name.
+ If the field is not present, an empty string is returned.
+ */
+ /** @{ */
+ String get (String const& field) const;
+ String operator[] (String const& field) const;
+ /** @} */
+
+private:
+ StringPairArray m_fields;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp
new file mode 100644
index 0000000000..aeb743843e
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.cpp
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPMessage::HTTPMessage (HTTPVersion const& version_,
+ StringPairArray& fields,
+ ContentBodyBuffer& body)
+ : m_version (version_)
+ , m_headers (fields)
+{
+ m_body.swapWith (body);
+}
+
+HTTPVersion const& HTTPMessage::version () const
+{
+ return m_version;
+}
+
+HTTPHeaders const& HTTPMessage::headers () const
+{
+ return m_headers;
+}
+
+ContentBodyBuffer const& HTTPMessage::body () const
+{
+ return m_body;
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h
new file mode 100644
index 0000000000..549d7d43c1
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPMessage.h
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPMESSAGE_H_INCLUDED
+#define BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
+
+/** A complete HTTP message.
+
+ This provides the information common to all HTTP messages, including
+ the version, content body, and headers.
+ Derived classes provide the request or response specific data.
+
+ Because a single HTTP message can be a fairly expensive object to
+ make copies of, this is a SharedObject.
+
+ @see HTTPRequest, HTTPResponse
+*/
+class HTTPMessage : public SharedObject
+{
+public:
+ /** Construct the common HTTP message parts from values.
+ Ownership of the fields and body parameters are
+ transferred from the caller.
+ */
+ HTTPMessage (HTTPVersion const& version_,
+ StringPairArray& fields,
+ ContentBodyBuffer& body);
+
+ /** Returns the HTTP version of this message. */
+ HTTPVersion const& version () const;
+
+ /** Returns the set of HTTP headers associated with this message. */
+ HTTPHeaders const& headers () const;
+
+ /** Returns the content-body. */
+ ContentBodyBuffer const& body () const;
+
+private:
+ HTTPVersion m_version;
+ HTTPHeaders m_headers;
+ ContentBodyBuffer m_body;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp
new file mode 100644
index 0000000000..5ca1c9ed83
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPParser.cpp
@@ -0,0 +1,79 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPParser::HTTPParser (Type type)
+ : m_type (type)
+ , m_impl (new HTTPParserImpl (
+ (type == typeResponse) ? HTTP_RESPONSE : HTTP_REQUEST))
+{
+}
+
+HTTPParser::~HTTPParser ()
+{
+}
+
+unsigned char HTTPParser::error () const
+{
+ return m_impl->http_errno ();
+}
+
+String HTTPParser::message () const
+{
+ return m_impl->http_errno_message ();
+}
+
+std::size_t HTTPParser::process (void const* buf, std::size_t bytes)
+{
+ std::size_t const bytes_used (m_impl->process (buf, bytes));
+
+ if (m_impl->finished ())
+ {
+ if (m_type == typeResponse)
+ {
+ m_response = new HTTPResponse (
+ m_impl->version (),
+ m_impl->fields (),
+ m_impl->body (),
+ m_impl->status_code ());
+ }
+ else
+ {
+ // m_request = new HTTPRequest (
+ }
+ }
+
+ return bytes_used;
+}
+
+void HTTPParser::process_eof ()
+{
+ m_impl->process_eof ();
+}
+
+bool HTTPParser::finished () const
+{
+ return m_impl->finished();
+}
+
+SharedPtr const& HTTPParser::response ()
+{
+ bassert (m_type == typeResponse);
+
+ return m_response;
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParser.h b/Subtrees/beast/modules/beast_asio/http/HTTPParser.h
new file mode 100644
index 0000000000..d6e3a287e2
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPParser.h
@@ -0,0 +1,74 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPPARSER_H_INCLUDED
+#define BEAST_ASIO_HTTPPARSER_H_INCLUDED
+
+class HTTPParserImpl;
+
+/** A parser for HTTPRequest and HTTPResponse objects. */
+class HTTPParser
+{
+public:
+ enum Type
+ {
+ typeRequest,
+ typeResponse
+ };
+
+ /** Construct a new parser for the specified HTTPMessage type. */
+ explicit HTTPParser (Type type);
+
+ /** Destroy the parser. */
+ ~HTTPParser ();
+
+ /** Returns a non zero error code if parsing fails. */
+ unsigned char error () const;
+
+ /** Returns the error message text when error is non zero. */
+ String message () const;
+
+ /** Parse the buffer and return the amount used.
+ Typically it is an error when this returns less than
+ the amount passed in.
+ */
+ std::size_t process (void const* buf, std::size_t bytes);
+
+ /** Notify the parser that eof was received.
+ */
+ void process_eof ();
+
+ /** Returns `true` when parsing is successful and complete. */
+ bool finished () const;
+
+ /** Return the HTTPResponse object produce from the parsing.
+ Only valid after finished returns `true`.
+ */
+ SharedPtr const& response ();
+
+ //SharedPtr const& request ();
+
+private:
+ Type m_type;
+ ScopedPointer m_impl;
+ SharedPtr m_response;
+ //SharedPtr m_request;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h b/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h
new file mode 100644
index 0000000000..c01fd58114
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPParserImpl.h
@@ -0,0 +1,256 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPPARSERIMPL_H_INCLUDED
+#define BEAST_HTTPPARSERIMPL_H_INCLUDED
+
+class HTTPParserImpl
+{
+public:
+ enum
+ {
+ stringReservation = 256
+ };
+
+ explicit HTTPParserImpl (enum http_parser_type type)
+ : m_finished (false)
+ , m_was_value (false)
+ {
+ m_settings.on_message_begin = &HTTPParserImpl::on_message_begin;
+ m_settings.on_url = &HTTPParserImpl::on_url;
+ m_settings.on_status_complete = &HTTPParserImpl::on_status_complete;
+ m_settings.on_header_field = &HTTPParserImpl::on_header_field;
+ m_settings.on_header_value = &HTTPParserImpl::on_header_value;
+ m_settings.on_headers_complete = &HTTPParserImpl::on_headers_complete;
+ m_settings.on_body = &HTTPParserImpl::on_body;
+ m_settings.on_message_complete = &HTTPParserImpl::on_message_complete;
+
+ m_field.reserve (stringReservation);
+ m_value.reserve (stringReservation);
+
+ http_parser_init (&m_parser, type);
+ m_parser.data = this;
+ }
+
+ ~HTTPParserImpl ()
+ {
+ }
+
+ unsigned char error () const
+ {
+ return m_parser.http_errno;
+ }
+
+ String message () const
+ {
+ return String (http_errno_name (static_cast <
+ enum http_errno> (m_parser.http_errno)));
+ }
+
+ std::size_t process (void const* buf, std::size_t bytes)
+ {
+ return http_parser_execute (&m_parser,
+ &m_settings, static_cast (buf), bytes);
+ }
+
+ void process_eof ()
+ {
+ http_parser_execute (&m_parser, &m_settings, nullptr, 0);
+ }
+
+ bool finished () const
+ {
+ return m_finished;
+ }
+
+ HTTPVersion version () const
+ {
+ return HTTPVersion (
+ m_parser.http_major, m_parser.http_minor);
+ }
+
+ // Only for HTTPResponse!
+ unsigned short status_code () const
+ {
+ return m_parser.status_code;
+ }
+
+ // Only for HTTPRequest!
+ unsigned char method () const
+ {
+ return m_parser.method;
+ }
+
+ unsigned char http_errno () const
+ {
+ return m_parser.http_errno;
+ }
+
+ String http_errno_message () const
+ {
+ return String (http_errno_name (
+ static_cast (
+ m_parser.http_errno)));
+ }
+
+ bool upgrade () const
+ {
+ return m_parser.upgrade != 0;
+ }
+
+ StringPairArray& fields ()
+ {
+ return m_fields;
+ }
+
+ ContentBodyBuffer& body ()
+ {
+ return m_body;
+ }
+
+private:
+ void addFieldValue ()
+ {
+ if (m_field.size () > 0 && m_value.size () > 0)
+ m_fields.set (m_field, m_value);
+ m_field.resize (0);
+ m_value.resize (0);
+ }
+
+ int onMessageBegin ()
+ {
+ int ec (0);
+ return ec;
+ }
+
+ int onUrl (char const*, std::size_t)
+ {
+ int ec (0);
+ // This is for HTTP Request
+ return ec;
+ }
+
+ int onStatusComplete ()
+ {
+ int ec (0);
+ return ec;
+ }
+
+ int onHeaderField (char const* at, std::size_t length)
+ {
+ int ec (0);
+ if (m_was_value)
+ {
+ addFieldValue ();
+ m_was_value = false;
+ }
+ m_field.append (at, length);
+ return ec;
+ }
+
+ int onHeaderValue (char const* at, std::size_t length)
+ {
+ int ec (0);
+ m_value.append (at, length);
+ m_was_value = true;
+ return ec;
+ }
+
+ int onHeadersComplete ()
+ {
+ int ec (0);
+ addFieldValue ();
+ return ec;
+ }
+
+ int onBody (char const* at, std::size_t length)
+ {
+ m_body.commit (boost::asio::buffer_copy (m_body.prepare (length),
+ boost::asio::buffer (at, length)));
+ return 0;
+ }
+
+ int onMessageComplete ()
+ {
+ int ec (0);
+ m_finished = true;
+ return ec;
+ }
+
+private:
+ static int on_message_begin (http_parser* parser)
+ {
+ return static_cast (parser->data)->
+ onMessageBegin ();
+ }
+
+ static int on_url (http_parser* parser, const char *at, size_t length)
+ {
+ return static_cast (parser->data)->
+ onUrl (at, length);
+ }
+
+ static int on_status_complete (http_parser* parser)
+ {
+ return static_cast (parser->data)->
+ onStatusComplete ();
+ }
+
+ static int on_header_field (http_parser* parser, const char *at, size_t length)
+ {
+ return static_cast (parser->data)->
+ onHeaderField (at, length);
+ }
+
+ static int on_header_value (http_parser* parser, const char *at, size_t length)
+ {
+ return static_cast (parser->data)->
+ onHeaderValue (at, length);
+ }
+
+ static int on_headers_complete (http_parser* parser)
+ {
+ return static_cast (parser->data)->
+ onHeadersComplete ();
+ }
+
+ static int on_body (http_parser* parser, const char *at, size_t length)
+ {
+ return static_cast (parser->data)->
+ onBody (at, length);
+ }
+
+ static int on_message_complete (http_parser* parser)
+ {
+ return static_cast (parser->data)->
+ onMessageComplete ();
+ }
+
+private:
+ bool m_finished;
+ http_parser_settings m_settings;
+ http_parser m_parser;
+ StringPairArray m_fields;
+ bool m_was_value;
+ std::string m_field;
+ std::string m_value;
+ ContentBodyBuffer m_body;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp
new file mode 100644
index 0000000000..7396127b5c
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.cpp
@@ -0,0 +1,33 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPResponse::HTTPResponse (
+ HTTPVersion const& version_,
+ StringPairArray& fields,
+ ContentBodyBuffer& body,
+ unsigned short status_)
+ : HTTPMessage (version_, fields, body)
+ , m_status (status_)
+{
+}
+
+unsigned short HTTPResponse::status () const
+{
+ return m_status;
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h
new file mode 100644
index 0000000000..bb3f89cb11
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPResponse.h
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPRESPONSE_H_INCLUDED
+#define BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
+
+class HTTPResponse : public HTTPMessage
+{
+public:
+ /** Construct a complete response from values.
+ Ownership of the fields and body parameters are
+ transferred from the caller.
+ */
+ HTTPResponse (
+ HTTPVersion const& version_,
+ StringPairArray& fields,
+ ContentBodyBuffer& body,
+ unsigned short status_);
+
+ unsigned short status () const;
+
+private:
+ unsigned short m_status;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp
new file mode 100644
index 0000000000..7fcf4dc5ad
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.cpp
@@ -0,0 +1,93 @@
+//------------------------------------------------------------------------------
+/*
+ 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.
+*/
+//==============================================================================
+
+HTTPVersion::HTTPVersion ()
+ : m_major (0)
+ , m_minor (0)
+{
+}
+
+HTTPVersion::HTTPVersion (unsigned short major_, unsigned short minor_)
+ : m_major (major_)
+ , m_minor (minor_)
+{
+}
+
+HTTPVersion::HTTPVersion (HTTPVersion const& other)
+ : m_major (other.m_major)
+ , m_minor (other.m_minor)
+{
+}
+
+HTTPVersion& HTTPVersion::operator= (HTTPVersion const& other)
+{
+ m_major = other.m_major;
+ m_minor = other.m_minor;
+ return *this;
+}
+
+String HTTPVersion::toString () const
+{
+ return String::fromNumber (major ()) + "." +
+ String::fromNumber (minor ());
+}
+
+unsigned short HTTPVersion::major () const
+{
+ return m_major;
+}
+
+unsigned short HTTPVersion::minor () const
+{
+ return m_minor;
+}
+
+bool HTTPVersion::operator== (HTTPVersion const& rhs) const
+{
+ return (m_major == rhs.m_major) && (m_minor == rhs.m_minor);
+}
+
+bool HTTPVersion::operator!= (HTTPVersion const& rhs) const
+{
+ return (m_major != rhs.m_major) || (m_minor != rhs.m_minor);
+}
+
+bool HTTPVersion::operator> (HTTPVersion const& rhs) const
+{
+ return (m_major > rhs.m_major) ||
+ ((m_major == rhs.m_major) && (m_minor > rhs.m_minor));
+}
+
+bool HTTPVersion::operator>= (HTTPVersion const& rhs) const
+{
+ return (m_major > rhs.m_major) ||
+ ((m_major == rhs.m_major) && (m_minor >= rhs.m_minor));
+}
+
+bool HTTPVersion::operator< (HTTPVersion const& rhs) const
+{
+ return (m_major < rhs.m_major) ||
+ ((m_major == rhs.m_major) && (m_minor < rhs.m_minor));
+}
+
+bool HTTPVersion::operator<= (HTTPVersion const& rhs) const
+{
+ return (m_major < rhs.m_major) ||
+ ((m_major == rhs.m_major) && (m_minor <= rhs.m_minor));
+}
diff --git a/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h
new file mode 100644
index 0000000000..c3e2a196c3
--- /dev/null
+++ b/Subtrees/beast/modules/beast_asio/http/HTTPVersion.h
@@ -0,0 +1,46 @@
+//------------------------------------------------------------------------------
+/*
+ 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_HTTPVERSION_H_INCLUDED
+#define BEAST_ASIO_HTTPVERSION_H_INCLUDED
+
+/** The HTTP version. This is the major.minor version number. */
+class HTTPVersion
+{
+public:
+ HTTPVersion ();
+ HTTPVersion (unsigned short major_, unsigned short minor_);
+ HTTPVersion (HTTPVersion const& other);
+ HTTPVersion& operator= (HTTPVersion const& other);
+ String toString () const;
+ unsigned short major () const;
+ unsigned short minor () const;
+ bool operator== (HTTPVersion const& rhs) const;
+ bool operator!= (HTTPVersion const& rhs) const;
+ bool operator> (HTTPVersion const& rhs) const;
+ bool operator>= (HTTPVersion const& rhs) const;
+ bool operator< (HTTPVersion const& rhs) const;
+ bool operator<= (HTTPVersion const& rhs) const;
+
+private:
+ unsigned short m_major;
+ unsigned short m_minor;;
+};
+
+#endif
diff --git a/Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.cpp b/Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.cpp
similarity index 100%
rename from Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.cpp
rename to Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.cpp
diff --git a/Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.h b/Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.h
similarity index 100%
rename from Subtrees/beast/modules/beast_asio/protocol/UniformResourceLocator.h
rename to Subtrees/beast/modules/beast_asio/http/UniformResourceLocator.h