2016-04-30 13:00:33 -04:00
|
|
|
//
|
2017-08-21 14:45:58 -07:00
|
|
|
// Copyright (w) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2016-04-30 13:00:33 -04: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)
|
|
|
|
|
//
|
2017-07-20 13:40:34 -07:00
|
|
|
// Official repository: https://github.com/boostorg/beast
|
|
|
|
|
//
|
2016-04-30 13:00:33 -04:00
|
|
|
|
|
|
|
|
// Test that header file is self-contained.
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/websocket/stream.hpp>
|
2016-04-30 13:00:33 -04:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/core/ostream.hpp>
|
|
|
|
|
#include <boost/beast/core/multi_buffer.hpp>
|
2017-08-01 20:15:07 -07:00
|
|
|
#include <boost/beast/test/stream.hpp>
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/test/yield_to.hpp>
|
|
|
|
|
#include <boost/beast/unit_test/suite.hpp>
|
2017-08-22 18:08:56 -07:00
|
|
|
#include <boost/optional.hpp>
|
2017-08-01 20:15:07 -07:00
|
|
|
#include <memory>
|
2017-08-22 18:08:56 -07:00
|
|
|
#include <random>
|
2016-04-30 13:00:33 -04:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
namespace boost {
|
2016-04-30 13:00:33 -04:00
|
|
|
namespace beast {
|
|
|
|
|
namespace websocket {
|
|
|
|
|
|
2016-05-04 17:27:50 -04:00
|
|
|
class stream_test
|
2016-05-06 19:14:17 -04:00
|
|
|
: public beast::unit_test::suite
|
2016-05-04 17:27:50 -04:00
|
|
|
, public test::enable_yield_to
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
|
|
|
|
public:
|
2016-05-15 16:22:25 -04:00
|
|
|
using self = stream_test;
|
2016-04-30 13:00:33 -04:00
|
|
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
|
|
|
|
using address_type = boost::asio::ip::address;
|
|
|
|
|
using socket_type = boost::asio::ip::tcp::socket;
|
|
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
using ws_type =
|
|
|
|
|
websocket::stream<test::stream&>;
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
enum class kind
|
|
|
|
|
{
|
|
|
|
|
sync,
|
|
|
|
|
async,
|
|
|
|
|
async_client
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
class echo_server
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
buf_size = 20000
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
std::ostream& log_;
|
2017-08-21 14:45:58 -07:00
|
|
|
boost::asio::io_service ios_;
|
2017-08-22 18:08:56 -07:00
|
|
|
boost::optional<
|
|
|
|
|
boost::asio::io_service::work> work_;
|
|
|
|
|
static_buffer<buf_size> buffer_;
|
2017-08-21 14:45:58 -07:00
|
|
|
test::stream ts_;
|
|
|
|
|
std::thread t_;
|
|
|
|
|
websocket::stream<test::stream&> ws_;
|
2017-08-01 20:15:07 -07:00
|
|
|
|
|
|
|
|
public:
|
2017-08-21 14:45:58 -07:00
|
|
|
explicit
|
|
|
|
|
echo_server(
|
2017-08-01 20:15:07 -07:00
|
|
|
std::ostream& log,
|
2017-08-22 18:08:56 -07:00
|
|
|
kind k = kind::sync)
|
2017-08-01 20:15:07 -07:00
|
|
|
: log_(log)
|
2017-08-22 18:08:56 -07:00
|
|
|
, work_(ios_)
|
2017-08-21 14:45:58 -07:00
|
|
|
, ts_(ios_)
|
|
|
|
|
, ws_(ts_)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
pmd.server_enable = true;
|
|
|
|
|
ws_.set_option(pmd);
|
|
|
|
|
|
|
|
|
|
switch(k)
|
2017-08-21 14:45:58 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
case kind::sync:
|
|
|
|
|
t_ = std::thread{[&]{ do_sync(); }};
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kind::async:
|
|
|
|
|
t_ = std::thread{[&]{ ios_.run(); }};
|
|
|
|
|
do_accept();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kind::async_client:
|
|
|
|
|
t_ = std::thread{[&]{ ios_.run(); }};
|
|
|
|
|
break;
|
2017-08-21 14:45:58 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~echo_server()
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
work_ = boost::none;
|
2017-08-21 14:45:58 -07:00
|
|
|
t_.join();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test::stream&
|
|
|
|
|
stream()
|
|
|
|
|
{
|
|
|
|
|
return ts_;
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
void
|
|
|
|
|
async_handshake()
|
|
|
|
|
{
|
|
|
|
|
ws_.async_handshake("localhost", "/",
|
|
|
|
|
std::bind(
|
|
|
|
|
&echo_server::on_handshake,
|
|
|
|
|
this,
|
|
|
|
|
std::placeholders::_1));
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
void
|
2017-08-21 14:45:58 -07:00
|
|
|
async_close()
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
ios_.post(
|
|
|
|
|
[&]
|
|
|
|
|
{
|
|
|
|
|
ws_.async_close({},
|
|
|
|
|
std::bind(
|
|
|
|
|
&echo_server::on_close,
|
|
|
|
|
this,
|
|
|
|
|
std::placeholders::_1));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void
|
2017-08-22 18:08:56 -07:00
|
|
|
do_sync()
|
2017-08-21 14:45:58 -07:00
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
ws_.accept();
|
2017-08-21 14:45:58 -07:00
|
|
|
for(;;)
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
ws_.read(buffer_);
|
|
|
|
|
ws_.text(ws_.got_text());
|
|
|
|
|
ws_.write(buffer_.data());
|
|
|
|
|
buffer_.consume(buffer_.size());
|
2017-08-21 14:45:58 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
boost::ignore_unused(se);
|
|
|
|
|
#if 0
|
2017-08-21 14:45:58 -07:00
|
|
|
if( se.code() != error::closed &&
|
|
|
|
|
se.code() != error::failed &&
|
|
|
|
|
se.code() != boost::asio::error::eof)
|
|
|
|
|
log_ << "echo_server: " << se.code().message() << std::endl;
|
2017-08-22 18:08:56 -07:00
|
|
|
#endif
|
2017-08-21 14:45:58 -07:00
|
|
|
}
|
|
|
|
|
catch(std::exception const& e)
|
|
|
|
|
{
|
|
|
|
|
log_ << "echo_server: " << e.what() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2017-08-22 18:08:56 -07:00
|
|
|
do_accept()
|
2017-08-21 14:45:58 -07:00
|
|
|
{
|
|
|
|
|
ws_.async_accept(std::bind(
|
|
|
|
|
&echo_server::on_accept,
|
|
|
|
|
this,
|
|
|
|
|
std::placeholders::_1));
|
2017-08-22 18:08:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
on_handshake(error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec);
|
|
|
|
|
do_read();
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
on_accept(error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec);
|
|
|
|
|
do_read();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_read()
|
|
|
|
|
{
|
|
|
|
|
ws_.async_read(buffer_,
|
2017-08-21 14:45:58 -07:00
|
|
|
std::bind(
|
|
|
|
|
&echo_server::on_read,
|
|
|
|
|
this,
|
|
|
|
|
std::placeholders::_1));
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
on_read(error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec);
|
|
|
|
|
ws_.text(ws_.got_text());
|
|
|
|
|
ws_.async_write(buffer_.data(),
|
2017-08-21 14:45:58 -07:00
|
|
|
std::bind(
|
|
|
|
|
&echo_server::on_write,
|
|
|
|
|
this,
|
|
|
|
|
std::placeholders::_1));
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
on_write(error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec);
|
|
|
|
|
buffer_.consume(buffer_.size());
|
|
|
|
|
do_read();
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
void
|
|
|
|
|
on_close(error_code ec)
|
|
|
|
|
{
|
|
|
|
|
if(ec)
|
|
|
|
|
return fail(ec);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
void
|
|
|
|
|
fail(error_code ec)
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
boost::ignore_unused(ec);
|
|
|
|
|
#if 0
|
2017-08-01 20:15:07 -07:00
|
|
|
if( ec != error::closed &&
|
|
|
|
|
ec != error::failed &&
|
|
|
|
|
ec != boost::asio::error::eof)
|
|
|
|
|
log_ <<
|
2017-08-22 18:08:56 -07:00
|
|
|
"echo_server_async: " <<
|
2017-08-01 20:15:07 -07:00
|
|
|
ec.message() <<
|
|
|
|
|
std::endl;
|
2017-08-22 18:08:56 -07:00
|
|
|
#endif
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
template<class Test>
|
|
|
|
|
void
|
|
|
|
|
doTestLoop(Test const& f)
|
|
|
|
|
{
|
2017-08-12 15:03:39 -07:00
|
|
|
// This number has to be high for the
|
|
|
|
|
// test that writes the large buffer.
|
|
|
|
|
static std::size_t constexpr limit = 1000;
|
2017-08-01 20:15:07 -07:00
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
std::size_t n;
|
|
|
|
|
for(n = 0; n <= limit; ++n)
|
2017-08-21 14:45:58 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
test::fail_counter fc{n};
|
|
|
|
|
test::stream ts{ios_, fc};
|
|
|
|
|
try
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
f(ts);
|
2017-08-01 20:15:07 -07:00
|
|
|
ts.close();
|
2017-08-22 18:08:56 -07:00
|
|
|
break;
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
2017-08-22 18:08:56 -07:00
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == test::error::fail_error,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
catch(std::exception const& e)
|
|
|
|
|
{
|
|
|
|
|
fail(e.what(), __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
|
|
|
|
continue;
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
2017-08-22 18:08:56 -07:00
|
|
|
BEAST_EXPECT(n < limit);
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
2017-08-21 14:45:58 -07:00
|
|
|
|
|
|
|
|
template<class Test>
|
2017-08-01 20:15:07 -07:00
|
|
|
void
|
|
|
|
|
doTest(
|
|
|
|
|
permessage_deflate const& pmd,
|
|
|
|
|
Test const& f)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
// This number has to be high for the
|
|
|
|
|
// test that writes the large buffer.
|
|
|
|
|
static std::size_t constexpr limit = 1000;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 2; ++i)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
std::size_t n;
|
|
|
|
|
for(n = 0; n <= limit; ++n)
|
|
|
|
|
{
|
|
|
|
|
test::fail_counter fc{n};
|
|
|
|
|
test::stream ts{ios_, fc};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.set_option(pmd);
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, i==1 ?
|
|
|
|
|
kind::async : kind::sync};
|
2017-08-21 14:45:58 -07:00
|
|
|
error_code ec;
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
if(ec)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
if( ! BEAST_EXPECTS(
|
|
|
|
|
ec == test::error::fail_error,
|
|
|
|
|
ec.message()))
|
|
|
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
f(ws);
|
|
|
|
|
ts.close();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == test::error::fail_error,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
catch(std::exception const& e)
|
|
|
|
|
{
|
|
|
|
|
fail(e.what(), __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
BEAST_EXPECT(n < limit);
|
|
|
|
|
}
|
2017-08-01 20:15:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
2017-08-12 15:03:39 -07:00
|
|
|
doCloseTest(
|
2017-08-01 20:15:07 -07:00
|
|
|
Wrap const& w,
|
2017-08-21 14:45:58 -07:00
|
|
|
ws_type& ws,
|
2017-08-01 20:15:07 -07:00
|
|
|
close_code code)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
2017-08-12 15:03:39 -07:00
|
|
|
if(se.code() != error::closed)
|
2017-08-01 20:15:07 -07:00
|
|
|
throw;
|
|
|
|
|
BEAST_EXPECT(
|
|
|
|
|
ws.reason().code == code);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
|
|
|
|
doFailTest(
|
|
|
|
|
Wrap const& w,
|
2017-08-21 14:45:58 -07:00
|
|
|
ws_type& ws,
|
2017-08-12 15:03:39 -07:00
|
|
|
error_code ev)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
if(se.code() != ev)
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-05-04 05:01:50 -07:00
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
static
|
|
|
|
|
std::string
|
|
|
|
|
to_string(ConstBufferSequence const& bs)
|
|
|
|
|
{
|
2017-07-21 08:55:25 -07:00
|
|
|
using boost::asio::buffer_cast;
|
|
|
|
|
using boost::asio::buffer_size;
|
|
|
|
|
std::string s;
|
|
|
|
|
s.reserve(buffer_size(bs));
|
|
|
|
|
for(boost::asio::const_buffer b : bs)
|
|
|
|
|
s.append(buffer_cast<char const*>(b),
|
|
|
|
|
buffer_size(b));
|
|
|
|
|
return s;
|
2017-05-04 05:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
template<std::size_t N>
|
|
|
|
|
class cbuf_helper
|
|
|
|
|
{
|
|
|
|
|
std::array<std::uint8_t, N> v_;
|
|
|
|
|
boost::asio::const_buffer cb_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
using value_type = decltype(cb_);
|
|
|
|
|
using const_iterator = value_type const*;
|
|
|
|
|
|
|
|
|
|
template<class... Vn>
|
|
|
|
|
explicit
|
|
|
|
|
cbuf_helper(Vn... vn)
|
|
|
|
|
: v_({{ static_cast<std::uint8_t>(vn)... }})
|
|
|
|
|
, cb_(v_.data(), v_.size())
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
const_iterator
|
|
|
|
|
begin() const
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
return &cb_;
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
2016-05-15 16:22:25 -04:00
|
|
|
|
|
|
|
|
const_iterator
|
|
|
|
|
end() const
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
return begin()+1;
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
2016-05-15 16:22:25 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class... Vn>
|
|
|
|
|
cbuf_helper<sizeof...(Vn)>
|
|
|
|
|
cbuf(Vn... vn)
|
|
|
|
|
{
|
|
|
|
|
return cbuf_helper<sizeof...(Vn)>(vn...);
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<std::size_t N>
|
|
|
|
|
static
|
|
|
|
|
boost::asio::const_buffers_1
|
2016-05-15 16:22:25 -04:00
|
|
|
sbuf(const char (&s)[N])
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
|
|
|
|
return boost::asio::const_buffers_1(&s[0], N-1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
template<
|
|
|
|
|
class DynamicBuffer,
|
|
|
|
|
class ConstBufferSequence>
|
|
|
|
|
static
|
|
|
|
|
void
|
|
|
|
|
put(
|
|
|
|
|
DynamicBuffer& buffer,
|
|
|
|
|
ConstBufferSequence const& buffers)
|
|
|
|
|
{
|
|
|
|
|
using boost::asio::buffer_copy;
|
|
|
|
|
using boost::asio::buffer_size;
|
|
|
|
|
buffer.commit(buffer_copy(
|
|
|
|
|
buffer.prepare(buffer_size(buffers)),
|
|
|
|
|
buffers));
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
template<class Pred>
|
|
|
|
|
static
|
|
|
|
|
bool
|
|
|
|
|
run_until(boost::asio::io_service& ios,
|
|
|
|
|
std::size_t limit, Pred&& pred)
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
for(std::size_t i = 0; i < limit; ++i)
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
if(pred())
|
|
|
|
|
return true;
|
|
|
|
|
ios.run_one();
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
2016-05-15 16:22:25 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
struct SyncClient
|
|
|
|
|
{
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
accept(stream<NextLayer>& ws) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Buffers>
|
2017-05-08 12:41:45 -07:00
|
|
|
typename std::enable_if<
|
|
|
|
|
! http::detail::is_header<Buffers>::value>::type
|
2017-04-25 10:12:43 -07:00
|
|
|
accept(stream<NextLayer>& ws,
|
|
|
|
|
Buffers const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept(buffers);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 13:00:09 -07:00
|
|
|
template<class NextLayer>
|
2017-04-25 10:12:43 -07:00
|
|
|
void
|
|
|
|
|
accept(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
|
|
|
|
ws.accept(req);
|
|
|
|
|
}
|
|
|
|
|
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
template<class NextLayer, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
accept_ex(stream<NextLayer>& ws,
|
|
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept_ex(d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer,
|
|
|
|
|
class Buffers, class Decorator>
|
2017-05-08 12:41:45 -07:00
|
|
|
typename std::enable_if<
|
|
|
|
|
! http::detail::is_header<Buffers>::value>::type
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
accept_ex(stream<NextLayer>& ws,
|
|
|
|
|
Buffers const& buffers,
|
|
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept_ex(buffers, d);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 13:00:09 -07:00
|
|
|
template<class NextLayer, class Decorator>
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
void
|
|
|
|
|
accept_ex(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept_ex(req, d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer,
|
2017-07-14 13:00:09 -07:00
|
|
|
class Buffers, class Decorator>
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
void
|
|
|
|
|
accept_ex(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Buffers const& buffers,
|
|
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.accept_ex(req, buffers, d);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
handshake(stream<NextLayer>& ws,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
|
|
|
|
ws.handshake(uri, path);
|
|
|
|
|
}
|
|
|
|
|
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
handshake(stream<NextLayer>& ws,
|
|
|
|
|
response_type& res,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path) const
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
|
|
|
|
ws.handshake(res, uri, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
handshake_ex(stream<NextLayer>& ws,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.handshake_ex(uri, path, d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
handshake_ex(stream<NextLayer>& ws,
|
|
|
|
|
response_type& res,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
ws.handshake_ex(res, uri, path, d);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
ping(stream<NextLayer>& ws,
|
|
|
|
|
ping_data const& payload) const
|
|
|
|
|
{
|
|
|
|
|
ws.ping(payload);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
pong(stream<NextLayer>& ws,
|
|
|
|
|
ping_data const& payload) const
|
|
|
|
|
{
|
|
|
|
|
ws.pong(payload);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
close(stream<NextLayer>& ws,
|
|
|
|
|
close_reason const& cr) const
|
|
|
|
|
{
|
|
|
|
|
ws.close(cr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class DynamicBuffer>
|
2017-07-25 08:50:58 -07:00
|
|
|
std::size_t
|
2017-04-25 10:12:43 -07:00
|
|
|
read(stream<NextLayer>& ws,
|
2017-06-08 19:55:42 -07:00
|
|
|
DynamicBuffer& buffer) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
2017-07-15 17:05:24 -07:00
|
|
|
return ws.read(buffer);
|
2017-04-25 10:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class DynamicBuffer>
|
|
|
|
|
std::size_t
|
|
|
|
|
read_some(stream<NextLayer>& ws,
|
|
|
|
|
std::size_t limit,
|
|
|
|
|
DynamicBuffer& buffer) const
|
|
|
|
|
{
|
|
|
|
|
return ws.read_some(buffer, limit);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 04:21:24 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class MutableBufferSequence>
|
|
|
|
|
std::size_t
|
|
|
|
|
read_some(stream<NextLayer>& ws,
|
|
|
|
|
MutableBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
return ws.read_some(buffers);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
write(stream<NextLayer>& ws,
|
|
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
ws.write(buffers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
2017-07-15 17:05:24 -07:00
|
|
|
write_some(stream<NextLayer>& ws, bool fin,
|
2017-04-25 10:12:43 -07:00
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
2017-07-15 17:05:24 -07:00
|
|
|
ws.write_some(fin, buffers);
|
2017-04-25 10:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
write_raw(stream<NextLayer>& ws,
|
|
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
boost::asio::write(
|
|
|
|
|
ws.next_layer(), buffers);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
class AsyncClient
|
|
|
|
|
{
|
|
|
|
|
yield_context& yield_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit
|
|
|
|
|
AsyncClient(yield_context& yield)
|
|
|
|
|
: yield_(yield)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
accept(stream<NextLayer>& ws) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept(yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Buffers>
|
2017-05-08 12:41:45 -07:00
|
|
|
typename std::enable_if<
|
|
|
|
|
! http::detail::is_header<Buffers>::value>::type
|
2017-04-25 10:12:43 -07:00
|
|
|
accept(stream<NextLayer>& ws,
|
|
|
|
|
Buffers const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept(buffers, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 13:00:09 -07:00
|
|
|
template<class NextLayer>
|
2017-04-25 10:12:43 -07:00
|
|
|
void
|
|
|
|
|
accept(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept(req, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
class Decorator>
|
2017-04-25 10:12:43 -07:00
|
|
|
void
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
accept_ex(stream<NextLayer>& ws,
|
|
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept_ex(d, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer,
|
|
|
|
|
class Buffers, class Decorator>
|
2017-05-08 12:41:45 -07:00
|
|
|
typename std::enable_if<
|
|
|
|
|
! http::detail::is_header<Buffers>::value>::type
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
accept_ex(stream<NextLayer>& ws,
|
|
|
|
|
Buffers const& buffers,
|
|
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept_ex(buffers, d, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 13:00:09 -07:00
|
|
|
template<class NextLayer, class Decorator>
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
void
|
|
|
|
|
accept_ex(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const& d) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept_ex(req, d, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 13:00:09 -07:00
|
|
|
template<class NextLayer,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
class Buffers, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
accept_ex(stream<NextLayer>& ws,
|
2017-07-14 13:00:09 -07:00
|
|
|
http::request<http::empty_body> const& req,
|
2017-04-25 10:12:43 -07:00
|
|
|
Buffers const& buffers,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const& d) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
error_code ec;
|
|
|
|
|
ws.async_accept_ex(
|
|
|
|
|
req, buffers, d, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2017-04-25 10:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
handshake(stream<NextLayer>& ws,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
|
|
|
|
error_code ec;
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
ws.async_handshake(
|
|
|
|
|
uri, path, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
handshake(stream<NextLayer>& ws,
|
|
|
|
|
response_type& res,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path) const
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_handshake(
|
|
|
|
|
res, uri, path, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
handshake_ex(stream<NextLayer>& ws,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const &d) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_handshake_ex(
|
|
|
|
|
uri, path, d, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer, class Decorator>
|
|
|
|
|
void
|
|
|
|
|
handshake_ex(stream<NextLayer>& ws,
|
|
|
|
|
response_type& res,
|
2017-06-04 10:52:28 -07:00
|
|
|
string_view uri,
|
|
|
|
|
string_view path,
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
Decorator const &d) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_handshake_ex(
|
|
|
|
|
res, uri, path, d, yield_[ec]);
|
2017-04-25 10:12:43 -07:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
ping(stream<NextLayer>& ws,
|
|
|
|
|
ping_data const& payload) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_ping(payload, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
pong(stream<NextLayer>& ws,
|
|
|
|
|
ping_data const& payload) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_pong(payload, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
close(stream<NextLayer>& ws,
|
|
|
|
|
close_reason const& cr) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_close(cr, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class DynamicBuffer>
|
2017-07-25 08:50:58 -07:00
|
|
|
std::size_t
|
2017-04-25 10:12:43 -07:00
|
|
|
read(stream<NextLayer>& ws,
|
2017-06-08 19:55:42 -07:00
|
|
|
DynamicBuffer& buffer) const
|
2017-04-25 10:12:43 -07:00
|
|
|
{
|
|
|
|
|
error_code ec;
|
2017-07-25 08:50:58 -07:00
|
|
|
auto const bytes_written =
|
|
|
|
|
ws.async_read(buffer, yield_[ec]);
|
2017-04-25 10:12:43 -07:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2017-07-25 08:50:58 -07:00
|
|
|
return bytes_written;
|
2017-04-25 10:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class DynamicBuffer>
|
|
|
|
|
std::size_t
|
|
|
|
|
read_some(stream<NextLayer>& ws,
|
|
|
|
|
std::size_t limit,
|
|
|
|
|
DynamicBuffer& buffer) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
auto const bytes_written =
|
|
|
|
|
ws.async_read_some(buffer, limit, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
return bytes_written;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 04:21:24 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class MutableBufferSequence>
|
|
|
|
|
std::size_t
|
|
|
|
|
read_some(stream<NextLayer>& ws,
|
|
|
|
|
MutableBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
auto const bytes_written =
|
|
|
|
|
ws.async_read_some(buffers, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
return bytes_written;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 10:12:43 -07:00
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
write(stream<NextLayer>& ws,
|
|
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.async_write(buffers, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
2017-07-15 17:05:24 -07:00
|
|
|
write_some(stream<NextLayer>& ws, bool fin,
|
2017-04-25 10:12:43 -07:00
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
2017-07-15 17:05:24 -07:00
|
|
|
ws.async_write_some(fin, buffers, yield_[ec]);
|
2017-04-25 10:12:43 -07:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
|
class NextLayer, class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
write_raw(stream<NextLayer>& ws,
|
|
|
|
|
ConstBufferSequence const& buffers) const
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::async_write(
|
|
|
|
|
ws.next_layer(), buffers, yield_[ec]);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-19 19:39:54 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Accept
|
|
|
|
|
//
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
template<class Wrap>
|
2017-04-25 10:12:43 -07:00
|
|
|
void
|
2017-08-21 14:45:58 -07:00
|
|
|
doTestAccept(Wrap const& w)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
class res_decorator
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
bool& b_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
res_decorator(res_decorator const&) = default;
|
|
|
|
|
|
|
|
|
|
explicit
|
|
|
|
|
res_decorator(bool& b)
|
|
|
|
|
: b_(b)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
operator()(response_type&) const
|
|
|
|
|
{
|
|
|
|
|
b_ = true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
auto const big = []
|
|
|
|
|
{
|
|
|
|
|
std::string s;
|
|
|
|
|
s += "X1: " + std::string(2000, '*') + "\r\n";
|
|
|
|
|
return s;
|
|
|
|
|
}();
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in stream
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ts.append(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws);
|
2017-08-01 20:15:07 -07:00
|
|
|
// VFALCO validate contents of ws.next_layer().str?
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in stream, oversized
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_,
|
|
|
|
|
"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"};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws);
|
2017-08-16 19:25:02 -07:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in stream, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ts.append(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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);
|
|
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, res_decorator{called});
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(called);
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in stream, decorator, oversized
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_,
|
|
|
|
|
"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"};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, res_decorator{called});
|
2017-08-16 19:25:02 -07:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in buffers
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
w.accept(ws, sbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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"
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in buffers, oversize
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws, boost::asio::buffer(
|
2017-08-16 19:25:02 -07:00
|
|
|
"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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in buffers, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-01 20:15:07 -07:00
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, sbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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);
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in buffers, decorator, oversized
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, boost::asio::buffer(
|
2017-08-16 19:25:02 -07:00
|
|
|
"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"),
|
|
|
|
|
res_decorator{called});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == error::buffer_overflow,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in buffers and stream
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ts.append(
|
2017-08-01 20:15:07 -07:00
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n");
|
|
|
|
|
ts.read_size(16);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws, sbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost\r\n"
|
|
|
|
|
"Upgrade: websocket\r\n"
|
|
|
|
|
));
|
|
|
|
|
// VFALCO validate contents of ws.next_layer().str?
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in buffers and stream, oversized
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_,
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
+ big +
|
|
|
|
|
"\r\n"};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws, sbuf(
|
2017-08-16 19:25:02 -07:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost\r\n"
|
|
|
|
|
"Upgrade: websocket\r\n"
|
|
|
|
|
));
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == http::error::buffer_overflow,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in buffers and stream, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ts.append(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, sbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost\r\n"
|
|
|
|
|
"Upgrade: websocket\r\n"),
|
|
|
|
|
res_decorator{called});
|
|
|
|
|
BEAST_EXPECT(called);
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-16 19:25:02 -07:00
|
|
|
// request in buffers and stream, decorator, oversize
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_,
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
+ big +
|
|
|
|
|
"\r\n"};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, sbuf(
|
2017-08-16 19:25:02 -07:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost\r\n"
|
|
|
|
|
"Upgrade: websocket\r\n"),
|
|
|
|
|
res_decorator{called});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == http::error::buffer_overflow,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// request in message
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-01 20:15:07 -07:00
|
|
|
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");
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws, req);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// request in message, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-01 20:15:07 -07:00
|
|
|
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;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept_ex(ws, req,
|
2017-08-01 20:15:07 -07:00
|
|
|
res_decorator{called});
|
|
|
|
|
BEAST_EXPECT(called);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// request in message, close frame in stream
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
2017-08-01 20:15:07 -07:00
|
|
|
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");
|
2017-08-21 14:45:58 -07:00
|
|
|
ts.append("\x88\x82\xff\xff\xff\xff\xfc\x17");
|
|
|
|
|
w.accept(ws, req);
|
2017-08-01 20:15:07 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
static_buffer<1> b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
fail("success", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& e)
|
|
|
|
|
{
|
|
|
|
|
if(e.code() != websocket::error::closed)
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// failed handshake (missing Sec-WebSocket-Key)
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream&> ws{ts};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ts.append(
|
2017-08-01 20:15:07 -07:00
|
|
|
"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
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws);
|
2017-08-01 20:15:07 -07:00
|
|
|
fail("success", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& e)
|
|
|
|
|
{
|
|
|
|
|
if( e.code() !=
|
|
|
|
|
websocket::error::handshake_failed &&
|
|
|
|
|
e.code() !=
|
|
|
|
|
boost::asio::error::eof)
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
});
|
2017-08-16 19:25:02 -07:00
|
|
|
|
|
|
|
|
// Closed by client
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
tr.close();
|
2017-08-16 19:25:02 -07:00
|
|
|
try
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.accept(ws);
|
2017-08-16 19:25:02 -07:00
|
|
|
fail("success", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& e)
|
|
|
|
|
{
|
|
|
|
|
if(! BEAST_EXPECTS(
|
|
|
|
|
e.code() == error::closed,
|
|
|
|
|
e.code().message()))
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-25 10:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testAccept()
|
|
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
doTestAccept(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestAccept(AsyncClient{yield});
|
|
|
|
|
});
|
2017-08-19 19:39:54 -07:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Bad requests
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
auto const check =
|
|
|
|
|
[&](error_code const& ev, std::string const& s)
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < 3; ++i)
|
|
|
|
|
{
|
|
|
|
|
std::size_t n;
|
|
|
|
|
switch(i)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
case 0:
|
|
|
|
|
n = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
n = s.size() / 2;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
n = s.size() - 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ws.next_layer().append(
|
2017-08-19 19:39:54 -07:00
|
|
|
s.substr(n, s.size() - n));
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ws.accept(
|
|
|
|
|
boost::asio::buffer(s.data(), n));
|
|
|
|
|
BEAST_EXPECTS(! ev, ev.message());
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(se.code() == ev, se.what());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// wrong version
|
|
|
|
|
check(http::error::end_of_stream,
|
|
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// wrong method
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"POST / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing Host
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing Sec-WebSocket-Key
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing Sec-WebSocket-Version
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// wrong Sec-WebSocket-Version
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive,upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 1\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing upgrade token
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: HTTP/2\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing connection token
|
|
|
|
|
check(error::handshake_failed,
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// valid request
|
|
|
|
|
check({},
|
|
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
|
"Host: localhost:80\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-08-19 19:39:54 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Close
|
|
|
|
|
//
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
|
|
|
|
doTestClose(Wrap const& w)
|
|
|
|
|
{
|
|
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
|
|
|
|
|
|
|
|
|
// normal close
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// double close
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-17 22:38:50 -07:00
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-17 22:38:50 -07:00
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == boost::asio::error::operation_aborted,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain a message after close
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append("\x81\x01\x2a");
|
2017-08-17 22:38:50 -07:00
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// drain a big message after close
|
|
|
|
|
{
|
|
|
|
|
std::string s;
|
|
|
|
|
s = "\x81\x7e\x10\x01";
|
|
|
|
|
s.append(4097, '*');
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append(s);
|
2017-08-17 22:38:50 -07:00
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain a ping after close
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append("\x89\x01*");
|
2017-08-17 22:38:50 -07:00
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// drain invalid message frame after close
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-17 22:38:50 -07:00
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-17 22:38:50 -07:00
|
|
|
w.handshake(ws, "localhost", "/");
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append("\x81\x81\xff\xff\xff\xff*");
|
2017-08-17 22:38:50 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == error::failed,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// drain invalid close frame after close
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-17 22:38:50 -07:00
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-17 22:38:50 -07:00
|
|
|
w.handshake(ws, "localhost", "/");
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append("\x88\x01*");
|
2017-08-17 22:38:50 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
se.code() == error::failed,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close with incomplete read message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append("\x81\x02**");
|
2017-08-17 22:38:50 -07:00
|
|
|
static_buffer<1> b;
|
|
|
|
|
w.read_some(ws, 1, b);
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2017-08-19 19:39:54 -07:00
|
|
|
testClose()
|
2017-08-17 22:38:50 -07:00
|
|
|
{
|
2017-08-19 19:39:54 -07:00
|
|
|
doTestClose(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestClose(AsyncClient{yield});
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-17 22:38:50 -07:00
|
|
|
// suspend on write
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-17 22:38:50 -07:00
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-17 22:38:50 -07:00
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// suspend on read
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-17 22:38:50 -07:00
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-17 22:38:50 -07:00
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == error::closed, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.rd_block_);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_close_);
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
template<class Wrap>
|
2017-08-01 20:15:07 -07:00
|
|
|
void
|
2017-08-21 14:45:58 -07:00
|
|
|
doTestHandshake(Wrap const& w)
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
class req_decorator
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
bool& b_;
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
public:
|
|
|
|
|
req_decorator(req_decorator const&) = default;
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
explicit
|
|
|
|
|
req_decorator(bool& b)
|
|
|
|
|
: b_(b)
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
|
|
|
|
}
|
2017-08-01 20:15:07 -07:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
operator()(request_type&) const
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
b_ = true;
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
}
|
2017-08-01 20:15:07 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// handshake
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// handshake, response
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-01 20:15:07 -07:00
|
|
|
response_type res;
|
2017-08-21 14:45:58 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.handshake(ws, res, "localhost", "/");
|
|
|
|
|
// VFALCO validate res?
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// handshake, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-01 20:15:07 -07:00
|
|
|
bool called = false;
|
2017-08-21 14:45:58 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.handshake_ex(ws, "localhost", "/",
|
|
|
|
|
req_decorator{called});
|
|
|
|
|
BEAST_EXPECT(called);
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// handshake, response, decorator
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-01 20:15:07 -07:00
|
|
|
bool called = false;
|
|
|
|
|
response_type res;
|
2017-08-21 14:45:58 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.handshake_ex(ws, res, "localhost", "/",
|
|
|
|
|
req_decorator{called});
|
|
|
|
|
// VFALCO validate res?
|
|
|
|
|
BEAST_EXPECT(called);
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testHandshake()
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
doTestHandshake(SyncClient{});
|
2017-08-01 20:15:07 -07:00
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
doTestHandshake(AsyncClient{yield});
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
Refactor websocket decorators (API Change):
fix #80, #212, fix #303, fix #314, fix #317
websocket::stream now provides the following families of
functions for performing handshakes:
When operating in the server role:
* stream::accept
* stream::accept_ex
* stream::async_accept
* stream::async_accept_ex
When operating in the client role:
* stream::handshake
* stream::handshake_ex
* stream::async_handshake
* stream::async_handshake_ex
Member functions ending with "_ex" allow an additional
RequestDecorator parameter (for the accept family of
functions) or ResponseDecorator parameter (for the
handshake family of functions).
The decorator is called to optionally modify the contents
of the HTTP request or HTTP response object generated by
the implementation, before the message is sent. This
permits callers to set the User-Agent or Server fields,
add or modify HTTP fields related to subprotocols, or
perform any required transformation of the HTTP message
for application-specific needs.
The handshake() family of functions now have an additional
set of overloads accepting a parameter of type response_type&,
allowing the caller to receive the HTTP Response to the
Upgrade handshake. This permits inspection of the response
to handle things like subprotocols, authentication, or
other application-specific needs.
The new implementation does not require any state to be
stored in the stream object. Therefore, websocket::stream
objects are now smaller in size.
The overload of set_option for setting a decorator on the
stream is removed. The only way to set decorators now is
with a suitable overload of accept or handshake.
2017-04-25 09:35:22 -07:00
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
auto const check =
|
2017-08-19 19:39:54 -07:00
|
|
|
[&](std::string const& s)
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
2017-08-21 14:45:58 -07:00
|
|
|
auto tr = connect(ws.next_layer());
|
|
|
|
|
ws.next_layer().append(s);
|
|
|
|
|
tr.close();
|
2017-08-19 19:39:54 -07:00
|
|
|
try
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
2017-08-19 19:39:54 -07:00
|
|
|
ws.handshake("localhost:80", "/");
|
|
|
|
|
fail();
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
2016-05-04 11:06:17 -04:00
|
|
|
{
|
2017-08-19 19:39:54 -07:00
|
|
|
BEAST_EXPECT(se.code() == error::handshake_failed);
|
|
|
|
|
}
|
|
|
|
|
};
|
2016-05-15 16:22:25 -04:00
|
|
|
// wrong HTTP version
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.0 101 Switching Protocols\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// wrong status
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.1 200 OK\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing upgrade token
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: HTTP/2\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing connection token
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: keep-alive\r\n"
|
|
|
|
|
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// missing accept key
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
|
|
|
|
// wrong accept key
|
|
|
|
|
check(
|
|
|
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
|
|
|
"Server: beast\r\n"
|
|
|
|
|
"Upgrade: WebSocket\r\n"
|
|
|
|
|
"Connection: upgrade\r\n"
|
|
|
|
|
"Sec-WebSocket-Accept: *\r\n"
|
|
|
|
|
"Sec-WebSocket-Version: 13\r\n"
|
|
|
|
|
"\r\n"
|
|
|
|
|
);
|
2016-05-04 11:06:17 -04:00
|
|
|
}
|
|
|
|
|
|
2017-08-19 19:39:54 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Ping
|
|
|
|
|
//
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
|
|
|
|
doTestPing(Wrap const& w)
|
|
|
|
|
{
|
|
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
|
|
|
|
|
|
|
|
|
// ping
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-19 19:39:54 -07:00
|
|
|
{
|
|
|
|
|
w.ping(ws, {});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// pong
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-19 19:39:54 -07:00
|
|
|
{
|
|
|
|
|
w.pong(ws, {});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testPing()
|
|
|
|
|
{
|
|
|
|
|
doTestPing(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestPing(AsyncClient{yield});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ping, already closed
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.ping({}, ec);
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// async_ping, already closed
|
|
|
|
|
{
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.async_ping({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pong, already closed
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.pong({}, ec);
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// async_pong, already closed
|
|
|
|
|
{
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.async_pong({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// suspend on write
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
2017-08-19 19:39:54 -07:00
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-19 19:39:54 -07:00
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_write(sbuf("*"),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
ws.async_close({}, [&](error_code){});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Read
|
|
|
|
|
//
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
static
|
|
|
|
|
std::string const&
|
|
|
|
|
random_string()
|
|
|
|
|
{
|
|
|
|
|
static std::string const s = []
|
|
|
|
|
{
|
|
|
|
|
std::size_t constexpr N = 16384;
|
|
|
|
|
std::mt19937 mt{1};
|
|
|
|
|
std::string tmp;
|
|
|
|
|
tmp.reserve(N);
|
|
|
|
|
for(std::size_t i = 0; i < N; ++ i)
|
|
|
|
|
tmp.push_back(static_cast<char>(
|
|
|
|
|
std::uniform_int_distribution<
|
|
|
|
|
unsigned>{0, 255}(mt)));
|
|
|
|
|
return tmp;
|
|
|
|
|
}();
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class Wrap>
|
|
|
|
|
void
|
|
|
|
|
doTestRead(Wrap const& w)
|
|
|
|
|
{
|
|
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
|
|
|
|
|
|
|
|
|
// Read close frames
|
|
|
|
|
{
|
|
|
|
|
// VFALCO What about asynchronous??
|
|
|
|
|
|
|
|
|
|
auto const check =
|
|
|
|
|
[&](error_code ev, string_view s)
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
|
|
|
|
stream<test::stream> ws{ios_};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
w.handshake(ws, "localhost", "/");
|
|
|
|
|
ws.next_layer().append(s);
|
|
|
|
|
static_buffer<1> b;
|
|
|
|
|
error_code ec;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
fail("", __FILE__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(se.code() == ev,
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
ws.next_layer().close();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// payload length 1
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x01\x01");
|
|
|
|
|
|
|
|
|
|
// invalid close code 1005
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x02\x03\xed");
|
|
|
|
|
|
|
|
|
|
// invalid utf8
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
|
|
|
|
|
|
|
|
|
|
// good utf8
|
|
|
|
|
check(error::closed,
|
|
|
|
|
"\x88\x06\xfc\x15utf8");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
pmd.server_enable = true;
|
|
|
|
|
|
|
|
|
|
// invalid inflate block
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
auto const& s = random_string();
|
|
|
|
|
ws.binary(true);
|
|
|
|
|
ws.next_layer().append(
|
|
|
|
|
"\xc2\x40" + s.substr(0, 64));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
}
|
|
|
|
|
catch(system_error const& se)
|
|
|
|
|
{
|
|
|
|
|
if(se.code() == test::error::fail_error)
|
|
|
|
|
throw;
|
|
|
|
|
BEAST_EXPECTS(se.code().category() ==
|
|
|
|
|
zlib::detail::get_error_category(),
|
|
|
|
|
se.code().message());
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-19 19:39:54 -07:00
|
|
|
void
|
|
|
|
|
testRead()
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
doTestRead(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestRead(AsyncClient{yield});
|
|
|
|
|
});
|
|
|
|
|
|
2017-08-19 19:39:54 -07:00
|
|
|
// Read close frames
|
|
|
|
|
{
|
|
|
|
|
auto const check =
|
|
|
|
|
[&](error_code ev, string_view s)
|
|
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
echo_server es{log};
|
|
|
|
|
stream<test::stream> ws{ios_};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-19 19:39:54 -07:00
|
|
|
ws.handshake("localhost", "/");
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().append(s);
|
2017-08-19 19:39:54 -07:00
|
|
|
static_buffer<1> b;
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.read(b, ec);
|
|
|
|
|
BEAST_EXPECTS(ec == ev, ec.message());
|
2017-08-21 14:45:58 -07:00
|
|
|
ws.next_layer().close();
|
2017-08-19 19:39:54 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// payload length 1
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x01\x01");
|
|
|
|
|
|
|
|
|
|
// invalid close code 1005
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x02\x03\xed");
|
|
|
|
|
|
|
|
|
|
// invalid utf8
|
|
|
|
|
check(error::failed,
|
|
|
|
|
"\x88\x06\xfc\x15\x0f\xd7\x73\x43");
|
|
|
|
|
|
|
|
|
|
// good utf8
|
|
|
|
|
check(error::closed,
|
|
|
|
|
"\x88\x06\xfc\x15utf8");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Write
|
|
|
|
|
//
|
2017-08-19 19:39:54 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
template<class Wrap>
|
2017-05-04 05:01:50 -07:00
|
|
|
void
|
2017-08-22 18:08:56 -07:00
|
|
|
doTestWrite(Wrap const& w)
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
|
|
|
|
|
|
|
|
|
// continuation
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
std::string const s = "Hello";
|
|
|
|
|
std::size_t const chop = 3;
|
|
|
|
|
BOOST_ASSERT(chop < s.size());
|
|
|
|
|
w.write_some(ws, false,
|
|
|
|
|
boost::asio::buffer(s.data(), chop));
|
|
|
|
|
w.write_some(ws, true, boost::asio::buffer(
|
|
|
|
|
s.data() + chop, s.size() - chop));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// mask
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.auto_fragment(false);
|
|
|
|
|
std::string const s = "Hello";
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// mask (large)
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
ws.auto_fragment(false);
|
|
|
|
|
ws.write_buffer_size(16);
|
|
|
|
|
std::string const s(32, '*');
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// mask, autofrag
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
std::string const s(16384, '*');
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// nomask
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log, kind::async_client};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
try
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
es.async_handshake();
|
|
|
|
|
w.accept(ws);
|
|
|
|
|
ws.auto_fragment(false);
|
|
|
|
|
std::string const s = "Hello";
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
ts.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// nomask, autofrag
|
|
|
|
|
doTestLoop([&](test::stream& ts)
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log, kind::async_client};
|
|
|
|
|
ws_type ws{ts};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
es.async_handshake();
|
|
|
|
|
w.accept(ws);
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
std::string const s(16384, '*');
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
w.close(ws, {});
|
|
|
|
|
}
|
|
|
|
|
catch(...)
|
|
|
|
|
{
|
|
|
|
|
ts.close();
|
|
|
|
|
throw;
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
2017-08-22 18:08:56 -07:00
|
|
|
ts.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
pmd.server_enable = true;
|
|
|
|
|
|
|
|
|
|
// deflate
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
auto const& s = random_string();
|
|
|
|
|
ws.binary(true);
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// deflate, continuation
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
std::string const s = "Hello";
|
|
|
|
|
std::size_t const chop = 3;
|
|
|
|
|
BOOST_ASSERT(chop < s.size());
|
|
|
|
|
// This call should produce no
|
|
|
|
|
// output due to compression latency.
|
|
|
|
|
w.write_some(ws, false,
|
|
|
|
|
boost::asio::buffer(s.data(), chop));
|
|
|
|
|
w.write_some(ws, true, boost::asio::buffer(
|
|
|
|
|
s.data() + chop, s.size() - chop));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// deflate, no context takeover
|
|
|
|
|
pmd.client_no_context_takeover = true;
|
|
|
|
|
doTest(pmd, [&](ws_type& ws)
|
|
|
|
|
{
|
|
|
|
|
auto const& s = random_string();
|
|
|
|
|
ws.binary(true);
|
|
|
|
|
w.write(ws, boost::asio::buffer(s));
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
w.read(ws, b);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testWrite()
|
|
|
|
|
{
|
|
|
|
|
doTestWrite(SyncClient{});
|
|
|
|
|
|
|
|
|
|
yield_to([&](yield_context yield)
|
|
|
|
|
{
|
|
|
|
|
doTestWrite(AsyncClient{yield});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// already closed
|
|
|
|
|
{
|
|
|
|
|
stream<test::stream> ws{ios_};
|
|
|
|
|
error_code ec;
|
|
|
|
|
ws.write(sbuf(""), ec);
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// async, already closed
|
|
|
|
|
{
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.async_write(sbuf(""),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// suspend on write
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log};
|
|
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_write(sbuf("*"),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == boost::asio::error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
ws.async_close({}, [&](error_code){});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// suspend on write, nomask, frag
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log, kind::async_client};
|
|
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
es.async_handshake();
|
|
|
|
|
ws.accept(ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s(16384, '*');
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
ws.async_write(boost::asio::buffer(s),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
ios.reset();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// suspend on write, mask, frag
|
|
|
|
|
{
|
|
|
|
|
echo_server es{log, kind::async};
|
|
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
std::string const s(16384, '*');
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
ws.async_write(boost::asio::buffer(s),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
ios.reset();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 4);
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
2017-08-22 18:08:56 -07:00
|
|
|
|
|
|
|
|
// suspend on write, deflate
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, kind::async};
|
|
|
|
|
error_code ec;
|
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
2016-05-04 17:27:50 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
permessage_deflate pmd;
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
ws.set_option(pmd);
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
2017-08-22 18:08:56 -07:00
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
auto const& s = random_string();
|
|
|
|
|
ws.binary(true);
|
|
|
|
|
ws.async_write(boost::asio::buffer(s),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
BEAST_EXPECT(ws.wr_block_);
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
ios.reset();
|
|
|
|
|
BEAST_EXPECT(count == 2);
|
|
|
|
|
flat_buffer b;
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
ios.run();
|
|
|
|
|
BEAST_EXPECT(count == 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testOptions()
|
|
|
|
|
{
|
|
|
|
|
stream<socket_type> ws(ios_);
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
ws.write_buffer_size(2048);
|
|
|
|
|
ws.binary(false);
|
|
|
|
|
ws.read_message_max(1 * 1024 * 1024);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ws.write_buffer_size(7);
|
|
|
|
|
fail();
|
|
|
|
|
}
|
|
|
|
|
catch(std::exception const&)
|
|
|
|
|
{
|
|
|
|
|
pass();
|
2016-05-04 17:27:50 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
void
|
|
|
|
|
testPausation1()
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
for(int i = 0; i < 2; ++i )
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, i==1 ?
|
|
|
|
|
kind::async : kind::sync};
|
2017-08-12 15:03:39 -07:00
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2017-08-12 15:03:39 -07:00
|
|
|
ws.handshake("localhost", "/");
|
2016-05-15 16:22:25 -04:00
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
// Make remote send a text message with bad utf8.
|
|
|
|
|
ws.binary(true);
|
|
|
|
|
put(ws.next_layer().buffer(), cbuf(
|
|
|
|
|
0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
|
// Read text message with bad utf8.
|
|
|
|
|
// Causes a close to be sent, blocking writes.
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
// Read should fail with protocol error
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(
|
|
|
|
|
ec == error::failed, ec.message());
|
|
|
|
|
// Reads after failure are aborted
|
|
|
|
|
ws.async_read(b,
|
|
|
|
|
[&](error_code ec, std::size_t)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
|
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
// Run until the read_op writes a close frame.
|
|
|
|
|
while(! ws.wr_block_)
|
|
|
|
|
ios.run_one();
|
|
|
|
|
// Write a text message, leaving
|
|
|
|
|
// the write_op suspended as a pausation.
|
|
|
|
|
ws.async_write(sbuf("Hello"),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
// Send is canceled because close received.
|
|
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
|
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
// Writes after close are aborted.
|
|
|
|
|
ws.async_write(sbuf("World"),
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
|
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
|
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
// Run until all completions are delivered.
|
|
|
|
|
while(! ios.stopped())
|
|
|
|
|
ios.run_one();
|
|
|
|
|
BEAST_EXPECT(count == 4);
|
2016-05-15 16:22:25 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
void
|
2017-08-21 14:45:58 -07:00
|
|
|
testPausation2()
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, kind::async};
|
2016-05-15 16:22:25 -04:00
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2016-05-15 16:22:25 -04:00
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
|
|
|
|
|
// Cause close to be received
|
2017-08-21 14:45:58 -07:00
|
|
|
es.async_close();
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
multi_buffer b;
|
2016-05-15 16:22:25 -04:00
|
|
|
std::size_t count = 0;
|
|
|
|
|
// Read a close frame.
|
|
|
|
|
// Sends a close frame, blocking writes.
|
2017-08-12 15:03:39 -07:00
|
|
|
ws.async_read(b,
|
2017-07-25 08:50:58 -07:00
|
|
|
[&](error_code ec, std::size_t)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
|
|
|
|
// Read should complete with error::closed
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == error::closed,
|
2016-05-15 16:22:25 -04:00
|
|
|
ec.message());
|
|
|
|
|
// Pings after a close are aborted
|
|
|
|
|
ws.async_ping("",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
2016-05-15 16:22:25 -04:00
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
2017-07-25 12:35:54 -07:00
|
|
|
if(! BEAST_EXPECT(run_until(ios, 100,
|
2016-05-15 16:22:25 -04:00
|
|
|
[&]{ return ws.wr_close_; })))
|
|
|
|
|
return;
|
|
|
|
|
// Try to ping
|
|
|
|
|
ws.async_ping("payload",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
// Pings after a close are aborted
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
2016-05-15 16:22:25 -04:00
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
// Subsequent calls to close are aborted
|
|
|
|
|
ws.async_close({},
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
2016-05-15 16:22:25 -04:00
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
static std::size_t constexpr limit = 100;
|
|
|
|
|
std::size_t n;
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
|
{
|
|
|
|
|
if(count >= 4)
|
|
|
|
|
break;
|
|
|
|
|
ios.run_one();
|
|
|
|
|
}
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-15 16:22:25 -04:00
|
|
|
ios.run();
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
void
|
2017-08-21 14:45:58 -07:00
|
|
|
testPausation3()
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, kind::async};
|
2016-05-15 16:22:25 -04:00
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
2016-05-15 16:22:25 -04:00
|
|
|
ws.handshake("localhost", "/");
|
|
|
|
|
|
|
|
|
|
// Cause close to be received
|
2017-08-21 14:45:58 -07:00
|
|
|
es.async_close();
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
multi_buffer b;
|
2016-05-15 16:22:25 -04:00
|
|
|
std::size_t count = 0;
|
2017-08-12 15:03:39 -07:00
|
|
|
ws.async_read(b,
|
2017-07-25 08:50:58 -07:00
|
|
|
[&](error_code ec, std::size_t)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == error::closed,
|
2016-05-15 16:22:25 -04:00
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
while(! ws.wr_block_)
|
|
|
|
|
ios.run_one();
|
|
|
|
|
// try to close
|
|
|
|
|
ws.async_close("payload",
|
|
|
|
|
[&](error_code ec)
|
|
|
|
|
{
|
|
|
|
|
++count;
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(ec == boost::asio::
|
2016-05-15 16:22:25 -04:00
|
|
|
error::operation_aborted,
|
|
|
|
|
ec.message());
|
|
|
|
|
});
|
|
|
|
|
static std::size_t constexpr limit = 100;
|
|
|
|
|
std::size_t n;
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
|
{
|
|
|
|
|
if(count >= 2)
|
|
|
|
|
break;
|
|
|
|
|
ios.run_one();
|
|
|
|
|
}
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-15 16:22:25 -04:00
|
|
|
ios.run();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-14 12:32:36 -07:00
|
|
|
/*
|
2017-07-29 05:03:05 -07:00
|
|
|
https://github.com/boostorg/beast/issues/300
|
2017-04-14 12:32:36 -07:00
|
|
|
|
|
|
|
|
Write a message as two individual frames
|
|
|
|
|
*/
|
|
|
|
|
void
|
2017-08-22 18:08:56 -07:00
|
|
|
testIssue300()
|
2017-04-14 12:32:36 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
for(int i = 0; i < 2; ++i )
|
2017-08-12 15:03:39 -07:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, i==1 ?
|
|
|
|
|
kind::async : kind::sync};
|
2017-08-21 14:45:58 -07:00
|
|
|
boost::asio::io_service ios;
|
|
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
|
2017-08-12 15:03:39 -07:00
|
|
|
error_code ec;
|
|
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
|
|
|
|
return;
|
|
|
|
|
ws.write_some(false, sbuf("u"));
|
|
|
|
|
ws.write_some(true, sbuf("v"));
|
|
|
|
|
multi_buffer b;
|
|
|
|
|
ws.read(b, ec);
|
|
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
|
|
|
|
}
|
2017-04-14 12:32:36 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-24 18:41:25 -04:00
|
|
|
void
|
2017-08-12 15:03:39 -07:00
|
|
|
testAsyncWriteFrame()
|
2016-10-24 18:41:25 -04:00
|
|
|
{
|
2017-08-12 15:03:39 -07:00
|
|
|
for(int i = 0; i < 2; ++i)
|
2016-10-24 18:41:25 -04:00
|
|
|
{
|
2017-08-12 15:03:39 -07:00
|
|
|
for(;;)
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
echo_server es{log, i==1 ?
|
|
|
|
|
kind::async : kind::sync};
|
2017-08-12 15:03:39 -07:00
|
|
|
boost::asio::io_service ios;
|
2017-08-21 14:45:58 -07:00
|
|
|
stream<test::stream> ws{ios};
|
|
|
|
|
ws.next_layer().connect(es.stream());
|
|
|
|
|
|
|
|
|
|
error_code ec;
|
2017-08-12 15:03:39 -07:00
|
|
|
ws.handshake("localhost", "/", ec);
|
|
|
|
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
|
|
|
|
break;
|
|
|
|
|
ws.async_write_some(false,
|
|
|
|
|
boost::asio::null_buffers{},
|
|
|
|
|
[&](error_code)
|
|
|
|
|
{
|
|
|
|
|
fail();
|
|
|
|
|
});
|
|
|
|
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
|
|
|
|
break;
|
|
|
|
|
//
|
|
|
|
|
// Destruction of the io_service will cause destruction
|
|
|
|
|
// of the write_some_op without invoking the final handler.
|
|
|
|
|
//
|
2016-10-24 18:41:25 -04:00
|
|
|
break;
|
2017-08-12 15:03:39 -07:00
|
|
|
}
|
2016-10-24 18:41:25 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
//--------------------------------------------------------------------------
|
2016-10-24 18:41:25 -04:00
|
|
|
|
2017-08-21 14:45:58 -07:00
|
|
|
template<class Wrap>
|
2016-10-24 18:41:25 -04:00
|
|
|
void
|
2017-08-22 18:08:56 -07:00
|
|
|
doTestStream(Wrap const& w,
|
2017-08-21 14:45:58 -07:00
|
|
|
permessage_deflate const& pmd)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
|
|
|
|
using boost::asio::buffer;
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// send empty message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
ws.text(true);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, boost::asio::null_buffers{});
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(ws.got_text());
|
|
|
|
|
BEAST_EXPECT(b.size() == 0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
ws.auto_fragment(false);
|
|
|
|
|
ws.binary(false);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Hello"));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(ws.got_text());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// read_some
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Hello"));
|
2017-08-01 20:15:07 -07:00
|
|
|
char buf[10];
|
|
|
|
|
auto const bytes_written =
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read_some(ws, buffer(buf, sizeof(buf)));
|
2017-08-12 15:03:39 -07:00
|
|
|
BEAST_EXPECT(bytes_written > 0);
|
|
|
|
|
buf[bytes_written] = 0;
|
|
|
|
|
BEAST_EXPECT(
|
|
|
|
|
string_view(buf).substr(0, bytes_written) ==
|
|
|
|
|
string_view("Hello").substr(0, bytes_written));
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-05-15 16:22:25 -04:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// close, no payload
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.close(ws, {});
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-05-15 16:22:25 -04:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// close with code
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.close(ws, close_code::going_away);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-11-03 17:53:32 -04:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// send ping and message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
bool once = false;
|
|
|
|
|
auto cb =
|
|
|
|
|
[&](frame_type kind, string_view s)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(kind == frame_type::pong);
|
|
|
|
|
BEAST_EXPECT(! once);
|
|
|
|
|
once = true;
|
|
|
|
|
BEAST_EXPECT(s == "");
|
|
|
|
|
};
|
|
|
|
|
ws.control_callback(cb);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.ping(ws, "");
|
2017-08-01 20:15:07 -07:00
|
|
|
ws.binary(true);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Hello"));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(once);
|
|
|
|
|
BEAST_EXPECT(ws.got_binary());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send ping and fragmented message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
bool once = false;
|
|
|
|
|
auto cb =
|
|
|
|
|
[&](frame_type kind, string_view s)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(kind == frame_type::pong);
|
|
|
|
|
BEAST_EXPECT(! once);
|
|
|
|
|
once = true;
|
|
|
|
|
BEAST_EXPECT(s == "payload");
|
|
|
|
|
};
|
|
|
|
|
ws.control_callback(cb);
|
|
|
|
|
ws.ping("payload");
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write_some(ws, false, sbuf("Hello, "));
|
|
|
|
|
w.write_some(ws, false, sbuf(""));
|
|
|
|
|
w.write_some(ws, true, sbuf("World!"));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(once);
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == "Hello, World!");
|
|
|
|
|
ws.control_callback();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send pong
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.pong(ws, "");
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send auto fragmented message
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
ws.auto_fragment(true);
|
|
|
|
|
ws.write_buffer_size(8);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Now is the time for all good men"));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(to_string(b.data()) == "Now is the time for all good men");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send message with write buffer limit
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
std::string s(2000, '*');
|
|
|
|
|
ws.write_buffer_size(1200);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, buffer(s.data(), s.size()));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(to_string(b.data()) == s);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// unexpected cont
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write_raw(ws, cbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
0x80, 0x80, 0xff, 0xff, 0xff, 0xff));
|
2017-08-21 14:45:58 -07:00
|
|
|
doCloseTest(w, ws, close_code::protocol_error);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// invalid fixed frame header
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write_raw(ws, cbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
0x8f, 0x80, 0xff, 0xff, 0xff, 0xff));
|
2017-08-21 14:45:58 -07:00
|
|
|
doCloseTest(w, ws, close_code::protocol_error);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if(! pmd.client_enable)
|
|
|
|
|
{
|
|
|
|
|
// expected cont
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write_some(ws, false, boost::asio::null_buffers{});
|
|
|
|
|
w.write_raw(ws, cbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
0x81, 0x80, 0xff, 0xff, 0xff, 0xff));
|
2017-08-21 14:45:58 -07:00
|
|
|
doCloseTest(w, ws, close_code::protocol_error);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-05-15 16:22:25 -04:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// message size above 2^64
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write_some(ws, false, cbuf(0x00));
|
|
|
|
|
w.write_raw(ws, cbuf(
|
2017-08-01 20:15:07 -07:00
|
|
|
0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff));
|
2017-08-21 14:45:58 -07:00
|
|
|
doCloseTest(w, ws, close_code::too_big);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-05-15 16:22:25 -04:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
/*
|
|
|
|
|
// message size exceeds max
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
2017-08-01 20:15:07 -07:00
|
|
|
// VFALCO This was never implemented correctly
|
|
|
|
|
ws.read_message_max(1);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, cbuf(0x81, 0x02, '*', '*'));
|
|
|
|
|
doCloseTest(w, ws, close_code::too_big);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
*/
|
2016-05-15 16:22:25 -04:00
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
// receive ping
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
put(ws.next_layer().buffer(), cbuf(
|
|
|
|
|
0x89, 0x00));
|
|
|
|
|
bool invoked = false;
|
|
|
|
|
auto cb = [&](frame_type kind, string_view)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECT(! invoked);
|
|
|
|
|
BEAST_EXPECT(kind == frame_type::ping);
|
|
|
|
|
invoked = true;
|
|
|
|
|
};
|
|
|
|
|
ws.control_callback(cb);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Hello"));
|
2017-08-01 20:15:07 -07:00
|
|
|
multi_buffer b;
|
2017-08-21 14:45:58 -07:00
|
|
|
w.read(ws, b);
|
2017-08-01 20:15:07 -07:00
|
|
|
BEAST_EXPECT(invoked);
|
|
|
|
|
BEAST_EXPECT(ws.got_text());
|
|
|
|
|
BEAST_EXPECT(to_string(b.data()) == "Hello");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// receive ping
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
put(ws.next_layer().buffer(), cbuf(
|
|
|
|
|
0x88, 0x00));
|
|
|
|
|
bool invoked = false;
|
|
|
|
|
auto cb = [&](frame_type kind, string_view)
|
|
|
|
|
{
|
|
|
|
|
BEAST_EXPECT(! invoked);
|
|
|
|
|
BEAST_EXPECT(kind == frame_type::close);
|
|
|
|
|
invoked = true;
|
|
|
|
|
};
|
|
|
|
|
ws.control_callback(cb);
|
2017-08-21 14:45:58 -07:00
|
|
|
w.write(ws, sbuf("Hello"));
|
|
|
|
|
doCloseTest(w, ws, close_code::none);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// receive bad utf8
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
put(ws.next_layer().buffer(), cbuf(
|
|
|
|
|
0x81, 0x06, 0x03, 0xea, 0xf0, 0x28, 0x8c, 0xbc));
|
2017-08-21 14:45:58 -07:00
|
|
|
doFailTest(w, ws, error::failed);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// receive bad close
|
2017-08-21 14:45:58 -07:00
|
|
|
doTest(pmd, [&](ws_type& ws)
|
2017-08-01 20:15:07 -07:00
|
|
|
{
|
|
|
|
|
put(ws.next_layer().buffer(), cbuf(
|
|
|
|
|
0x88, 0x02, 0x03, 0xed));
|
2017-08-21 14:45:58 -07:00
|
|
|
doFailTest(w, ws, error::failed);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2017-07-29 17:47:04 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
2017-06-07 17:41:27 -07:00
|
|
|
void
|
|
|
|
|
run() override
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(std::is_constructible<
|
|
|
|
|
stream<socket_type>, boost::asio::io_service&>::value);
|
2016-05-07 17:06:46 -04:00
|
|
|
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(std::is_move_constructible<
|
|
|
|
|
stream<socket_type>>::value);
|
2016-04-30 13:00:33 -04:00
|
|
|
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(std::is_move_assignable<
|
|
|
|
|
stream<socket_type>>::value);
|
2016-04-30 13:00:33 -04:00
|
|
|
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(std::is_constructible<
|
|
|
|
|
stream<socket_type&>, socket_type&>::value);
|
2016-04-30 13:00:33 -04:00
|
|
|
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(std::is_move_constructible<
|
|
|
|
|
stream<socket_type&>>::value);
|
2016-05-04 11:06:17 -04:00
|
|
|
|
2017-05-23 12:33:31 -07:00
|
|
|
BOOST_STATIC_ASSERT(! std::is_move_assignable<
|
|
|
|
|
stream<socket_type&>>::value);
|
2016-05-04 17:27:50 -04:00
|
|
|
|
2016-06-10 15:48:39 -04:00
|
|
|
log << "sizeof(websocket::stream) == " <<
|
2017-08-16 19:25:02 -07:00
|
|
|
sizeof(websocket::stream<test::stream&>) << std::endl;
|
|
|
|
|
|
|
|
|
|
testAccept();
|
2017-08-17 22:38:50 -07:00
|
|
|
testClose();
|
2017-08-19 19:39:54 -07:00
|
|
|
testHandshake();
|
|
|
|
|
testPing();
|
2017-08-17 22:38:50 -07:00
|
|
|
testRead();
|
2017-08-22 18:08:56 -07:00
|
|
|
testWrite();
|
2017-08-12 15:03:39 -07:00
|
|
|
|
2016-10-24 18:41:25 -04:00
|
|
|
testOptions();
|
2017-08-12 15:03:39 -07:00
|
|
|
testPausation1();
|
2017-08-21 14:45:58 -07:00
|
|
|
testPausation2();
|
|
|
|
|
testPausation3();
|
2017-08-22 18:08:56 -07:00
|
|
|
testIssue300();
|
2017-08-12 15:03:39 -07:00
|
|
|
testAsyncWriteFrame();
|
2016-10-24 18:41:25 -04:00
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
auto const testStream =
|
2017-08-01 20:15:07 -07:00
|
|
|
[this](permessage_deflate const& pmd)
|
2016-10-24 18:41:25 -04:00
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
doTestStream(SyncClient{}, pmd);
|
2017-08-21 14:45:58 -07:00
|
|
|
|
2017-08-01 20:15:07 -07:00
|
|
|
yield_to(
|
|
|
|
|
[&](yield_context yield)
|
|
|
|
|
{
|
2017-08-22 18:08:56 -07:00
|
|
|
doTestStream(AsyncClient{yield}, pmd);
|
2017-08-01 20:15:07 -07:00
|
|
|
});
|
2016-10-24 18:41:25 -04:00
|
|
|
};
|
|
|
|
|
|
2017-08-22 18:08:56 -07:00
|
|
|
permessage_deflate pmd;
|
|
|
|
|
|
2016-10-24 18:41:25 -04:00
|
|
|
pmd.client_enable = false;
|
|
|
|
|
pmd.server_enable = false;
|
2017-08-22 18:08:56 -07:00
|
|
|
testStream(pmd);
|
2016-10-24 18:41:25 -04:00
|
|
|
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
pmd.server_enable = true;
|
|
|
|
|
pmd.client_max_window_bits = 10;
|
|
|
|
|
pmd.client_no_context_takeover = false;
|
2017-07-31 18:48:22 -07:00
|
|
|
pmd.compLevel = 1;
|
|
|
|
|
pmd.memLevel = 1;
|
2017-08-22 18:08:56 -07:00
|
|
|
testStream(pmd);
|
2016-10-24 18:41:25 -04:00
|
|
|
|
|
|
|
|
pmd.client_enable = true;
|
|
|
|
|
pmd.server_enable = true;
|
|
|
|
|
pmd.client_max_window_bits = 10;
|
|
|
|
|
pmd.client_no_context_takeover = true;
|
2017-07-31 18:48:22 -07:00
|
|
|
pmd.compLevel = 1;
|
|
|
|
|
pmd.memLevel = 1;
|
2017-08-22 18:08:56 -07:00
|
|
|
testStream(pmd);
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 17:01:57 -07:00
|
|
|
BEAST_DEFINE_TESTSUITE(beast,websocket,stream);
|
2016-04-30 13:00:33 -04:00
|
|
|
|
|
|
|
|
} // websocket
|
|
|
|
|
} // beast
|
2017-07-20 13:40:34 -07:00
|
|
|
} // boost
|