//
-// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Test that header file is self-contained.
#include <boost/beast/websocket/stream.hpp>
+#include <boost/beast/_experimental/test/stream.hpp>
+#include <boost/beast/_experimental/test/tcp.hpp>
+#include <boost/beast/_experimental/unit_test/suite.hpp>
#include "test.hpp"
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/strand.hpp>
-
namespace boost {
namespace beast {
namespace websocket {
-class accept_test : public websocket_test_suite
+class accept_test : public unit_test::suite //: public websocket_test_suite
{
public:
- template<class Wrap>
- void
- doTestAccept(Wrap const& w)
+ class res_decorator
{
- class res_decorator
+ bool& b_;
+
+ public:
+ res_decorator(res_decorator const&) = default;
+
+ explicit
+ res_decorator(bool& b)
+ : b_(b)
{
- bool& b_;
+ }
- public:
- res_decorator(res_decorator const&) = default;
+ void
+ operator()(response_type&) const
+ {
+ this->b_ = true;
+ }
+ };
+
+ template<std::size_t N>
+ static
+ net::const_buffer
+ sbuf(const char (&s)[N])
+ {
+ return net::const_buffer(&s[0], N-1);
+ }
- explicit
- res_decorator(bool& b)
- : b_(b)
+ static
+ void
+ fail_loop(
+ std::function<void(stream<test::stream>&)> f,
+ std::chrono::steady_clock::duration amount =
+ std::chrono::seconds(5))
+ {
+ using clock_type = std::chrono::steady_clock;
+ auto const expires_at =
+ clock_type::now() + amount;
+ net::io_context ioc;
+ for(std::size_t n = 0;;++n)
+ {
+ test::fail_count fc(n);
+ try
{
+ stream<test::stream> ws(ioc, fc);
+ auto tr = connect(ws.next_layer());
+ f(ws);
+ break;
}
-
- void
- operator()(response_type&) const
+ catch(system_error const& se)
{
- this->b_ = true;
+ // VFALCO Commented this out after the short
+ // read change, because it converts test_failure
+ // into http::partial_message
+ //
+ boost::ignore_unused(se);
+ #if 0
+ if(! BEAST_EXPECTS(
+ se.code() == test::error::test_failure,
+ se.code().message()))
+ throw;
+ #endif
+ if(! BEAST_EXPECTS(
+ clock_type::now() < expires_at,
+ "a test timeout occurred"))
+ break;
}
- };
+ }
+ }
- auto const big = []
- {
- std::string s;
- s += "X1: " + std::string(2000, '*') + "\r\n";
- return s;
- }();
+ template<class Api>
+ void
+ testMatrix(Api api)
+ {
+ net::io_context ioc;
// request in stream
- doStreamLoop([&](test::stream& ts)
+ fail_loop([&](stream<test::stream>& ws)
{
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- ts.append(
+ ws.next_layer().append(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n");
- ts.read_size(20);
- w.accept(ws);
- // VFALCO validate contents of ws.next_layer().str?
+ ws.next_layer().read_size(20);
+ api.accept(ws);
});
- // request in stream, oversized
+ // request in stream, decorator
+ fail_loop([&](stream<test::stream>& ws)
{
- stream<test::stream> ws{ioc_,
+ ws.next_layer().append(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
- + big +
- "\r\n"};
- auto tr = connect(ws.next_layer());
- try
- {
- w.accept(ws);
- fail("", __FILE__, __LINE__);
- }
- catch(system_error const& se)
- {
- // VFALCO Its the http error category...
- BEAST_EXPECTS(
- se.code() == http::error::buffer_overflow,
- se.code().message());
- }
- }
+ "\r\n");
+ ws.next_layer().read_size(20);
+ bool called = false;
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws);
+ BEAST_EXPECT(called);
+ });
- // request in stream, decorator
- doStreamLoop([&](test::stream& ts)
+ // request in buffers
+ fail_loop([&](stream<test::stream>& ws)
{
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- ts.append(
+ api.accept(ws, sbuf(
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"
+ ));
+ });
+
+ // request in buffers, decorator
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ bool called = false;
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws, sbuf(
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n"));
+ BEAST_EXPECT(called);
+ });
+
+ // request in buffers and stream
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ ws.next_layer().append(
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n");
+ ws.next_layer().read_size(16);
+ api.accept(ws, sbuf(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
+ ));
+ // VFALCO validate contents of ws.next_layer().str?
+ });
+
+ // request in buffers and stream, decorator
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ ws.next_layer().append(
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n");
- ts.read_size(20);
+ ws.next_layer().read_size(16);
bool called = false;
- w.accept_ex(ws, res_decorator{called});
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws, sbuf(
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Upgrade: websocket\r\n"));
BEAST_EXPECT(called);
});
- // request in stream, decorator, oversized
+ // request in message
+ {
+ request_type req;
+ req.method(http::verb::get);
+ req.target("/");
+ req.version(11);
+ req.insert(http::field::host, "localhost");
+ req.insert(http::field::upgrade, "websocket");
+ req.insert(http::field::connection, "upgrade");
+ req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
+ req.insert(http::field::sec_websocket_version, "13");
+
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ api.accept(ws, req);
+ });
+ }
+
+ // request in message, decorator
+ {
+ request_type req;
+ req.method(http::verb::get);
+ req.target("/");
+ req.version(11);
+ req.insert(http::field::host, "localhost");
+ req.insert(http::field::upgrade, "websocket");
+ req.insert(http::field::connection, "upgrade");
+ req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
+ req.insert(http::field::sec_websocket_version, "13");
+
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ bool called = false;
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws, req);
+ BEAST_EXPECT(called);
+ });
+ }
+
+ // request in message, close frame in stream
+ {
+ request_type req;
+ req.method(http::verb::get);
+ req.target("/");
+ req.version(11);
+ req.insert(http::field::host, "localhost");
+ req.insert(http::field::upgrade, "websocket");
+ req.insert(http::field::connection, "upgrade");
+ req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
+ req.insert(http::field::sec_websocket_version, "13");
+
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ ws.next_layer().append("\x88\x82\xff\xff\xff\xff\xfc\x17");
+ api.accept(ws, req);
+ try
+ {
+ static_buffer<1> b;
+ api.read(ws, b);
+ fail("success", __FILE__, __LINE__);
+ }
+ catch(system_error const& e)
+ {
+ if(e.code() != websocket::error::closed)
+ throw;
+ }
+ });
+ }
+
+ // failed handshake (missing Sec-WebSocket-Key)
+ fail_loop([&](stream<test::stream>& ws)
+ {
+ ws.next_layer().append(
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n");
+ ws.next_layer().read_size(20);
+ try
+ {
+ api.accept(ws);
+ BEAST_FAIL();
+ }
+ catch(system_error const& e)
+ {
+ if( e.code() != websocket::error::no_sec_key &&
+ e.code() != net::error::eof)
+ throw;
+ }
+ });
+ }
+
+ template<class Api>
+ void
+ testOversized(Api const& api)
+ {
+ net::io_context ioc;
+
+ auto const big = []
+ {
+ std::string s;
+ s += "X1: " + std::string(2000, '*') + "\r\n";
+ return s;
+ }();
+
+ // request in stream
{
- stream<test::stream> ws{ioc_,
+ stream<test::stream> ws{ioc,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
auto tr = connect(ws.next_layer());
try
{
- bool called = false;
- w.accept_ex(ws, res_decorator{called});
- fail("", __FILE__, __LINE__);
+ api.accept(ws);
+ BEAST_FAIL();
}
catch(system_error const& se)
{
}
}
- // request in buffers
- doStreamLoop([&](test::stream& ts)
+ // request in stream, decorator
{
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- w.accept(ws, sbuf(
+ stream<test::stream> ws{ioc,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
- "\r\n"
- ));
- });
+ + big +
+ "\r\n"};
+ auto tr = connect(ws.next_layer());
+ try
+ {
+ bool called = false;
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws);
+ BEAST_FAIL();
+ }
+ catch(system_error const& se)
+ {
+ // VFALCO Its the http error category...
+ BEAST_EXPECTS(
+ se.code() == http::error::buffer_overflow,
+ se.code().message());
+ }
+ }
- // request in buffers, oversize
+ // request in buffers
{
- stream<test::stream> ws{ioc_};
+ stream<test::stream> ws{ioc};
auto tr = connect(ws.next_layer());
try
{
- w.accept(ws, boost::asio::buffer(
+ api.accept(ws, net::buffer(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
+ big +
"\r\n"
));
- fail("", __FILE__, __LINE__);
+ BEAST_FAIL();
}
catch(system_error const& se)
{
}
// request in buffers, decorator
- doStreamLoop([&](test::stream& ts)
{
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- bool called = false;
- w.accept_ex(ws, sbuf(
- "GET / HTTP/1.1\r\n"
- "Host: localhost\r\n"
- "Upgrade: websocket\r\n"
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n"),
- res_decorator{called});
- BEAST_EXPECT(called);
- });
-
- // request in buffers, decorator, oversized
- {
- stream<test::stream> ws{ioc_};
+ stream<test::stream> ws{ioc};
auto tr = connect(ws.next_layer());
try
{
bool called = false;
- w.accept_ex(ws, boost::asio::buffer(
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws, net::buffer(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
+ big +
- "\r\n"),
- res_decorator{called});
- fail("", __FILE__, __LINE__);
+ "\r\n"));
+ BEAST_FAIL();
}
catch(system_error const& se)
{
}
// request in buffers and stream
- doStreamLoop([&](test::stream& ts)
{
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- ts.append(
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n");
- ts.read_size(16);
- w.accept(ws, sbuf(
- "GET / HTTP/1.1\r\n"
- "Host: localhost\r\n"
- "Upgrade: websocket\r\n"
- ));
- // VFALCO validate contents of ws.next_layer().str?
- });
-
- // request in buffers and stream, oversized
- {
- stream<test::stream> ws{ioc_,
+ stream<test::stream> ws{ioc,
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
auto tr = connect(ws.next_layer());
try
{
- w.accept(ws, sbuf(
+ api.accept(ws, websocket_test_suite::sbuf(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
));
- fail("", __FILE__, __LINE__);
+ BEAST_FAIL();
}
catch(system_error const& se)
{
}
// request in buffers and stream, decorator
- doStreamLoop([&](test::stream& ts)
- {
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- ts.append(
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n");
- ts.read_size(16);
- bool called = false;
- w.accept_ex(ws, sbuf(
- "GET / HTTP/1.1\r\n"
- "Host: localhost\r\n"
- "Upgrade: websocket\r\n"),
- res_decorator{called});
- BEAST_EXPECT(called);
- });
-
- // request in buffers and stream, decorator, oversize
{
- stream<test::stream> ws{ioc_,
+ stream<test::stream> ws{ioc,
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
try
{
bool called = false;
- w.accept_ex(ws, sbuf(
+ ws.set_option(stream_base::decorator(
+ res_decorator{called}));
+ api.accept(ws, websocket_test_suite::sbuf(
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
- "Upgrade: websocket\r\n"),
- res_decorator{called});
- fail("", __FILE__, __LINE__);
+ "Upgrade: websocket\r\n"));
+ BEAST_FAIL();
}
catch(system_error const& se)
{
se.code().message());
}
}
-
- // request in message
- doStreamLoop([&](test::stream& ts)
- {
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- request_type req;
- req.method(http::verb::get);
- req.target("/");
- req.version(11);
- req.insert(http::field::host, "localhost");
- req.insert(http::field::upgrade, "websocket");
- req.insert(http::field::connection, "upgrade");
- req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
- req.insert(http::field::sec_websocket_version, "13");
- w.accept(ws, req);
- });
-
- // request in message, decorator
- doStreamLoop([&](test::stream& ts)
- {
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- request_type req;
- req.method(http::verb::get);
- req.target("/");
- req.version(11);
- req.insert(http::field::host, "localhost");
- req.insert(http::field::upgrade, "websocket");
- req.insert(http::field::connection, "upgrade");
- req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
- req.insert(http::field::sec_websocket_version, "13");
- bool called = false;
- w.accept_ex(ws, req,
- res_decorator{called});
- BEAST_EXPECT(called);
- });
-
- // request in message, close frame in stream
- doStreamLoop([&](test::stream& ts)
- {
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- request_type req;
- req.method(http::verb::get);
- req.target("/");
- req.version(11);
- req.insert(http::field::host, "localhost");
- req.insert(http::field::upgrade, "websocket");
- req.insert(http::field::connection, "upgrade");
- req.insert(http::field::sec_websocket_key, "dGhlIHNhbXBsZSBub25jZQ==");
- req.insert(http::field::sec_websocket_version, "13");
- ts.append("\x88\x82\xff\xff\xff\xff\xfc\x17");
- w.accept(ws, req);
- try
- {
- static_buffer<1> b;
- w.read(ws, b);
- fail("success", __FILE__, __LINE__);
- }
- catch(system_error const& e)
- {
- if(e.code() != websocket::error::closed)
- throw;
- }
- });
-
- // failed handshake (missing Sec-WebSocket-Key)
- doStreamLoop([&](test::stream& ts)
- {
- stream<test::stream&> ws{ts};
- auto tr = connect(ws.next_layer());
- ts.append(
- "GET / HTTP/1.1\r\n"
- "Host: localhost\r\n"
- "Upgrade: websocket\r\n"
- "Connection: upgrade\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n");
- ts.read_size(20);
- try
- {
- w.accept(ws);
- fail("success", __FILE__, __LINE__);
- }
- catch(system_error const& e)
- {
- if( e.code() !=
- websocket::error::no_sec_key &&
- e.code() !=
- boost::asio::error::eof)
- throw;
- }
- });
-
- // Closed by client
- {
- stream<test::stream> ws{ioc_};
- auto tr = connect(ws.next_layer());
- tr.close();
- try
- {
- w.accept(ws);
- fail("success", __FILE__, __LINE__);
- }
- catch(system_error const& e)
- {
- if(! BEAST_EXPECTS(
- e.code() == error::closed,
- e.code().message()))
- throw;
- }
- }
}
void
- testAccept()
+ testInvalidInputs()
{
- doTestAccept(SyncClient{});
-
- yield_to([&](yield_context yield)
- {
- doTestAccept(AsyncClient{yield});
- });
-
- //
- // Bad requests
- //
+ net::io_context ioc;
auto const check =
- [&](error_code const& ev, std::string const& s)
+ [&](error_code ev, string_view s)
{
for(int i = 0; i < 3; ++i)
{
n = s.size() - 1;
break;
}
- stream<test::stream> ws{ioc_};
+ stream<test::stream> ws(ioc);
auto tr = connect(ws.next_layer());
ws.next_layer().append(
s.substr(n, s.size() - n));
+ tr.close();
try
{
- ws.accept(
- boost::asio::buffer(s.data(), n));
+ ws.accept(net::buffer(s.data(), n));
BEAST_EXPECTS(! ev, ev.message());
}
catch(system_error const& se)
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// bad method
check(error::bad_method,
"POST / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Host
check(error::no_host,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Connection
check(error::no_connection,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Connection upgrade
check(error::no_connection_upgrade,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Upgrade
check(error::no_upgrade,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Upgrade websocket
check(error::no_upgrade_websocket,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Sec-WebSocket-Key
check(error::no_sec_key,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// bad Sec-WebSocket-Key
check(error::bad_sec_key,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"
);
+
// no Sec-WebSocket-Version
check(error::no_sec_version,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"\r\n"
);
+
// bad Sec-WebSocket-Version
check(error::bad_sec_version,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 1\r\n"
"\r\n"
);
+
// bad Sec-WebSocket-Version
check(error::bad_sec_version,
"GET / HTTP/1.1\r\n"
"Sec-WebSocket-Version: 12\r\n"
"\r\n"
);
+
// valid request
check({},
"GET / HTTP/1.1\r\n"
}
void
- testMoveOnly()
+ testEndOfStream()
{
- boost::asio::io_context ioc;
- stream<test::stream> ws{ioc};
- ws.async_accept(move_only_handler{});
+ net::io_context ioc;
+ {
+ stream<test::stream> ws(ioc);
+ auto tr = connect(ws.next_layer());
+ tr.close();
+ try
+ {
+ test_sync_api api;
+ api.accept(ws, net::const_buffer{});
+ BEAST_FAIL();
+ }
+ catch(system_error const& se)
+ {
+ BEAST_EXPECTS(
+ se.code() == error::closed,
+ se.code().message());
+ }
+ }
+ {
+ stream<test::stream> ws(ioc);
+ auto tr = connect(ws.next_layer());
+ tr.close();
+ try
+ {
+ test_async_api api;
+ api.accept(ws, net::const_buffer{});
+ BEAST_FAIL();
+ }
+ catch(system_error const& se)
+ {
+ BEAST_EXPECTS(
+ se.code() == error::closed,
+ se.code().message());
+ }
+ }
}
- struct copyable_handler
+ void
+ testAsync()
{
- template<class... Args>
- void
- operator()(Args&&...) const
+ using tcp = net::ip::tcp;
+
+ net::io_context ioc;
+
+ // success, no 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_for(ioc, std::chrono::seconds(1));
}
- };
- void
- testAsioHandlerInvoke()
- {
- // make sure things compile, also can set a
- // breakpoint in asio_handler_invoke to make sure
- // it is instantiated.
- boost::asio::io_context ioc;
- boost::asio::io_service::strand s{ioc};
- stream<test::stream> ws{ioc};
- ws.async_accept(s.wrap(copyable_handler{}));
+ {
+ 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));
+ }
+
+ // abandoned operation
+
+ {
+ {
+ stream<tcp::socket> ws1(ioc);
+ ws1.async_accept(test::fail_handler(
+ net::error::operation_aborted));
+ }
+ test::run(ioc);
+ }
+
+ {
+ {
+ stream<tcp::socket> ws1(ioc);
+ string_view s =
+ "GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n";
+ error_code ec;
+ http::request_parser<http::empty_body> p;
+ p.put(net::const_buffer(s.data(), s.size()), ec);
+ ws1.async_accept(p.get(), test::fail_handler(
+ net::error::operation_aborted));
+ }
+ test::run(ioc);
+ }
}
void
run() override
{
- testAccept();
- testMoveOnly();
- testAsioHandlerInvoke();
+ testMatrix(test_sync_api{});
+ testMatrix(test_async_api{});
+ testOversized(test_sync_api{});
+ testOversized(test_async_api{});
+ testInvalidInputs();
+ testEndOfStream();
+ testAsync();
}
};