Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d7052d2ae | |||
| d68fd03e40 | |||
| e161ffde69 | |||
| 371d2cdaef | |||
| 174698f1df | |||
| 214cedf949 | |||
| c39412ee38 | |||
| 643e7a0ce1 | |||
| 349717ad46 | |||
| f9b08ccea1 | |||
| fccc78479e | |||
| 3017a9c5e4 | |||
| 17544d4d62 | |||
| 4d1693c96c | |||
| c021766592 | |||
| 7f7e9d2c2c | |||
| 70923eea23 | |||
| 99ae2f768c | |||
| 884e7d210c | |||
| 75dd6f3ba5 | |||
| 2ee496c08d | |||
| aabf87b6b1 | |||
| cfabe17e83 | |||
| e62823a0af | |||
| 8ce05cd228 | |||
| eb314e55de | |||
| ccbd93f725 | |||
| be9a320fc1 | |||
| 9a73b74a37 | |||
| 48add58dc2 | |||
| e967ffc74d | |||
| 475c478a2e | |||
| b8d962950f | |||
| ba0094a0eb | |||
| eb362007ab | |||
| 4d63c10be7 | |||
| 28f949d955 | |||
| 11906dc2ce | |||
| c60e089553 | |||
| b809bf3706 | |||
| 6920b39aa2 | |||
| f7376ccf46 | |||
| 243cea16db | |||
| 98a75b8cea | |||
| 5323076007 | |||
| d0d97b860b | |||
| 25e8d522b2 | |||
| bd408944fd | |||
| 14aa71091f | |||
| 4607150f82 | |||
| 359f03fb1e | |||
| 4a52e548fd | |||
| 0501f77b57 | |||
| 631261c365 | |||
| a90ccd83dd | |||
| c103032e9c | |||
| c32bebba3e | |||
| 6c6c6951e5 | |||
| aeb0e8fa7d |
+7
-2
@@ -125,6 +125,7 @@ elif env['CXX'].startswith('clang++'):
|
||||
|
||||
# Wpadded
|
||||
# Wsign-conversion
|
||||
#
|
||||
|
||||
platform_libs = []
|
||||
tls_libs = []
|
||||
@@ -240,8 +241,12 @@ testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = b
|
||||
# testee_client
|
||||
testee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0)
|
||||
|
||||
# utility_client
|
||||
utility_client = SConscript('#/examples/utility_client/SConscript',variant_dir = builddir + 'utility_client',duplicate = 0)
|
||||
# scratch_client
|
||||
scratch_client = SConscript('#/examples/scratch_client/SConscript',variant_dir = builddir + 'scratch_client',duplicate = 0)
|
||||
|
||||
# scratch_server
|
||||
scratch_server = SConscript('#/examples/scratch_server/SConscript',variant_dir = builddir + 'scratch_server',duplicate = 0)
|
||||
|
||||
|
||||
# debug_client
|
||||
debug_client = SConscript('#/examples/debug_client/SConscript',variant_dir = builddir + 'debug_client',duplicate = 0)
|
||||
|
||||
@@ -13,6 +13,8 @@ int main() {
|
||||
server print_server;
|
||||
|
||||
print_server.set_message_handler(&on_message);
|
||||
print_server.set_access_channels(websocketpp::log::alevel::all);
|
||||
print_server.set_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
print_server.init_asio();
|
||||
print_server.listen(9002);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
## Scratch client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('scratch_client', ["scratch_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.
|
||||
// Additional related material can be found in the tutorials/utility_client
|
||||
// directory of the WebSocket++ repository.
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
class connection_metadata {
|
||||
public:
|
||||
typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;
|
||||
|
||||
connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)
|
||||
: m_id(id)
|
||||
, m_hdl(hdl)
|
||||
, m_status("Connecting")
|
||||
, m_uri(uri)
|
||||
, m_server("N/A")
|
||||
{}
|
||||
|
||||
void on_open(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Open";
|
||||
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
m_server = con->get_response_header("Server");
|
||||
}
|
||||
|
||||
void on_fail(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Failed";
|
||||
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
m_server = con->get_response_header("Server");
|
||||
m_error_reason = con->get_ec().message();
|
||||
}
|
||||
|
||||
void on_close(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Closed";
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
std::stringstream s;
|
||||
s << "close code: " << con->get_remote_close_code() << " ("
|
||||
<< websocketpp::close::status::get_string(con->get_remote_close_code())
|
||||
<< "), close reason: " << con->get_remote_close_reason();
|
||||
m_error_reason = s.str();
|
||||
}
|
||||
|
||||
websocketpp::connection_hdl get_hdl() const {
|
||||
return m_hdl;
|
||||
}
|
||||
|
||||
int get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::string get_status() const {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);
|
||||
private:
|
||||
int m_id;
|
||||
websocketpp::connection_hdl m_hdl;
|
||||
std::string m_status;
|
||||
std::string m_uri;
|
||||
std::string m_server;
|
||||
std::string m_error_reason;
|
||||
};
|
||||
|
||||
std::ostream & operator<< (std::ostream & out, connection_metadata const & data) {
|
||||
out << "> URI: " << data.m_uri << "\n"
|
||||
<< "> Status: " << data.m_status << "\n"
|
||||
<< "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
|
||||
<< "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
class websocket_endpoint {
|
||||
public:
|
||||
websocket_endpoint () : m_next_id(0) {
|
||||
m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
|
||||
m_endpoint.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
m_endpoint.init_asio();
|
||||
m_endpoint.start_perpetual();
|
||||
|
||||
m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));
|
||||
}
|
||||
|
||||
~websocket_endpoint() {
|
||||
m_endpoint.stop_perpetual();
|
||||
|
||||
for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {
|
||||
if (it->second->get_status() != "Open") {
|
||||
// Only close open connections
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "> Closing connection " << it->second->get_id() << std::endl;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, "", ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error closing connection " << it->second->get_id() << ": "
|
||||
<< ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
m_thread->join();
|
||||
}
|
||||
|
||||
int connect(std::string const & uri) {
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
|
||||
|
||||
if (ec) {
|
||||
std::cout << "> Connect initialization error: " << ec.message() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int new_id = m_next_id++;
|
||||
connection_metadata::ptr metadata_ptr(new connection_metadata(new_id, con->get_handle(), uri));
|
||||
m_connection_list[new_id] = metadata_ptr;
|
||||
|
||||
con->set_open_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_open,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
con->set_fail_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_fail,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
con->set_close_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_close,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
|
||||
m_endpoint.connect(con);
|
||||
|
||||
return new_id;
|
||||
}
|
||||
|
||||
void close(int id, websocketpp::close::status::value code, std::string reason) {
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
con_list::iterator metadata_it = m_connection_list.find(id);
|
||||
if (metadata_it == m_connection_list.end()) {
|
||||
std::cout << "> No connection found with id " << id << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error initiating close: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
connection_metadata::ptr get_metadata(int id) const {
|
||||
con_list::const_iterator metadata_it = m_connection_list.find(id);
|
||||
if (metadata_it == m_connection_list.end()) {
|
||||
return connection_metadata::ptr();
|
||||
} else {
|
||||
return metadata_it->second;
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef std::map<int,connection_metadata::ptr> con_list;
|
||||
|
||||
client m_endpoint;
|
||||
websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;
|
||||
|
||||
con_list m_connection_list;
|
||||
int m_next_id;
|
||||
};
|
||||
|
||||
int main() {
|
||||
bool done = false;
|
||||
std::string input;
|
||||
websocket_endpoint endpoint;
|
||||
|
||||
while (!done) {
|
||||
std::cout << "Enter Command: ";
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input == "quit") {
|
||||
done = true;
|
||||
} else if (input == "help") {
|
||||
std::cout
|
||||
<< "\nCommand List:\n"
|
||||
<< "connect <ws uri>\n"
|
||||
<< "close <connection id> [<close code:default=1000>] [<close reason>]\n"
|
||||
<< "show <connection id>\n"
|
||||
<< "help: Display this help text\n"
|
||||
<< "quit: Exit the program\n"
|
||||
<< std::endl;
|
||||
} else if (input.substr(0,7) == "connect") {
|
||||
int id = endpoint.connect(input.substr(8));
|
||||
if (id != -1) {
|
||||
std::cout << "> Created connection with id " << id << std::endl;
|
||||
}
|
||||
} else if (input.substr(0,5) == "close") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
std::string cmd;
|
||||
int id;
|
||||
int close_code = websocketpp::close::status::normal;
|
||||
std::string reason = "";
|
||||
|
||||
ss >> cmd >> id >> close_code;
|
||||
std::getline(ss,reason);
|
||||
|
||||
endpoint.close(id, close_code, reason);
|
||||
} else if (input.substr(0,4) == "show") {
|
||||
int id = atoi(input.substr(5).c_str());
|
||||
|
||||
connection_metadata::ptr metadata = endpoint.get_metadata(id);
|
||||
if (metadata) {
|
||||
std::cout << *metadata << std::endl;
|
||||
} else {
|
||||
std::cout << "> Unknown connection id " << id << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << "> Unrecognized Command" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
## Scratch server example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']
|
||||
prgs += env_cpp11.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']
|
||||
prgs += env.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* This example is presently used as a scratch space. It may or may not be broken
|
||||
* at any given time.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/config/debug_asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
|
||||
struct deflate_config : public websocketpp::config::debug_core {
|
||||
typedef deflate_config type;
|
||||
typedef debug_core base;
|
||||
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::basic_socket::endpoint
|
||||
socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<deflate_config> server;
|
||||
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
// Define a callback to handle incoming messages
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
/*std::cout << "on_message called with hdl: " << hdl.lock().get()
|
||||
<< " and message (" << msg->get_payload().size() << "): " << msg->get_payload()
|
||||
<< std::endl;
|
||||
*/
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
std::cout << "Echo failed because: " << e
|
||||
<< "(" << e.message() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// Create a server endpoint
|
||||
server echo_server;
|
||||
|
||||
try {
|
||||
// Set logging settings
|
||||
if (argc > 1 && std::string(argv[1]) == "-d") {
|
||||
echo_server.set_access_channels(websocketpp::log::alevel::all);
|
||||
echo_server.set_error_channels(websocketpp::log::elevel::all);
|
||||
} else {
|
||||
echo_server.set_access_channels(websocketpp::log::alevel::none);
|
||||
echo_server.set_error_channels(websocketpp::log::elevel::none);
|
||||
}
|
||||
|
||||
// Initialize ASIO
|
||||
echo_server.init_asio();
|
||||
|
||||
// Register our message handler
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,_1,_2));
|
||||
|
||||
// Listen on port 9002
|
||||
echo_server.listen(9002);
|
||||
|
||||
// Start the server accept loop
|
||||
echo_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_server.run();
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,10 @@ prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,10 +1,75 @@
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
/*
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
struct deflate_config : public websocketpp::config::asio_client {
|
||||
typedef deflate_config type;
|
||||
typedef asio_client base;
|
||||
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::basic_socket::endpoint
|
||||
socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::client<deflate_config> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
|
||||
@@ -14,10 +14,10 @@ prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct testee_config : public websocketpp::config::asio {
|
||||
@@ -64,6 +65,12 @@ struct testee_config : public websocketpp::config::asio {
|
||||
websocketpp::log::elevel::none;
|
||||
static const websocketpp::log::level alog_level =
|
||||
websocketpp::log::alevel::none;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<testee_config> server;
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
## Utility client example
|
||||
##
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
init_target (utility_client)
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
prgs = []
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,23 +1,11 @@
|
||||
## Utility client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
init_target (utility_client)
|
||||
|
||||
prgs = []
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -322,4 +322,4 @@ int main() {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -100,10 +100,10 @@ BOOST_AUTO_TEST_CASE( negotiation_invalid_attr ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
// Negotiate s2c_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) {
|
||||
// Negotiate server_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_no_context_takeover"] = "foo";
|
||||
v.attr["server_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -111,30 +111,30 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_server_initiated ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_s2c_no_context_takeover();
|
||||
v.exts.enable_server_no_context_takeover();
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover");
|
||||
}
|
||||
|
||||
// Negotiate c2s_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) {
|
||||
// Negotiate client_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_no_context_takeover"] = "foo";
|
||||
v.attr["client_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -142,29 +142,29 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_server_initiated ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_c2s_no_context_takeover();
|
||||
v.exts.enable_client_no_context_takeover();
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover");
|
||||
}
|
||||
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
// Negotiate server_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["s2c_max_window_bits"] = *it;
|
||||
v.attr["server_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -184,16 +184,16 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
|
||||
v.attr["s2c_max_window_bits"] = "15";
|
||||
v.attr["server_max_window_bits"] = "15";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
@@ -201,21 +201,21 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_s2c_max_window_bits ) {
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_server_max_window_bits ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(7,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(7,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(16,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(16,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::decline);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
@@ -223,44 +223,44 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_accept ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::accept);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::accept);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_largest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::largest);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::largest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::smallest);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::smallest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
// Negotiate server_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
@@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["c2s_max_window_bits"] = *it;
|
||||
v.attr["client_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -279,43 +279,43 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_valid ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "";
|
||||
v.attr["client_max_window_bits"] = "";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "15";
|
||||
v.attr["client_max_window_bits"] = "15";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_c2s_max_window_bits ) {
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_client_max_window_bits ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(7,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(7,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(16,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(16,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(8,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(8,pmd_mode::decline);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
@@ -323,40 +323,40 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_accept ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::accept);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::accept);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_largest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::largest);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::largest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::smallest);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::smallest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
|
||||
@@ -364,180 +364,286 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated1 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated2 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated3 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated4 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated5 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated6 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated1 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated2 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated3 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated4 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_four_client_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
// Compression
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE( compress_data ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string in = "Hello";
|
||||
std::string out;
|
||||
std::string in2;
|
||||
std::string out2;
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.exts.init();
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(in,out);
|
||||
|
||||
std::cout << "in : " << websocketpp::utility::to_hex(in) << std::endl;
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
|
||||
|
||||
in2 = out;
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(in2.data()),in2.size(),out2);
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out2) << std::endl;
|
||||
BOOST_CHECK_EQUAL( out, out2 );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_multiple ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.init(true);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_large ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in(600,'*');
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
websocketpp::http::attribute_list alist;
|
||||
|
||||
alist["server_max_window_bits"] = "8";
|
||||
v.exts.set_server_max_window_bits(8,websocketpp::extensions::permessage_deflate::mode::smallest);
|
||||
|
||||
v.exts.negotiate(alist);
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out1;
|
||||
std::string compress_out2;
|
||||
std::string decompress_out;
|
||||
|
||||
websocketpp::http::attribute_list alist;
|
||||
|
||||
alist["server_no_context_takeover"] = "";
|
||||
v.exts.enable_server_no_context_takeover();
|
||||
|
||||
v.exts.negotiate(alist);
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out1);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(
|
||||
reinterpret_cast<const uint8_t *>(compress_out1.data()),
|
||||
compress_out1.size(),
|
||||
decompress_out
|
||||
);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
|
||||
decompress_out = "";
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out2);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(
|
||||
reinterpret_cast<const uint8_t *>(compress_out2.data()),
|
||||
compress_out2.size(),
|
||||
decompress_out
|
||||
);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
|
||||
BOOST_CHECK_EQUAL( compress_out1, compress_out2 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_empty ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in = "";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
|
||||
compress_out = "";
|
||||
decompress_out = "";
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
/// @todo: more compression tests
|
||||
/**
|
||||
* - compress at different compression levels
|
||||
*/
|
||||
|
||||
// Decompression
|
||||
BOOST_AUTO_TEST_CASE( decompress_data ) {
|
||||
ext_vars v;
|
||||
|
||||
uint8_t in[12] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
std::string out;
|
||||
uint8_t in[11] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
std::string out = "";
|
||||
std::string reference = "Hello";
|
||||
|
||||
v.exts.init();
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.decompress(in,12,out);
|
||||
v.ec = v.exts.decompress(in,11,out);
|
||||
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
|
||||
BOOST_CHECK( false );
|
||||
BOOST_CHECK_EQUAL( out, reference );
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) {
|
||||
processor_setup_ext env(true);
|
||||
|
||||
env.req.replace_header("Sec-WebSocket-Extensions",
|
||||
"permessage-deflate; c2s_max_window_bits");
|
||||
"permessage-deflate; client_max_window_bits");
|
||||
|
||||
std::pair<websocketpp::lib::error_code,std::string> neg_results;
|
||||
neg_results = env.p.negotiate_extensions(env.req);
|
||||
|
||||
@@ -140,7 +140,10 @@ enum value {
|
||||
unsupported_version,
|
||||
|
||||
/// HTTP parse error
|
||||
http_parse_error
|
||||
http_parse_error,
|
||||
|
||||
/// Extension negotiation failed
|
||||
extension_neg_failed
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -216,6 +219,8 @@ public:
|
||||
return "Unsupported version";
|
||||
case error::http_parse_error:
|
||||
return "HTTP parse error";
|
||||
case error::extension_neg_failed:
|
||||
return "Extension negotiation failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class disabled {
|
||||
public:
|
||||
/// Negotiate extension
|
||||
/**
|
||||
* The disabled extension always fails the negotiation with a disabled
|
||||
* The disabled extension always fails the negotiation with a disabled
|
||||
* error.
|
||||
*
|
||||
* @param offer Attribute from client's offer
|
||||
@@ -65,6 +65,17 @@ public:
|
||||
return make_pair(make_error_code(error::disabled),std::string());
|
||||
}
|
||||
|
||||
/// Initialize state
|
||||
/**
|
||||
* For the disabled extension state initialization is a no-op.
|
||||
*
|
||||
* @param is_server True to initialize as a server, false for a client.
|
||||
* @return A code representing the error that occurred, if any
|
||||
*/
|
||||
lib::error_code init(bool) {
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Returns true if the extension is capable of providing
|
||||
/// permessage_deflate functionality
|
||||
bool is_implemented() const {
|
||||
@@ -77,6 +88,17 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Generate extension offer
|
||||
/**
|
||||
* Creates an offer string to include in the Sec-WebSocket-Extensions
|
||||
* header of outgoing client requests.
|
||||
*
|
||||
* @return A WebSocket extension offer string for this extension
|
||||
*/
|
||||
std::string generate_offer() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Compress bytes
|
||||
/**
|
||||
* @param [in] in String to compress
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -50,9 +50,13 @@ namespace extensions {
|
||||
/**
|
||||
* ### permessage-deflate interface
|
||||
*
|
||||
* **is_implemented**\n
|
||||
* `bool is_implemented()`\n
|
||||
* Returns whether or not the object implements the extension or not
|
||||
* **init**\n
|
||||
* `lib::error_code init(bool is_server)`\n
|
||||
* Performs initialization
|
||||
*
|
||||
* **is_implimented**\n
|
||||
* `bool is_implimented()`\n
|
||||
* Returns whether or not the object impliments the extension or not
|
||||
*
|
||||
* **is_enabled**\n
|
||||
* `bool is_enabled()`\n
|
||||
@@ -136,7 +140,7 @@ public:
|
||||
case zlib_error:
|
||||
return "A zlib function returned an error";
|
||||
case uninitialized:
|
||||
return "Object must be initialized before use";
|
||||
return "Deflate extension must be initialized before use";
|
||||
default:
|
||||
return "Unknown permessage-compress error";
|
||||
}
|
||||
@@ -144,13 +148,13 @@ public:
|
||||
};
|
||||
|
||||
/// Get a reference to a static copy of the permessage-deflate error category
|
||||
lib::error_category const & get_category() {
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Create an error code in the permessage-deflate category
|
||||
lib::error_code make_error_code(error::value e) {
|
||||
inline lib::error_code make_error_code(error::value e) {
|
||||
return lib::error_code(static_cast<int>(e), get_category());
|
||||
}
|
||||
|
||||
@@ -170,19 +174,19 @@ namespace websocketpp {
|
||||
namespace extensions {
|
||||
namespace permessage_deflate {
|
||||
|
||||
/// Default value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const default_s2c_max_window_bits = 15;
|
||||
/// Minimum value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const min_s2c_max_window_bits = 8;
|
||||
/// Maximum value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const max_s2c_max_window_bits = 15;
|
||||
/// Default value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const default_server_max_window_bits = 15;
|
||||
/// Minimum value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const min_server_max_window_bits = 8;
|
||||
/// Maximum value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const max_server_max_window_bits = 15;
|
||||
|
||||
/// Default value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const default_c2s_max_window_bits = 15;
|
||||
/// Minimum value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const min_c2s_max_window_bits = 8;
|
||||
/// Maximum value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const max_c2s_max_window_bits = 15;
|
||||
/// Default value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const default_client_max_window_bits = 15;
|
||||
/// Minimum value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const min_client_max_window_bits = 8;
|
||||
/// Maximum value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const max_client_max_window_bits = 15;
|
||||
|
||||
namespace mode {
|
||||
enum value {
|
||||
@@ -202,12 +206,12 @@ class enabled {
|
||||
public:
|
||||
enabled()
|
||||
: m_enabled(false)
|
||||
, m_s2c_no_context_takeover(false)
|
||||
, m_c2s_no_context_takeover(false)
|
||||
, m_s2c_max_window_bits(15)
|
||||
, m_c2s_max_window_bits(15)
|
||||
, m_s2c_max_window_bits_mode(mode::accept)
|
||||
, m_c2s_max_window_bits_mode(mode::accept)
|
||||
, m_server_no_context_takeover(false)
|
||||
, m_client_no_context_takeover(false)
|
||||
, m_server_max_window_bits(15)
|
||||
, m_client_max_window_bits(15)
|
||||
, m_server_max_window_bits_mode(mode::accept)
|
||||
, m_client_max_window_bits_mode(mode::accept)
|
||||
, m_initialized(false)
|
||||
, m_compress_buffer_size(16384)
|
||||
{
|
||||
@@ -244,20 +248,25 @@ public:
|
||||
|
||||
/// Initialize zlib state
|
||||
/**
|
||||
* Note: this should be called *after* the negotiation methods. It will use
|
||||
* information from the negotiation to determine how to initialize the zlib
|
||||
* data structures.
|
||||
*
|
||||
* @todo memory level, strategy, etc are hardcoded
|
||||
* @todo server detection is hardcoded
|
||||
*
|
||||
* @param is_server True to initialize as a server, false for a client.
|
||||
* @return A code representing the error that occurred, if any
|
||||
*/
|
||||
lib::error_code init() {
|
||||
lib::error_code init(bool is_server) {
|
||||
uint8_t deflate_bits;
|
||||
uint8_t inflate_bits;
|
||||
|
||||
if (true /*is_server*/) {
|
||||
deflate_bits = m_s2c_max_window_bits;
|
||||
inflate_bits = m_c2s_max_window_bits;
|
||||
if (is_server) {
|
||||
deflate_bits = m_server_max_window_bits;
|
||||
inflate_bits = m_client_max_window_bits;
|
||||
} else {
|
||||
deflate_bits = m_c2s_max_window_bits;
|
||||
inflate_bits = m_s2c_max_window_bits;
|
||||
deflate_bits = m_client_max_window_bits;
|
||||
inflate_bits = m_server_max_window_bits;
|
||||
}
|
||||
|
||||
int ret = deflateInit2(
|
||||
@@ -265,8 +274,8 @@ public:
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED,
|
||||
-1*deflate_bits,
|
||||
8, // memory level 1-9
|
||||
/*Z_DEFAULT_STRATEGY*/Z_FIXED
|
||||
4, // memory level 1-9
|
||||
Z_DEFAULT_STRATEGY
|
||||
);
|
||||
|
||||
if (ret != Z_OK) {
|
||||
@@ -283,6 +292,13 @@ public:
|
||||
}
|
||||
|
||||
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
|
||||
if ((m_server_no_context_takeover && is_server) ||
|
||||
(m_client_no_context_takeover && !is_server))
|
||||
{
|
||||
m_flush = Z_FULL_FLUSH;
|
||||
} else {
|
||||
m_flush = Z_SYNC_FLUSH;
|
||||
}
|
||||
m_initialized = true;
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -329,8 +345,8 @@ public:
|
||||
* the option will be in use so they can optimize resource usage if they
|
||||
* are able.
|
||||
*/
|
||||
void enable_s2c_no_context_takeover() {
|
||||
m_s2c_no_context_takeover = true;
|
||||
void enable_server_no_context_takeover() {
|
||||
m_server_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Reset client's outgoing LZ77 sliding window for each new message
|
||||
@@ -348,8 +364,8 @@ public:
|
||||
* This option is supported by all compliant clients and servers. Enabling
|
||||
* it via either endpoint should be sufficient to ensure it is used.
|
||||
*/
|
||||
void enable_c2s_no_context_takeover() {
|
||||
m_c2s_no_context_takeover = true;
|
||||
void enable_client_no_context_takeover() {
|
||||
m_client_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Limit server LZ77 sliding window size
|
||||
@@ -374,12 +390,12 @@ public:
|
||||
* @param mode The mode to use for negotiating this parameter
|
||||
* @return A status code
|
||||
*/
|
||||
lib::error_code set_s2c_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) {
|
||||
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
|
||||
return error::make_error_code(error::invalid_max_window_bits);
|
||||
}
|
||||
m_s2c_max_window_bits = bits;
|
||||
m_s2c_max_window_bits_mode = mode;
|
||||
m_server_max_window_bits = bits;
|
||||
m_server_max_window_bits_mode = mode;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -405,12 +421,12 @@ public:
|
||||
* @param mode The mode to use for negotiating this parameter
|
||||
* @return A status code
|
||||
*/
|
||||
lib::error_code set_c2s_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_c2s_max_window_bits || bits > max_c2s_max_window_bits) {
|
||||
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
|
||||
return error::make_error_code(error::invalid_max_window_bits);
|
||||
}
|
||||
m_c2s_max_window_bits = bits;
|
||||
m_c2s_max_window_bits_mode = mode;
|
||||
m_client_max_window_bits = bits;
|
||||
m_client_max_window_bits_mode = mode;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -423,7 +439,8 @@ public:
|
||||
* @return A WebSocket extension offer string for this extension
|
||||
*/
|
||||
std::string generate_offer() const {
|
||||
return "";
|
||||
// TODO: this should be dynamically generated based on user settings
|
||||
return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
|
||||
}
|
||||
|
||||
/// Validate extension response
|
||||
@@ -435,7 +452,7 @@ public:
|
||||
* @return Validation error or 0 on success
|
||||
*/
|
||||
lib::error_code validate_offer(http::attribute_list const &) {
|
||||
return make_error_code(error::general);
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Negotiate extension
|
||||
@@ -452,14 +469,14 @@ public:
|
||||
|
||||
http::attribute_list::const_iterator it;
|
||||
for (it = offer.begin(); it != offer.end(); ++it) {
|
||||
if (it->first == "s2c_no_context_takeover") {
|
||||
negotiate_s2c_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "c2s_no_context_takeover") {
|
||||
negotiate_c2s_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "s2c_max_window_bits") {
|
||||
negotiate_s2c_max_window_bits(it->second,ret.first);
|
||||
} else if (it->first == "c2s_max_window_bits") {
|
||||
negotiate_c2s_max_window_bits(it->second,ret.first);
|
||||
if (it->first == "server_no_context_takeover") {
|
||||
negotiate_server_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "client_no_context_takeover") {
|
||||
negotiate_client_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "server_max_window_bits") {
|
||||
negotiate_server_max_window_bits(it->second,ret.first);
|
||||
} else if (it->first == "client_max_window_bits") {
|
||||
negotiate_client_max_window_bits(it->second,ret.first);
|
||||
} else {
|
||||
ret.first = make_error_code(error::invalid_attributes);
|
||||
}
|
||||
@@ -479,6 +496,9 @@ public:
|
||||
|
||||
/// Compress bytes
|
||||
/**
|
||||
* @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames
|
||||
* on 64 bit machines.
|
||||
*
|
||||
* @param [in] in String to compress
|
||||
* @param [out] out String to append compressed bytes to
|
||||
* @return Error or status code
|
||||
@@ -490,7 +510,13 @@ public:
|
||||
|
||||
size_t output;
|
||||
|
||||
m_dstate.avail_out = m_compress_buffer_size;
|
||||
if (in.empty()) {
|
||||
uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
out.append((char *)(buf),6);
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
m_dstate.avail_in = in.size();
|
||||
m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
|
||||
|
||||
do {
|
||||
@@ -498,7 +524,7 @@ public:
|
||||
m_dstate.avail_out = m_compress_buffer_size;
|
||||
m_dstate.next_out = m_compress_buffer.get();
|
||||
|
||||
deflate(&m_dstate, Z_SYNC_FLUSH);
|
||||
deflate(&m_dstate, m_flush);
|
||||
|
||||
output = m_compress_buffer_size - m_dstate.avail_out;
|
||||
|
||||
@@ -553,35 +579,35 @@ private:
|
||||
std::string generate_response() {
|
||||
std::string ret = "permessage-deflate";
|
||||
|
||||
if (m_s2c_no_context_takeover) {
|
||||
ret += "; s2c_no_context_takeover";
|
||||
if (m_server_no_context_takeover) {
|
||||
ret += "; server_no_context_takeover";
|
||||
}
|
||||
|
||||
if (m_c2s_no_context_takeover) {
|
||||
ret += "; c2s_no_context_takeover";
|
||||
if (m_client_no_context_takeover) {
|
||||
ret += "; client_no_context_takeover";
|
||||
}
|
||||
|
||||
if (m_s2c_max_window_bits < default_s2c_max_window_bits) {
|
||||
if (m_server_max_window_bits < default_server_max_window_bits) {
|
||||
std::stringstream s;
|
||||
s << int(m_s2c_max_window_bits);
|
||||
ret += "; s2c_max_window_bits="+s.str();
|
||||
s << int(m_server_max_window_bits);
|
||||
ret += "; server_max_window_bits="+s.str();
|
||||
}
|
||||
|
||||
if (m_c2s_max_window_bits < default_c2s_max_window_bits) {
|
||||
if (m_client_max_window_bits < default_client_max_window_bits) {
|
||||
std::stringstream s;
|
||||
s << int(m_c2s_max_window_bits);
|
||||
ret += "; c2s_max_window_bits="+s.str();
|
||||
s << int(m_client_max_window_bits);
|
||||
ret += "; client_max_window_bits="+s.str();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Negotiate s2c_no_context_takeover attribute
|
||||
/// Negotiate server_no_context_takeover attribute
|
||||
/**
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_s2c_no_context_takeover(std::string const & value,
|
||||
void negotiate_server_no_context_takeover(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
if (!value.empty()) {
|
||||
@@ -589,15 +615,15 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
m_s2c_no_context_takeover = true;
|
||||
m_server_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Negotiate c2s_no_context_takeover attribute
|
||||
/// Negotiate client_no_context_takeover attribute
|
||||
/**
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_c2s_no_context_takeover(std::string const & value,
|
||||
void negotiate_client_no_context_takeover(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
if (!value.empty()) {
|
||||
@@ -605,13 +631,13 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
m_c2s_no_context_takeover = true;
|
||||
m_client_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Negotiate s2c_max_window_bits attribute
|
||||
/// Negotiate server_max_window_bits attribute
|
||||
/**
|
||||
* When this method starts, m_s2c_max_window_bits will contain the server's
|
||||
* preferred value and m_s2c_max_window_bits_mode will contain the mode the
|
||||
* When this method starts, m_server_max_window_bits will contain the server's
|
||||
* preferred value and m_server_max_window_bits_mode will contain the mode the
|
||||
* server wants to use to for negotiation. `value` contains the value the
|
||||
* client requested that we use.
|
||||
*
|
||||
@@ -624,39 +650,39 @@ private:
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_s2c_max_window_bits(std::string const & value,
|
||||
void negotiate_server_max_window_bits(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
uint8_t bits = uint8_t(atoi(value.c_str()));
|
||||
|
||||
if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) {
|
||||
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
|
||||
ec = make_error_code(error::invalid_attribute_value);
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_s2c_max_window_bits_mode) {
|
||||
switch (m_server_max_window_bits_mode) {
|
||||
case mode::decline:
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
break;
|
||||
case mode::accept:
|
||||
m_s2c_max_window_bits = bits;
|
||||
m_server_max_window_bits = bits;
|
||||
break;
|
||||
case mode::largest:
|
||||
m_s2c_max_window_bits = (std::min)(bits,m_s2c_max_window_bits);
|
||||
m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
|
||||
break;
|
||||
case mode::smallest:
|
||||
m_s2c_max_window_bits = min_s2c_max_window_bits;
|
||||
m_server_max_window_bits = min_server_max_window_bits;
|
||||
break;
|
||||
default:
|
||||
ec = make_error_code(error::invalid_mode);
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
}
|
||||
}
|
||||
|
||||
/// Negotiate c2s_max_window_bits attribute
|
||||
/// Negotiate client_max_window_bits attribute
|
||||
/**
|
||||
* When this method starts, m_c2s_max_window_bits and m_c2s_max_window_mode
|
||||
* When this method starts, m_client_max_window_bits and m_c2s_max_window_mode
|
||||
* will contain the server's preferred values for window size and
|
||||
* negotiation mode.
|
||||
*
|
||||
@@ -669,49 +695,50 @@ private:
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_c2s_max_window_bits(std::string const & value,
|
||||
void negotiate_client_max_window_bits(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
uint8_t bits = uint8_t(atoi(value.c_str()));
|
||||
|
||||
if (value.empty()) {
|
||||
bits = default_c2s_max_window_bits;
|
||||
} else if (bits < min_c2s_max_window_bits ||
|
||||
bits > max_c2s_max_window_bits)
|
||||
bits = default_client_max_window_bits;
|
||||
} else if (bits < min_client_max_window_bits ||
|
||||
bits > max_client_max_window_bits)
|
||||
{
|
||||
ec = make_error_code(error::invalid_attribute_value);
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_c2s_max_window_bits_mode) {
|
||||
switch (m_client_max_window_bits_mode) {
|
||||
case mode::decline:
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
break;
|
||||
case mode::accept:
|
||||
m_c2s_max_window_bits = bits;
|
||||
m_client_max_window_bits = bits;
|
||||
break;
|
||||
case mode::largest:
|
||||
m_c2s_max_window_bits = std::min(bits,m_c2s_max_window_bits);
|
||||
m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
|
||||
break;
|
||||
case mode::smallest:
|
||||
m_c2s_max_window_bits = min_c2s_max_window_bits;
|
||||
m_client_max_window_bits = min_client_max_window_bits;
|
||||
break;
|
||||
default:
|
||||
ec = make_error_code(error::invalid_mode);
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
}
|
||||
}
|
||||
|
||||
bool m_enabled;
|
||||
bool m_s2c_no_context_takeover;
|
||||
bool m_c2s_no_context_takeover;
|
||||
uint8_t m_s2c_max_window_bits;
|
||||
uint8_t m_c2s_max_window_bits;
|
||||
mode::value m_s2c_max_window_bits_mode;
|
||||
mode::value m_c2s_max_window_bits_mode;
|
||||
bool m_server_no_context_takeover;
|
||||
bool m_client_no_context_takeover;
|
||||
uint8_t m_server_max_window_bits;
|
||||
uint8_t m_client_max_window_bits;
|
||||
mode::value m_server_max_window_bits_mode;
|
||||
mode::value m_client_max_window_bits_mode;
|
||||
|
||||
bool m_initialized;
|
||||
int m_flush;
|
||||
size_t m_compress_buffer_size;
|
||||
lib::unique_ptr_uchar_array m_compress_buffer;
|
||||
z_stream m_dstate;
|
||||
|
||||
@@ -85,6 +85,7 @@ lib::error_code connection<config>::send(std::string const & payload,
|
||||
{
|
||||
message_ptr msg = m_msg_manager->get_message(op,payload.size());
|
||||
msg->append_payload(payload);
|
||||
msg->set_compressed(true);
|
||||
|
||||
return send(msg);
|
||||
}
|
||||
@@ -1026,6 +1027,12 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
|
||||
|
||||
lib::error_code consume_ec;
|
||||
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
std::stringstream s;
|
||||
s << "Processing Bytes: " << utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);
|
||||
m_alog.write(log::alevel::devel,s.str());
|
||||
}
|
||||
|
||||
p += m_processor->consume(
|
||||
reinterpret_cast<uint8_t*>(m_buf)+p,
|
||||
bytes_transferred-p,
|
||||
@@ -1587,6 +1594,25 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
|
||||
return;
|
||||
}
|
||||
|
||||
// Read extension parameters and set up values necessary for the end
|
||||
// user to complete extension negotiation.
|
||||
std::pair<lib::error_code,std::string> neg_results;
|
||||
neg_results = m_processor->negotiate_extensions(m_response);
|
||||
|
||||
if (neg_results.first) {
|
||||
// There was a fatal error in extension negotiation. For the moment
|
||||
// kill all connections that fail extension negotiation.
|
||||
|
||||
// TODO: deal with cases where the response is well formed but
|
||||
// doesn't match the options requested by the client. Its possible
|
||||
// that the best behavior in this cases is to log and continue with
|
||||
// an unextended connection.
|
||||
m_alog.write(log::alevel::devel, "Extension negotiation failed: "
|
||||
+ neg_results.first.message());
|
||||
this->terminate(make_error_code(error::extension_neg_failed));
|
||||
// TODO: close connection with reason 1010 (and list extensions)
|
||||
}
|
||||
|
||||
// response is valid, connection can now be assumed to be open
|
||||
m_internal_state = istate::PROCESS_CONNECTION;
|
||||
m_state = session::state::open;
|
||||
|
||||
@@ -146,10 +146,10 @@ public:
|
||||
|
||||
/// Set or clear the compression flag
|
||||
/**
|
||||
* The compression flag is used to indicate whether or not the message is
|
||||
* or should be compressed. Compression is not guaranteed. Both endpoints
|
||||
* must support a compression extension and the connection must have had
|
||||
* that extension negotiated in its handshake.
|
||||
* Setting the compression flag indicates that the data in this message
|
||||
* would benefit from compression. If both endpoints negotiate a compression
|
||||
* extension WebSocket++ will attempt to compress messages with this flag.
|
||||
* Setting this flag does not guarantee that the message will be compressed.
|
||||
*
|
||||
* @param value The value to set the compressed flag to
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -85,7 +85,21 @@ public:
|
||||
return m_permessage_deflate.is_implemented();
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(request_type const & req) {
|
||||
err_str_pair negotiate_extensions(request_type const & request) {
|
||||
return negotiate_extensions_helper(request);
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(response_type const & response) {
|
||||
return negotiate_extensions_helper(response);
|
||||
}
|
||||
|
||||
/// Extension negotiation helper function
|
||||
/**
|
||||
* This exists mostly because the code for requests and responses is
|
||||
* identical and I can't have virtual template methods.
|
||||
*/
|
||||
template <typename header_type>
|
||||
err_str_pair negotiate_extensions_helper(header_type const & header) {
|
||||
err_str_pair ret;
|
||||
|
||||
// Respect blanket disabling of all extensions and don't even parse
|
||||
@@ -97,7 +111,7 @@ public:
|
||||
|
||||
http::parameter_list p;
|
||||
|
||||
bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
|
||||
if (error) {
|
||||
ret.first = make_error_code(error::extension_parse_error);
|
||||
@@ -116,6 +130,14 @@ public:
|
||||
for (it = p.begin(); it != p.end(); ++it) {
|
||||
// look through each extension, if the key is permessage-deflate
|
||||
if (it->first == "permessage-deflate") {
|
||||
// if we have already successfully negotiated this extension
|
||||
// then skip any other requests to negotiate the same one
|
||||
// with different parameters
|
||||
if (m_permessage_deflate.is_enabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
neg_ret = m_permessage_deflate.negotiate(it->second);
|
||||
|
||||
if (neg_ret.first) {
|
||||
@@ -128,6 +150,7 @@ public:
|
||||
// Note: this list will need commas if WebSocket++ ever
|
||||
// supports more than one extension
|
||||
ret.second += neg_ret.second;
|
||||
m_permessage_deflate.init(base::m_server);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -223,6 +246,13 @@ public:
|
||||
|
||||
req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16));
|
||||
|
||||
if (m_permessage_deflate.is_implemented()) {
|
||||
std::string offer = m_permessage_deflate.generate_offer();
|
||||
if (!offer.empty()) {
|
||||
req.replace_header("Sec-WebSocket-Extensions",offer);
|
||||
}
|
||||
}
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -264,6 +294,8 @@ public:
|
||||
return error::make_error_code(error::missing_required_header);
|
||||
}
|
||||
|
||||
// check extensions
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -391,6 +423,10 @@ public:
|
||||
m_msg_manager->get_message(op,m_bytes_needed),
|
||||
frame::get_masking_key(m_basic_header,m_extended_header)
|
||||
);
|
||||
|
||||
if (m_permessage_deflate.is_enabled()) {
|
||||
m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header));
|
||||
}
|
||||
} else {
|
||||
// Fetch the underlying payload buffer from the data message we
|
||||
// are writing into.
|
||||
@@ -432,15 +468,10 @@ public:
|
||||
// If this was the last frame in the message set the ready flag.
|
||||
// Otherwise, reset processor state to read additional frames.
|
||||
if (frame::get_fin(m_basic_header)) {
|
||||
// ensure that text messages end on a valid UTF8 code point
|
||||
if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {
|
||||
if (!m_current_msg->validator.complete()) {
|
||||
ec = make_error_code(error::invalid_utf8);
|
||||
break;
|
||||
}
|
||||
ec = finalize_message();
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = READY;
|
||||
} else {
|
||||
this->reset_headers();
|
||||
}
|
||||
@@ -454,6 +485,44 @@ public:
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Perform any finalization actions on an incoming message
|
||||
/**
|
||||
* Called after the full message is received. Provides the opportunity for
|
||||
* extensions to complete any data post processing as well as final UTF8
|
||||
* validation checks for text messages.
|
||||
*
|
||||
* @return A code indicating errors, if any
|
||||
*/
|
||||
lib::error_code finalize_message() {
|
||||
std::string & out = m_current_msg->msg_ptr->get_raw_payload();
|
||||
|
||||
// if the frame is compressed, append the compression
|
||||
// trailer and flush the compression buffer.
|
||||
if (m_permessage_deflate.is_enabled()
|
||||
&& m_current_msg->msg_ptr->get_compressed())
|
||||
{
|
||||
uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff};
|
||||
|
||||
// Decompress current buffer into the message buffer
|
||||
lib::error_code ec;
|
||||
ec = m_permessage_deflate.decompress(trailer,4,out);
|
||||
if (ec) {
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that text messages end on a valid UTF8 code point
|
||||
if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {
|
||||
if (!m_current_msg->validator.complete()) {
|
||||
return make_error_code(error::invalid_utf8);
|
||||
}
|
||||
}
|
||||
|
||||
m_state = READY;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
void reset_headers() {
|
||||
m_state = HEADER_BASIC;
|
||||
m_bytes_needed = frame::BASIC_HEADER_LENGTH;
|
||||
@@ -551,18 +620,10 @@ public:
|
||||
&& in->get_compressed();
|
||||
bool fin = in->get_fin();
|
||||
|
||||
// generate header
|
||||
frame::basic_header h(op,i.size(),fin,masked,compressed);
|
||||
|
||||
if (masked) {
|
||||
// Generate masking key.
|
||||
key.i = m_rng();
|
||||
|
||||
frame::extended_header e(i.size(),key.i);
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
} else {
|
||||
frame::extended_header e(i.size());
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
key.i = 0;
|
||||
}
|
||||
|
||||
@@ -571,6 +632,14 @@ public:
|
||||
// compress and store in o after header.
|
||||
m_permessage_deflate.compress(i,o);
|
||||
|
||||
if (o.size() < 4) {
|
||||
return make_error_code(error::general);
|
||||
}
|
||||
|
||||
// Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the
|
||||
// wire
|
||||
o.resize(o.size()-4);
|
||||
|
||||
// mask in place if necessary
|
||||
if (masked) {
|
||||
this->masked_copy(o,o,key);
|
||||
@@ -589,6 +658,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// generate header
|
||||
frame::basic_header h(op,o.size(),fin,masked,compressed);
|
||||
|
||||
if (masked) {
|
||||
frame::extended_header e(o.size(),key.i);
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
} else {
|
||||
frame::extended_header e(o.size());
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
}
|
||||
|
||||
out->set_prepared(true);
|
||||
out->set_opcode(op);
|
||||
|
||||
@@ -731,13 +811,13 @@ protected:
|
||||
|
||||
// decompress message if needed.
|
||||
if (m_permessage_deflate.is_enabled()
|
||||
&& frame::get_rsv1(m_basic_header))
|
||||
&& m_current_msg->msg_ptr->get_compressed())
|
||||
{
|
||||
// Decompress current buffer into the message buffer
|
||||
m_permessage_deflate.decompress(buf,len,out);
|
||||
|
||||
// get the length of the newly uncompressed output
|
||||
offset = out.size() - offset;
|
||||
ec = m_permessage_deflate.decompress(buf,len,out);
|
||||
if (ec) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// No compression, straight copy
|
||||
out.append(reinterpret_cast<char *>(buf),len);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -217,13 +217,28 @@ public:
|
||||
/**
|
||||
* Reads the Sec-WebSocket-Extensions header and determines if any of the
|
||||
* requested extensions are supported by this processor. If they are their
|
||||
* settings data is initialized.
|
||||
* settings data is initialized and an extension string to send to the
|
||||
* is returned.
|
||||
*
|
||||
* @param request The request headers to look at.
|
||||
* @param request The request or response headers to look at.
|
||||
*/
|
||||
virtual err_str_pair negotiate_extensions(request_type const &) {
|
||||
return err_str_pair();
|
||||
}
|
||||
|
||||
/// Initializes extensions based on the Sec-WebSocket-Extensions header
|
||||
/**
|
||||
* Reads the Sec-WebSocket-Extensions header and determines if any of the
|
||||
* requested extensions were accepted by the server. If they are their
|
||||
* settings data is initialized. If they are not a list of required
|
||||
* extensions (if any) is returned. This list may be sent back to the server
|
||||
* as a part of the 1010/Extension required close code.
|
||||
*
|
||||
* @param response The request or response headers to look at.
|
||||
*/
|
||||
virtual err_str_pair negotiate_extensions(response_type const &) {
|
||||
return err_str_pair();
|
||||
}
|
||||
|
||||
/// validate a WebSocket handshake request for this version
|
||||
/**
|
||||
|
||||
@@ -44,16 +44,16 @@ static int const major_version = 0;
|
||||
/// Library minor version number
|
||||
static int const minor_version = 6;
|
||||
/// Library patch version number
|
||||
static int const patch_version = 1;
|
||||
static int const patch_version = 0;
|
||||
/// Library pre-release flag
|
||||
/**
|
||||
* This is a textual flag indicating the type and number for pre-release
|
||||
* versions (dev, alpha, beta, rc). This will be blank for release versions.
|
||||
*/
|
||||
static char const prerelease_flag[] = "";
|
||||
static char const prerelease_flag[] = "permessagedeflate";
|
||||
|
||||
/// Default user agent string
|
||||
static char const user_agent[] = "WebSocket++/0.6.0";
|
||||
static char const user_agent[] = "WebSocketpp/0.6.0-permessagedeflate";
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user