New http::client_session for making requests:

- Add 10,000 popular URL data set for unit tests
This commit is contained in:
Vinnie Falco
2014-03-19 09:28:19 -07:00
parent 6e8230e1fb
commit bfa8dec6f6
16 changed files with 11831 additions and 16 deletions

View File

@@ -70,7 +70,6 @@
<None Include="..\..\scripts\compile.sh" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\BeastConfig.h" />
<ClInclude Include="..\..\beast\Arithmetic.h" />
<ClInclude Include="..\..\beast\asio\abstract_socket.h" />
<ClInclude Include="..\..\beast\asio\bind_handler.h" />
@@ -150,10 +149,15 @@
<ClInclude Include="..\..\beast\cxx14\utility.h" />
<ClInclude Include="..\..\beast\HeapBlock.h" />
<ClInclude Include="..\..\beast\http\basic_message.h" />
<ClInclude Include="..\..\beast\http\basic_url.h" />
<ClInclude Include="..\..\beast\http\client_session.h" />
<ClInclude Include="..\..\beast\http\detail\header_traits.h" />
<ClInclude Include="..\..\beast\http\get.h" />
<ClInclude Include="..\..\beast\http\impl\http-parser\http_parser.h" />
<ClInclude Include="..\..\beast\http\impl\joyent_parser.h" />
<ClInclude Include="..\..\beast\http\ParsedURL.h" />
<ClInclude Include="..\..\beast\http\raw_parser.h" />
<ClInclude Include="..\..\beast\http\tests\urls_large_data.h" />
<ClInclude Include="..\..\beast\http\URL.h" />
<ClInclude Include="..\..\beast\Insight.h" />
<ClInclude Include="..\..\beast\insight\Base.h" />
@@ -257,6 +261,7 @@
<ClInclude Include="..\..\beast\utility\type_name.h" />
<ClInclude Include="..\..\beast\utility\zero.h" />
<ClInclude Include="..\..\beast\Version.h" />
<ClInclude Include="..\..\BeastConfig.h" />
<ClInclude Include="..\..\modules\beast_asio\async\AsyncObject.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\FixedInputBuffer.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\PeerRole.h" />
@@ -525,6 +530,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\http\HTTP.unity.cpp" />
<ClCompile Include="..\..\beast\http\impl\basic_url.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="..\..\beast\http\impl\get.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="..\..\beast\http\impl\raw_parser.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -573,7 +590,31 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\ParsedURL.test.cpp">
<ClCompile Include="..\..\beast\http\tests\basic_url.test.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="..\..\beast\http\tests\basic_message.test.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="..\..\beast\http\tests\client_session.test.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="..\..\beast\http\tests\ParsedURL.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="..\..\beast\http\tests\urls_large_data.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>

View File

@@ -274,6 +274,12 @@
<Filter Include="beast\streams">
<UniqueIdentifier>{899ea9a6-1969-4cde-b26d-8ad60acebfa4}</UniqueIdentifier>
</Filter>
<Filter Include="beast\http\tests">
<UniqueIdentifier>{f95a83a1-5d46-48f9-9877-1d04a525b18e}</UniqueIdentifier>
</Filter>
<Filter Include="beast\http\detail">
<UniqueIdentifier>{7bf4f91a-a7ee-4095-9be3-c1627b8adf02}</UniqueIdentifier>
</Filter>
<Filter Include="beast\utility\tests">
<UniqueIdentifier>{3c58ba5e-1855-4865-8a9f-c0afd5014e74}</UniqueIdentifier>
</Filter>
@@ -1114,11 +1120,14 @@
<ClInclude Include="..\..\beast\streams\abstract_ostream.h">
<Filter>beast\streams</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\streams\basic_abstract_ostream.h">
<Filter>beast\streams</Filter>
<ClInclude Include="..\..\beast\http\client_session.h">
<Filter>beast\http</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\streams\basic_scoped_ostream.h">
<Filter>beast\streams</Filter>
<ClInclude Include="..\..\beast\http\tests\urls_large_data.h">
<Filter>beast\http\tests</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\http\detail\header_traits.h">
<Filter>beast\http\detail</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\utility\maybe_const.h">
<Filter>beast\utility</Filter>
@@ -1210,6 +1219,18 @@
<ClInclude Include="..\..\beast\utility\ci_char_traits.h">
<Filter>beast\utility</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\streams\basic_scoped_ostream.h">
<Filter>beast\streams</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\streams\basic_abstract_ostream.h">
<Filter>beast\streams</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\http\basic_url.h">
<Filter>beast\http</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\http\get.h">
<Filter>beast\http</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\files\DirectoryIterator.cpp">
@@ -1446,9 +1467,6 @@
<ClCompile Include="..\..\beast\http\impl\URL.cpp">
<Filter>beast\http\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\impl\ParsedURL.cpp">
<Filter>beast\http\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\crypto\impl\sha2\sha2.c">
<Filter>beast\crypto\impl\sha2</Filter>
</ClCompile>
@@ -1593,15 +1611,21 @@
<ClCompile Include="..\..\beast\chrono\impl\chrono_io.cpp">
<Filter>beast\chrono\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\ParsedURL.test.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\net\tests\IPEndpoint.test.cpp">
<Filter>beast\net\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\streams\tests\basic_abstract_ostream.test.cpp">
<Filter>beast\streams\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\urls_large_data.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\basic_message.test.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\client_session.test.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\threads\tests\Atomic.test.cpp">
<Filter>beast\threads\tests</Filter>
</ClCompile>
@@ -1674,6 +1698,21 @@
<ClCompile Include="..\..\modules\beast_sqlite\beast_sqlite.unity.c">
<Filter>beast_sqlite</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\basic_url.test.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\impl\basic_url.cpp">
<Filter>beast\http\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\impl\ParsedURL.cpp">
<Filter>beast\http\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\tests\ParsedURL.cpp">
<Filter>beast\http\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\http\impl\get.cpp">
<Filter>beast\http\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\TODO.txt">

View File

@@ -21,9 +21,14 @@
#include "../../BeastConfig.h"
#endif
#include "impl/URL.cpp"
#include "impl/ParsedURL.cpp"
#include "impl/basic_url.cpp"
#include "impl/get.cpp"
#include "impl/joyent_parser.cpp"
#include "impl/ParsedURL.cpp"
#include "impl/raw_parser.cpp"
#include "impl/URL.cpp"
#include "tests/basic_url.test.cpp"
#include "tests/client_session.test.cpp"
#include "tests/ParsedURL.cpp"
#include "tests/urls_large_data.cpp"

View File

@@ -17,8 +17,8 @@
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTP_BASIC_MESSAGE_H_INCLUDED
#define BEAST_ASIO_HTTP_BASIC_MESSAGE_H_INCLUDED
#ifndef BEAST_HTTP_BASIC_MESSAGE_H_INCLUDED
#define BEAST_HTTP_BASIC_MESSAGE_H_INCLUDED
#include <memory>

174
beast/http/basic_url.h Normal file
View File

@@ -0,0 +1,174 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_BASIC_URL_H_INCLUDED
#define BEAST_HTTP_BASIC_URL_H_INCLUDED
#include <boost/system/error_code.hpp>
#include <boost/utility/string_ref.hpp>
#include "../utility/noexcept.h"
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
namespace beast {
namespace http {
namespace detail {
class basic_url_base
{
public:
typedef char value_type;
typedef std::char_traits <value_type> traits_type;
typedef boost::basic_string_ref <
value_type, traits_type> string_ref;
string_ref
scheme () const noexcept
{
return m_scheme;
}
string_ref
host () const noexcept
{
return m_host;
}
std::uint16_t
port () const noexcept
{
return m_port;
}
string_ref
port_string () const noexcept
{
return m_port_string;
}
string_ref
path () const noexcept
{
return m_path;
}
string_ref
query () const noexcept
{
return m_query;
}
string_ref
fragment () const noexcept
{
return m_fragment;
}
string_ref
userinfo () const noexcept
{
return m_userinfo;
}
protected:
void
parse_impl (string_ref s, boost::system::error_code& ec);
string_ref m_string_ref;
string_ref m_scheme;
string_ref m_host;
std::uint16_t m_port;
string_ref m_port_string;
string_ref m_path;
string_ref m_query;
string_ref m_fragment;
string_ref m_userinfo;
};
}
/** A URL. */
template <
class Alloc = std::allocator <char>
>
class basic_url : public detail::basic_url_base
{
public:
typedef std::basic_string <
value_type, traits_type, Alloc> string_type;
basic_url() = default;
explicit basic_url (Alloc const& alloc)
: m_string (alloc)
{
}
void
parse (string_ref s)
{
boost::system::error_code ec;
parse (s, ec);
if (ec)
throw std::invalid_argument ("invalid url string");
}
boost::system::error_code
parse (string_ref s,
boost::system::error_code& ec)
{
parse_impl (s, ec);
if (!ec)
{
m_string = string_type (s.begin(), s.end());
m_string_ref = m_string;
}
return ec;
}
bool
empty () const noexcept
{
return m_string.empty();
}
template <class Alloc1, class Alloc2>
friend
int
compare (basic_url const& lhs,
basic_url const& rhs) noexcept
{
return lhs.m_buf.compare (rhs.m_buf);
}
private:
string_type m_string;
};
using url = basic_url <std::allocator <char>>;
}
}
#endif

727
beast/http/client_session.h Normal file
View File

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

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_HEADER_TRAITS_H_INCLUDED
#define BEAST_HTTP_HEADER_TRAITS_H_INCLUDED
#include "../../utility/ci_char_traits.h"
#include <boost/utility/string_ref.hpp>
#include <memory>
#include <string>
namespace beast {
namespace http {
namespace detail {
// Utilities for dealing with HTTP headers
template <class Allocator = std::allocator <char>>
using basic_field_string =
std::basic_string <char, ci_char_traits, Allocator>;
typedef basic_field_string <> field_string;
typedef boost::basic_string_ref <char, ci_char_traits> field_string_ref;
/** Returns `true` if two header fields are the same.
The comparison is case-insensitive.
*/
template <class Alloc1, class Alloc2>
inline
bool field_eq (
std::basic_string <char, std::char_traits <char>, Alloc1> const& s1,
std::basic_string <char, std::char_traits <char>, Alloc2> const& s2)
{
return field_string_ref (s1.c_str(), s1.size()) ==
field_string_ref (s2.c_str(), s2.size());
}
/** Returns the string with leading and trailing LWS removed. */
}
}
}
#endif

38
beast/http/get.h Normal file
View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_GET_H_INCLUDED
#define BEAST_HTTP_GET_H_INCLUDED
#include <boost/system/error_code.hpp>
#include <string>
#include <utility>
namespace beast {
namespace http {
/** Perform simple HTTP GET to retrieve a resource as a string. */
std::pair <std::string, boost::system::error_code>
get (std::string const& url_string);
}
}
#endif

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "../basic_url.h"
#include "joyent_parser.h"
namespace beast {
namespace http {
namespace detail {
void
basic_url_base::parse_impl (string_ref s, boost::system::error_code& ec)
{
joyent::http_parser_url p;
value_type const* const data (s.data());
int const error (joyent::http_parser_parse_url (
data, s.size(), false, &p));
if (error)
{
ec = boost::system::error_code (
boost::system::errc::invalid_argument,
boost::system::generic_category());
return;
}
if ((p.field_set & (1<<joyent::UF_SCHEMA)) != 0)
{
m_scheme = string_ref (
data + p.field_data [joyent::UF_SCHEMA].off,
p.field_data [joyent::UF_SCHEMA].len);
}
else
{
m_scheme = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_HOST)) != 0)
{
m_host = string_ref (
data + p.field_data [joyent::UF_HOST].off,
p.field_data [joyent::UF_HOST].len);
}
else
{
m_host = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_PORT)) != 0)
{
m_port = p.port;
m_port_string = string_ref (
data + p.field_data [joyent::UF_PORT].off,
p.field_data [joyent::UF_PORT].len);
}
else
{
m_port = 0;
m_port_string = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_PATH)) != 0)
{
m_path = string_ref (
data + p.field_data [joyent::UF_PATH].off,
p.field_data [joyent::UF_PATH].len);
}
else
{
m_path = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_QUERY)) != 0)
{
m_query = string_ref (
data + p.field_data [joyent::UF_QUERY].off,
p.field_data [joyent::UF_QUERY].len);
}
else
{
m_query = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_FRAGMENT)) != 0)
{
m_fragment = string_ref (
data + p.field_data [joyent::UF_FRAGMENT].off,
p.field_data [joyent::UF_FRAGMENT].len);
}
else
{
m_fragment = string_ref {};
}
if ((p.field_set & (1<<joyent::UF_USERINFO)) != 0)
{
m_userinfo = string_ref (
data + p.field_data [joyent::UF_USERINFO].off,
p.field_data [joyent::UF_USERINFO].len);
}
else
{
m_userinfo = string_ref {};
}
}
} // detail
} // http
} // beast

42
beast/http/impl/get.cpp Normal file
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.
*/
//==============================================================================
#include "../get.h"
#include "../basic_url.h"
namespace beast {
namespace http {
std::pair <std::string, boost::system::error_code>
get (std::string const& url_string)
{
std::pair <std::string, boost::system::error_code> result;
url u;
u.parse (url_string, result.second);
if (result.second)
return result;
return result;
}
}
}

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#include "joyent_parser.h"
#include "../basic_message.h"
#include <boost/system/error_code.hpp>

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include "../../BeastConfig.h"
#endif
#include "../../unit_test/suite.h"
namespace beast {
namespace http {
class basic_message_tests : public unit_test::suite
{
public:
void testCreate()
{
pass();
}
void run()
{
testCreate();
}
};
BEAST_DEFINE_TESTSUITE(basic_message,http,beast);
}
}

View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "../basic_url.h"
#include "../../unit_test/suite.h"
namespace beast {
class basic_url_test : public unit_test::suite
{
public:
void
run ()
{
std::vector <char const*> const urls {
"http://www.example.com/#%c2%a9",
"http://127.0.0.1:443",
"http://192.168.0.1 hello.urltest.lookout.net/",
"http://\\uff10\\uff38\\uff43\\uff10\\uff0e\\uff10\\uff12\\uff15\\uff10\\uff0e\\uff10\\uff11.urltest.lookout.net/"
};
http::url url;
for (auto const& s : urls)
{
try
{
url.parse (s);
pass();
}
catch(...)
{
fail();
}
}
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(basic_url,http,beast);
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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