mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 13:27:33 +02:00
websocket test coverage
This commit is contained in:
@@ -189,13 +189,7 @@ struct impl_base<true>
|
|||||||
build_response_pmd(
|
build_response_pmd(
|
||||||
http::response<http::string_body>& res,
|
http::response<http::string_body>& res,
|
||||||
http::request<Body,
|
http::request<Body,
|
||||||
http::basic_fields<Allocator>> const& req)
|
http::basic_fields<Allocator>> const& req);
|
||||||
{
|
|
||||||
pmd_offer offer;
|
|
||||||
pmd_offer unused;
|
|
||||||
pmd_read(offer, req);
|
|
||||||
pmd_negotiate(res, unused, offer, pmd_opts_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
on_response_pmd(
|
on_response_pmd(
|
||||||
@@ -399,9 +393,7 @@ struct impl_base<false>
|
|||||||
build_response_pmd(
|
build_response_pmd(
|
||||||
http::response<http::string_body>&,
|
http::response<http::string_body>&,
|
||||||
http::request<Body,
|
http::request<Body,
|
||||||
http::basic_fields<Allocator>> const&)
|
http::basic_fields<Allocator>> const&);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
on_response_pmd(
|
on_response_pmd(
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
#ifndef BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
#ifndef BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
||||||
#define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
#define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
||||||
|
|
||||||
#include <boost/beast/core/buffer_size.hpp>
|
|
||||||
#include <boost/beast/websocket/impl/stream_impl.hpp>
|
#include <boost/beast/websocket/impl/stream_impl.hpp>
|
||||||
#include <boost/beast/websocket/detail/type_traits.hpp>
|
#include <boost/beast/websocket/detail/type_traits.hpp>
|
||||||
#include <boost/beast/http/empty_body.hpp>
|
#include <boost/beast/http/empty_body.hpp>
|
||||||
@@ -19,10 +18,11 @@
|
|||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <boost/beast/http/write.hpp>
|
#include <boost/beast/http/write.hpp>
|
||||||
#include <boost/beast/core/async_op_base.hpp>
|
#include <boost/beast/core/async_op_base.hpp>
|
||||||
#include <boost/beast/core/buffers_prefix.hpp>
|
#include <boost/beast/core/buffer_size.hpp>
|
||||||
#include <boost/beast/core/stream_traits.hpp>
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
#include <boost/beast/core/detail/buffer.hpp>
|
#include <boost/beast/core/detail/buffer.hpp>
|
||||||
#include <boost/beast/core/detail/type_traits.hpp>
|
#include <boost/beast/core/detail/type_traits.hpp>
|
||||||
|
#include <boost/beast/version.hpp>
|
||||||
#include <boost/asio/coroutine.hpp>
|
#include <boost/asio/coroutine.hpp>
|
||||||
#include <boost/asio/post.hpp>
|
#include <boost/asio/post.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
@@ -34,6 +34,134 @@ namespace boost {
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
namespace websocket {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Body, class Allocator>
|
||||||
|
void
|
||||||
|
impl_base<true>::
|
||||||
|
build_response_pmd(
|
||||||
|
http::response<http::string_body>& res,
|
||||||
|
http::request<Body,
|
||||||
|
http::basic_fields<Allocator>> const& req)
|
||||||
|
{
|
||||||
|
pmd_offer offer;
|
||||||
|
pmd_offer unused;
|
||||||
|
pmd_read(offer, req);
|
||||||
|
pmd_negotiate(res, unused, offer, pmd_opts_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Body, class Allocator>
|
||||||
|
void
|
||||||
|
impl_base<false>::
|
||||||
|
build_response_pmd(
|
||||||
|
http::response<http::string_body>&,
|
||||||
|
http::request<Body,
|
||||||
|
http::basic_fields<Allocator>> const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
template<class Body, class Allocator, class Decorator>
|
||||||
|
response_type
|
||||||
|
stream<NextLayer, deflateSupported>::impl_type::
|
||||||
|
build_response(
|
||||||
|
http::request<Body,
|
||||||
|
http::basic_fields<Allocator>> const& req,
|
||||||
|
Decorator const& decorator,
|
||||||
|
error_code& result)
|
||||||
|
{
|
||||||
|
auto const decorate =
|
||||||
|
[&decorator](response_type& res)
|
||||||
|
{
|
||||||
|
decorator(res);
|
||||||
|
if(! res.count(http::field::server))
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(sizeof(BOOST_BEAST_VERSION_STRING) < 20);
|
||||||
|
static_string<20> s(BOOST_BEAST_VERSION_STRING);
|
||||||
|
res.set(http::field::server, s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto err =
|
||||||
|
[&](error e)
|
||||||
|
{
|
||||||
|
result = e;
|
||||||
|
response_type res;
|
||||||
|
res.version(req.version());
|
||||||
|
res.result(http::status::bad_request);
|
||||||
|
res.body() = result.message();
|
||||||
|
res.prepare_payload();
|
||||||
|
decorate(res);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
if(req.version() != 11)
|
||||||
|
return err(error::bad_http_version);
|
||||||
|
if(req.method() != http::verb::get)
|
||||||
|
return err(error::bad_method);
|
||||||
|
if(! req.count(http::field::host))
|
||||||
|
return err(error::no_host);
|
||||||
|
{
|
||||||
|
auto const it = req.find(http::field::connection);
|
||||||
|
if(it == req.end())
|
||||||
|
return err(error::no_connection);
|
||||||
|
if(! http::token_list{it->value()}.exists("upgrade"))
|
||||||
|
return err(error::no_connection_upgrade);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const it = req.find(http::field::upgrade);
|
||||||
|
if(it == req.end())
|
||||||
|
return err(error::no_upgrade);
|
||||||
|
if(! http::token_list{it->value()}.exists("websocket"))
|
||||||
|
return err(error::no_upgrade_websocket);
|
||||||
|
}
|
||||||
|
string_view key;
|
||||||
|
{
|
||||||
|
auto const it = req.find(http::field::sec_websocket_key);
|
||||||
|
if(it == req.end())
|
||||||
|
return err(error::no_sec_key);
|
||||||
|
key = it->value();
|
||||||
|
if(key.size() > detail::sec_ws_key_type::max_size_n)
|
||||||
|
return err(error::bad_sec_key);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const it = req.find(http::field::sec_websocket_version);
|
||||||
|
if(it == req.end())
|
||||||
|
return err(error::no_sec_version);
|
||||||
|
if(it->value() != "13")
|
||||||
|
{
|
||||||
|
response_type res;
|
||||||
|
res.result(http::status::upgrade_required);
|
||||||
|
res.version(req.version());
|
||||||
|
res.set(http::field::sec_websocket_version, "13");
|
||||||
|
result = error::bad_sec_version;
|
||||||
|
res.body() = result.message();
|
||||||
|
res.prepare_payload();
|
||||||
|
decorate(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response_type res;
|
||||||
|
res.result(http::status::switching_protocols);
|
||||||
|
res.version(req.version());
|
||||||
|
res.set(http::field::upgrade, "websocket");
|
||||||
|
res.set(http::field::connection, "upgrade");
|
||||||
|
{
|
||||||
|
detail::sec_ws_accept_type acc;
|
||||||
|
detail::make_sec_ws_accept(acc, key);
|
||||||
|
res.set(http::field::sec_websocket_accept, acc);
|
||||||
|
}
|
||||||
|
this->build_response_pmd(res, req);
|
||||||
|
decorate(res);
|
||||||
|
result = {};
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Respond to an HTTP request
|
/** Respond to an HTTP request
|
||||||
*/
|
*/
|
||||||
template<class NextLayer, bool deflateSupported>
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
@@ -10,7 +10,14 @@
|
|||||||
#ifndef BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
|
#ifndef BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
|
||||||
#define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
|
#define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_IMPL_HPP
|
||||||
|
|
||||||
#include <boost/beast/version.hpp>
|
#include <boost/beast/websocket/rfc6455.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/frame.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/hybi13.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/mask.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/prng.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/soft_mutex.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/utf8_checker.hpp>
|
||||||
#include <boost/beast/http/read.hpp>
|
#include <boost/beast/http/read.hpp>
|
||||||
#include <boost/beast/http/write.hpp>
|
#include <boost/beast/http/write.hpp>
|
||||||
#include <boost/beast/http/rfc7230.hpp>
|
#include <boost/beast/http/rfc7230.hpp>
|
||||||
@@ -23,14 +30,6 @@
|
|||||||
#include <boost/beast/core/stream_traits.hpp>
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
#include <boost/beast/core/detail/clamp.hpp>
|
#include <boost/beast/core/detail/clamp.hpp>
|
||||||
#include <boost/beast/core/detail/type_traits.hpp>
|
#include <boost/beast/core/detail/type_traits.hpp>
|
||||||
#include <boost/beast/websocket/rfc6455.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/frame.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/hybi13.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/mask.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/prng.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/soft_mutex.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/utf8_checker.hpp>
|
|
||||||
#include <boost/beast/version.hpp>
|
#include <boost/beast/version.hpp>
|
||||||
#include <boost/asio/bind_executor.hpp>
|
#include <boost/asio/bind_executor.hpp>
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
@@ -588,104 +587,6 @@ on_response(
|
|||||||
this->open(role_type::client);
|
this->open(role_type::client);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class NextLayer, bool deflateSupported>
|
|
||||||
template<class Body, class Allocator, class Decorator>
|
|
||||||
response_type
|
|
||||||
stream<NextLayer, deflateSupported>::impl_type::
|
|
||||||
build_response(
|
|
||||||
http::request<Body,
|
|
||||||
http::basic_fields<Allocator>> const& req,
|
|
||||||
Decorator const& decorator,
|
|
||||||
error_code& result)
|
|
||||||
{
|
|
||||||
auto const decorate =
|
|
||||||
[&decorator](response_type& res)
|
|
||||||
{
|
|
||||||
decorator(res);
|
|
||||||
if(! res.count(http::field::server))
|
|
||||||
{
|
|
||||||
BOOST_STATIC_ASSERT(sizeof(BOOST_BEAST_VERSION_STRING) < 20);
|
|
||||||
static_string<20> s(BOOST_BEAST_VERSION_STRING);
|
|
||||||
res.set(http::field::server, s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
auto err =
|
|
||||||
[&](error e)
|
|
||||||
{
|
|
||||||
result = e;
|
|
||||||
response_type res;
|
|
||||||
res.version(req.version());
|
|
||||||
res.result(http::status::bad_request);
|
|
||||||
res.body() = result.message();
|
|
||||||
res.prepare_payload();
|
|
||||||
decorate(res);
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
if(req.version() != 11)
|
|
||||||
return err(error::bad_http_version);
|
|
||||||
if(req.method() != http::verb::get)
|
|
||||||
return err(error::bad_method);
|
|
||||||
if(! req.count(http::field::host))
|
|
||||||
return err(error::no_host);
|
|
||||||
{
|
|
||||||
auto const it = req.find(http::field::connection);
|
|
||||||
if(it == req.end())
|
|
||||||
return err(error::no_connection);
|
|
||||||
if(! http::token_list{it->value()}.exists("upgrade"))
|
|
||||||
return err(error::no_connection_upgrade);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto const it = req.find(http::field::upgrade);
|
|
||||||
if(it == req.end())
|
|
||||||
return err(error::no_upgrade);
|
|
||||||
if(! http::token_list{it->value()}.exists("websocket"))
|
|
||||||
return err(error::no_upgrade_websocket);
|
|
||||||
}
|
|
||||||
string_view key;
|
|
||||||
{
|
|
||||||
auto const it = req.find(http::field::sec_websocket_key);
|
|
||||||
if(it == req.end())
|
|
||||||
return err(error::no_sec_key);
|
|
||||||
key = it->value();
|
|
||||||
if(key.size() > detail::sec_ws_key_type::max_size_n)
|
|
||||||
return err(error::bad_sec_key);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto const it = req.find(http::field::sec_websocket_version);
|
|
||||||
if(it == req.end())
|
|
||||||
return err(error::no_sec_version);
|
|
||||||
if(it->value() != "13")
|
|
||||||
{
|
|
||||||
response_type res;
|
|
||||||
res.result(http::status::upgrade_required);
|
|
||||||
res.version(req.version());
|
|
||||||
res.set(http::field::sec_websocket_version, "13");
|
|
||||||
result = error::bad_sec_version;
|
|
||||||
res.body() = result.message();
|
|
||||||
res.prepare_payload();
|
|
||||||
decorate(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response_type res;
|
|
||||||
res.result(http::status::switching_protocols);
|
|
||||||
res.version(req.version());
|
|
||||||
res.set(http::field::upgrade, "websocket");
|
|
||||||
res.set(http::field::connection, "upgrade");
|
|
||||||
{
|
|
||||||
detail::sec_ws_accept_type acc;
|
|
||||||
detail::make_sec_ws_accept(acc, key);
|
|
||||||
res.set(http::field::sec_websocket_accept, acc);
|
|
||||||
}
|
|
||||||
this->build_response_pmd(res, req);
|
|
||||||
decorate(res);
|
|
||||||
result = {};
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Attempt to read a complete frame header.
|
// Attempt to read a complete frame header.
|
||||||
|
@@ -3570,10 +3570,10 @@ seed_prng(std::seed_seq& ss)
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#include <boost/beast/websocket/impl/stream_impl.hpp> // must be first
|
||||||
#include <boost/beast/websocket/impl/accept.hpp>
|
#include <boost/beast/websocket/impl/accept.hpp>
|
||||||
#include <boost/beast/websocket/impl/close.hpp>
|
#include <boost/beast/websocket/impl/close.hpp>
|
||||||
#include <boost/beast/websocket/impl/handshake.hpp>
|
#include <boost/beast/websocket/impl/handshake.hpp>
|
||||||
#include <boost/beast/websocket/impl/stream_impl.hpp>
|
|
||||||
#include <boost/beast/websocket/impl/ping.hpp>
|
#include <boost/beast/websocket/impl/ping.hpp>
|
||||||
#include <boost/beast/websocket/impl/read.hpp>
|
#include <boost/beast/websocket/impl/read.hpp>
|
||||||
#include <boost/beast/websocket/impl/stream.hpp>
|
#include <boost/beast/websocket/impl/stream.hpp>
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <boost/beast/websocket/stream.hpp>
|
#include <boost/beast/websocket/stream.hpp>
|
||||||
|
|
||||||
|
#include <boost/beast/_experimental/test/stream.hpp>
|
||||||
#include <boost/beast/_experimental/test/tcp.hpp>
|
#include <boost/beast/_experimental/test/tcp.hpp>
|
||||||
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
@@ -20,90 +22,82 @@ namespace boost {
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
namespace websocket {
|
||||||
|
|
||||||
class accept_test : public websocket_test_suite
|
class accept_test : public unit_test::suite //: public websocket_test_suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class Wrap>
|
class res_decorator
|
||||||
void
|
|
||||||
doTestAccept(Wrap const& w)
|
|
||||||
{
|
{
|
||||||
class res_decorator
|
bool& b_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
res_decorator(res_decorator const&) = default;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
res_decorator(bool& b)
|
||||||
|
: b_(b)
|
||||||
{
|
{
|
||||||
bool& b_;
|
}
|
||||||
|
|
||||||
public:
|
void
|
||||||
res_decorator(res_decorator const&) = default;
|
operator()(response_type&) const
|
||||||
|
|
||||||
explicit
|
|
||||||
res_decorator(bool& b)
|
|
||||||
: b_(b)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()(response_type&) const
|
|
||||||
{
|
|
||||||
this->b_ = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const big = []
|
|
||||||
{
|
{
|
||||||
std::string s;
|
this->b_ = true;
|
||||||
s += "X1: " + std::string(2000, '*') + "\r\n";
|
}
|
||||||
return s;
|
};
|
||||||
}();
|
|
||||||
|
|
||||||
// request in stream
|
template<std::size_t N>
|
||||||
doStreamLoop([&](test::stream& ts)
|
static
|
||||||
{
|
net::const_buffer
|
||||||
stream<test::stream&> ws{ts};
|
sbuf(const char (&s)[N])
|
||||||
auto tr = connect(ws.next_layer());
|
{
|
||||||
ts.append(
|
return net::const_buffer(&s[0], N-1);
|
||||||
"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");
|
|
||||||
ts.read_size(20);
|
|
||||||
w.accept(ws);
|
|
||||||
// VFALCO validate contents of ws.next_layer().str?
|
|
||||||
});
|
|
||||||
|
|
||||||
// request in stream, oversized
|
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)
|
||||||
{
|
{
|
||||||
stream<test::stream> ws{ioc_,
|
test::fail_count fc(n);
|
||||||
"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
|
try
|
||||||
{
|
{
|
||||||
w.accept(ws);
|
stream<test::stream> ws(ioc, fc);
|
||||||
fail("", __FILE__, __LINE__);
|
auto tr = connect(ws.next_layer());
|
||||||
|
f(ws);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
catch(system_error const& se)
|
catch(system_error const& se)
|
||||||
{
|
{
|
||||||
// VFALCO Its the http error category...
|
if(! BEAST_EXPECTS(
|
||||||
BEAST_EXPECTS(
|
se.code() == test::error::test_failure,
|
||||||
se.code() == http::error::buffer_overflow,
|
se.code().message()))
|
||||||
se.code().message());
|
throw;
|
||||||
|
if(! BEAST_EXPECTS(
|
||||||
|
clock_type::now() < expires_at,
|
||||||
|
"a test timeout occurred"))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// request in stream, decorator
|
template<class Api>
|
||||||
doStreamLoop([&](test::stream& ts)
|
void
|
||||||
|
testMatrix(Api api)
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
|
||||||
|
// request in stream
|
||||||
|
fail_loop([&](stream<test::stream>& ws)
|
||||||
{
|
{
|
||||||
stream<test::stream&> ws{ts};
|
ws.next_layer().append(
|
||||||
auto tr = connect(ws.next_layer());
|
|
||||||
ts.append(
|
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
@@ -111,45 +105,31 @@ public:
|
|||||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
ts.read_size(20);
|
ws.next_layer().read_size(20);
|
||||||
|
api.accept(ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
// request in stream, decorator
|
||||||
|
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-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
ws.next_layer().read_size(20);
|
||||||
bool called = false;
|
bool called = false;
|
||||||
w.accept_ex(ws, res_decorator{called});
|
api.accept_ex(ws, res_decorator{called});
|
||||||
BEAST_EXPECT(called);
|
BEAST_EXPECT(called);
|
||||||
});
|
});
|
||||||
|
|
||||||
// request in stream, decorator, oversized
|
|
||||||
{
|
|
||||||
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"
|
|
||||||
+ big +
|
|
||||||
"\r\n"};
|
|
||||||
auto tr = connect(ws.next_layer());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool called = false;
|
|
||||||
w.accept_ex(ws, res_decorator{called});
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// request in buffers
|
// request in buffers
|
||||||
doStreamLoop([&](test::stream& ts)
|
fail_loop([&](stream<test::stream>& ws)
|
||||||
{
|
{
|
||||||
stream<test::stream&> ws{ts};
|
api.accept(ws, sbuf(
|
||||||
auto tr = connect(ws.next_layer());
|
|
||||||
w.accept(ws, sbuf(
|
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
@@ -160,39 +140,11 @@ public:
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
// request in buffers, oversize
|
|
||||||
{
|
|
||||||
stream<test::stream> ws{ioc_};
|
|
||||||
auto tr = connect(ws.next_layer());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
w.accept(ws, net::buffer(
|
|
||||||
"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"
|
|
||||||
));
|
|
||||||
fail("", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
catch(system_error const& se)
|
|
||||||
{
|
|
||||||
BEAST_EXPECTS(
|
|
||||||
se.code() == error::buffer_overflow,
|
|
||||||
se.code().message());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// request in buffers, decorator
|
// request in buffers, decorator
|
||||||
doStreamLoop([&](test::stream& ts)
|
fail_loop([&](stream<test::stream>& ws)
|
||||||
{
|
{
|
||||||
stream<test::stream&> ws{ts};
|
|
||||||
auto tr = connect(ws.next_layer());
|
|
||||||
bool called = false;
|
bool called = false;
|
||||||
w.accept_ex(ws, sbuf(
|
api.accept_ex(ws, sbuf(
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
@@ -204,14 +156,235 @@ public:
|
|||||||
BEAST_EXPECT(called);
|
BEAST_EXPECT(called);
|
||||||
});
|
});
|
||||||
|
|
||||||
// request in buffers, decorator, oversized
|
// request in buffers and stream
|
||||||
|
fail_loop([&](stream<test::stream>& ws)
|
||||||
{
|
{
|
||||||
stream<test::stream> ws{ioc_};
|
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");
|
||||||
|
ws.next_layer().read_size(16);
|
||||||
|
bool called = false;
|
||||||
|
api.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 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;
|
||||||
|
api.accept_ex(ws, req,
|
||||||
|
res_decorator{called});
|
||||||
|
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,
|
||||||
|
"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
|
||||||
|
{
|
||||||
|
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 stream, decorator
|
||||||
|
{
|
||||||
|
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"
|
||||||
|
+ big +
|
||||||
|
"\r\n"};
|
||||||
auto tr = connect(ws.next_layer());
|
auto tr = connect(ws.next_layer());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool called = false;
|
bool called = false;
|
||||||
w.accept_ex(ws, net::buffer(
|
api.accept_ex(ws, res_decorator{called});
|
||||||
|
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
|
||||||
|
{
|
||||||
|
stream<test::stream> ws{ioc};
|
||||||
|
auto tr = connect(ws.next_layer());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
api.accept(ws, net::buffer(
|
||||||
|
"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"
|
||||||
|
));
|
||||||
|
BEAST_FAIL();
|
||||||
|
}
|
||||||
|
catch(system_error const& se)
|
||||||
|
{
|
||||||
|
BEAST_EXPECTS(
|
||||||
|
se.code() == error::buffer_overflow,
|
||||||
|
se.code().message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// request in buffers, decorator
|
||||||
|
{
|
||||||
|
stream<test::stream> ws{ioc};
|
||||||
|
auto tr = connect(ws.next_layer());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
api.accept_ex(ws, net::buffer(
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
@@ -221,7 +394,7 @@ public:
|
|||||||
+ big +
|
+ big +
|
||||||
"\r\n"),
|
"\r\n"),
|
||||||
res_decorator{called});
|
res_decorator{called});
|
||||||
fail("", __FILE__, __LINE__);
|
BEAST_FAIL();
|
||||||
}
|
}
|
||||||
catch(system_error const& se)
|
catch(system_error const& se)
|
||||||
{
|
{
|
||||||
@@ -232,27 +405,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// request in buffers and stream
|
// request in buffers and stream
|
||||||
doStreamLoop([&](test::stream& ts)
|
|
||||||
{
|
{
|
||||||
stream<test::stream&> ws{ts};
|
stream<test::stream> ws{ioc,
|
||||||
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_,
|
|
||||||
"Connection: upgrade\r\n"
|
"Connection: upgrade\r\n"
|
||||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
@@ -261,12 +415,12 @@ public:
|
|||||||
auto tr = connect(ws.next_layer());
|
auto tr = connect(ws.next_layer());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
w.accept(ws, sbuf(
|
api.accept(ws, websocket_test_suite::sbuf(
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
));
|
));
|
||||||
fail("", __FILE__, __LINE__);
|
BEAST_FAIL();
|
||||||
}
|
}
|
||||||
catch(system_error const& se)
|
catch(system_error const& se)
|
||||||
{
|
{
|
||||||
@@ -277,28 +431,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// request in buffers and stream, decorator
|
// request in buffers and stream, decorator
|
||||||
doStreamLoop([&](test::stream& ts)
|
|
||||||
{
|
{
|
||||||
stream<test::stream&> ws{ts};
|
stream<test::stream> ws{ioc,
|
||||||
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_,
|
|
||||||
"Connection: upgrade\r\n"
|
"Connection: upgrade\r\n"
|
||||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
@@ -308,12 +442,12 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool called = false;
|
bool called = false;
|
||||||
w.accept_ex(ws, sbuf(
|
api.accept_ex(ws, websocket_test_suite::sbuf(
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"Upgrade: websocket\r\n"),
|
"Upgrade: websocket\r\n"),
|
||||||
res_decorator{called});
|
res_decorator{called});
|
||||||
fail("", __FILE__, __LINE__);
|
BEAST_FAIL();
|
||||||
}
|
}
|
||||||
catch(system_error const& se)
|
catch(system_error const& se)
|
||||||
{
|
{
|
||||||
@@ -322,137 +456,15 @@ public:
|
|||||||
se.code().message());
|
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() !=
|
|
||||||
net::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
|
void
|
||||||
testAccept()
|
testInvalidInputs()
|
||||||
{
|
{
|
||||||
doTestAccept(SyncClient{});
|
net::io_context ioc;
|
||||||
|
|
||||||
yield_to([&](yield_context yield)
|
|
||||||
{
|
|
||||||
doTestAccept(AsyncClient{yield});
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
|
||||||
// Bad requests
|
|
||||||
//
|
|
||||||
|
|
||||||
auto const check =
|
auto const check =
|
||||||
[&](error_code const& ev, std::string const& s)
|
[&](error_code ev, string_view s)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 3; ++i)
|
for(int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
@@ -470,14 +482,14 @@ public:
|
|||||||
n = s.size() - 1;
|
n = s.size() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stream<test::stream> ws{ioc_};
|
stream<test::stream> ws(ioc);
|
||||||
auto tr = connect(ws.next_layer());
|
auto tr = connect(ws.next_layer());
|
||||||
ws.next_layer().append(
|
ws.next_layer().append(
|
||||||
s.substr(n, s.size() - n));
|
s.substr(n, s.size() - n));
|
||||||
|
tr.close();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ws.accept(
|
ws.accept(net::buffer(s.data(), n));
|
||||||
net::buffer(s.data(), n));
|
|
||||||
BEAST_EXPECTS(! ev, ev.message());
|
BEAST_EXPECTS(! ev, ev.message());
|
||||||
}
|
}
|
||||||
catch(system_error const& se)
|
catch(system_error const& se)
|
||||||
@@ -497,6 +509,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// bad method
|
// bad method
|
||||||
check(error::bad_method,
|
check(error::bad_method,
|
||||||
"POST / HTTP/1.1\r\n"
|
"POST / HTTP/1.1\r\n"
|
||||||
@@ -507,6 +520,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Host
|
// no Host
|
||||||
check(error::no_host,
|
check(error::no_host,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -516,6 +530,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Connection
|
// no Connection
|
||||||
check(error::no_connection,
|
check(error::no_connection,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -525,6 +540,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Connection upgrade
|
// no Connection upgrade
|
||||||
check(error::no_connection_upgrade,
|
check(error::no_connection_upgrade,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -535,6 +551,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Upgrade
|
// no Upgrade
|
||||||
check(error::no_upgrade,
|
check(error::no_upgrade,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -544,6 +561,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Upgrade websocket
|
// no Upgrade websocket
|
||||||
check(error::no_upgrade_websocket,
|
check(error::no_upgrade_websocket,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -554,6 +572,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Sec-WebSocket-Key
|
// no Sec-WebSocket-Key
|
||||||
check(error::no_sec_key,
|
check(error::no_sec_key,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -563,6 +582,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// bad Sec-WebSocket-Key
|
// bad Sec-WebSocket-Key
|
||||||
check(error::bad_sec_key,
|
check(error::bad_sec_key,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -573,6 +593,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no Sec-WebSocket-Version
|
// no Sec-WebSocket-Version
|
||||||
check(error::no_sec_version,
|
check(error::no_sec_version,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -582,6 +603,7 @@ public:
|
|||||||
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// bad Sec-WebSocket-Version
|
// bad Sec-WebSocket-Version
|
||||||
check(error::bad_sec_version,
|
check(error::bad_sec_version,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -592,6 +614,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 1\r\n"
|
"Sec-WebSocket-Version: 1\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// bad Sec-WebSocket-Version
|
// bad Sec-WebSocket-Version
|
||||||
check(error::bad_sec_version,
|
check(error::bad_sec_version,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -602,6 +625,7 @@ public:
|
|||||||
"Sec-WebSocket-Version: 12\r\n"
|
"Sec-WebSocket-Version: 12\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// valid request
|
// valid request
|
||||||
check({},
|
check({},
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
@@ -615,13 +639,53 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testTimeout()
|
testEndOfStream()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testAsync()
|
||||||
{
|
{
|
||||||
using tcp = net::ip::tcp;
|
using tcp = net::ip::tcp;
|
||||||
|
|
||||||
net::io_context ioc;
|
net::io_context ioc;
|
||||||
|
|
||||||
// success
|
// success, no timeout
|
||||||
|
|
||||||
{
|
{
|
||||||
stream<tcp::socket> ws1(ioc);
|
stream<tcp::socket> ws1(ioc);
|
||||||
@@ -700,47 +764,49 @@ public:
|
|||||||
ws1.async_accept(test::fail_handler(beast::error::timeout));
|
ws1.async_accept(test::fail_handler(beast::error::timeout));
|
||||||
test::run_for(ioc, std::chrono::seconds(1));
|
test::run_for(ioc, std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
// abandoned operation
|
||||||
testMoveOnly()
|
|
||||||
{
|
|
||||||
net::io_context ioc;
|
|
||||||
stream<test::stream> ws{ioc};
|
|
||||||
ws.async_accept(move_only_handler{});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct copyable_handler
|
|
||||||
{
|
|
||||||
template<class... Args>
|
|
||||||
void
|
|
||||||
operator()(Args&&...) const
|
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
stream<tcp::socket> ws1(ioc);
|
||||||
|
ws1.async_accept(test::fail_handler(
|
||||||
|
net::error::operation_aborted));
|
||||||
|
}
|
||||||
|
test::run(ioc);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
void
|
{
|
||||||
testAsioHandlerInvoke()
|
{
|
||||||
{
|
stream<tcp::socket> ws1(ioc);
|
||||||
// make sure things compile, also can set a
|
string_view s =
|
||||||
// breakpoint in asio_handler_invoke to make sure
|
"GET / HTTP/1.1\r\n"
|
||||||
// it is instantiated.
|
"Host: localhost\r\n"
|
||||||
net::io_context ioc;
|
"Upgrade: websocket\r\n"
|
||||||
net::strand<
|
"Connection: upgrade\r\n"
|
||||||
net::io_context::executor_type> s(
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
ioc.get_executor());
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
stream<test::stream> ws{ioc};
|
"\r\n";
|
||||||
ws.async_accept(net::bind_executor(
|
error_code ec;
|
||||||
s, copyable_handler{}));
|
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
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
testAccept();
|
testMatrix(test_sync_api{});
|
||||||
testTimeout();
|
testMatrix(test_async_api{});
|
||||||
testMoveOnly();
|
testOversized(test_sync_api{});
|
||||||
testAsioHandlerInvoke();
|
testOversized(test_async_api{});
|
||||||
|
testInvalidInputs();
|
||||||
|
testEndOfStream();
|
||||||
|
testAsync();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1013,6 +1013,612 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct test_sync_api
|
||||||
|
{
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
stream<NextLayer, deflateSupported>& ws) const
|
||||||
|
{
|
||||||
|
ws.accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers>
|
||||||
|
typename std::enable_if<
|
||||||
|
! http::detail::is_header<Buffers>::value>::type
|
||||||
|
accept(stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Buffers const& buffers) const
|
||||||
|
{
|
||||||
|
ws.accept(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req) const
|
||||||
|
{
|
||||||
|
ws.accept(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.accept_ex(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers, class Decorator>
|
||||||
|
typename std::enable_if<
|
||||||
|
! http::detail::is_header<Buffers>::value>::type
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Buffers const& buffers,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.accept_ex(buffers, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.accept_ex(req, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers, class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req,
|
||||||
|
Buffers const& buffers,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.accept_ex(req, buffers, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
handshake(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
response_type& res,
|
||||||
|
string_view uri,
|
||||||
|
string_view path) const
|
||||||
|
{
|
||||||
|
ws.handshake(res, uri, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
handshake_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
string_view uri,
|
||||||
|
string_view path,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.handshake_ex(uri, path, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
handshake_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
response_type& res,
|
||||||
|
string_view uri,
|
||||||
|
string_view path,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
ws.handshake_ex(res, uri, path, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
ping(stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ping_data const& payload) const
|
||||||
|
{
|
||||||
|
ws.ping(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
pong(stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ping_data const& payload) const
|
||||||
|
{
|
||||||
|
ws.pong(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
close(stream<NextLayer, deflateSupported>& ws,
|
||||||
|
close_reason const& cr) const
|
||||||
|
{
|
||||||
|
ws.close(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class DynamicBuffer>
|
||||||
|
std::size_t
|
||||||
|
read(stream<NextLayer, deflateSupported>& ws,
|
||||||
|
DynamicBuffer& buffer) const
|
||||||
|
{
|
||||||
|
return ws.read(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class DynamicBuffer>
|
||||||
|
std::size_t
|
||||||
|
read_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
std::size_t limit,
|
||||||
|
DynamicBuffer& buffer) const
|
||||||
|
{
|
||||||
|
return ws.read_some(buffer, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
MutableBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
return ws.read_some(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
return ws.write(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
bool fin,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
return ws.write_some(fin, buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_raw(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
return net::write(
|
||||||
|
ws.next_layer(), buffers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class test_async_api
|
||||||
|
{
|
||||||
|
struct handler
|
||||||
|
{
|
||||||
|
error_code& ec_;
|
||||||
|
std::size_t* n_ = 0;
|
||||||
|
bool pass_ = false;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
handler(error_code& ec)
|
||||||
|
: ec_(ec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit
|
||||||
|
handler(error_code& ec, std::size_t& n)
|
||||||
|
: ec_(ec)
|
||||||
|
, n_(&n)
|
||||||
|
{
|
||||||
|
*n_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(handler&& other)
|
||||||
|
: ec_(other.ec_)
|
||||||
|
, pass_(boost::exchange(other.pass_, true))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~handler()
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(pass_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(! pass_);
|
||||||
|
pass_ = true;
|
||||||
|
ec_ = ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec, std::size_t n)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(! pass_);
|
||||||
|
pass_ = true;
|
||||||
|
ec_ = ec;
|
||||||
|
if(n_)
|
||||||
|
*n_ = n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
stream<NextLayer, deflateSupported>& ws) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers>
|
||||||
|
typename std::enable_if<
|
||||||
|
! http::detail::is_header<Buffers>::value>::type
|
||||||
|
accept(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Buffers const& buffers) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(buffers, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
accept(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(req, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept_ex(d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers, class Decorator>
|
||||||
|
typename std::enable_if<
|
||||||
|
! http::detail::is_header<Buffers>::value>::type
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
Buffers const& buffers,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept_ex(buffers, d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept_ex(req, d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Buffers, class Decorator>
|
||||||
|
void
|
||||||
|
accept_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
http::request<http::empty_body> const& req,
|
||||||
|
Buffers const& buffers,
|
||||||
|
Decorator const& d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept_ex(
|
||||||
|
req, buffers, d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
handshake(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
string_view uri,
|
||||||
|
string_view path) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_handshake(
|
||||||
|
uri, path, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
handshake(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
response_type& res,
|
||||||
|
string_view uri,
|
||||||
|
string_view path) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_handshake(
|
||||||
|
res, uri, path, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
handshake_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
string_view uri,
|
||||||
|
string_view path,
|
||||||
|
Decorator const &d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_handshake_ex(
|
||||||
|
uri, path, d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class Decorator>
|
||||||
|
void
|
||||||
|
handshake_ex(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
response_type& res,
|
||||||
|
string_view uri,
|
||||||
|
string_view path,
|
||||||
|
Decorator const &d) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_handshake_ex(
|
||||||
|
res, uri, path, d, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
ping(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ping_data const& payload) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_ping(payload, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
pong(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ping_data const& payload) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_pong(payload, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class NextLayer, bool deflateSupported>
|
||||||
|
void
|
||||||
|
close(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
close_reason const& cr) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ws.async_close(cr, handler(ec));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class DynamicBuffer>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
DynamicBuffer& buffer) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
ws.async_read(buffer, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class DynamicBuffer>
|
||||||
|
std::size_t
|
||||||
|
read_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
std::size_t limit,
|
||||||
|
DynamicBuffer& buffer) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
ws.async_read_some(buffer, limit, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
MutableBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
ws.async_read_some(buffers, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
ws.async_write(buffers, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
bool fin,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
ws.async_write_some(fin, buffers, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class NextLayer, bool deflateSupported,
|
||||||
|
class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_raw(
|
||||||
|
stream<NextLayer, deflateSupported>& ws,
|
||||||
|
ConstBufferSequence const& buffers) const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n;
|
||||||
|
net::async_write(ws.next_layer(),
|
||||||
|
buffers, handler(ec, n));
|
||||||
|
ws.get_executor().context().run();
|
||||||
|
ws.get_executor().context().restart();
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // websocket
|
} // websocket
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
Reference in New Issue
Block a user