forked from boostorg/beast
Fixes, fail testing:
Core: * Test buffer_cat iterator move members HTTP: * Fixed yield / resume in writer * Fixed message serialization with chunked encoding * Test yield / resume in writer * Test all conditional branches during message serialization * Test chunked encoding * Increase coverage on parse_error * Add parse_error::general WebSocket: * Add error::general * Increase coverage in error
This commit is contained in:
1 parent
c49cde844b
commit
b62d1b2164
44 files changed
+1064
-688
No files matched your search
@@ -59,6 +59,7 @@ unit-test http-tests :
|
||||
http/string_body.cpp
|
||||
http/type_check.cpp
|
||||
http/write.cpp
|
||||
http/detail/chunk_encode.cpp
|
||||
;
|
||||
|
||||
unit-test bench-tests :
|
||||
|
||||
@@ -81,7 +81,15 @@ public:
|
||||
const_buffer{buf+4, 2},
|
||||
const_buffer{buf+6, 3}}};
|
||||
auto bs = buffer_cat(b1, b2);
|
||||
|
||||
for(int n = 0;
|
||||
n <= std::distance(bs.begin(), bs.end()); ++n)
|
||||
{
|
||||
auto it = std::next(bs.begin(), n);
|
||||
decltype(it) it2(std::move(it));
|
||||
it = std::move(it2);
|
||||
auto pit = ⁢
|
||||
it = std::move(*pit);
|
||||
}
|
||||
try
|
||||
{
|
||||
std::size_t n = 0;
|
||||
|
||||
@@ -9,15 +9,22 @@
|
||||
#include <beast/core/streambuf_readstream.hpp>
|
||||
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/test/fail_stream.hpp>
|
||||
#include <beast/test/string_stream.hpp>
|
||||
#include <beast/test/yield_to.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class streambuf_readstream_test : public beast::unit_test::suite
|
||||
class streambuf_readstream_test
|
||||
: public unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
using self = streambuf_readstream_test;
|
||||
|
||||
public:
|
||||
void testSpecial()
|
||||
void testSpecialMembers()
|
||||
{
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
boost::asio::io_service ios;
|
||||
@@ -33,12 +40,100 @@ public:
|
||||
streambuf_readstream<socket_type&, streambuf> srs(sock);
|
||||
streambuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
|
||||
}
|
||||
pass();
|
||||
}
|
||||
|
||||
void testRead(yield_context do_yield)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
static std::size_t constexpr limit = 100;
|
||||
std::size_t n;
|
||||
std::string s;
|
||||
s.resize(13);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
||||
if(! ec)
|
||||
{
|
||||
expect(s == "Hello, world!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.capacity(3);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
||||
if(! ec)
|
||||
{
|
||||
expect(s == "Hello, world!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
boost::system::error_code ec;
|
||||
boost::asio::async_read(
|
||||
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
||||
if(! ec)
|
||||
{
|
||||
expect(s == "Hello, world!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_stream<
|
||||
test::string_stream> fs(n, ios_, ", world!");
|
||||
streambuf_readstream<
|
||||
decltype(fs)&, streambuf> srs(fs);
|
||||
srs.capacity(3);
|
||||
srs.buffer().commit(buffer_copy(
|
||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||
boost::system::error_code ec;
|
||||
boost::asio::async_read(
|
||||
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
||||
if(! ec)
|
||||
{
|
||||
expect(s == "Hello, world!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testSpecial();
|
||||
testSpecialMembers();
|
||||
|
||||
yield_to(std::bind(&self::testRead,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ add_executable (http-tests
|
||||
string_body.cpp
|
||||
type_check.cpp
|
||||
write.cpp
|
||||
detail/chunk_encode.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
|
||||
@@ -58,5 +58,5 @@ public:
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
|
||||
|
||||
} // asio
|
||||
} // http
|
||||
} // beast
|
||||
@@ -573,11 +573,14 @@ public:
|
||||
parse_ev<true>("GET / HTTP/1.1\r\nf :", parse_error::bad_field);
|
||||
}
|
||||
|
||||
void testCorrupt()
|
||||
void testInvalidMatrix()
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
static std::size_t constexpr limit = 200;
|
||||
std::string s;
|
||||
for(std::size_t n = 0;;++n)
|
||||
std::size_t n;
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
// Create a request and set one octet to an invalid char
|
||||
s =
|
||||
@@ -607,6 +610,41 @@ public:
|
||||
expect(ec);
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
// Create a response and set one octet to an invalid char
|
||||
s =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"Transer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"10\r\n"
|
||||
"****************\r\n"
|
||||
"0\r\n\r\n";
|
||||
auto const len = s.size();
|
||||
if(n >= s.size())
|
||||
{
|
||||
pass();
|
||||
break;
|
||||
}
|
||||
s[n] = 0;
|
||||
for(std::size_t m = 1; m < len - 1; ++m)
|
||||
{
|
||||
null_parser<true> p;
|
||||
error_code ec;
|
||||
p.write(buffer(s.data(), m), ec);
|
||||
if(ec)
|
||||
{
|
||||
pass();
|
||||
continue;
|
||||
}
|
||||
p.write(buffer(s.data() + m, len - m), ec);
|
||||
expect(ec);
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -758,7 +796,7 @@ public:
|
||||
testFlags();
|
||||
testUpgrade();
|
||||
testBad();
|
||||
testCorrupt();
|
||||
testInvalidMatrix();
|
||||
testRandomReq(100);
|
||||
testRandomResp(100);
|
||||
testBody();
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
class chunk_encode_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct final_chunk
|
||||
{
|
||||
std::string s;
|
||||
|
||||
final_chunk() = default;
|
||||
|
||||
explicit
|
||||
final_chunk(std::string s_)
|
||||
: s(std::move(s_))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
encode1(std::string& s, final_chunk const& fc)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
if(! fc.s.empty())
|
||||
s.append(to_string(
|
||||
chunk_encode(buffer(fc.s.data(), fc.s.size()))));
|
||||
s.append(to_string(chunk_encode_final()));
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
encode1(std::string& s, std::string const& piece)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
s.append(to_string(
|
||||
chunk_encode(buffer(piece.data(), piece.size()))));
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
encode(std::string&)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Arg, class... Args>
|
||||
static
|
||||
void
|
||||
encode(std::string& s, Arg const& arg, Args const&... args)
|
||||
{
|
||||
encode1(s, arg);
|
||||
encode(s, args...);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
check(std::string const& answer, Args const&... args)
|
||||
{
|
||||
std::string s;
|
||||
encode(s, args...);
|
||||
expect(s == answer);
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
check(
|
||||
"0\r\n\r\n"
|
||||
"0\r\n\r\n",
|
||||
"", final_chunk{});
|
||||
|
||||
check(
|
||||
"1\r\n"
|
||||
"*\r\n"
|
||||
"0\r\n\r\n",
|
||||
final_chunk("*"));
|
||||
|
||||
check(
|
||||
"2\r\n"
|
||||
"**\r\n"
|
||||
"0\r\n\r\n",
|
||||
final_chunk("**"));
|
||||
|
||||
check(
|
||||
"1\r\n"
|
||||
"*\r\n"
|
||||
"1\r\n"
|
||||
"*\r\n"
|
||||
"0\r\n\r\n",
|
||||
"*", final_chunk("*"));
|
||||
|
||||
check(
|
||||
"5\r\n"
|
||||
"*****\r\n"
|
||||
"7\r\n"
|
||||
"*******\r\n"
|
||||
"0\r\n\r\n",
|
||||
"*****", final_chunk("*******"));
|
||||
|
||||
check(
|
||||
"1\r\n"
|
||||
"*\r\n"
|
||||
"1\r\n"
|
||||
"*\r\n"
|
||||
"0\r\n\r\n",
|
||||
"*", "*", final_chunk{});
|
||||
|
||||
check(
|
||||
"4\r\n"
|
||||
"****\r\n"
|
||||
"0\r\n\r\n",
|
||||
"****", final_chunk{});
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
check("http", parse_error::bad_on_headers_rv);
|
||||
check("http", parse_error::invalid_chunk_size);
|
||||
check("http", parse_error::short_read);
|
||||
check("http", parse_error::general);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+6
-7
@@ -27,7 +27,8 @@ public:
|
||||
{
|
||||
static std::size_t constexpr limit = 100;
|
||||
std::size_t n;
|
||||
for(n = 1; n < limit; ++n)
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
streambuf sb;
|
||||
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||
@@ -48,7 +49,8 @@ public:
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
for(n = 1; n < limit; ++n)
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
streambuf sb;
|
||||
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||
@@ -65,11 +67,8 @@ public:
|
||||
break;
|
||||
}
|
||||
expect(n < limit);
|
||||
ios_.post(
|
||||
[&]{
|
||||
n = 1;
|
||||
});
|
||||
for(n = 1; n < limit; ++n)
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
streambuf sb;
|
||||
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||
|
||||
+390
-50
@@ -16,20 +16,40 @@
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/test/fail_stream.hpp>
|
||||
#include <beast/test/yield_to.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
class write_test : public beast::unit_test::suite
|
||||
class write_test
|
||||
: public beast::unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
struct string_SyncStream
|
||||
class string_write_stream
|
||||
{
|
||||
boost::asio::io_service& ios_;
|
||||
|
||||
public:
|
||||
std::string str;
|
||||
|
||||
|
||||
explicit
|
||||
string_write_stream(boost::asio::io_service& ios)
|
||||
: ios_(ios)
|
||||
{
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
{
|
||||
return ios_;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
@@ -42,7 +62,8 @@ public:
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t write_some(
|
||||
std::size_t
|
||||
write_some(
|
||||
ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
auto const n = buffer_size(buffers);
|
||||
@@ -54,9 +75,25 @@ public:
|
||||
buffer_size(buffer));
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
async_write_some(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
auto const bytes_transferred = write_some(buffers, ec);
|
||||
async_completion<
|
||||
WriteHandler, void(error_code, std::size_t)
|
||||
> completion(handler);
|
||||
get_io_service().post(
|
||||
bind_handler(completion.handler, ec, bytes_transferred));
|
||||
return completion.result.get();
|
||||
}
|
||||
};
|
||||
|
||||
struct fail_body
|
||||
struct unsized_body
|
||||
{
|
||||
using value_type = std::string;
|
||||
|
||||
@@ -64,6 +101,70 @@ public:
|
||||
{
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
explicit
|
||||
writer(message<isRequest, unsized_body, Allocator> const& msg)
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
{
|
||||
write(boost::asio::buffer(body_));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct fail_body
|
||||
{
|
||||
class writer;
|
||||
|
||||
class value_type
|
||||
{
|
||||
friend class writer;
|
||||
|
||||
std::string s_;
|
||||
test::fail_counter& fc_;
|
||||
boost::asio::io_service& ios_;
|
||||
|
||||
public:
|
||||
value_type(test::fail_counter& fc,
|
||||
boost::asio::io_service& ios)
|
||||
: fc_(fc)
|
||||
, ios_(ios)
|
||||
{
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service() const
|
||||
{
|
||||
return ios_;
|
||||
}
|
||||
|
||||
value_type&
|
||||
operator=(std::string s)
|
||||
{
|
||||
s_ = std::move(s);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class writer
|
||||
{
|
||||
std::size_t n_ = 0;
|
||||
value_type const& body_;
|
||||
bool suspend_ = false;
|
||||
enable_yield_to yt_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
explicit
|
||||
@@ -75,48 +176,44 @@ public:
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
ec = boost::system::errc::make_error_code(
|
||||
boost::system::errc::errc_t::invalid_argument);
|
||||
body_.fc_.fail(ec);
|
||||
}
|
||||
|
||||
class do_resume
|
||||
{
|
||||
resume_context rc_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
do_resume(resume_context&& rc)
|
||||
: rc_(std::move(rc))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
rc_();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Write>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
operator()(resume_context&& rc, error_code& ec, Write&& write)
|
||||
{
|
||||
write(boost::asio::buffer(body_));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct test_body
|
||||
{
|
||||
using value_type = std::string;
|
||||
|
||||
class writer
|
||||
{
|
||||
std::size_t pos_ = 0;
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
explicit
|
||||
writer(message<isRequest, test_body, Allocator> const& msg)
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
{
|
||||
write(boost::asio::buffer(body_));
|
||||
return true;
|
||||
if(body_.fc_.fail(ec))
|
||||
return false;
|
||||
suspend_ = ! suspend_;
|
||||
if(suspend_)
|
||||
{
|
||||
yt_.get_io_service().post(do_resume{std::move(rc)});
|
||||
return boost::indeterminate;
|
||||
}
|
||||
if(n_ >= body_.s_.size())
|
||||
return true;
|
||||
write(boost::asio::buffer(body_.s_.data() + n_, 1));
|
||||
++n_;
|
||||
return n_ == body_.s_.size();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -125,13 +222,228 @@ public:
|
||||
std::string
|
||||
str(message_v1<isRequest, Body, Headers> const& m)
|
||||
{
|
||||
string_SyncStream ss;
|
||||
string_write_stream ss(ios_);
|
||||
write(ss, m);
|
||||
return ss.str;
|
||||
}
|
||||
|
||||
void
|
||||
testWrite()
|
||||
testAsyncWrite(yield_context do_yield)
|
||||
{
|
||||
{
|
||||
message_v1<false, string_body, headers> m;
|
||||
m.version = 10;
|
||||
m.status = 200;
|
||||
m.reason = "OK";
|
||||
m.headers.insert("Server", "test");
|
||||
m.headers.insert("Content-Length", "5");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
string_write_stream ss(ios_);
|
||||
async_write(ss, m, do_yield[ec]);
|
||||
if(expect(! ec, ec.message()))
|
||||
expect(ss.str ==
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****");
|
||||
}
|
||||
{
|
||||
message_v1<false, string_body, headers> m;
|
||||
m.version = 11;
|
||||
m.status = 200;
|
||||
m.reason = "OK";
|
||||
m.headers.insert("Server", "test");
|
||||
m.headers.insert("Transfer-Encoding", "chunked");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
string_write_stream ss(ios_);
|
||||
async_write(ss, m, do_yield[ec]);
|
||||
if(expect(! ec, ec.message()))
|
||||
expect(ss.str ==
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"5\r\n"
|
||||
"*****\r\n"
|
||||
"0\r\n\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testFailures(yield_context do_yield)
|
||||
{
|
||||
static std::size_t constexpr limit = 100;
|
||||
std::size_t n;
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
string_write_stream> fs(fc, ios_);
|
||||
message_v1<true, fail_body, headers> m(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(fc, ios_));
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.headers.insert("Content-Length", "5");
|
||||
m.body = "*****";
|
||||
try
|
||||
{
|
||||
write(fs, m);
|
||||
expect(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****"
|
||||
);
|
||||
pass();
|
||||
break;
|
||||
}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
string_write_stream> fs(fc, ios_);
|
||||
message_v1<true, fail_body, headers> m(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(fc, ios_));
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.headers.insert("Transfer-Encoding", "chunked");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
write(fs, m, ec);
|
||||
if(ec == boost::asio::error::eof)
|
||||
{
|
||||
expect(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"0\r\n\r\n"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
string_write_stream> fs(fc, ios_);
|
||||
message_v1<true, fail_body, headers> m(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(fc, ios_));
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.headers.insert("Transfer-Encoding", "chunked");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
async_write(fs, m, do_yield[ec]);
|
||||
if(ec == boost::asio::error::eof)
|
||||
{
|
||||
expect(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"1\r\n*\r\n"
|
||||
"0\r\n\r\n"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
string_write_stream> fs(fc, ios_);
|
||||
message_v1<true, fail_body, headers> m(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(fc, ios_));
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.headers.insert("Content-Length", "5");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
write(fs, m, ec);
|
||||
if(! ec)
|
||||
{
|
||||
expect(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
string_write_stream> fs(fc, ios_);
|
||||
message_v1<true, fail_body, headers> m(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(fc, ios_));
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.headers.insert("Content-Length", "5");
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
async_write(fs, m, do_yield[ec]);
|
||||
if(! ec)
|
||||
{
|
||||
expect(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(n < limit);
|
||||
}
|
||||
|
||||
void
|
||||
testOutput()
|
||||
{
|
||||
// auto content-length HTTP/1.0
|
||||
{
|
||||
@@ -188,14 +500,14 @@ public:
|
||||
}
|
||||
// no content-length HTTP/1.0
|
||||
{
|
||||
message_v1<true, test_body, headers> m;
|
||||
message_v1<true, unsized_body, headers> m;
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 10;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.body = "*";
|
||||
prepare(m);
|
||||
string_SyncStream ss;
|
||||
string_write_stream ss(ios_);
|
||||
error_code ec;
|
||||
write(ss, m, ec);
|
||||
expect(ec == boost::asio::error::eof);
|
||||
@@ -232,7 +544,7 @@ public:
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.body = "*";
|
||||
prepare(m, connection::close);
|
||||
string_SyncStream ss;
|
||||
string_write_stream ss(ios_);
|
||||
error_code ec;
|
||||
write(ss, m, ec);
|
||||
expect(ec == boost::asio::error::eof);
|
||||
@@ -262,14 +574,14 @@ public:
|
||||
}
|
||||
// no content-length HTTP/1.1
|
||||
{
|
||||
message_v1<true, test_body, headers> m;
|
||||
message_v1<true, unsized_body, headers> m;
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 11;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.body = "*";
|
||||
prepare(m);
|
||||
string_SyncStream ss;
|
||||
string_write_stream ss(ios_);
|
||||
error_code ec;
|
||||
write(ss, m, ec);
|
||||
expect(ss.str ==
|
||||
@@ -297,10 +609,38 @@ public:
|
||||
"GET / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 1\r\n\r\n*");
|
||||
}
|
||||
|
||||
void testOstream()
|
||||
{
|
||||
message_v1<true, string_body, headers> m;
|
||||
m.method = "GET";
|
||||
m.url = "/";
|
||||
m.version = 11;
|
||||
m.headers.insert("User-Agent", "test");
|
||||
m.body = "*";
|
||||
prepare(m);
|
||||
std::stringstream ss;
|
||||
ss.setstate(ss.rdstate() |
|
||||
std::stringstream::failbit);
|
||||
try
|
||||
{
|
||||
ss << m;
|
||||
fail();
|
||||
}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
pass();
|
||||
}
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testWrite();
|
||||
yield_to(std::bind(&write_test::testAsyncWrite,
|
||||
this, std::placeholders::_1));
|
||||
yield_to(std::bind(&write_test::testFailures,
|
||||
this, std::placeholders::_1));
|
||||
testOutput();
|
||||
testConvert();
|
||||
testOstream();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -154,6 +154,14 @@ public:
|
||||
check(fh);
|
||||
fh.rsv1 = false;
|
||||
|
||||
fh.rsv2 = true;
|
||||
check(fh);
|
||||
fh.rsv2 = false;
|
||||
|
||||
fh.rsv3 = true;
|
||||
check(fh);
|
||||
fh.rsv3 = false;
|
||||
|
||||
fh.op = opcode::rsv3;
|
||||
check(fh);
|
||||
fh.op = opcode::text;
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
check("websocket", error::request_malformed);
|
||||
check("websocket", error::request_invalid);
|
||||
check("websocket", error::request_denied);
|
||||
check("websocket", error::general);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+47
-15
@@ -33,6 +33,13 @@ public:
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
void testClamp()
|
||||
{
|
||||
expect(detail::clamp(
|
||||
std::numeric_limits<std::uint64_t>::max()) ==
|
||||
std::numeric_limits<std::size_t>::max());
|
||||
}
|
||||
|
||||
void testSpecialMembers()
|
||||
{
|
||||
stream<socket_type> ws(ios_);
|
||||
@@ -304,7 +311,7 @@ public:
|
||||
std::size_t n;
|
||||
|
||||
// synchronous, exceptions
|
||||
for(n = 1; n < limit; ++n)
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
error_code ec;
|
||||
socket_type sock(ios_);
|
||||
@@ -343,7 +350,7 @@ public:
|
||||
expect(n < limit);
|
||||
|
||||
// synchronous, error codes
|
||||
for(n = 1; n < limit; ++n)
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
error_code ec;
|
||||
socket_type sock(ios_);
|
||||
@@ -378,7 +385,7 @@ public:
|
||||
expect(n < limit);
|
||||
|
||||
// asynchronous
|
||||
for(n = 1; n < limit; ++n)
|
||||
for(n = 0; n < limit; ++n)
|
||||
{
|
||||
error_code ec;
|
||||
socket_type sock(ios_);
|
||||
@@ -470,8 +477,35 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testWriteFrame(endpoint_type const& ep)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
error_code ec;
|
||||
socket_type sock(ios);
|
||||
sock.connect(ep, ec);
|
||||
if(! expect(! ec, ec.message()))
|
||||
break;
|
||||
stream<socket_type&> ws(sock);
|
||||
ws.handshake("localhost", "/", ec);
|
||||
if(! expect(! ec, ec.message()))
|
||||
break;
|
||||
ws.async_write_frame(false,
|
||||
boost::asio::null_buffers{},
|
||||
[](error_code){ });
|
||||
//
|
||||
// Destruction of the io_service will cause destruction
|
||||
// of the write_frame_op without invoking the final handler.
|
||||
//
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testClamp();
|
||||
|
||||
testSpecialMembers();
|
||||
|
||||
testOptions();
|
||||
@@ -483,33 +517,31 @@ public:
|
||||
address_type::from_string("127.0.0.1"), 0};
|
||||
{
|
||||
sync_echo_peer server(true, any);
|
||||
auto const ep = server.local_endpoint();
|
||||
|
||||
yield_to(std::bind(&stream_test::testHandshake,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testErrorHandling,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testMask,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
testWriteFrame(ep);
|
||||
}
|
||||
{
|
||||
async_echo_peer server(true, any, 1);
|
||||
auto const ep = server.local_endpoint();
|
||||
|
||||
yield_to(std::bind(&stream_test::testHandshake,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testErrorHandling,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testMask,
|
||||
this, server.local_endpoint(),
|
||||
std::placeholders::_1));
|
||||
this, ep, std::placeholders::_1));
|
||||
}
|
||||
|
||||
pass();
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED
|
||||
#define BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#include "websocket_async_echo_peer.hpp"
|
||||
#include "websocket_sync_echo_peer.hpp"
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||
#define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||
|
||||
Reference in new issue
Block a user