forked from boostorg/beast
Add websocket::stream timeouts
This commit is contained in:
1 parent
dfd08bf6ae
commit
f21358186e
38 files changed
+3305
-2393
No files matched your search
@@ -17,7 +17,7 @@ add_executable (tests-beast-websocket
|
||||
${TEST_MAIN}
|
||||
Jamfile
|
||||
_detail_prng.cpp
|
||||
_detail_stream_base.cpp
|
||||
_detail_impl_base.cpp
|
||||
test.hpp
|
||||
_detail_prng.cpp
|
||||
accept.cpp
|
||||
@@ -29,6 +29,7 @@ add_executable (tests-beast-websocket
|
||||
ping.cpp
|
||||
read1.cpp
|
||||
read2.cpp
|
||||
read3.cpp
|
||||
rfc6455.cpp
|
||||
role.cpp
|
||||
stream.cpp
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#
|
||||
|
||||
local SOURCES =
|
||||
_detail_impl_base.cpp
|
||||
_detail_prng.cpp
|
||||
_detail_stream_base.cpp
|
||||
accept.cpp
|
||||
close.cpp
|
||||
error.cpp
|
||||
@@ -19,6 +19,7 @@ local SOURCES =
|
||||
ping.cpp
|
||||
read1.cpp
|
||||
read2.cpp
|
||||
read3.cpp
|
||||
rfc6455.cpp
|
||||
role.cpp
|
||||
stream.cpp
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -8,4 +8,4 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/detail/stream_base.hpp>
|
||||
#include <boost/beast/websocket/detail/impl_base.hpp>
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -10,6 +10,7 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/test/tcp.hpp>
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
@@ -613,6 +614,94 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
testTimeout()
|
||||
{
|
||||
using tcp = net::ip::tcp;
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
// success
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// success, timeout enabled
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_accept(test::success_handler());
|
||||
ws2.async_handshake("test", "/", test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_accept(test::success_handler());
|
||||
ws2.async_handshake("test", "/", test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// timeout
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_accept(test::fail_handler(beast::error::timeout));
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_accept(test::fail_handler(beast::error::timeout));
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMoveOnly()
|
||||
{
|
||||
@@ -649,6 +738,7 @@ public:
|
||||
run() override
|
||||
{
|
||||
testAccept();
|
||||
testTimeout();
|
||||
testMoveOnly();
|
||||
testAsioHandlerInvoke();
|
||||
}
|
||||
|
||||
+112
-17
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -10,6 +10,8 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/test/stream.hpp>
|
||||
#include <boost/beast/_experimental/test/tcp.hpp>
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
@@ -168,6 +170,114 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
testTimeout()
|
||||
{
|
||||
using tcp = net::ip::tcp;
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
// success
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.async_close({}, test::success_handler());
|
||||
ws2.async_close({}, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.async_close({}, test::success_handler());
|
||||
ws2.async_close({}, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// success, timeout enabled
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_close({}, test::success_handler());
|
||||
ws2.async_close({}, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_close({}, test::success_handler());
|
||||
ws2.async_close({}, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// timeout
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_close({}, test::fail_handler(
|
||||
beast::error::timeout));
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_close({}, test::fail_handler(
|
||||
beast::error::timeout));
|
||||
test::run(ioc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testSuspend()
|
||||
{
|
||||
@@ -625,28 +735,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsioHandlerInvoke()
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
net::io_context ioc;
|
||||
net::strand<
|
||||
net::io_context::executor_type> s(
|
||||
ioc.get_executor());
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.async_close({}, net::bind_executor(
|
||||
s, copyable_handler{}));
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testClose();
|
||||
testTimeout();
|
||||
testSuspend();
|
||||
testMoveOnly();
|
||||
testAsioHandlerInvoke();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -10,6 +10,9 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/test/stream.hpp>
|
||||
#include <boost/beast/_experimental/test/tcp.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
@@ -235,6 +238,96 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
testTimeout()
|
||||
{
|
||||
using tcp = net::ip::tcp;
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
// success
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// success, timeout enabled
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// timeout
|
||||
|
||||
{
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_handshake("test", "/",
|
||||
test::fail_handler(beast::error::timeout));
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
{
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
|
||||
ws1.set_option(stream_base::timeout{
|
||||
std::chrono::milliseconds(50),
|
||||
stream_base::none(),
|
||||
false});
|
||||
ws1.async_handshake("test", "/",
|
||||
test::fail_handler(beast::error::timeout));
|
||||
test::run_for(ioc, std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
// Compression Extensions for WebSocket
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc7692
|
||||
@@ -504,31 +597,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsioHandlerInvoke()
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
net::io_context ioc;
|
||||
net::strand<
|
||||
net::io_context::executor_type> s(
|
||||
ioc.get_executor());
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.async_handshake("localhost", "/",
|
||||
net::bind_executor(
|
||||
s, copyable_handler{}));
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testHandshake();
|
||||
testTimeout();
|
||||
testExtRead();
|
||||
testExtWrite();
|
||||
testExtNegotiate();
|
||||
testMoveOnly();
|
||||
testAsioHandlerInvoke();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -440,28 +440,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsioHandlerInvoke()
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
net::io_context ioc;
|
||||
net::strand<
|
||||
net::io_context::executor_type> s(
|
||||
ioc.get_executor());
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.async_ping({}, net::bind_executor(
|
||||
s, copyable_handler{}));
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testPing();
|
||||
testSuspend();
|
||||
testMoveOnly();
|
||||
testAsioHandlerInvoke();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+106
-639
@@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -10,672 +10,139 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
|
||||
#include <boost/config/workaround.hpp>
|
||||
#if BOOST_WORKAROUND(BOOST_GCC, < 80200)
|
||||
#define BOOST_BEAST_SYMBOL_HIDDEN __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define BOOST_BEAST_SYMBOL_HIDDEN
|
||||
#endif
|
||||
#include <boost/beast/_experimental/test/stream.hpp>
|
||||
#include <boost/beast/_experimental/test/tcp.hpp>
|
||||
#include <boost/beast/core/flat_buffer.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
class BOOST_BEAST_SYMBOL_HIDDEN read1_test
|
||||
: public websocket_test_suite
|
||||
class read1_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
template<class Wrap, bool deflateSupported>
|
||||
void
|
||||
doReadTest(
|
||||
Wrap const& w,
|
||||
ws_type_t<deflateSupported>& ws,
|
||||
close_code code)
|
||||
testTimeout()
|
||||
{
|
||||
try
|
||||
using tcp = net::ip::tcp;
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
// success
|
||||
|
||||
{
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
fail("", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() != error::closed)
|
||||
throw;
|
||||
BEAST_EXPECT(
|
||||
ws.reason().code == code);
|
||||
}
|
||||
}
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
template<class Wrap, bool deflateSupported>
|
||||
void
|
||||
doFailTest(
|
||||
Wrap const& w,
|
||||
ws_type_t<deflateSupported>& ws,
|
||||
error_code ev)
|
||||
{
|
||||
try
|
||||
{
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
fail("", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() != ev)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool deflateSupported = true, class Wrap>
|
||||
void
|
||||
doTestRead(Wrap const& w)
|
||||
{
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = false;
|
||||
pmd.server_enable = false;
|
||||
|
||||
// already closed
|
||||
{
|
||||
echo_server es{log};
|
||||
stream<test::stream, deflateSupported> ws{ioc_};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.close({});
|
||||
try
|
||||
{
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
fail("", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
BEAST_EXPECTS(
|
||||
se.code() == net::error::operation_aborted,
|
||||
se.code().message());
|
||||
}
|
||||
}
|
||||
|
||||
// empty, fragmented message
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.next_layer().append(
|
||||
string_view(
|
||||
"\x01\x00" "\x80\x00", 4));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(b.size() == 0);
|
||||
});
|
||||
|
||||
// two part message
|
||||
// triggers "fill the read buffer first"
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_raw(ws, sbuf(
|
||||
"\x01\x81\xff\xff\xff\xff"));
|
||||
w.write_raw(ws, sbuf(
|
||||
"\xd5"));
|
||||
w.write_raw(ws, sbuf(
|
||||
"\x80\x81\xff\xff\xff\xff\xd5"));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "**");
|
||||
});
|
||||
|
||||
// ping
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x89, 0x00));
|
||||
bool invoked = false;
|
||||
ws.control_callback(
|
||||
[&](frame_type kind, string_view)
|
||||
{
|
||||
BEAST_EXPECT(! invoked);
|
||||
BEAST_EXPECT(kind == frame_type::ping);
|
||||
invoked = true;
|
||||
});
|
||||
w.write(ws, sbuf("Hello"));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(invoked);
|
||||
BEAST_EXPECT(ws.got_text());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "Hello");
|
||||
});
|
||||
|
||||
// ping
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x88, 0x00));
|
||||
bool invoked = false;
|
||||
ws.control_callback(
|
||||
[&](frame_type kind, string_view)
|
||||
{
|
||||
BEAST_EXPECT(! invoked);
|
||||
BEAST_EXPECT(kind == frame_type::close);
|
||||
invoked = true;
|
||||
});
|
||||
w.write(ws, sbuf("Hello"));
|
||||
doReadTest(w, ws, close_code::none);
|
||||
});
|
||||
|
||||
// ping then message
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
bool once = false;
|
||||
ws.control_callback(
|
||||
[&](frame_type kind, string_view s)
|
||||
{
|
||||
BEAST_EXPECT(kind == frame_type::pong);
|
||||
BEAST_EXPECT(! once);
|
||||
once = true;
|
||||
BEAST_EXPECT(s == "");
|
||||
});
|
||||
w.ping(ws, "");
|
||||
ws.binary(true);
|
||||
w.write(ws, sbuf("Hello"));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(once);
|
||||
BEAST_EXPECT(ws.got_binary());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "Hello");
|
||||
});
|
||||
|
||||
// ping then fragmented message
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
bool once = false;
|
||||
ws.control_callback(
|
||||
[&](frame_type kind, string_view s)
|
||||
{
|
||||
BEAST_EXPECT(kind == frame_type::pong);
|
||||
BEAST_EXPECT(! once);
|
||||
once = true;
|
||||
BEAST_EXPECT(s == "payload");
|
||||
});
|
||||
ws.ping("payload");
|
||||
w.write_some(ws, false, sbuf("Hello, "));
|
||||
w.write_some(ws, false, sbuf(""));
|
||||
w.write_some(ws, true, sbuf("World!"));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(once);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "Hello, World!");
|
||||
});
|
||||
|
||||
// masked message, big
|
||||
doStreamLoop([&](test::stream& ts)
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
ws_type_t<deflateSupported> ws{ts};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.set_option(pmd);
|
||||
es.async_handshake();
|
||||
try
|
||||
{
|
||||
w.accept(ws);
|
||||
std::string const s(2000, '*');
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(ws.got_text());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
ws.next_layer().close();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
ts.close();
|
||||
throw;
|
||||
}
|
||||
});
|
||||
|
||||
// close
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log, kind::async};
|
||||
net::io_context ioc;
|
||||
stream<test::stream, deflateSupported> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// Cause close to be received
|
||||
es.async_close();
|
||||
std::size_t count = 0;
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
++count;
|
||||
if(ec != error::closed)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
});
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 1);
|
||||
});
|
||||
|
||||
// already closed
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.close(ws, {});
|
||||
multi_buffer b;
|
||||
doFailTest(w, ws,
|
||||
net::error::operation_aborted);
|
||||
});
|
||||
|
||||
// buffer overflow
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s = "Hello, world!";
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
w.write(ws, net::buffer(s));
|
||||
try
|
||||
{
|
||||
multi_buffer b(3);
|
||||
w.read(ws, b);
|
||||
fail("", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() != error::buffer_overflow)
|
||||
throw;
|
||||
}
|
||||
});
|
||||
|
||||
// bad utf8, big
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
auto const s = std::string(2000, '*') +
|
||||
random_string();
|
||||
ws.text(true);
|
||||
w.write(ws, net::buffer(s));
|
||||
doReadTest(w, ws, close_code::bad_payload);
|
||||
});
|
||||
|
||||
// invalid fixed frame header
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_raw(ws, cbuf(
|
||||
0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
|
||||
doReadTest(w, ws, close_code::protocol_error);
|
||||
});
|
||||
|
||||
// bad close
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x88, 0x02, 0x03, 0xed));
|
||||
doFailTest(w, ws, error::bad_close_code);
|
||||
});
|
||||
|
||||
// message size above 2^64
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
w.write_some(ws, false, sbuf("*"));
|
||||
w.write_raw(ws, cbuf(
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
|
||||
doReadTest(w, ws, close_code::too_big);
|
||||
});
|
||||
|
||||
// message size exceeds max
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
ws.read_message_max(1);
|
||||
w.write(ws, sbuf("**"));
|
||||
doFailTest(w, ws, error::message_too_big);
|
||||
});
|
||||
|
||||
// bad utf8
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
put(ws.next_layer().buffer(), cbuf(
|
||||
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
||||
doFailTest(w, ws, error::bad_frame_payload);
|
||||
});
|
||||
|
||||
// incomplete utf8
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s =
|
||||
"Hello, world!" "\xc0";
|
||||
w.write(ws, net::buffer(s));
|
||||
doReadTest(w, ws, close_code::bad_payload);
|
||||
});
|
||||
|
||||
// incomplete utf8, big
|
||||
doTest<deflateSupported>(pmd,
|
||||
[&](ws_type_t<deflateSupported>& ws)
|
||||
{
|
||||
std::string const s =
|
||||
"\x81\x7e\x0f\xa1" +
|
||||
std::string(4000, '*') + "\xc0";
|
||||
ws.next_layer().append(s);
|
||||
multi_buffer b;
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
b.commit(w.read_some(ws, b.prepare(4000)));
|
||||
}
|
||||
while(! ws.is_message_done());
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() != error::bad_frame_payload)
|
||||
throw;
|
||||
}
|
||||
});
|
||||
|
||||
// close frames
|
||||
{
|
||||
auto const check =
|
||||
[&](error_code ev, string_view s)
|
||||
{
|
||||
echo_server es{log};
|
||||
stream<test::stream, deflateSupported> ws{ioc_};
|
||||
ws.next_layer().connect(es.stream());
|
||||
w.handshake(ws, "localhost", "/");
|
||||
ws.next_layer().append(s);
|
||||
static_buffer<1> b;
|
||||
try
|
||||
{
|
||||
w.read(ws, b);
|
||||
fail("", __FILE__, __LINE__);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
BEAST_EXPECTS(se.code() == ev,
|
||||
se.code().message());
|
||||
}
|
||||
ws.next_layer().close();
|
||||
};
|
||||
|
||||
// payload length 1
|
||||
check(error::bad_close_size,
|
||||
"\x88\x01\x01");
|
||||
|
||||
// invalid close code 1005
|
||||
check(error::bad_close_code,
|
||||
"\x88\x02\x03\xed");
|
||||
|
||||
// invalid utf8
|
||||
check(error::bad_close_payload,
|
||||
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
|
||||
|
||||
// good utf8
|
||||
check(error::closed,
|
||||
"\x88\x06\xfc\x15utf8");
|
||||
}
|
||||
}
|
||||
|
||||
template<class Wrap>
|
||||
void
|
||||
doTestReadDeflate(Wrap const& w)
|
||||
{
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.client_max_window_bits = 9;
|
||||
pmd.server_max_window_bits = 9;
|
||||
pmd.compLevel = 1;
|
||||
|
||||
// message size limit
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
std::string const s = std::string(128, '*');
|
||||
w.write(ws, net::buffer(s));
|
||||
ws.read_message_max(32);
|
||||
doFailTest(w, ws, error::message_too_big);
|
||||
});
|
||||
|
||||
// invalid inflate block
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
auto const& s = random_string();
|
||||
ws.binary(true);
|
||||
ws.next_layer().append(
|
||||
"\xc2\x40" + s.substr(0, 64));
|
||||
flat_buffer b;
|
||||
try
|
||||
{
|
||||
w.read(ws, b);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() == test::error::test_failure)
|
||||
throw;
|
||||
BEAST_EXPECTS(se.code().category() ==
|
||||
zlib::detail::get_error_category(),
|
||||
se.code().message());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
});
|
||||
ws1.async_write(net::const_buffer("Hello, world!", 13),
|
||||
test::success_handler());
|
||||
ws2.async_read(b, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// no_context_takeover
|
||||
pmd.server_no_context_takeover = true;
|
||||
doTest<true>(pmd,
|
||||
[&](ws_type_t<true>& ws)
|
||||
{
|
||||
auto const& s = random_string();
|
||||
ws.binary(true);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
pmd.client_no_context_takeover = false;
|
||||
}
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
flat_buffer b;
|
||||
ws1.async_write(net::const_buffer("Hello, world!", 13),
|
||||
test::success_handler());
|
||||
ws2.async_read(b, test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// success, timeout enabled
|
||||
|
||||
template<class Wrap>
|
||||
void
|
||||
doTestRead(
|
||||
permessage_deflate const& pmd,
|
||||
Wrap const& w)
|
||||
{
|
||||
// message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
std::string const s = "Hello, world!";
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(ws.got_text());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
flat_buffer b;
|
||||
ws1.set_option(stream_base::timeout{
|
||||
stream_base::none(),
|
||||
std::chrono::milliseconds(50),
|
||||
false});
|
||||
ws1.async_read(b, test::success_handler());
|
||||
ws2.async_write(net::const_buffer("Hello, world!", 13),
|
||||
test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// masked message
|
||||
doStreamLoop([&](test::stream& ts)
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
ws_type ws{ts};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.set_option(pmd);
|
||||
es.async_handshake();
|
||||
try
|
||||
{
|
||||
w.accept(ws);
|
||||
std::string const s = "Hello, world!";
|
||||
ws.auto_fragment(false);
|
||||
ws.binary(false);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(ws.got_text());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
ws.next_layer().close();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
ts.close();
|
||||
throw;
|
||||
}
|
||||
});
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
flat_buffer b;
|
||||
ws1.set_option(stream_base::timeout{
|
||||
stream_base::none(),
|
||||
std::chrono::milliseconds(50),
|
||||
false});
|
||||
ws1.async_read(b, test::success_handler());
|
||||
ws2.async_write(net::const_buffer("Hello, world!", 13),
|
||||
test::success_handler());
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// timeout
|
||||
|
||||
// empty message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
std::string const s = "";
|
||||
ws.text(true);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(ws.got_text());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
flat_buffer b;
|
||||
ws1.set_option(stream_base::timeout{
|
||||
stream_base::none(),
|
||||
std::chrono::milliseconds(50),
|
||||
false});
|
||||
ws1.async_read(b, test::fail_handler(
|
||||
beast::error::timeout));
|
||||
test::run(ioc);
|
||||
}
|
||||
|
||||
// partial message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
std::string const s = "Hello";
|
||||
w.write(ws, net::buffer(s));
|
||||
char buf[3];
|
||||
auto const bytes_written =
|
||||
w.read_some(ws, net::buffer(buf, sizeof(buf)));
|
||||
BEAST_EXPECT(bytes_written > 0);
|
||||
BEAST_EXPECT(
|
||||
string_view(buf, 3).substr(0, bytes_written) ==
|
||||
s.substr(0, bytes_written));
|
||||
});
|
||||
stream<test::stream> ws1(ioc);
|
||||
stream<test::stream> ws2(ioc);
|
||||
test::connect(ws1.next_layer(), ws2.next_layer());
|
||||
ws1.async_handshake("test", "/", test::success_handler());
|
||||
ws2.async_accept(test::success_handler());
|
||||
test::run(ioc);
|
||||
|
||||
// partial message, dynamic buffer
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
std::string const s = "Hello, world!";
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
auto bytes_written =
|
||||
w.read_some(ws, 3, b);
|
||||
BEAST_EXPECT(bytes_written > 0);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) ==
|
||||
s.substr(0, b.size()));
|
||||
w.read_some(ws, 256, b);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
|
||||
// big message
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
auto const& s = random_string();
|
||||
ws.binary(true);
|
||||
w.write(ws, net::buffer(s));
|
||||
multi_buffer b;
|
||||
w.read(ws, b);
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
|
||||
// message, bad utf8
|
||||
doTest(pmd, [&](ws_type& ws)
|
||||
{
|
||||
std::string const s = "\x03\xea\xf0\x28\x8c\xbc";
|
||||
ws.auto_fragment(false);
|
||||
ws.text(true);
|
||||
w.write(ws, net::buffer(s));
|
||||
doReadTest(w, ws, close_code::bad_payload);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
testRead()
|
||||
{
|
||||
doTestRead<false>(SyncClient{});
|
||||
doTestRead<true>(SyncClient{});
|
||||
doTestReadDeflate(SyncClient{});
|
||||
yield_to([&](yield_context yield)
|
||||
{
|
||||
doTestRead<false>(AsyncClient{yield});
|
||||
doTestRead<true>(AsyncClient{yield});
|
||||
doTestReadDeflate(AsyncClient{yield});
|
||||
});
|
||||
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = false;
|
||||
pmd.server_enable = false;
|
||||
doTestRead(pmd, SyncClient{});
|
||||
yield_to([&](yield_context yield)
|
||||
{
|
||||
doTestRead(pmd, AsyncClient{yield});
|
||||
});
|
||||
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.client_max_window_bits = 9;
|
||||
pmd.server_max_window_bits = 9;
|
||||
pmd.compLevel = 1;
|
||||
doTestRead(pmd, SyncClient{});
|
||||
yield_to([&](yield_context yield)
|
||||
{
|
||||
doTestRead(pmd, AsyncClient{yield});
|
||||
});
|
||||
|
||||
// Read close frames
|
||||
{
|
||||
auto const check =
|
||||
[&](error_code ev, string_view s)
|
||||
{
|
||||
echo_server es{log};
|
||||
stream<test::stream> ws{ioc_};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.next_layer().append(s);
|
||||
static_buffer<1> b;
|
||||
error_code ec;
|
||||
ws.read(b, ec);
|
||||
BEAST_EXPECTS(ec == ev, ec.message());
|
||||
ws.next_layer().close();
|
||||
};
|
||||
|
||||
// payload length 1
|
||||
check(error::bad_close_size,
|
||||
"\x88\x01\x01");
|
||||
|
||||
// invalid close code 1005
|
||||
check(error::bad_close_code,
|
||||
"\x88\x02\x03\xed");
|
||||
|
||||
// invalid utf8
|
||||
check(error::bad_close_payload,
|
||||
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
|
||||
|
||||
// good utf8
|
||||
check(error::closed,
|
||||
"\x88\x06\xfc\x15utf8");
|
||||
flat_buffer b;
|
||||
ws1.set_option(stream_base::timeout{
|
||||
stream_base::none(),
|
||||
std::chrono::milliseconds(50),
|
||||
false});
|
||||
ws1.async_read(b, test::fail_handler(
|
||||
beast::error::timeout));
|
||||
test::run(ioc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testRead();
|
||||
testTimeout();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+597
-566
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,655 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
class read3_test : public websocket_test_suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
testSuspend()
|
||||
{
|
||||
// suspend on read block
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
std::size_t count = 0;
|
||||
ws.async_close({},
|
||||
[&](error_code ec)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 1);
|
||||
});
|
||||
while(! ws.impl_->rd_block.is_locked())
|
||||
ioc.run_one();
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec != net::error::operation_aborted)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 2);
|
||||
});
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 2);
|
||||
});
|
||||
|
||||
// suspend on release read block
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
std::size_t count = 0;
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec != net::error::operation_aborted)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 2);
|
||||
});
|
||||
BOOST_ASSERT(ws.impl_->rd_block.is_locked());
|
||||
ws.async_close({},
|
||||
[&](error_code ec)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 1);
|
||||
});
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 2);
|
||||
});
|
||||
|
||||
// suspend on write pong
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// insert a ping
|
||||
ws.next_layer().append(string_view(
|
||||
"\x89\x00", 2));
|
||||
std::size_t count = 0;
|
||||
std::string const s = "Hello, world";
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
++count;
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->rd_block.is_locked());
|
||||
ws.async_write(net::buffer(s),
|
||||
[&](error_code ec, std::size_t n)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(n == s.size());
|
||||
++count;
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 2);
|
||||
});
|
||||
|
||||
// Ignore ping when closing
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
std::size_t count = 0;
|
||||
// insert fragmented message with
|
||||
// a ping in between the frames.
|
||||
ws.next_layer().append(string_view(
|
||||
"\x01\x01*"
|
||||
"\x89\x00"
|
||||
"\x80\x01*", 8));
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "**");
|
||||
BEAST_EXPECT(++count == 1);
|
||||
b.consume(b.size());
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec != net::error::operation_aborted)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 3);
|
||||
});
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->rd_block.is_locked());
|
||||
ws.async_close({},
|
||||
[&](error_code ec)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 2);
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 3);
|
||||
});
|
||||
|
||||
// See if we are already closing
|
||||
doFailLoop([&](test::fail_count& fc)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc, fc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
std::size_t count = 0;
|
||||
// insert fragmented message with
|
||||
// a close in between the frames.
|
||||
ws.next_layer().append(string_view(
|
||||
"\x01\x01*"
|
||||
"\x88\x00"
|
||||
"\x80\x01*", 8));
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
if(ec != net::error::operation_aborted)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 2);
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->rd_block.is_locked());
|
||||
ws.async_close({},
|
||||
[&](error_code ec)
|
||||
{
|
||||
if(ec)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
system_error{ec});
|
||||
BEAST_EXPECT(++count == 1);
|
||||
});
|
||||
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 2);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
testParseFrame()
|
||||
{
|
||||
auto const bad =
|
||||
[&](string_view s)
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.next_layer().append(s);
|
||||
error_code ec;
|
||||
multi_buffer b;
|
||||
ws.read(b, ec);
|
||||
BEAST_EXPECT(ec);
|
||||
};
|
||||
|
||||
// chopped frame header
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.next_layer().append(
|
||||
"\x81\x7e\x01");
|
||||
std::size_t count = 0;
|
||||
std::string const s(257, '*');
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
++count;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
||||
});
|
||||
ioc.run_one();
|
||||
es.stream().write_some(
|
||||
net::buffer("\x01" + s));
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 1);
|
||||
}
|
||||
|
||||
// new data frame when continuation expected
|
||||
bad("\x01\x01*" "\x81\x01*");
|
||||
|
||||
// reserved bits not cleared
|
||||
bad("\xb1\x01*");
|
||||
bad("\xc1\x01*");
|
||||
bad("\xd1\x01*");
|
||||
|
||||
// continuation without an active message
|
||||
bad("\x80\x01*");
|
||||
|
||||
// reserved bits not cleared (cont)
|
||||
bad("\x01\x01*" "\xb0\x01*");
|
||||
bad("\x01\x01*" "\xc0\x01*");
|
||||
bad("\x01\x01*" "\xd0\x01*");
|
||||
|
||||
// reserved opcode
|
||||
bad("\x83\x01*");
|
||||
|
||||
// fragmented control message
|
||||
bad("\x09\x01*");
|
||||
|
||||
// invalid length for control message
|
||||
bad("\x89\x7e\x01\x01");
|
||||
|
||||
// reserved bits not cleared (control)
|
||||
bad("\xb9\x01*");
|
||||
bad("\xc9\x01*");
|
||||
bad("\xd9\x01*");
|
||||
|
||||
// unmasked frame from client
|
||||
{
|
||||
echo_server es{log, kind::async_client};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
es.async_handshake();
|
||||
ws.accept();
|
||||
ws.next_layer().append(
|
||||
"\x81\x01*");
|
||||
error_code ec;
|
||||
multi_buffer b;
|
||||
ws.read(b, ec);
|
||||
BEAST_EXPECT(ec);
|
||||
}
|
||||
|
||||
// masked frame from server
|
||||
bad("\x81\x80\xff\xff\xff\xff");
|
||||
|
||||
// chopped control frame payload
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.next_layer().append(
|
||||
"\x89\x02*");
|
||||
std::size_t count = 0;
|
||||
multi_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
++count;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "**");
|
||||
});
|
||||
ioc.run_one();
|
||||
es.stream().write_some(
|
||||
net::buffer(
|
||||
"*" "\x81\x02**"));
|
||||
ioc.run();
|
||||
BEAST_EXPECT(count == 1);
|
||||
}
|
||||
|
||||
// length not canonical
|
||||
bad(string_view("\x81\x7e\x00\x7d", 4));
|
||||
bad(string_view("\x81\x7f\x00\x00\x00\x00\x00\x00\xff\xff", 10));
|
||||
}
|
||||
|
||||
void
|
||||
testIssue802()
|
||||
{
|
||||
for(std::size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
echo_server es{log, kind::async};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// too-big message frame indicates payload of 2^64-1
|
||||
net::write(ws.next_layer(), sbuf(
|
||||
"\x81\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"));
|
||||
multi_buffer b;
|
||||
error_code ec;
|
||||
ws.read(b, ec);
|
||||
BEAST_EXPECT(ec == error::closed);
|
||||
BEAST_EXPECT(ws.reason().code == 1009);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testIssue807()
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
ws.write(sbuf("Hello, world!"));
|
||||
char buf[4];
|
||||
net::mutable_buffer b{buf, 0};
|
||||
auto const n = ws.read_some(b);
|
||||
BEAST_EXPECT(n == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
When the internal read buffer contains a control frame and
|
||||
stream::async_read_some is called, it is possible for the control
|
||||
callback to be invoked on the caller's stack instead of through
|
||||
the executor associated with the final completion handler.
|
||||
*/
|
||||
void
|
||||
testIssue954()
|
||||
{
|
||||
echo_server es{log};
|
||||
multi_buffer b;
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// message followed by ping
|
||||
ws.next_layer().append({
|
||||
"\x81\x00"
|
||||
"\x89\x00",
|
||||
4});
|
||||
bool called_cb = false;
|
||||
bool called_handler = false;
|
||||
ws.control_callback(
|
||||
[&called_cb](frame_type, string_view)
|
||||
{
|
||||
called_cb = true;
|
||||
});
|
||||
ws.async_read(b,
|
||||
[&](error_code, std::size_t)
|
||||
{
|
||||
called_handler = true;
|
||||
});
|
||||
BEAST_EXPECT(! called_cb);
|
||||
BEAST_EXPECT(! called_handler);
|
||||
ioc.run();
|
||||
BEAST_EXPECT(! called_cb);
|
||||
BEAST_EXPECT(called_handler);
|
||||
ws.async_read(b,
|
||||
[&](error_code, std::size_t)
|
||||
{
|
||||
});
|
||||
BEAST_EXPECT(! called_cb);
|
||||
}
|
||||
|
||||
/* Bishop Fox Hybrid Assessment issue 1
|
||||
|
||||
Happens with permessage-deflate enabled and a
|
||||
compressed frame with the FIN bit set ends with an
|
||||
invalid prefix.
|
||||
*/
|
||||
void
|
||||
testIssueBF1()
|
||||
{
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
|
||||
// read
|
||||
#if 0
|
||||
{
|
||||
echo_server es{log};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.set_option(pmd);
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// invalid 1-byte deflate block in frame
|
||||
net::write(ws.next_layer(), sbuf(
|
||||
"\xc1\x81\x3a\xa1\x74\x3b\x49"));
|
||||
}
|
||||
#endif
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> wsc{ioc};
|
||||
stream<test::stream> wss{ioc};
|
||||
wsc.set_option(pmd);
|
||||
wss.set_option(pmd);
|
||||
wsc.next_layer().connect(wss.next_layer());
|
||||
wsc.async_handshake(
|
||||
"localhost", "/", [](error_code){});
|
||||
wss.async_accept([](error_code){});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(wsc.is_open());
|
||||
BEAST_EXPECT(wss.is_open());
|
||||
// invalid 1-byte deflate block in frame
|
||||
net::write(wsc.next_layer(), sbuf(
|
||||
"\xc1\x81\x3a\xa1\x74\x3b\x49"));
|
||||
error_code ec;
|
||||
multi_buffer b;
|
||||
wss.read(b, ec);
|
||||
BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
|
||||
}
|
||||
|
||||
// async read
|
||||
#if 0
|
||||
{
|
||||
echo_server es{log, kind::async};
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.set_option(pmd);
|
||||
ws.next_layer().connect(es.stream());
|
||||
ws.handshake("localhost", "/");
|
||||
// invalid 1-byte deflate block in frame
|
||||
net::write(ws.next_layer(), sbuf(
|
||||
"\xc1\x81\x3a\xa1\x74\x3b\x49"));
|
||||
}
|
||||
#endif
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> wsc{ioc};
|
||||
stream<test::stream> wss{ioc};
|
||||
wsc.set_option(pmd);
|
||||
wss.set_option(pmd);
|
||||
wsc.next_layer().connect(wss.next_layer());
|
||||
wsc.async_handshake(
|
||||
"localhost", "/", [](error_code){});
|
||||
wss.async_accept([](error_code){});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(wsc.is_open());
|
||||
BEAST_EXPECT(wss.is_open());
|
||||
// invalid 1-byte deflate block in frame
|
||||
net::write(wsc.next_layer(), sbuf(
|
||||
"\xc1\x81\x3a\xa1\x74\x3b\x49"));
|
||||
error_code ec;
|
||||
flat_buffer b;
|
||||
wss.async_read(b,
|
||||
[&ec](error_code ec_, std::size_t){ ec = ec_; });
|
||||
ioc.run();
|
||||
BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/* Bishop Fox Hybrid Assessment issue 2
|
||||
|
||||
Happens with permessage-deflate enabled,
|
||||
and a deflate block with the BFINAL bit set
|
||||
is encountered in a compressed payload.
|
||||
*/
|
||||
void
|
||||
testIssueBF2()
|
||||
{
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
|
||||
// read
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> wsc{ioc};
|
||||
stream<test::stream> wss{ioc};
|
||||
wsc.set_option(pmd);
|
||||
wss.set_option(pmd);
|
||||
wsc.next_layer().connect(wss.next_layer());
|
||||
wsc.async_handshake(
|
||||
"localhost", "/", [](error_code){});
|
||||
wss.async_accept([](error_code){});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(wsc.is_open());
|
||||
BEAST_EXPECT(wss.is_open());
|
||||
// contains a deflate block with BFINAL set
|
||||
net::write(wsc.next_layer(), sbuf(
|
||||
"\xc1\xf8\xd1\xe4\xcc\x3e\xda\xe4\xcc\x3e"
|
||||
"\x2b\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\x1e"
|
||||
"\x36\x3e\x35\xae\x4f\x54\x18\xae\x4f\x7b"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
|
||||
"\xd1\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\xe4"
|
||||
"\x28\x74\x52\x8e\x05\x74\x52\xa1\xcc\x3e"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\x36\x3e"
|
||||
"\xd1\xec\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e"));
|
||||
error_code ec;
|
||||
flat_buffer b;
|
||||
wss.read(b, ec);
|
||||
BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
|
||||
}
|
||||
|
||||
// async read
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> wsc{ioc};
|
||||
stream<test::stream> wss{ioc};
|
||||
wsc.set_option(pmd);
|
||||
wss.set_option(pmd);
|
||||
wsc.next_layer().connect(wss.next_layer());
|
||||
wsc.async_handshake(
|
||||
"localhost", "/", [](error_code){});
|
||||
wss.async_accept([](error_code){});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(wsc.is_open());
|
||||
BEAST_EXPECT(wss.is_open());
|
||||
// contains a deflate block with BFINAL set
|
||||
net::write(wsc.next_layer(), sbuf(
|
||||
"\xc1\xf8\xd1\xe4\xcc\x3e\xda\xe4\xcc\x3e"
|
||||
"\x2b\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\x1e"
|
||||
"\x36\x3e\x35\xae\x4f\x54\x18\xae\x4f\x7b"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
|
||||
"\xd1\x1e\x36\xc4\x2b\x1e\x36\xc4\x2b\xe4"
|
||||
"\x28\x74\x52\x8e\x05\x74\x52\xa1\xcc\x3e"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e"
|
||||
"\xd1\xe4\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4\x36\x3e"
|
||||
"\xd1\xec\xcc\x3e\xd1\xe4\xcc\x3e\xd1\xe4"
|
||||
"\xcc\x3e\xd1\xe4\xcc\x3e"));
|
||||
error_code ec;
|
||||
flat_buffer b;
|
||||
wss.async_read(b,
|
||||
[&ec](error_code ec_, std::size_t){ ec = ec_; });
|
||||
ioc.run();
|
||||
BEAST_EXPECTS(ec == zlib::error::end_of_stream, ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMoveOnly()
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws{ioc};
|
||||
ws.async_read_some(
|
||||
net::mutable_buffer{},
|
||||
move_only_handler{});
|
||||
}
|
||||
|
||||
struct copyable_handler
|
||||
{
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(Args&&...) const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsioHandlerInvoke()
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
{
|
||||
net::io_context ioc;
|
||||
net::strand<
|
||||
net::io_context::executor_type> s(
|
||||
ioc.get_executor());
|
||||
stream<test::stream> ws{ioc};
|
||||
flat_buffer b;
|
||||
ws.async_read(b, net::bind_executor(
|
||||
s, copyable_handler{}));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testParseFrame();
|
||||
testIssue802();
|
||||
testIssue807();
|
||||
testIssue954();
|
||||
testIssueBF1();
|
||||
testIssueBF2();
|
||||
testMoveOnly();
|
||||
testAsioHandlerInvoke();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,websocket,read3);
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
@@ -10,6 +10,9 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include <boost/beast/core/tcp_stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
namespace boost {
|
||||
@@ -19,6 +22,32 @@ namespace websocket {
|
||||
class stream_test : public websocket_test_suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
testGetSetOption()
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws(ioc);
|
||||
|
||||
{
|
||||
ws.set_option(
|
||||
stream_base::suggested_settings(
|
||||
role_type::client));
|
||||
|
||||
ws.set_option(
|
||||
stream_base::suggested_settings(
|
||||
role_type::server));
|
||||
|
||||
ws.set_option({
|
||||
std::chrono::seconds(30),
|
||||
std::chrono::seconds(300),
|
||||
true});
|
||||
|
||||
stream_base::timeout opt;
|
||||
ws.get_option(opt);
|
||||
ws.set_option(opt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testOptions()
|
||||
{
|
||||
@@ -109,6 +138,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testJavadoc()
|
||||
{
|
||||
net::io_context ioc;
|
||||
{
|
||||
websocket::stream<tcp_stream<
|
||||
net::io_context::strand>> ws{net::io_context::strand(ioc)};
|
||||
}
|
||||
{
|
||||
websocket::stream<tcp_stream<net::io_context::executor_type>> ws(ioc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -136,6 +178,7 @@ public:
|
||||
sizeof(websocket::stream<test::stream&>::impl_type) << std::endl;
|
||||
|
||||
testOptions();
|
||||
testJavadoc();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/stream.hpp>
|
||||
|
||||
#include <boost/beast/core/flat_buffer.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
@@ -25,108 +24,9 @@ class timer_test
|
||||
public:
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
|
||||
static
|
||||
void
|
||||
connect(
|
||||
stream<tcp::socket>& ws1,
|
||||
stream<tcp::socket>& ws2)
|
||||
{
|
||||
struct handler
|
||||
{
|
||||
void
|
||||
operator()(error_code ec)
|
||||
{
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
}
|
||||
};
|
||||
|
||||
tcp::acceptor a(ws1.get_executor().context());
|
||||
auto ep = tcp::endpoint(
|
||||
net::ip::make_address_v4("127.0.0.1"), 0);
|
||||
a.open(ep.protocol());
|
||||
a.set_option(
|
||||
net::socket_base::reuse_address(true));
|
||||
a.bind(ep);
|
||||
a.listen(0);
|
||||
ep = a.local_endpoint();
|
||||
a.async_accept(ws2.next_layer(), handler{});
|
||||
ws1.next_layer().async_connect(ep, handler{});
|
||||
for(;;)
|
||||
{
|
||||
if( ws1.get_executor().context().run_one() +
|
||||
ws2.get_executor().context().run_one() == 0)
|
||||
{
|
||||
ws1.get_executor().context().restart();
|
||||
ws2.get_executor().context().restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
BEAST_EXPECT(
|
||||
ws1.next_layer().remote_endpoint() ==
|
||||
ws2.next_layer().local_endpoint());
|
||||
BEAST_EXPECT(
|
||||
ws2.next_layer().remote_endpoint() ==
|
||||
ws1.next_layer().local_endpoint());
|
||||
ws2.async_accept(handler{});
|
||||
ws1.async_handshake("test", "/", handler{});
|
||||
for(;;)
|
||||
{
|
||||
if( ws1.get_executor().context().run_one() +
|
||||
ws2.get_executor().context().run_one() == 0)
|
||||
{
|
||||
ws1.get_executor().context().restart();
|
||||
ws2.get_executor().context().restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
BEAST_EXPECT(ws1.is_open());
|
||||
BEAST_EXPECT(ws2.is_open());
|
||||
BEAST_EXPECT(! ws1.get_executor().context().stopped());
|
||||
BEAST_EXPECT(! ws2.get_executor().context().stopped());
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
testRead0()
|
||||
{
|
||||
echo_server es(log, kind::async);
|
||||
|
||||
net::io_context ioc;
|
||||
stream<test::stream> ws(ioc);
|
||||
ws.next_layer().connect(es.stream());
|
||||
|
||||
ws.handshake("localhost", "/");
|
||||
flat_buffer b;
|
||||
ws.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
log << ec.message() << "\n";
|
||||
});
|
||||
ioc.run();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
testRead()
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream<tcp::socket> ws1(ioc);
|
||||
stream<tcp::socket> ws2(ioc);
|
||||
connect(ws1, ws2);
|
||||
flat_buffer b;
|
||||
|
||||
ws2.async_read(b,
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
log << "ws1.async_read: " << ec.message() << "\n";
|
||||
});
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testRead();
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2016-2017 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)
|
||||
|
||||
Reference in new issue
Block a user