Merge subtree Beast 1.0.0-b5

Merge commit 'a9e507da9b636d394bb43d6bf8002d013530f57a' into develop
This commit is contained in:
Vinnie Falco
2016-05-25 14:47:27 -04:00
82 changed files with 3885 additions and 2710 deletions

View File

@@ -35,6 +35,7 @@ unit-test core-tests :
core/write_streambuf.cpp
core/detail/base64.cpp
core/detail/empty_base_optimization.cpp
core/detail/get_lowest_layer.cpp
core/detail/sha1.cpp
;
@@ -43,6 +44,7 @@ unit-test http-tests :
http/basic_headers.cpp
http/basic_parser_v1.cpp
http/body_type.cpp
http/concepts.cpp
http/empty_body.cpp
http/headers.cpp
http/message.cpp
@@ -57,7 +59,6 @@ unit-test http-tests :
http/status.cpp
http/streambuf_body.cpp
http/string_body.cpp
http/type_check.cpp
http/write.cpp
http/detail/chunk_encode.cpp
;
@@ -77,6 +78,7 @@ unit-test websocket-tests :
websocket/teardown.cpp
websocket/detail/frame.cpp
websocket/detail/mask.cpp
websocket/detail/stream_base.cpp
websocket/detail/utf8_checker.cpp
;

View File

@@ -29,6 +29,7 @@ add_executable (core-tests
write_streambuf.cpp
detail/base64.cpp
detail/empty_base_optimization.cpp
detail/get_lowest_layer.cpp
detail/sha1.cpp
)

View File

@@ -66,6 +66,14 @@ public:
expect(buffer_size(buffer_cat(
sb1.data(), sb2.data())) == 12);
}
for(auto it = bs.begin(); it != bs.end(); ++it)
{
decltype(bs)::const_iterator copy;
copy = it;
expect(copy == it);
copy = copy;
expect(copy == it);
}
}
void testIterators()

View File

@@ -0,0 +1,88 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/detail/get_lowest_layer.hpp>
#include <beast/unit_test/suite.hpp>
#include <type_traits>
namespace beast {
namespace detail {
class get_lowest_layer_test
: public beast::unit_test::suite
{
public:
struct F1
{
};
struct F2
{
};
template<class F>
struct F3
{
using next_layer_type =
typename std::remove_reference<F>::type;
using lowest_layer_type = typename
get_lowest_layer<next_layer_type>::type;
};
template<class F>
struct F4
{
using next_layer_type =
typename std::remove_reference<F>::type;
using lowest_layer_type = typename
get_lowest_layer<next_layer_type>::type;
};
void
run()
{
static_assert(! has_lowest_layer<F1>::value, "");
static_assert(! has_lowest_layer<F2>::value, "");
static_assert(has_lowest_layer<F3<F1>>::value, "");
static_assert(has_lowest_layer<F4<F3<F2>>>::value, "");
static_assert(std::is_same<
get_lowest_layer<F1>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F2>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F3<F1>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F3<F2>>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F1>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F2>>::type, F2>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F3<F1>>>::type, F1>::value, "");
static_assert(std::is_same<
get_lowest_layer<F4<F3<F2>>>::type, F2>::value, "");
pass();
}
};
BEAST_DEFINE_TESTSUITE(get_lowest_layer,core,beast);
} // detail
} // beast

View File

@@ -89,6 +89,7 @@ public:
void testIterator()
{
using boost::asio::buffer_size;
using boost::asio::const_buffer;
char b[3];
std::array<const_buffer, 3> bs{{
@@ -98,7 +99,12 @@ public:
auto pb = prepare_buffers(2, bs);
std::size_t n = 0;
for(auto it = pb.end(); it != pb.begin(); --it)
{
decltype(pb)::const_iterator it2(std::move(it));
expect(buffer_size(*it2) == 1);
it = std::move(it2);
++n;
}
expect(n == 2);
}

View File

@@ -10,6 +10,7 @@ add_executable (http-tests
basic_headers.cpp
basic_parser_v1.cpp
body_type.cpp
concepts.cpp
empty_body.cpp
headers.cpp
message.cpp
@@ -24,7 +25,6 @@ add_executable (http-tests
status.cpp
streambuf_body.cpp
string_body.cpp
type_check.cpp
write.cpp
detail/chunk_encode.cpp
)

View File

@@ -532,6 +532,7 @@ public:
void testInvalidMatrix()
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
std::string s;
for(std::size_t n = 0;; ++n)
@@ -549,15 +550,24 @@ public:
s[n] = 0;
for(std::size_t m = 1; m < len - 1; ++m)
{
// Use separately allocated buffers so
// address sanitizer has something to chew on.
//
std::unique_ptr<char[]> p1(new char[m]);
std::unique_ptr<char[]> p2(new char[len - m]);
auto const b1 = buffer(p1.get(), m);
auto const b2 = buffer(p2.get(), len - m);
buffer_copy(b1, buffer(s.data(), m));
buffer_copy(b2, buffer(s.data() + m, len - m));
null_parser<true> p;
error_code ec;
p.write(buffer(s.data(), m), ec);
p.write(b1, ec);
if(ec)
{
pass();
continue;
}
p.write(buffer(s.data() + m, len - m), ec);
p.write(b2, ec);
expect(ec);
}
}

View File

@@ -6,4 +6,4 @@
//
// Test that header file is self-contained.
#include <beast/http/type_check.hpp>
#include <beast/http/concepts.hpp>

View File

@@ -59,6 +59,7 @@ public:
}
catch(std::exception const&)
{
pass();
}
m.headers.erase("Content-Length");
m.headers.insert("Connection", "keep-alive");
@@ -69,7 +70,12 @@ public:
}
catch(std::exception const&)
{
pass();
}
m.version = 11;
m.headers.erase("Connection");
m.headers.insert("Connection", "close");
expect(! is_keep_alive(m));
}
void run() override

View File

@@ -85,7 +85,7 @@ public:
{
using namespace std::chrono;
using clock_type = std::chrono::high_resolution_clock;
log << name;
log << name << std::endl;
for(std::size_t trial = 1; trial <= repeat; ++trial)
{
auto const t0 = clock_type::now();
@@ -93,7 +93,7 @@ public:
auto const elapsed = clock_type::now() - t0;
log <<
"Trial " << trial << ": " <<
duration_cast<milliseconds>(elapsed).count() << " ms";
duration_cast<milliseconds>(elapsed).count() << " ms" << std::endl;
}
}
@@ -109,10 +109,10 @@ public:
static std::size_t constexpr Repeat = 50;
log << "sizeof(request parser) == " <<
sizeof(basic_parser_v1<true, null_parser<true>>);
sizeof(basic_parser_v1<true, null_parser<true>>) << '\n';
log << "sizeof(response parser) == " <<
sizeof(basic_parser_v1<false, null_parser<true>>);
sizeof(basic_parser_v1<false, null_parser<true>>)<< '\n';
testcase << "Parser speed test, " <<
((Repeat * size_ + 512) / 1024) << "KB in " <<

View File

@@ -12,8 +12,10 @@
#include <beast/http/headers.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/test/string_stream.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/lexical_cast.hpp>
namespace beast {
namespace http {
@@ -25,16 +27,18 @@ class streambuf_body_test : public beast::unit_test::suite
public:
void run() override
{
test::string_stream ss(ios_,
std::string const s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 3\r\n"
"\r\n"
"xyz");
"xyz";
test::string_stream ss(ios_, s);
parser_v1<false, streambuf_body, headers> p;
streambuf sb;
parse(ss, sb, p);
expect(to_string(p.get().body.data()) == "xyz");
expect(boost::lexical_cast<std::string>(p.get()) == s);
}
};

View File

@@ -16,6 +16,7 @@ add_executable (websocket-tests
teardown.cpp
detail/frame.cpp
detail/mask.cpp
detail/stream_base.cpp
detail/utf8_checker.cpp
)

View File

@@ -225,7 +225,6 @@ public:
testCloseCodes();
testFrameHeader();
testBadFrameHeaders();
pass();
}
};

View File

@@ -5,7 +5,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/websocket/detail/mask.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {

View File

@@ -0,0 +1,40 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/unit_test/suite.hpp>
#include <initializer_list>
#include <climits>
namespace beast {
namespace websocket {
namespace detail {
class stream_base_test : public beast::unit_test::suite
{
public:
void testClamp()
{
expect(detail::clamp(
std::numeric_limits<std::uint64_t>::max()) ==
std::numeric_limits<std::size_t>::max());
}
void run() override
{
testClamp();
}
};
BEAST_DEFINE_TESTSUITE(stream_base,websocket,beast);
} // detail
} // websocket
} // beast

File diff suppressed because it is too large Load Diff

View File

@@ -91,14 +91,16 @@ private:
bool log;
int state = 0;
boost::optional<endpoint_type> ep;
websocket::stream<socket_type> ws;
websocket::opcode op;
stream<socket_type> ws;
boost::asio::io_service::strand strand;
opcode op;
beast::streambuf sb;
int id;
data(bool log_, socket_type&& sock_)
: log(log_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
, id([]
{
static int n = 0;
@@ -112,6 +114,7 @@ private:
: log(log_)
, ep(ep_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
, id([]
{
static int n = 0;
@@ -174,8 +177,34 @@ private:
}
}
template<class Streambuf, std::size_t N>
static
bool
match(Streambuf& sb, char const(&s)[N])
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
if(sb.size() < N-1)
return false;
static_string<N-1> t;
t.resize(N-1);
buffer_copy(buffer(t.data(), t.size()),
sb.data());
if(t != s)
return false;
sb.consume(N-1);
return true;
}
void operator()(error_code ec, std::size_t)
{
(*this)(ec);
}
void operator()(error_code ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
auto& d = *d_;
switch(d.state)
{
@@ -191,19 +220,54 @@ private:
d.sb.consume(d.sb.size());
// read message
d.state = 2;
d.ws.async_read(d.op, d.sb, std::move(*this));
d.ws.async_read(d.op, d.sb,
d.strand.wrap(std::move(*this)));
return;
// got message
case 2:
if(ec == websocket::error::closed)
if(ec == error::closed)
return;
if(ec)
return fail(ec, "async_read");
if(match(d.sb, "RAW"))
{
d.state = 1;
boost::asio::async_write(d.ws.next_layer(),
d.sb.data(), d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.sb, "TEXT"))
{
d.state = 1;
d.ws.set_option(message_type{opcode::text});
d.ws.async_write(
d.sb.data(), d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.sb, "PING"))
{
ping_data payload;
d.sb.consume(buffer_copy(
buffer(payload.data(), payload.size()),
d.sb.data()));
d.state = 1;
d.ws.async_ping(payload,
d.strand.wrap(std::move(*this)));
return;
}
else if(match(d.sb, "CLOSE"))
{
d.state = 1;
d.ws.async_close({},
d.strand.wrap(std::move(*this)));
return;
}
// write message
d.state = 1;
d.ws.set_option(websocket::message_type(d.op));
d.ws.async_write(d.sb.data(), std::move(*this));
d.ws.set_option(message_type(d.op));
d.ws.async_write(d.sb.data(),
d.strand.wrap(std::move(*this)));
return;
// connected
@@ -214,7 +278,7 @@ private:
d.ws.async_handshake(
d.ep->address().to_string() + ":" +
std::to_string(d.ep->port()),
"/", std::move(*this));
"/", d.strand.wrap(std::move(*this)));
return;
}
}
@@ -226,7 +290,7 @@ private:
auto& d = *d_;
if(d.log)
{
if(ec != websocket::error::closed)
if(ec != error::closed)
std::cerr << "#" << d_->id << " " <<
what << ": " << ec.message() << std::endl;
}
@@ -256,6 +320,8 @@ private:
{
if(! acceptor_.is_open())
return;
if(ec == boost::asio::error::operation_aborted)
return;
maybe_throw(ec, "accept");
socket_type sock(std::move(sock_));
acceptor_.async_accept(sock_,

View File

@@ -101,15 +101,17 @@ private:
{
int id;
sync_echo_peer& self;
socket_type sock;
boost::asio::io_service::work work;
// Must be destroyed before work otherwise the
// io_service could be destroyed before the socket.
socket_type sock;
lambda(int id_, sync_echo_peer& self_,
socket_type&& sock_)
: id(id_)
, self(self_)
, work(sock_.get_io_service())
, sock(std::move(sock_))
, work(sock.get_io_service())
{
}
@@ -149,10 +151,31 @@ private:
}
};
template<class Streambuf, std::size_t N>
static
bool
match(Streambuf& sb, char const(&s)[N])
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
if(sb.size() < N-1)
return false;
static_string<N-1> t;
t.resize(N-1);
buffer_copy(buffer(t.data(), t.size()),
sb.data());
if(t != s)
return false;
sb.consume(N-1);
return true;
}
void
do_peer(int id, socket_type&& sock)
{
websocket::stream<socket_type> ws(std::move(sock));
using boost::asio::buffer;
using boost::asio::buffer_copy;
stream<socket_type> ws(std::move(sock));
ws.set_option(decorate(identity{}));
ws.set_option(read_message_max(64 * 1024 * 1024));
error_code ec;
@@ -164,17 +187,45 @@ private:
}
for(;;)
{
websocket::opcode op;
opcode op;
beast::streambuf sb;
ws.read(op, sb, ec);
if(ec)
{
auto const s = ec.message();
break;
ws.set_option(websocket::message_type(op));
ws.write(sb.data(), ec);
}
ws.set_option(message_type(op));
if(match(sb, "RAW"))
{
boost::asio::write(
ws.next_layer(), sb.data(), ec);
}
else if(match(sb, "TEXT"))
{
ws.set_option(message_type{opcode::text});
ws.write(sb.data(), ec);
}
else if(match(sb, "PING"))
{
ping_data payload;
sb.consume(buffer_copy(
buffer(payload.data(), payload.size()),
sb.data()));
ws.ping(payload, ec);
}
else if(match(sb, "CLOSE"))
{
ws.close({}, ec);
}
else
{
ws.write(sb.data(), ec);
}
if(ec)
break;
}
if(ec && ec != websocket::error::closed)
if(ec && ec != error::closed)
{
fail(id, ec, "read");
}