Add permessage-deflate WebSocket extension:

This implements the permessage-deflate WebSocket
extension as described in HyBi Working Group
draft-ietf-hybi-permessage-compression-28:
https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28

This extension allows messages to be compressed using
the raw "deflate" algorithm described in RFC 1951,
"DEFLATE Compressed Data Format Specification version 1.3":
https://www.ietf.org/rfc/rfc1951.txt
This commit is contained in:
Vinnie Falco committed 2017-07-20 08:12:14 -07:00
1 parent 99706347cd
commit 911617c43f
26 files changed
+2404 -1324

No files matched your search

+54 -89
View File
@@ -8,6 +8,7 @@
#ifndef BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED
#define BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED
#include "options_set.hpp"
#include <beast/core/placeholders.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/websocket.hpp>
@@ -33,12 +34,30 @@ public:
using socket_type = boost::asio::ip::tcp::socket;
private:
struct identity
{
template<class Body, class Fields>
void
operator()(http::message<true, Body, Fields>& req)
{
req.fields.replace("User-Agent", "async_echo_client");
}
template<class Body, class Fields>
void
operator()(http::message<false, Body, Fields>& resp)
{
resp.fields.replace("Server", "async_echo_server");
}
};
std::ostream* log_;
boost::asio::io_service ios_;
socket_type sock_;
boost::asio::ip::tcp::acceptor acceptor_;
std::vector<std::thread> thread_;
boost::optional<boost::asio::io_service::work> work_;
options_set<socket_type> opts_;
public:
async_echo_server(async_echo_server const&) = delete;
@@ -51,6 +70,8 @@ public:
, acceptor_(ios_)
, work_(ios_)
{
opts_.set_option(
beast::websocket::decorate(identity{}));
thread_.reserve(threads);
for(std::size_t i = 0; i < threads; ++i)
thread_.emplace_back(
@@ -67,44 +88,43 @@ public:
t.join();
}
template<class Opt>
void
open(bool server,
endpoint_type const& ep, error_code& ec)
set_option(Opt const& opt)
{
if(server)
opts_.set_option(opt);
}
void
open(endpoint_type const& ep, error_code& ec)
{
acceptor_.open(ep.protocol(), ec);
if(ec)
{
acceptor_.open(ep.protocol(), ec);
if(ec)
{
if(log_)
(*log_) << "open: " << ec.message() << std::endl;
return;
}
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
if(ec)
{
if(log_)
(*log_) << "bind: " << ec.message() << std::endl;
return;
}
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
if(ec)
{
if(log_)
(*log_) << "listen: " << ec.message() << std::endl;
return;
}
acceptor_.async_accept(sock_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
if(log_)
(*log_) << "open: " << ec.message() << std::endl;
return;
}
else
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
if(ec)
{
Peer{*this, std::move(sock_), ep};
if(log_)
(*log_) << "bind: " << ec.message() << std::endl;
return;
}
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
if(ec)
{
if(log_)
(*log_) << "listen: " << ec.message() << std::endl;
return;
}
acceptor_.async_accept(sock_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
endpoint_type
@@ -120,7 +140,6 @@ private:
{
async_echo_server& server;
int state = 0;
boost::optional<endpoint_type> ep;
stream<socket_type> ws;
boost::asio::io_service::strand strand;
opcode op;
@@ -139,20 +158,6 @@ private:
}())
{
}
data(async_echo_server& server_,
socket_type&& sock_, endpoint_type const& ep_)
: server(server_)
, ep(ep_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
, id([]
{
static int n = 0;
return ++n;
}())
{
}
};
std::shared_ptr<data> d_;
@@ -163,23 +168,6 @@ private:
Peer& operator=(Peer&&) = delete;
Peer& operator=(Peer const&) = delete;
struct identity
{
template<class Body, class Fields>
void
operator()(http::message<true, Body, Fields>& req)
{
req.fields.replace("User-Agent", "async_echo_client");
}
template<class Body, class Fields>
void
operator()(http::message<false, Body, Fields>& resp)
{
resp.fields.replace("Server", "async_echo_server");
}
};
template<class... Args>
explicit
Peer(async_echo_server& server,
@@ -189,26 +177,14 @@ private:
std::forward<Args>(args)...))
{
auto& d = *d_;
d.ws.set_option(decorate(identity{}));
d.ws.set_option(read_message_max(64 * 1024 * 1024));
d.ws.set_option(auto_fragment{false});
//d.ws.set_option(write_buffer_size{64 * 1024});
d.server.opts_.set_options(d.ws);
run();
}
void run()
{
auto& d = *d_;
if(! d.ep)
{
d.ws.async_accept(std::move(*this));
}
else
{
d.state = 4;
d.ws.next_layer().async_connect(
*d.ep, std::move(*this));
}
d.ws.async_accept(std::move(*this));
}
template<class DynamicBuffer, std::size_t N>
@@ -303,17 +279,6 @@ private:
d.ws.async_write(d.db.data(),
d.strand.wrap(std::move(*this)));
return;
// connected
case 4:
if(ec)
return fail(ec, "async_connect");
d.state = 1;
d.ws.async_handshake(
d.ep->address().to_string() + ":" +
boost::lexical_cast<std::string>(d.ep->port()),
"/", d.strand.wrap(std::move(*this)));
return;
}
}