2017-08-24 06:21:30 -07:00
|
|
|
//
|
2019-02-13 08:00:07 -08:00
|
|
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2017-08-24 06:21:30 -07:00
|
|
|
//
|
|
|
|
|
// 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>
|
|
|
|
|
|
2019-02-13 08:00:07 -08:00
|
|
|
#include <boost/beast/_experimental/test/stream.hpp>
|
|
|
|
|
#include <boost/beast/_experimental/test/tcp.hpp>
|
2017-08-24 06:21:30 -07:00
|
|
|
#include "test.hpp"
|
|
|
|
|
|
2018-11-22 20:49:30 -08:00
|
|
|
#include <boost/asio/io_context.hpp>
|
2018-03-01 06:36:18 -08:00
|
|
|
#include <boost/asio/strand.hpp>
|
|
|
|
|
|
2017-08-24 06:21:30 -07:00
|
|
|
namespace boost {
|
|
|
|
|
namespace beast {
|
|
|
|
|
namespace websocket {
|
|
|
|
|
|
2017-08-26 06:13:11 -07:00
|
|
|
class close_test : public websocket_test_suite
|
2017-08-24 06:21:30 -07:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
|
|
|
|
doTestClose(Wrap const& w)
|
|
|
|
|
{
|
|
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
|
|
|
|
|
2017-08-24 07:41:27 -07:00
|
|
|
// close
|
2017-08-24 06:21:30 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-24 07:41:27 -07:00
|
|
|
// close with code
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, close_code::going_away);
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-31 17:52:09 -07:00
|
|
|
// close with code and reason
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {
|
|
|
|
|
close_code::going_away,
|
|
|
|
|
"going away"});
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-26 06:13:11 -07:00
|
|
|
// already closed
|
2017-08-24 06:21:30 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc_};
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
2018-11-30 14:58:38 -08:00
|
|
|
se.code() == net::error::operation_aborted,
|
2017-08-24 06:21:30 -07:00
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain a message after close
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.next_layer().append("\x81\x01\x2a");
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// drain a big message after close
|
|
|
|
|
{
|
|
|
|
|
std::string s;
|
|
|
|
|
s = "\x81\x7e\x10\x01";
|
|
|
|
|
s.append(4097, '*');
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.next_layer().append(s);
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain a ping after close
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.next_layer().append("\x89\x01*");
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// drain invalid message frame after close
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc_};
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
ws.next_layer().append("\x81\x81\xff\xff\xff\xff*");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
2018-01-01 17:49:19 -08:00
|
|
|
se.code() == error::bad_masked_frame,
|
2017-08-24 06:21:30 -07:00
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain invalid close frame after close
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc_};
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
ws.next_layer().append("\x88\x01*");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
2018-01-01 17:49:19 -08:00
|
|
|
se.code() == error::bad_close_size,
|
2017-08-24 06:21:30 -07:00
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-31 17:52:09 -07:00
|
|
|
// drain masked close frame
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log, kind::async_client};
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc_};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.set_option(pmd);
|
|
|
|
|
es.async_handshake();
|
|
|
|
|
ws.accept();
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 06:21:30 -07:00
|
|
|
// close with incomplete read message
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.next_layer().append("\x81\x02**");
|
|
|
|
|
static_buffer<1> b;
|
|
|
|
|
w.read_some(ws, 1, b);
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testClose()
|
|
|
|
|
{
|
|
|
|
|
doTestClose(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestClose(AsyncClient{yield});
|
|
|
|
|
});
|
2017-08-26 20:10:04 -07:00
|
|
|
}
|
2017-08-24 06:21:30 -07:00
|
|
|
|
2019-02-13 08:00:07 -08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-26 20:10:04 -07:00
|
|
|
void
|
2017-08-31 17:52:09 -07:00
|
|
|
testSuspend()
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
|
|
|
|
// suspend on ping
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-24 06:21:30 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-26 20:10:04 -07:00
|
|
|
ws.handshake("localhost", "/");
|
2017-08-24 06:21:30 -07:00
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-08-26 20:10:04 -07:00
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-24 06:21:30 -07:00
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 0);
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-08-26 20:10:04 -07:00
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-24 06:21:30 -07:00
|
|
|
});
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-24 06:21:30 -07:00
|
|
|
BEAST_EXPECT(count == 2);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// suspend on write
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-26 20:10:04 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_write(sbuf("*"),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t n)
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-09-03 06:18:07 -07:00
|
|
|
BEAST_EXPECT(n == 1);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 0);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
});
|
2017-08-24 06:21:30 -07:00
|
|
|
|
2017-08-26 20:10:04 -07:00
|
|
|
// suspend on read ping + message
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-24 06:21:30 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-26 20:10:04 -07:00
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
// add a ping and message to the input
|
|
|
|
|
ws.next_layer().append(string_view{
|
|
|
|
|
"\x89\x00" "\x81\x01*", 5});
|
2017-08-24 06:21:30 -07:00
|
|
|
std::size_t count = 0;
|
2017-08-26 20:10:04 -07:00
|
|
|
multi_buffer b;
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-08-26 20:10:04 -07:00
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-24 06:21:30 -07:00
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
while(! ws.impl_->wr_block.is_locked())
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run_one();
|
|
|
|
|
if(! BEAST_EXPECT(! ioc.stopped()))
|
2017-08-26 20:10:04 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-08-24 06:21:30 -07:00
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-08-26 20:10:04 -07:00
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-24 06:21:30 -07:00
|
|
|
});
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-24 06:21:30 -07:00
|
|
|
BEAST_EXPECT(count == 2);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// suspend on read bad message
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-26 20:10:04 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
// add an invalid frame to the input
|
|
|
|
|
ws.next_layer().append(string_view{
|
|
|
|
|
"\x09\x00", 2});
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-01-01 17:49:19 -08:00
|
|
|
if(ec != error::bad_control_fragment)
|
2017-08-26 20:10:04 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 1);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
while(! ws.impl_->wr_block.is_locked())
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run_one();
|
|
|
|
|
if(! BEAST_EXPECT(! ioc.stopped()))
|
2017-08-26 20:10:04 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-26 20:10:04 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 2);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// suspend on read close #1
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-26 20:10:04 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
// add a close frame to the input
|
|
|
|
|
ws.next_layer().append(string_view{
|
|
|
|
|
"\x88\x00", 2});
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
if(ec != error::closed)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 1);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
while(! ws.impl_->wr_block.is_locked())
|
2017-08-26 20:10:04 -07:00
|
|
|
{
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run_one();
|
|
|
|
|
if(! BEAST_EXPECT(! ioc.stopped()))
|
2017-08-26 20:10:04 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-26 20:10:04 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 2);
|
2017-08-26 20:10:04 -07:00
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-26 20:10:04 -07:00
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-31 17:52:09 -07:00
|
|
|
// teardown on received close
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
// add a close frame to the input
|
|
|
|
|
ws.next_layer().append(string_view{
|
|
|
|
|
"\x88\x00", 2});
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s = "Hello, world!";
|
2019-02-02 20:44:04 -08:00
|
|
|
ws.async_write(net::buffer(s),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t n)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-09-03 06:18:07 -07:00
|
|
|
BEAST_EXPECT(n == s.size());
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 1);
|
|
|
|
|
});
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 3);
|
|
|
|
|
});
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 2);
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 3);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// check for deadlock
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
// add a ping frame to the input
|
|
|
|
|
ws.next_layer().append(string_view{
|
|
|
|
|
"\x89\x00", 2});
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
std::string const s = "Hello, world!";
|
2019-02-02 20:44:04 -08:00
|
|
|
ws.async_write(net::buffer(s),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t n)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-09-03 06:18:07 -07:00
|
|
|
BEAST_EXPECT(n == s.size());
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 1);
|
|
|
|
|
});
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 3);
|
|
|
|
|
});
|
2019-01-19 07:24:00 -08:00
|
|
|
BEAST_EXPECT(ws.impl_->rd_block.is_locked());
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 2);
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.is_open());
|
2019-01-19 07:24:00 -08:00
|
|
|
BEAST_EXPECT(ws.impl_->wr_block.is_locked());
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 3);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Four-way: close, read, write, ping
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s = "Hello, world!";
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 1);
|
|
|
|
|
});
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
++count;
|
|
|
|
|
});
|
2019-02-02 20:44:04 -08:00
|
|
|
ws.async_write(net::buffer(s),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
++count;
|
|
|
|
|
});
|
|
|
|
|
ws.async_ping({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
++count;
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 4);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Four-way: read, write, ping, close
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s = "Hello, world!";
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec && ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(ec, ec.message());
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
}
|
|
|
|
|
if(! ec)
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(b.data()) == s);
|
2017-08-31 17:52:09 -07:00
|
|
|
++count;
|
2017-10-15 08:47:40 -07:00
|
|
|
if(count == 4)
|
|
|
|
|
BEAST_EXPECT(
|
2018-11-30 14:58:38 -08:00
|
|
|
ec == net::error::operation_aborted);
|
2017-08-31 17:52:09 -07:00
|
|
|
});
|
2019-02-02 20:44:04 -08:00
|
|
|
ws.async_write(net::buffer(s),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t n)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-09-03 06:18:07 -07:00
|
|
|
BEAST_EXPECT(n == s.size());
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(++count == 1);
|
|
|
|
|
});
|
|
|
|
|
ws.async_ping({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(ec, ec.message());
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
}
|
|
|
|
|
++count;
|
|
|
|
|
});
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
2017-10-15 08:47:40 -07:00
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECT(count == 2 || count == 3);
|
2017-08-31 17:52:09 -07:00
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 4);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Four-way: ping, read, write, close
|
2018-05-01 14:19:35 -07:00
|
|
|
doFailLoop([&](test::fail_count& fc)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2017-09-07 07:39:52 -07:00
|
|
|
stream<test::stream> ws{ioc, fc};
|
2017-08-31 17:52:09 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s = "Hello, world!";
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.async_ping({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 1);
|
|
|
|
|
});
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
++count;
|
|
|
|
|
});
|
2019-02-02 20:44:04 -08:00
|
|
|
ws.async_write(net::buffer(s),
|
2017-09-03 06:18:07 -07:00
|
|
|
[&](error_code ec, std::size_t)
|
2017-08-31 17:52:09 -07:00
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
if(ec != net::error::operation_aborted)
|
2017-08-31 17:52:09 -07:00
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
++count;
|
|
|
|
|
});
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
|
system_error{ec});
|
|
|
|
|
BEAST_EXPECT(++count == 2);
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(count == 0);
|
2017-09-07 07:39:52 -07:00
|
|
|
ioc.run();
|
2017-08-31 17:52:09 -07:00
|
|
|
BEAST_EXPECT(count == 4);
|
|
|
|
|
});
|
2017-08-24 06:21:30 -07:00
|
|
|
}
|
|
|
|
|
|
2018-02-28 13:36:47 -08:00
|
|
|
void
|
|
|
|
|
testMoveOnly()
|
|
|
|
|
{
|
2018-11-30 14:58:38 -08:00
|
|
|
net::io_context ioc;
|
2018-02-28 13:36:47 -08:00
|
|
|
stream<test::stream> ws{ioc};
|
|
|
|
|
ws.async_close({}, move_only_handler{});
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 06:36:18 -08:00
|
|
|
struct copyable_handler
|
|
|
|
|
{
|
|
|
|
|
template<class... Args>
|
|
|
|
|
void
|
|
|
|
|
operator()(Args&&...) const
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-24 06:21:30 -07:00
|
|
|
void
|
|
|
|
|
run() override
|
|
|
|
|
{
|
|
|
|
|
testClose();
|
2019-02-13 08:00:07 -08:00
|
|
|
testTimeout();
|
2017-08-31 17:52:09 -07:00
|
|
|
testSuspend();
|
2018-02-28 13:36:47 -08:00
|
|
|
testMoveOnly();
|
2017-08-24 06:21:30 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-26 06:13:11 -07:00
|
|
|
BEAST_DEFINE_TESTSUITE(beast,websocket,close);
|
2017-08-24 06:21:30 -07:00
|
|
|
|
|
|
|
|
} // websocket
|
|
|
|
|
} // beast
|
|
|
|
|
} // boost
|