Add HTTPClientType and HTTPMessage related helpers

This commit is contained in:
Vinnie Falco
2013-09-06 14:44:01 -07:00
parent 4a30b259b2
commit 1d1587c2ac
21 changed files with 2007 additions and 15 deletions

View File

@@ -84,11 +84,21 @@
<ClInclude Include="..\..\modules\beast_asio\async\SharedHandlerAllocator.h" />
<ClInclude Include="..\..\modules\beast_asio\async\SharedHandlerPtr.h" />
<ClInclude Include="..\..\modules\beast_asio\async\SharedHandlerType.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\ContentBodyBuffer.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\BufferType.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\FixedInputBuffer.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\PeerRole.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\SSLContext.h" />
<ClInclude Include="..\..\modules\beast_asio\beast_asio.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPClientType.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPField.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPHeaders.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPMessage.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPParserImpl.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPParser.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPResponse.h" />
<ClInclude Include="..\..\modules\beast_asio\http\HTTPVersion.h" />
<ClInclude Include="..\..\modules\beast_asio\http\UniformResourceLocator.h" />
<ClInclude Include="..\..\modules\beast_asio\parsehttp\http_parser.h" />
<ClInclude Include="..\..\modules\beast_asio\protocol\HandshakeDetectLogic.h" />
<ClInclude Include="..\..\modules\beast_asio\protocol\HandshakeDetectLogicPROXY.h" />
@@ -97,7 +107,6 @@
<ClInclude Include="..\..\modules\beast_asio\protocol\HandshakeDetector.h" />
<ClInclude Include="..\..\modules\beast_asio\protocol\InputParser.h" />
<ClInclude Include="..\..\modules\beast_asio\protocol\PrefilledReadStream.h" />
<ClInclude Include="..\..\modules\beast_asio\protocol\UniformResourceLocator.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\Socket.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\SocketBase.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\SocketWrapper.h" />
@@ -350,6 +359,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\basics\ContentBodyBuffer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\basics\PeerRole.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -361,6 +376,54 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\beast_asio.cpp" />
<ClCompile Include="..\..\modules\beast_asio\http\HTTPClientType.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPField.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPHeaders.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPMessage.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPParser.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPResponse.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPVersion.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\UniformResourceLocator.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\parsehttp\http_parser.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -373,12 +436,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\protocol\UniformResourceLocator.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\sockets\Socket.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>

View File

@@ -176,6 +176,9 @@
<Filter Include="beast_asio\protocol">
<UniqueIdentifier>{c0724499-ab69-40c3-90e2-65242dbd2eaa}</UniqueIdentifier>
</Filter>
<Filter Include="beast_asio\http">
<UniqueIdentifier>{f7252567-a5bb-4be2-bbd0-c9d9b62298de}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -989,12 +992,39 @@
<ClInclude Include="..\..\modules\beast_asio\protocol\PrefilledReadStream.h">
<Filter>beast_asio\protocol</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\protocol\UniformResourceLocator.h">
<Filter>beast_asio\protocol</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\functional\SharedFunction.h">
<Filter>beast_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\basics\ContentBodyBuffer.h">
<Filter>beast_asio\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPResponse.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPClientType.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPMessage.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPVersion.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPField.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPHeaders.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPParser.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPParserImpl.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\UniformResourceLocator.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
@@ -1483,8 +1513,32 @@
<ClCompile Include="..\..\modules\beast_asio\protocol\HandshakeDetectLogicPROXY.cpp">
<Filter>beast_asio\protocol</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\protocol\UniformResourceLocator.cpp">
<Filter>beast_asio\protocol</Filter>
<ClCompile Include="..\..\modules\beast_asio\basics\ContentBodyBuffer.cpp">
<Filter>beast_asio\basics</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPResponse.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPClientType.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPMessage.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPVersion.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPField.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPHeaders.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\HTTPParser.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\http\UniformResourceLocator.cpp">
<Filter>beast_asio\http</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>

View File

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

View File

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

View File

@@ -0,0 +1,838 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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 <typename Handler>
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 <typename Query>
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 <query> (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 <socket&> ssl_stream;
m_stream = new SocketWrapper <ssl_stream> (m_socket, m_context);
/*
m_stream->set_verify_mode (
boost::asio::ssl::verify_peer |
boost::asio::ssl::verify_fail_if_no_peer_cert);
*/
m_stream->async_handshake (
Socket::client, HandshakeHandler (this));
return;
}
m_stream = new SocketWrapper <socket&> (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 <int> 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 <Socket> 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 <AsyncGetOp> m_async_op;
Result m_result;
};
//------------------------------------------------------------------------------
HTTPClientBase* HTTPClientBase::New (
double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
{
ScopedPointer <HTTPClientBase> 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 <HTTPClientBase> client (
HTTPClientBase::New (timeoutSeconds));
log (client->get (ParsedURL (s).url ()));
}
void testAsync (String const& s, double timeoutSeconds)
{
IoServiceThread t;
ScopedPointer <HTTPClientBase> 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;

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
class HTTPClientBase
{
public:
struct Result
{
boost::system::error_code error;
SharedPtr <HTTPResponse> 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

View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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;
}

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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

View File

@@ -0,0 +1,74 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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);
}

View File

@@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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;
}

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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 <HTTPResponse> const& HTTPParser::response ()
{
bassert (m_type == typeResponse);
return m_response;
}

View File

@@ -0,0 +1,74 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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 <HTTPResponse> const& response ();
//SharedPtr <HTTPRequest> const& request ();
private:
Type m_type;
ScopedPointer <HTTPParserImpl> m_impl;
SharedPtr <HTTPResponse> m_response;
//SharedPtr <HTTPRequest> m_request;
};
#endif

View File

@@ -0,0 +1,256 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_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 <char const*> (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 <enum http_errno> (
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 <HTTPParserImpl*> (parser->data)->
onMessageBegin ();
}
static int on_url (http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onUrl (at, length);
}
static int on_status_complete (http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onStatusComplete ();
}
static int on_header_field (http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderField (at, length);
}
static int on_header_value (http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderValue (at, length);
}
static int on_headers_complete (http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeadersComplete ();
}
static int on_body (http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onBody (at, length);
}
static int on_message_complete (http_parser* parser)
{
return static_cast <HTTPParserImpl*> (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

View File

@@ -0,0 +1,33 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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;
}

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
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));
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_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