2017-07-20 08:01:46 -07:00
|
|
|
//
|
|
|
|
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
|
|
|
//
|
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#ifndef BEAST_WEBSOCKET_IMPL_STREAM_IPP
|
|
|
|
|
#define BEAST_WEBSOCKET_IMPL_STREAM_IPP
|
|
|
|
|
|
|
|
|
|
#include <beast/websocket/teardown.hpp>
|
|
|
|
|
#include <beast/websocket/detail/hybi13.hpp>
|
|
|
|
|
#include <beast/websocket/impl/accept_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/close_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/handshake_op.ipp>
|
2016-05-15 16:22:25 -04:00
|
|
|
#include <beast/websocket/impl/ping_op.ipp>
|
2017-07-20 08:01:46 -07:00
|
|
|
#include <beast/websocket/impl/read_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/read_frame_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/response_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/write_op.ipp>
|
|
|
|
|
#include <beast/websocket/impl/write_frame_op.ipp>
|
2016-05-01 12:33:35 -04:00
|
|
|
#include <beast/http/read.hpp>
|
|
|
|
|
#include <beast/http/write.hpp>
|
|
|
|
|
#include <beast/http/reason.hpp>
|
2016-05-24 06:17:04 -04:00
|
|
|
#include <beast/http/rfc7230.hpp>
|
2016-05-07 14:57:15 -04:00
|
|
|
#include <beast/core/buffer_cat.hpp>
|
|
|
|
|
#include <beast/core/buffer_concepts.hpp>
|
|
|
|
|
#include <beast/core/consuming_buffers.hpp>
|
|
|
|
|
#include <beast/core/prepare_buffers.hpp>
|
|
|
|
|
#include <beast/core/static_streambuf.hpp>
|
|
|
|
|
#include <beast/core/stream_concepts.hpp>
|
2016-09-25 12:17:32 -04:00
|
|
|
#include <boost/assert.hpp>
|
2017-07-20 08:01:46 -07:00
|
|
|
#include <boost/endian/buffers.hpp>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
namespace beast {
|
|
|
|
|
namespace websocket {
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class... Args>
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
stream(Args&&... args)
|
2016-04-30 13:00:33 -04:00
|
|
|
: stream_(std::forward<Args>(args)...)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
accept()
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
|
|
|
|
error_code ec;
|
|
|
|
|
accept(boost::asio::null_buffers{}, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
accept(error_code& ec)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
accept(boost::asio::null_buffers{}, ec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class AcceptHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
AcceptHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_accept(AcceptHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
return async_accept(boost::asio::null_buffers{},
|
|
|
|
|
std::forward<AcceptHandler>(handler));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
accept(ConstBufferSequence const& buffers)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
|
|
|
|
error_code ec;
|
|
|
|
|
accept(buffers, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
accept(ConstBufferSequence const& buffers, error_code& ec)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
|
|
|
|
using boost::asio::buffer_copy;
|
|
|
|
|
using boost::asio::buffer_size;
|
2016-05-15 16:22:25 -04:00
|
|
|
reset();
|
2017-07-20 08:01:46 -07:00
|
|
|
stream_.buffer().commit(buffer_copy(
|
|
|
|
|
stream_.buffer().prepare(
|
|
|
|
|
buffer_size(buffers)), buffers));
|
2016-05-18 12:30:15 -04:00
|
|
|
http::request_v1<http::string_body> m;
|
2016-04-30 13:00:33 -04:00
|
|
|
http::read(next_layer(), stream_.buffer(), m, ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
if(ec)
|
|
|
|
|
return;
|
|
|
|
|
accept(m, ec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence, class AcceptHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
AcceptHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
|
|
|
|
beast::async_completion<
|
|
|
|
|
AcceptHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
|
|
|
|
accept_op<decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, bs};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class Body, class Headers>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-01 11:14:10 -04:00
|
|
|
accept(http::request_v1<Body, Headers> const& request)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
error_code ec;
|
|
|
|
|
accept(request, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class Body, class Headers>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-01 11:14:10 -04:00
|
|
|
accept(http::request_v1<Body, Headers> const& req,
|
2017-07-20 08:01:46 -07:00
|
|
|
error_code& ec)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-15 16:22:25 -04:00
|
|
|
reset();
|
2016-05-07 15:18:22 -04:00
|
|
|
auto const res = build_response(req);
|
|
|
|
|
http::write(stream_, res, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
return;
|
2016-05-07 15:18:22 -04:00
|
|
|
if(res.status != 101)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
ec = error::handshake_failed;
|
|
|
|
|
// VFALCO TODO Respect keep alive setting, perform
|
|
|
|
|
// teardown if Connection: close.
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-05-15 16:22:25 -04:00
|
|
|
open(detail::role_type::server);
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class Body, class Headers, class AcceptHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
AcceptHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
2016-05-01 11:14:10 -04:00
|
|
|
async_accept(http::request_v1<Body, Headers> const& req,
|
2017-07-20 08:01:46 -07:00
|
|
|
AcceptHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
beast::async_completion<
|
|
|
|
|
AcceptHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
2016-05-15 16:22:25 -04:00
|
|
|
reset();
|
2017-07-20 08:01:46 -07:00
|
|
|
response_op<decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, req,
|
|
|
|
|
boost_asio_handler_cont_helpers::
|
|
|
|
|
is_continuation(completion.handler)};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
handshake(boost::string_ref const& host,
|
|
|
|
|
boost::string_ref const& resource)
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
|
|
|
|
error_code ec;
|
|
|
|
|
handshake(host, resource, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
handshake(boost::string_ref const& host,
|
|
|
|
|
boost::string_ref const& resource, error_code& ec)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-15 16:22:25 -04:00
|
|
|
reset();
|
2017-07-20 08:01:46 -07:00
|
|
|
std::string key;
|
|
|
|
|
http::write(stream_,
|
|
|
|
|
build_request(host, resource, key), ec);
|
|
|
|
|
if(ec)
|
|
|
|
|
return;
|
2016-05-07 15:18:22 -04:00
|
|
|
http::response_v1<http::string_body> res;
|
|
|
|
|
http::read(next_layer(), stream_.buffer(), res, ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
if(ec)
|
|
|
|
|
return;
|
2016-05-07 15:18:22 -04:00
|
|
|
do_response(res, key, ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class HandshakeHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
HandshakeHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_handshake(boost::string_ref const& host,
|
|
|
|
|
boost::string_ref const& resource, HandshakeHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
beast::async_completion<
|
|
|
|
|
HandshakeHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
|
|
|
|
handshake_op<decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, host, resource};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
close(close_reason const& cr)
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
|
|
|
|
error_code ec;
|
|
|
|
|
close(cr, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
close(close_reason const& cr, error_code& ec)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-09-25 12:17:32 -04:00
|
|
|
BOOST_ASSERT(! wr_close_);
|
2017-07-20 08:01:46 -07:00
|
|
|
wr_close_ = true;
|
|
|
|
|
detail::frame_streambuf fb;
|
|
|
|
|
write_close<static_streambuf>(fb, cr);
|
|
|
|
|
boost::asio::write(stream_, fb.data(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class CloseHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
CloseHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_close(close_reason const& cr, CloseHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
beast::async_completion<
|
|
|
|
|
CloseHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
|
|
|
|
close_op<decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, cr};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
ping(ping_data const& payload)
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
ping(payload, ec);
|
|
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
ping(ping_data const& payload, error_code& ec)
|
|
|
|
|
{
|
2016-05-28 09:23:54 -04:00
|
|
|
detail::frame_streambuf db;
|
2016-05-15 16:22:25 -04:00
|
|
|
write_ping<static_streambuf>(
|
2016-05-28 09:23:54 -04:00
|
|
|
db, opcode::ping, payload);
|
|
|
|
|
boost::asio::write(stream_, db.data(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class PingHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
PingHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_ping(ping_data const& payload, PingHandler&& handler)
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
|
|
|
|
beast::async_completion<
|
|
|
|
|
PingHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
|
|
|
|
ping_op<decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, payload};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer>
|
2016-04-30 13:00:33 -04:00
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-28 09:23:54 -04:00
|
|
|
read(opcode& op, DynamicBuffer& dynabuf)
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2016-04-30 13:00:33 -04:00
|
|
|
error_code ec;
|
2016-05-28 09:23:54 -04:00
|
|
|
read(op, dynabuf, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer>
|
2017-07-20 08:01:46 -07:00
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-28 09:23:54 -04:00
|
|
|
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
frame_info fi;
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
2016-05-28 09:23:54 -04:00
|
|
|
read_frame(fi, dynabuf, ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
if(ec)
|
|
|
|
|
break;
|
|
|
|
|
op = fi.op;
|
|
|
|
|
if(fi.fin)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer, class ReadHandler>
|
2017-07-20 08:01:46 -07:00
|
|
|
typename async_completion<
|
|
|
|
|
ReadHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_read(opcode& op,
|
2016-05-28 09:23:54 -04:00
|
|
|
DynamicBuffer& dynabuf, ReadHandler&& handler)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
beast::async_completion<
|
|
|
|
|
ReadHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
2016-05-28 09:23:54 -04:00
|
|
|
read_op<DynamicBuffer, decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, op, dynabuf};
|
2017-07-20 08:01:46 -07:00
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer>
|
2016-04-30 13:00:33 -04:00
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-28 09:23:54 -04:00
|
|
|
read_frame(frame_info& fi, DynamicBuffer& dynabuf)
|
2016-04-30 13:00:33 -04:00
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2016-04-30 13:00:33 -04:00
|
|
|
error_code ec;
|
2016-05-28 09:23:54 -04:00
|
|
|
read_frame(fi, dynabuf, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer>
|
2017-07-20 08:01:46 -07:00
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-28 09:23:54 -04:00
|
|
|
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2016-04-30 13:00:33 -04:00
|
|
|
close_code::value code{};
|
2017-07-20 08:01:46 -07:00
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
if(rd_need_ == 0)
|
|
|
|
|
{
|
|
|
|
|
// read header
|
|
|
|
|
detail::frame_streambuf fb;
|
|
|
|
|
do_read_fh(fb, code, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
if(code != close_code::none)
|
|
|
|
|
break;
|
|
|
|
|
if(detail::is_control(rd_fh_.op))
|
|
|
|
|
{
|
|
|
|
|
// read control payload
|
|
|
|
|
if(rd_fh_.len > 0)
|
|
|
|
|
{
|
|
|
|
|
auto const mb = fb.prepare(
|
|
|
|
|
static_cast<std::size_t>(rd_fh_.len));
|
|
|
|
|
fb.commit(boost::asio::read(stream_, mb, ec));
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
if(rd_fh_.mask)
|
|
|
|
|
detail::mask_inplace(mb, rd_key_);
|
|
|
|
|
fb.commit(static_cast<std::size_t>(rd_fh_.len));
|
|
|
|
|
}
|
|
|
|
|
if(rd_fh_.op == opcode::ping)
|
|
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
ping_data data;
|
|
|
|
|
detail::read(data, fb.data());
|
2017-07-20 08:01:46 -07:00
|
|
|
fb.reset();
|
|
|
|
|
write_ping<static_streambuf>(
|
|
|
|
|
fb, opcode::pong, data);
|
|
|
|
|
boost::asio::write(stream_, fb.data(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if(rd_fh_.op == opcode::pong)
|
|
|
|
|
{
|
2016-05-15 16:22:25 -04:00
|
|
|
ping_data payload;
|
|
|
|
|
detail::read(payload, fb.data());
|
|
|
|
|
if(pong_cb_)
|
|
|
|
|
pong_cb_(payload);
|
2017-07-20 08:01:46 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
2016-09-25 12:17:32 -04:00
|
|
|
BOOST_ASSERT(rd_fh_.op == opcode::close);
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
detail::read(cr_, fb.data(), code);
|
|
|
|
|
if(code != close_code::none)
|
|
|
|
|
break;
|
|
|
|
|
if(! wr_close_)
|
|
|
|
|
{
|
|
|
|
|
auto cr = cr_;
|
|
|
|
|
if(cr.code == close_code::none)
|
|
|
|
|
cr.code = close_code::normal;
|
|
|
|
|
cr.reason = "";
|
|
|
|
|
fb.reset();
|
|
|
|
|
wr_close_ = true;
|
|
|
|
|
write_close<static_streambuf>(fb, cr);
|
|
|
|
|
boost::asio::write(stream_, fb.data(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(rd_need_ == 0 && ! rd_fh_.fin)
|
|
|
|
|
{
|
|
|
|
|
// empty frame
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// read payload
|
2016-05-28 09:23:54 -04:00
|
|
|
auto smb = dynabuf.prepare(
|
2017-07-20 08:01:46 -07:00
|
|
|
detail::clamp(rd_need_));
|
|
|
|
|
auto const bytes_transferred =
|
|
|
|
|
stream_.read_some(smb, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
rd_need_ -= bytes_transferred;
|
|
|
|
|
auto const pb = prepare_buffers(
|
|
|
|
|
bytes_transferred, smb);
|
|
|
|
|
if(rd_fh_.mask)
|
|
|
|
|
detail::mask_inplace(pb, rd_key_);
|
|
|
|
|
if(rd_opcode_ == opcode::text)
|
|
|
|
|
{
|
|
|
|
|
if(! rd_utf8_check_.write(pb) ||
|
|
|
|
|
(rd_need_ == 0 && rd_fh_.fin &&
|
|
|
|
|
! rd_utf8_check_.finish()))
|
|
|
|
|
{
|
|
|
|
|
code = close_code::bad_payload;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-28 09:23:54 -04:00
|
|
|
dynabuf.commit(bytes_transferred);
|
2017-07-20 08:01:46 -07:00
|
|
|
fi.op = rd_opcode_;
|
|
|
|
|
fi.fin = rd_fh_.fin && rd_need_ == 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(code != close_code::none)
|
|
|
|
|
{
|
|
|
|
|
// Fail the connection (per rfc6455)
|
|
|
|
|
if(! wr_close_)
|
|
|
|
|
{
|
|
|
|
|
wr_close_ = true;
|
|
|
|
|
detail::frame_streambuf fb;
|
|
|
|
|
write_close<static_streambuf>(fb, code);
|
|
|
|
|
boost::asio::write(stream_, fb.data(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-05-01 12:33:35 -04:00
|
|
|
websocket_helpers::call_teardown(next_layer(), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
ec = error::failed;
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = true;
|
2017-07-20 08:01:46 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(! ec)
|
2016-05-01 12:33:35 -04:00
|
|
|
websocket_helpers::call_teardown(next_layer(), ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
if(! ec)
|
|
|
|
|
ec = error::closed;
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
2016-05-28 09:23:54 -04:00
|
|
|
template<class DynamicBuffer, class ReadHandler>
|
2017-07-20 08:01:46 -07:00
|
|
|
typename async_completion<
|
|
|
|
|
ReadHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_read_frame(frame_info& fi,
|
2016-05-28 09:23:54 -04:00
|
|
|
DynamicBuffer& dynabuf, ReadHandler&& handler)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
|
|
|
|
|
"DynamicBuffer requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
beast::async_completion<
|
|
|
|
|
ReadHandler, void(error_code)> completion(handler);
|
2016-05-28 09:23:54 -04:00
|
|
|
read_frame_op<DynamicBuffer, decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, fi, dynabuf};
|
2017-07-20 08:01:46 -07:00
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
write(ConstBufferSequence const& buffers)
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
2016-04-30 13:00:33 -04:00
|
|
|
error_code ec;
|
|
|
|
|
write(buffers, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-06-10 15:48:39 -04:00
|
|
|
write(ConstBufferSequence const& buffers, error_code& ec)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
2016-06-10 15:48:39 -04:00
|
|
|
write_frame(true, buffers, ec);
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence, class WriteHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
WriteHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
|
|
|
|
beast::async_completion<
|
|
|
|
|
WriteHandler, void(error_code)> completion(handler);
|
|
|
|
|
write_op<ConstBufferSequence, decltype(completion.handler)>{
|
|
|
|
|
completion.handler, *this, bs};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 13:00:33 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
write_frame(bool fin, ConstBufferSequence const& buffers)
|
|
|
|
|
{
|
|
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2016-05-28 09:23:54 -04:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
2016-04-30 13:00:33 -04:00
|
|
|
error_code ec;
|
|
|
|
|
write_frame(fin, buffers, ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
if(ec)
|
|
|
|
|
throw system_error{ec};
|
2016-04-30 13:00:33 -04:00
|
|
|
}
|
|
|
|
|
|
2016-06-10 15:48:39 -04:00
|
|
|
/*
|
|
|
|
|
if(compress)
|
|
|
|
|
compress buffers into write_buffer
|
|
|
|
|
if(write_buffer_avail == write_buffer_size || fin`)
|
|
|
|
|
if(mask)
|
|
|
|
|
apply mask to write buffer
|
|
|
|
|
write frame header, write_buffer as one frame
|
|
|
|
|
else if(auto-fragment)
|
|
|
|
|
if(fin || write_buffer_avail + buffers size == write_buffer_size)
|
|
|
|
|
if(mask)
|
|
|
|
|
append buffers to write buffer
|
|
|
|
|
apply mask to write buffer
|
|
|
|
|
write frame header, write buffer as one frame
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
write frame header, write buffer, and buffers as one frame
|
|
|
|
|
else:
|
|
|
|
|
append buffers to write buffer
|
|
|
|
|
else if(mask)
|
|
|
|
|
copy buffers to write_buffer
|
|
|
|
|
apply mask to write_buffer
|
|
|
|
|
write frame header and possibly full write_buffer in a single call
|
|
|
|
|
loop:
|
|
|
|
|
copy buffers to write_buffer
|
|
|
|
|
apply mask to write_buffer
|
|
|
|
|
write write_buffer in a single call
|
|
|
|
|
else
|
|
|
|
|
write frame header, buffers as one frame
|
|
|
|
|
*/
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-06-10 15:48:39 -04:00
|
|
|
write_frame(bool fin,
|
|
|
|
|
ConstBufferSequence const& buffers, error_code& ec)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_SyncStream<next_layer_type>::value,
|
|
|
|
|
"SyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
2016-06-10 15:48:39 -04:00
|
|
|
using boost::asio::buffer;
|
2017-07-20 08:01:46 -07:00
|
|
|
using boost::asio::buffer_copy;
|
|
|
|
|
using boost::asio::buffer_size;
|
2016-06-10 15:48:39 -04:00
|
|
|
bool const compress = false;
|
|
|
|
|
if(! wr_.cont)
|
|
|
|
|
wr_prepare(compress);
|
2017-07-20 08:01:46 -07:00
|
|
|
detail::frame_header fh;
|
2016-06-10 15:48:39 -04:00
|
|
|
fh.op = wr_.cont ? opcode::cont : wr_opcode_;
|
2017-07-20 08:01:46 -07:00
|
|
|
fh.rsv1 = false;
|
|
|
|
|
fh.rsv2 = false;
|
|
|
|
|
fh.rsv3 = false;
|
2016-05-15 16:22:25 -04:00
|
|
|
fh.mask = role_ == detail::role_type::client;
|
2016-06-10 15:48:39 -04:00
|
|
|
auto remain = buffer_size(buffers);
|
|
|
|
|
if(compress)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-06-10 15:48:39 -04:00
|
|
|
// TODO
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
2016-06-10 15:48:39 -04:00
|
|
|
else if(wr_.autofrag)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-06-10 15:48:39 -04:00
|
|
|
consuming_buffers<ConstBufferSequence> cb(buffers);
|
|
|
|
|
do
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-06-10 15:48:39 -04:00
|
|
|
auto const room = wr_.max - wr_.size;
|
|
|
|
|
if(! fin && remain < room)
|
|
|
|
|
{
|
|
|
|
|
buffer_copy(
|
|
|
|
|
buffer(wr_.buf.get() + wr_.size, remain), cb);
|
|
|
|
|
wr_.size += remain;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto const n = detail::clamp(remain, room);
|
|
|
|
|
buffer_copy(
|
|
|
|
|
buffer(wr_.buf.get() + wr_.size, n), cb);
|
|
|
|
|
auto const mb = buffer(wr_.buf.get(), wr_.size + n);
|
|
|
|
|
if(fh.mask)
|
|
|
|
|
{
|
|
|
|
|
fh.key = maskgen_();
|
|
|
|
|
detail::prepared_key_type key;
|
|
|
|
|
detail::prepare_key(key, fh.key);
|
|
|
|
|
detail::mask_inplace(mb, key);
|
|
|
|
|
}
|
|
|
|
|
fh.fin = fin && n == remain;
|
|
|
|
|
fh.len = buffer_size(mb);
|
|
|
|
|
detail::fh_streambuf fh_buf;
|
|
|
|
|
detail::write<static_streambuf>(fh_buf, fh);
|
|
|
|
|
// send header and payload
|
|
|
|
|
boost::asio::write(stream_,
|
|
|
|
|
buffer_cat(fh_buf.data(), mb), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
2016-06-10 15:48:39 -04:00
|
|
|
if(failed_)
|
|
|
|
|
return;
|
|
|
|
|
remain -= n;
|
|
|
|
|
cb.consume(n);
|
|
|
|
|
wr_.size = 0;
|
|
|
|
|
fh.op = opcode::cont;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
2016-06-10 15:48:39 -04:00
|
|
|
while(remain > 0);
|
|
|
|
|
wr_.cont = ! fh.fin;
|
|
|
|
|
return;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
2016-06-10 15:48:39 -04:00
|
|
|
else if(fh.mask)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-06-10 15:48:39 -04:00
|
|
|
consuming_buffers<ConstBufferSequence> cb(buffers);
|
|
|
|
|
fh.fin = fin;
|
|
|
|
|
fh.len = remain;
|
|
|
|
|
fh.key = maskgen_();
|
|
|
|
|
wr_.cont = ! fh.fin;
|
|
|
|
|
detail::fh_streambuf fh_buf;
|
|
|
|
|
detail::write<static_streambuf>(fh_buf, fh);
|
|
|
|
|
detail::prepared_key_type key;
|
|
|
|
|
detail::prepare_key(key, fh.key);
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
2016-06-10 15:48:39 -04:00
|
|
|
auto const n = detail::clamp(remain, wr_.max);
|
|
|
|
|
auto const mb = buffer(wr_.buf.get(), n);
|
|
|
|
|
buffer_copy(mb, cb);
|
|
|
|
|
cb.consume(n);
|
|
|
|
|
remain -= n;
|
|
|
|
|
detail::mask_inplace(mb, key);
|
|
|
|
|
// send header and payload
|
|
|
|
|
boost::asio::write(stream_,
|
|
|
|
|
buffer_cat(fh_buf.data(), mb), ec);
|
2016-05-15 16:22:25 -04:00
|
|
|
failed_ = ec != 0;
|
2016-06-10 15:48:39 -04:00
|
|
|
if(failed_)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while(remain > 0)
|
|
|
|
|
{
|
|
|
|
|
auto const n = detail::clamp(remain, wr_.max);
|
|
|
|
|
auto const mb = buffer(wr_.buf.get(), n);
|
|
|
|
|
buffer_copy(mb, cb);
|
|
|
|
|
cb.consume(n);
|
|
|
|
|
remain -= n;
|
|
|
|
|
detail::mask_inplace(mb, key);
|
|
|
|
|
// send payload
|
|
|
|
|
boost::asio::write(stream_, mb, ec);
|
|
|
|
|
failed_ = ec != 0;
|
|
|
|
|
if(failed_)
|
|
|
|
|
return;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
2016-06-10 15:48:39 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// send header and payload
|
|
|
|
|
fh.fin = fin;
|
|
|
|
|
fh.len = remain;
|
|
|
|
|
wr_.cont = ! fh.fin;
|
|
|
|
|
detail::fh_streambuf fh_buf;
|
|
|
|
|
detail::write<static_streambuf>(fh_buf, fh);
|
|
|
|
|
boost::asio::write(stream_,
|
|
|
|
|
buffer_cat(fh_buf.data(), buffers), ec);
|
|
|
|
|
failed_ = ec != 0;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class ConstBufferSequence, class WriteHandler>
|
|
|
|
|
typename async_completion<
|
|
|
|
|
WriteHandler, void(error_code)>::result_type
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
async_write_frame(bool fin,
|
|
|
|
|
ConstBufferSequence const& bs, WriteHandler&& handler)
|
|
|
|
|
{
|
2016-04-30 13:00:33 -04:00
|
|
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
|
|
|
|
"AsyncStream requirements not met");
|
2017-07-20 08:01:46 -07:00
|
|
|
static_assert(beast::is_ConstBufferSequence<
|
|
|
|
|
ConstBufferSequence>::value,
|
|
|
|
|
"ConstBufferSequence requirements not met");
|
|
|
|
|
beast::async_completion<
|
|
|
|
|
WriteHandler, void(error_code)
|
|
|
|
|
> completion(handler);
|
|
|
|
|
write_frame_op<ConstBufferSequence, decltype(
|
|
|
|
|
completion.handler)>{completion.handler,
|
|
|
|
|
*this, fin, bs};
|
|
|
|
|
return completion.result.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
2016-05-15 16:22:25 -04:00
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
reset()
|
|
|
|
|
{
|
|
|
|
|
failed_ = false;
|
|
|
|
|
rd_need_ = 0;
|
|
|
|
|
rd_cont_ = false;
|
|
|
|
|
wr_close_ = false;
|
2016-06-10 15:48:39 -04:00
|
|
|
wr_.cont = false;
|
2016-05-15 16:22:25 -04:00
|
|
|
wr_block_ = nullptr; // should be nullptr on close anyway
|
|
|
|
|
pong_data_ = nullptr; // should be nullptr on close anyway
|
|
|
|
|
|
|
|
|
|
stream_.buffer().consume(
|
|
|
|
|
stream_.buffer().size());
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-20 08:01:46 -07:00
|
|
|
template<class NextLayer>
|
2016-05-01 11:14:10 -04:00
|
|
|
http::request_v1<http::empty_body>
|
2017-07-20 08:01:46 -07:00
|
|
|
stream<NextLayer>::
|
|
|
|
|
build_request(boost::string_ref const& host,
|
|
|
|
|
boost::string_ref const& resource, std::string& key)
|
|
|
|
|
{
|
2016-05-01 11:14:10 -04:00
|
|
|
http::request_v1<http::empty_body> req;
|
2016-08-26 07:57:07 -04:00
|
|
|
req.url = { resource.data(), resource.size() };
|
2017-07-20 08:01:46 -07:00
|
|
|
req.version = 11;
|
2016-04-29 06:04:40 -04:00
|
|
|
req.method = "GET";
|
2017-07-20 08:01:46 -07:00
|
|
|
req.headers.insert("Host", host);
|
|
|
|
|
req.headers.insert("Upgrade", "websocket");
|
|
|
|
|
key = detail::make_sec_ws_key(maskgen_);
|
|
|
|
|
req.headers.insert("Sec-WebSocket-Key", key);
|
|
|
|
|
req.headers.insert("Sec-WebSocket-Version", "13");
|
|
|
|
|
(*d_)(req);
|
2016-04-29 06:04:40 -04:00
|
|
|
http::prepare(req, http::connection::upgrade);
|
2017-07-20 08:01:46 -07:00
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class Body, class Headers>
|
2016-05-01 11:14:10 -04:00
|
|
|
http::response_v1<http::string_body>
|
2017-07-20 08:01:46 -07:00
|
|
|
stream<NextLayer>::
|
2016-05-01 11:14:10 -04:00
|
|
|
build_response(http::request_v1<Body, Headers> const& req)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
auto err =
|
|
|
|
|
[&](std::string const& text)
|
|
|
|
|
{
|
2016-05-07 15:18:22 -04:00
|
|
|
http::response_v1<http::string_body> res;
|
|
|
|
|
res.status = 400;
|
|
|
|
|
res.reason = http::reason_string(res.status);
|
|
|
|
|
res.version = req.version;
|
|
|
|
|
res.body = text;
|
2016-05-15 16:22:25 -04:00
|
|
|
(*d_)(res);
|
|
|
|
|
prepare(res,
|
|
|
|
|
(is_keep_alive(req) && keep_alive_) ?
|
|
|
|
|
http::connection::keep_alive :
|
|
|
|
|
http::connection::close);
|
2016-05-07 15:18:22 -04:00
|
|
|
return res;
|
2017-07-20 08:01:46 -07:00
|
|
|
};
|
|
|
|
|
if(req.version < 11)
|
|
|
|
|
return err("HTTP version 1.1 required");
|
2016-04-29 06:04:40 -04:00
|
|
|
if(req.method != "GET")
|
2017-07-20 08:01:46 -07:00
|
|
|
return err("Wrong method");
|
|
|
|
|
if(! is_upgrade(req))
|
|
|
|
|
return err("Expected Upgrade request");
|
|
|
|
|
if(! req.headers.exists("Host"))
|
|
|
|
|
return err("Missing Host");
|
|
|
|
|
if(! req.headers.exists("Sec-WebSocket-Key"))
|
|
|
|
|
return err("Missing Sec-WebSocket-Key");
|
2016-05-24 06:17:04 -04:00
|
|
|
if(! http::token_list{req.headers["Upgrade"]}.exists("websocket"))
|
2016-05-15 16:22:25 -04:00
|
|
|
return err("Missing websocket Upgrade token");
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
auto const version =
|
|
|
|
|
req.headers["Sec-WebSocket-Version"];
|
|
|
|
|
if(version.empty())
|
|
|
|
|
return err("Missing Sec-WebSocket-Version");
|
|
|
|
|
if(version != "13")
|
2016-05-15 16:22:25 -04:00
|
|
|
{
|
|
|
|
|
http::response_v1<http::string_body> res;
|
|
|
|
|
res.status = 426;
|
|
|
|
|
res.reason = http::reason_string(res.status);
|
|
|
|
|
res.version = req.version;
|
|
|
|
|
res.headers.insert("Sec-WebSocket-Version", "13");
|
|
|
|
|
prepare(res,
|
|
|
|
|
(is_keep_alive(req) && keep_alive_) ?
|
|
|
|
|
http::connection::keep_alive :
|
|
|
|
|
http::connection::close);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
2016-05-07 15:18:22 -04:00
|
|
|
http::response_v1<http::string_body> res;
|
|
|
|
|
res.status = 101;
|
|
|
|
|
res.reason = http::reason_string(res.status);
|
|
|
|
|
res.version = req.version;
|
|
|
|
|
res.headers.insert("Upgrade", "websocket");
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
auto const key =
|
|
|
|
|
req.headers["Sec-WebSocket-Key"];
|
2016-05-07 15:18:22 -04:00
|
|
|
res.headers.insert("Sec-WebSocket-Accept",
|
2017-07-20 08:01:46 -07:00
|
|
|
detail::make_sec_ws_accept(key));
|
|
|
|
|
}
|
2016-05-07 15:18:22 -04:00
|
|
|
res.headers.replace("Server", "Beast.WSProto");
|
|
|
|
|
(*d_)(res);
|
|
|
|
|
http::prepare(res, http::connection::upgrade);
|
|
|
|
|
return res;
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
template<class Body, class Headers>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
2016-05-07 15:18:22 -04:00
|
|
|
do_response(http::response_v1<Body, Headers> const& res,
|
2017-07-20 08:01:46 -07:00
|
|
|
boost::string_ref const& key, error_code& ec)
|
|
|
|
|
{
|
|
|
|
|
// VFALCO Review these error codes
|
|
|
|
|
auto fail = [&]{ ec = error::response_failed; };
|
2016-05-15 16:22:25 -04:00
|
|
|
if(res.version < 11)
|
|
|
|
|
return fail();
|
2016-05-07 15:18:22 -04:00
|
|
|
if(res.status != 101)
|
2017-07-20 08:01:46 -07:00
|
|
|
return fail();
|
2016-05-07 15:18:22 -04:00
|
|
|
if(! is_upgrade(res))
|
2017-07-20 08:01:46 -07:00
|
|
|
return fail();
|
2016-05-24 06:17:04 -04:00
|
|
|
if(! http::token_list{res.headers["Upgrade"]}.exists("websocket"))
|
2017-07-20 08:01:46 -07:00
|
|
|
return fail();
|
2016-05-07 15:18:22 -04:00
|
|
|
if(! res.headers.exists("Sec-WebSocket-Accept"))
|
2017-07-20 08:01:46 -07:00
|
|
|
return fail();
|
2016-05-07 15:18:22 -04:00
|
|
|
if(res.headers["Sec-WebSocket-Accept"] !=
|
2017-07-20 08:01:46 -07:00
|
|
|
detail::make_sec_ws_accept(key))
|
|
|
|
|
return fail();
|
2016-05-15 16:22:25 -04:00
|
|
|
open(detail::role_type::client);
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class NextLayer>
|
|
|
|
|
void
|
|
|
|
|
stream<NextLayer>::
|
|
|
|
|
do_read_fh(detail::frame_streambuf& fb,
|
2016-04-30 13:00:33 -04:00
|
|
|
close_code::value& code, error_code& ec)
|
2017-07-20 08:01:46 -07:00
|
|
|
{
|
|
|
|
|
fb.commit(boost::asio::read(
|
|
|
|
|
stream_, fb.prepare(2), ec));
|
|
|
|
|
if(ec)
|
|
|
|
|
return;
|
2016-06-10 09:43:57 -04:00
|
|
|
auto const n = read_fh1(fb, code);
|
2017-07-20 08:01:46 -07:00
|
|
|
if(code != close_code::none)
|
|
|
|
|
return;
|
|
|
|
|
if(n > 0)
|
|
|
|
|
{
|
|
|
|
|
fb.commit(boost::asio::read(
|
|
|
|
|
stream_, fb.prepare(n), ec));
|
|
|
|
|
if(ec)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-10 09:43:57 -04:00
|
|
|
read_fh2(fb, code);
|
2017-07-20 08:01:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // websocket
|
|
|
|
|
} // beast
|
|
|
|
|
|
|
|
|
|
#endif
|