forked from boostorg/beast
Parser concept, fixes:
A new concept Parser is introduced with routines to read from a stream into the parser. This solves a problem with the old read interface where messages must be default constructible and move assignable. Parser fixes: * Fix detect invalid reason-phrase octets * Fix write_eof to set the 'complete' state on success * Fix consider parse complete if eof received on empty body WebSocket: * Increase coverage
This commit is contained in:
1 parent
8921da91b8
commit
2a8de0fd6b
28 files changed
+1536
-701
No files matched your search
@@ -14,9 +14,9 @@ add_executable (websocket-tests
|
||||
rfc6455.cpp
|
||||
stream.cpp
|
||||
teardown.cpp
|
||||
utf8_checker.cpp
|
||||
detail/frame.cpp
|
||||
detail/mask.cpp
|
||||
detail/utf8_checker.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
|
||||
@@ -32,7 +32,7 @@ operator==(frame_header const& lhs, frame_header const& rhs)
|
||||
class frame_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void testValidOpcode()
|
||||
void testCloseCodes()
|
||||
{
|
||||
expect(! is_valid(0));
|
||||
expect(! is_valid(1));
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
expect(! is_valid(1016));
|
||||
expect(! is_valid(2000));
|
||||
expect(! is_valid(2999));
|
||||
expect(is_valid(1000));
|
||||
expect(is_valid(1002));
|
||||
expect(is_valid(3000));
|
||||
expect(is_valid(4000));
|
||||
expect(is_valid(5000));
|
||||
@@ -220,7 +222,7 @@ public:
|
||||
|
||||
void run() override
|
||||
{
|
||||
testValidOpcode();
|
||||
testCloseCodes();
|
||||
testFrameHeader();
|
||||
testBadFrameHeaders();
|
||||
pass();
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/websocket/detail/utf8_checker.hpp>
|
||||
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
class utf8_checker_test : public beast::unit_test::suite
|
||||
{
|
||||
@@ -21,7 +23,7 @@ public:
|
||||
void
|
||||
testOneByteSequence()
|
||||
{
|
||||
detail::utf8_checker utf8;
|
||||
utf8_checker utf8;
|
||||
std::array<std::uint8_t, 256> const buf =
|
||||
([]()
|
||||
{
|
||||
@@ -50,7 +52,7 @@ public:
|
||||
void
|
||||
testTwoByteSequence()
|
||||
{
|
||||
detail::utf8_checker utf8;
|
||||
utf8_checker utf8;
|
||||
std::uint8_t buf[2];
|
||||
for(auto i = 194; i <= 223; ++i)
|
||||
{
|
||||
@@ -84,7 +86,7 @@ public:
|
||||
void
|
||||
testThreeByteSequence()
|
||||
{
|
||||
detail::utf8_checker utf8;
|
||||
utf8_checker utf8;
|
||||
std::uint8_t buf[3];
|
||||
for (auto i = 224; i <= 239; ++i)
|
||||
{
|
||||
@@ -140,7 +142,8 @@ public:
|
||||
void
|
||||
testFourByteSequence()
|
||||
{
|
||||
detail::utf8_checker utf8;
|
||||
using boost::asio::const_buffers_1;
|
||||
utf8_checker utf8;
|
||||
std::uint8_t buf[4];
|
||||
for (auto i = 240; i <= 244; ++i)
|
||||
{
|
||||
@@ -163,7 +166,7 @@ public:
|
||||
{
|
||||
// Fourth byte valid range 128-191
|
||||
buf[3] = static_cast<std::uint8_t>(n);
|
||||
expect(utf8.write(buf, 4));
|
||||
expect(utf8.write(const_buffers_1{buf, 4}));
|
||||
expect(utf8.finish());
|
||||
}
|
||||
|
||||
@@ -171,7 +174,7 @@ public:
|
||||
{
|
||||
// Fourth byte invalid range 0-127
|
||||
buf[3] = static_cast<std::uint8_t>(n);
|
||||
expect(! utf8.write(buf, 4));
|
||||
expect(! utf8.write(const_buffers_1{buf, 4}));
|
||||
}
|
||||
|
||||
for (auto n = 192; n <= 255; ++n)
|
||||
@@ -217,34 +220,47 @@ public:
|
||||
testWithStreamBuffer()
|
||||
{
|
||||
using namespace boost::asio;
|
||||
// Valid UTF8 encoded text
|
||||
std::vector<std::vector<std::uint8_t>> const data{
|
||||
{0x48,0x65,0x69,0x7A,0xC3,0xB6,0x6C,0x72,0xC3,0xBC,0x63,0x6B,
|
||||
0x73,0x74,0x6F,0xC3,0x9F,0x61,0x62,0x64,0xC3,0xA4,0x6D,0x70,
|
||||
0x66,0x75,0x6E,0x67},
|
||||
{0xCE,0x93,0xCE,0xB1,0xCE,0xB6,0xCE,0xAD,0xCE,0xB5,0xCF,0x82,
|
||||
0x20,0xCE,0xBA,0xCE,0xB1,0xE1,0xBD,0xB6,0x20,0xCE,0xBC,0xCF,
|
||||
0x85,0xCF,0x81,0xCF,0x84,0xCE,0xB9,0xE1,0xBD,0xB2,0xCF,0x82,
|
||||
0x20,0xCE,0xB4,0xE1,0xBD,0xB2,0xCE,0xBD,0x20,0xCE,0xB8,0xE1,
|
||||
0xBD,0xB0,0x20,0xCE,0xB2,0xCF,0x81,0xE1,0xBF,0xB6,0x20,0xCF,
|
||||
0x80,0xCE,0xB9,0xE1,0xBD,0xB0,0x20,0xCF,0x83,0xCF,0x84,0xE1,
|
||||
0xBD,0xB8,0x20,0xCF,0x87,0xCF,0x81,0xCF,0x85,0xCF,0x83,0xCE,
|
||||
0xB1,0xCF,0x86,0xE1,0xBD,0xB6,0x20,0xCE,0xBE,0xCE,0xAD,0xCF,
|
||||
0x86,0xCF,0x89,0xCF,0x84,0xCE,0xBF},
|
||||
{0xC3,0x81,0x72,0x76,0xC3,0xAD,0x7A,0x74,0xC5,0xB1,0x72,0xC5,
|
||||
0x91,0x20,0x74,0xC3,0xBC,0x6B,0xC3,0xB6,0x72,0x66,0xC3,0xBA,
|
||||
0x72,0xC3,0xB3,0x67,0xC3,0xA9,0x70}
|
||||
};
|
||||
detail::utf8_checker utf8;
|
||||
for(auto const& s : data)
|
||||
{
|
||||
beast::streambuf sb(
|
||||
s.size() / 4); // Force split across blocks
|
||||
sb.commit(buffer_copy(
|
||||
sb.prepare(s.size()),
|
||||
const_buffer(s.data(), s.size())));
|
||||
expect(utf8.write(sb.data()));
|
||||
expect(utf8.finish());
|
||||
// Valid UTF8 encoded text
|
||||
std::vector<std::vector<std::uint8_t>> const data{{
|
||||
0x48,0x65,0x69,0x7A,0xC3,0xB6,0x6C,0x72,0xC3,0xBC,0x63,0x6B,
|
||||
0x73,0x74,0x6F,0xC3,0x9F,0x61,0x62,0x64,0xC3,0xA4,0x6D,0x70,
|
||||
0x66,0x75,0x6E,0x67
|
||||
}, {
|
||||
0xCE,0x93,0xCE,0xB1,0xCE,0xB6,0xCE,0xAD,0xCE,0xB5,0xCF,0x82,
|
||||
0x20,0xCE,0xBA,0xCE,0xB1,0xE1,0xBD,0xB6,0x20,0xCE,0xBC,0xCF,
|
||||
0x85,0xCF,0x81,0xCF,0x84,0xCE,0xB9,0xE1,0xBD,0xB2,0xCF,0x82,
|
||||
0x20,0xCE,0xB4,0xE1,0xBD,0xB2,0xCE,0xBD,0x20,0xCE,0xB8,0xE1,
|
||||
0xBD,0xB0,0x20,0xCE,0xB2,0xCF,0x81,0xE1,0xBF,0xB6,0x20,0xCF,
|
||||
0x80,0xCE,0xB9,0xE1,0xBD,0xB0,0x20,0xCF,0x83,0xCF,0x84,0xE1,
|
||||
0xBD,0xB8,0x20,0xCF,0x87,0xCF,0x81,0xCF,0x85,0xCF,0x83,0xCE,
|
||||
0xB1,0xCF,0x86,0xE1,0xBD,0xB6,0x20,0xCE,0xBE,0xCE,0xAD,0xCF,
|
||||
0x86,0xCF,0x89,0xCF,0x84,0xCE,0xBF
|
||||
}, {
|
||||
0xC3,0x81,0x72,0x76,0xC3,0xAD,0x7A,0x74,0xC5,0xB1,0x72,0xC5,
|
||||
0x91,0x20,0x74,0xC3,0xBC,0x6B,0xC3,0xB6,0x72,0x66,0xC3,0xBA,
|
||||
0x72,0xC3,0xB3,0x67,0xC3,0xA9,0x70
|
||||
}
|
||||
};
|
||||
utf8_checker utf8;
|
||||
for(auto const& s : data)
|
||||
{
|
||||
static std::size_t constexpr size = 8;
|
||||
std::size_t n = s.size();
|
||||
auto cb = consumed_buffers(
|
||||
boost::asio::const_buffers_1(
|
||||
s.data(), n), 0);
|
||||
streambuf sb(size);
|
||||
while(n)
|
||||
{
|
||||
auto const amount = std::min(n, size);
|
||||
sb.commit(buffer_copy(sb.prepare(amount), cb));
|
||||
cb.consume(amount);
|
||||
n -= amount;
|
||||
}
|
||||
expect(utf8.write(sb.data()));
|
||||
expect(utf8.finish());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,5 +276,6 @@ public:
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(utf8_checker,websocket,beast);
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
@@ -477,6 +477,88 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
struct con
|
||||
{
|
||||
stream<socket_type> ws;
|
||||
|
||||
explicit
|
||||
con(endpoint_type const& ep, boost::asio::io_service& ios)
|
||||
: ws(ios)
|
||||
{
|
||||
ws.next_layer().connect(ep);
|
||||
ws.handshake("localhost", "/");
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t N>
|
||||
class cbuf_helper
|
||||
{
|
||||
std::array<std::uint8_t, N> v_;
|
||||
boost::asio::const_buffer cb_;
|
||||
|
||||
public:
|
||||
using value_type = decltype(cb_);
|
||||
using const_iterator = value_type const*;
|
||||
|
||||
template<class... Vn>
|
||||
explicit
|
||||
cbuf_helper(Vn... vn)
|
||||
: v_({{ static_cast<std::uint8_t>(vn)... }})
|
||||
, cb_(v_.data(), v_.size())
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return &cb_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return begin()+1;
|
||||
}
|
||||
};
|
||||
|
||||
template<class... Vn>
|
||||
cbuf_helper<sizeof...(Vn)>
|
||||
cbuf(Vn... vn)
|
||||
{
|
||||
return cbuf_helper<sizeof...(Vn)>(vn...);
|
||||
}
|
||||
|
||||
void testClose(endpoint_type const& ep, yield_context do_yield)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
{
|
||||
// payload length 1
|
||||
con c(ep, ios_);
|
||||
boost::asio::write(c.ws.next_layer(),
|
||||
cbuf(0x88, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00));
|
||||
}
|
||||
{
|
||||
// invalid close code 1005
|
||||
con c(ep, ios_);
|
||||
boost::asio::write(c.ws.next_layer(),
|
||||
cbuf(0x88, 0x82, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x12));
|
||||
}
|
||||
{
|
||||
// invalid utf8
|
||||
con c(ep, ios_);
|
||||
boost::asio::write(c.ws.next_layer(),
|
||||
cbuf(0x88, 0x86, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x15,
|
||||
0x0f, 0xd7, 0x73, 0x43));
|
||||
}
|
||||
{
|
||||
// good utf8
|
||||
con c(ep, ios_);
|
||||
boost::asio::write(c.ws.next_layer(),
|
||||
cbuf(0x88, 0x86, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x15,
|
||||
'u', 't', 'f', '8'));
|
||||
}
|
||||
}
|
||||
|
||||
void testWriteFrame(endpoint_type const& ep)
|
||||
{
|
||||
for(;;)
|
||||
@@ -528,6 +610,9 @@ public:
|
||||
yield_to(std::bind(&stream_test::testMask,
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testClose,
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
testWriteFrame(ep);
|
||||
}
|
||||
{
|
||||
@@ -542,6 +627,9 @@ public:
|
||||
|
||||
yield_to(std::bind(&stream_test::testMask,
|
||||
this, ep, std::placeholders::_1));
|
||||
|
||||
yield_to(std::bind(&stream_test::testClose,
|
||||
this, ep, std::placeholders::_1));
|
||||
}
|
||||
|
||||
pass();
|
||||
|
||||
Reference in new issue
Block a user