Merge branch 'develop' into integration_tests_sleep

This commit is contained in:
Peter Thorson authored and GitHub committed 2017-06-11 16:31:21 -05:00
commit 2819d364d9
10 files changed
+341 -124

No files matched your search

+18
View File
@@ -11,12 +11,28 @@ HEAD
rather than connection `pre_init`. This allows setting of socket options prior
to the bind/listen/accept system calls. Thank you ChristianRobl3D for
reporting #530.
- Improvement: Timers in transport integration tests should only fail if their
own test times out, rather than any test. #643 Thank you Alex Korotkin for
reporting and a patch.
- Compatibility: Make sure the chrono library used by Boost/Asio is in sync
with what the websocketpp is using. Thank you Flow86 for reporting and a
patch.
- Compatibility: Update `telemetry_client` to use a slightly more cross platform
method of sleeping. Should work on windows now. Thank you Meir Yanovich for
reporting.
- Compatibility: Updated permessage-deflate support to reflect that the zlib
library does not actually support a sliding window size of 256 bits.
WebSocket++ will no longer negotiate 256 bit deflate windows. If the user
of the library tries to request a 256 bit window a 512 bit window will be
specified instead (This was the previous behavior). #596 #653 Thank you
Vinnie Falco and Gianfranco Costamagna for reporting.
- Compatibility: Better error handling and logging in cases where extension
requests parse correctly but negotiation fails.
- Compatibility: Removed custom handling of SSL_R_SHORT_READ error condition.
This error code no longer exists in modern versions of OpenSSL and causes
a build error. It wasn't being used for anything particularly important
(slightly improving error reporting) and there isn't a great replacement.
#599 Thank you Gianfranco Costamagna for reporting.
- Bug: Store loggers in shared pointers to avoid crashes related to connections
trying to write logs entries after their respective endpoint has been
deallocated. Thank you Thalhammer for reporting and Jupp Müller for the
@@ -29,6 +45,8 @@ HEAD
- Bug/Documentation: Fix incorrect example code that used
`websocketpp::lib::error_code` instead of `websocketpp::exception`. Thank you
heretic13 for reporting
- Bug: Fix uninitialized shared pointer in Asio transport test suite. #647
Thank you Alex Korotkin for reporting and a patch.
0.7.0 - 2016-02-22
- MINOR BREAKING SOCKET POLICY CHANGE: Asio transport socket policy method
+129 -26
View File
@@ -186,15 +186,22 @@ BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_invalid ) {
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_valid ) {
ext_vars v;
// confirm that a request for a value of 8 is interpreted as 9
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; server_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=9");
v.attr["server_max_window_bits"] = "9";
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; server_max_window_bits=9");
v.attr["server_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() );
@@ -213,7 +220,7 @@ BOOST_AUTO_TEST_CASE( invalid_set_server_max_window_bits ) {
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) {
ext_vars v;
v.attr["server_max_window_bits"] = "8";
v.attr["server_max_window_bits"] = "9";
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::decline);
v.esp = v.exts.negotiate(v.attr);
@@ -223,7 +230,7 @@ BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) {
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept_8 ) {
ext_vars v;
v.attr["server_max_window_bits"] = "8";
@@ -232,10 +239,22 @@ BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {
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; server_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {
ext_vars v;
v.attr["server_max_window_bits"] = "9";
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; server_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest_8 ) {
ext_vars v;
v.attr["server_max_window_bits"] = "8";
@@ -244,10 +263,22 @@ BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {
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; server_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {
ext_vars v;
v.attr["server_max_window_bits"] = "9";
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; server_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest_8 ) {
ext_vars v;
v.attr["server_max_window_bits"] = "8";
@@ -256,7 +287,19 @@ BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {
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; server_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {
ext_vars v;
v.attr["server_max_window_bits"] = "9";
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; server_max_window_bits=9");
}
// Negotiate server_max_window_bits
@@ -292,7 +335,13 @@ BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_valid ) {
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; client_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=9");
v.attr["client_max_window_bits"] = "9";
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; client_max_window_bits=9");
v.attr["client_max_window_bits"] = "15";
v.esp = v.exts.negotiate(v.attr);
@@ -311,7 +360,7 @@ BOOST_AUTO_TEST_CASE( invalid_set_client_max_window_bits ) {
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline_8 ) {
ext_vars v;
v.attr["client_max_window_bits"] = "8";
@@ -323,7 +372,19 @@ BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {
ext_vars v;
v.attr["client_max_window_bits"] = "9";
v.ec = v.exts.set_client_max_window_bits(9,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() );
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept_8 ) {
ext_vars v;
v.attr["client_max_window_bits"] = "8";
@@ -332,10 +393,22 @@ BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {
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; client_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {
ext_vars v;
v.attr["client_max_window_bits"] = "9";
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; client_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest_8 ) {
ext_vars v;
v.attr["client_max_window_bits"] = "8";
@@ -344,10 +417,22 @@ BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {
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; client_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {
ext_vars v;
v.attr["client_max_window_bits"] = "9";
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; client_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest_8 ) {
ext_vars v;
v.attr["client_max_window_bits"] = "8";
@@ -356,7 +441,19 @@ BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {
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; client_max_window_bits=8");
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=9");
}
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {
ext_vars v;
v.attr["client_max_window_bits"] = "9";
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; client_max_window_bits=9");
}
@@ -507,7 +604,8 @@ BOOST_AUTO_TEST_CASE( compress_data ) {
std::string compress_out;
std::string decompress_out;
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
v.ec = v.exts.compress(compress_in,compress_out);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
@@ -520,7 +618,8 @@ BOOST_AUTO_TEST_CASE( compress_data ) {
BOOST_AUTO_TEST_CASE( compress_data_multiple ) {
ext_vars v;
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
for (int i = 0; i < 2; i++) {
std::string compress_in = "Hello";
@@ -545,11 +644,12 @@ BOOST_AUTO_TEST_CASE( compress_data_large ) {
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);
alist["server_max_window_bits"] = "9";
v.exts.set_server_max_window_bits(9,websocketpp::extensions::permessage_deflate::mode::smallest);
v.exts.negotiate(alist);
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
v.ec = v.exts.compress(compress_in,compress_out);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
@@ -573,7 +673,8 @@ BOOST_AUTO_TEST_CASE( compress_data_no_context_takeover ) {
v.exts.enable_server_no_context_takeover();
v.exts.negotiate(alist);
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
v.ec = v.exts.compress(compress_in,compress_out1);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
@@ -609,7 +710,8 @@ BOOST_AUTO_TEST_CASE( compress_empty ) {
std::string compress_out;
std::string decompress_out;
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
v.ec = v.exts.compress(compress_in,compress_out);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
@@ -640,7 +742,8 @@ BOOST_AUTO_TEST_CASE( decompress_data ) {
std::string out;
std::string reference = "Hello";
v.exts.init(true);
v.ec = v.exts.init(true);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
v.ec = v.exts.decompress(in,11,out);
+6 -1
View File
@@ -140,7 +140,10 @@ typedef websocketpp::lib::shared_ptr<mock_con> connection_ptr;
struct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {
typedef websocketpp::transport::asio::endpoint<config> base;
mock_endpoint() {
mock_endpoint()
: alog(websocketpp::lib::make_shared<config::alog_type>())
, elog(websocketpp::lib::make_shared<config::elog_type>())
{
alog->set_channels(websocketpp::log::alevel::all);
base::init_logging(alog,elog);
init_asio();
@@ -182,6 +185,8 @@ BOOST_AUTO_TEST_CASE( tls_handshake_timeout ) {
dummy_server.detach();
timer.detach();
sleep(1); // give the server thread some time to start
mock_endpoint endpoint;
endpoint.set_tls_init_handler(&on_tls_init);
endpoint.connect("wss://localhost:9005");
+40 -20
View File
@@ -354,11 +354,35 @@ void close(T * e, websocketpp::connection_hdl hdl) {
e->get_con_from_hdl(hdl)->close(websocketpp::close::status::normal,"");
}
// Wait for the specified time period then fail the test
void run_test_timer(long value) {
sleep(value);
BOOST_FAIL( "Test timed out" );
}
class test_deadline_timer
{
public:
test_deadline_timer(int seconds)
: m_timer(m_io_service, boost::posix_time::seconds(seconds))
{
m_timer.async_wait(bind(&test_deadline_timer::expired, this, ::_1));
std::size_t (boost::asio::io_service::*run)() = &boost::asio::io_service::run;
m_timer_thread = websocketpp::lib::thread(websocketpp::lib::bind(run, &m_io_service));
}
~test_deadline_timer()
{
m_timer.cancel();
m_timer_thread.join();
}
private:
void expired(const boost::system::error_code & ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
BOOST_CHECK(!ec);
BOOST_FAIL("Test timed out");
}
boost::asio::io_service m_io_service;
boost::asio::deadline_timer m_timer;
websocketpp::lib::thread m_timer_thread;
};
BOOST_AUTO_TEST_CASE( pong_no_timeout ) {
server s;
@@ -400,11 +424,10 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) {
websocketpp::lib::error_code(),::_1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
tthread.detach();
sleep(1); // give the server thread some time to start
test_deadline_timer deadline(10);
run_client(c, "http://localhost:9005",false);
sthread.join();
@@ -420,12 +443,12 @@ BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) {
websocketpp::error::open_handshake_timeout,::_1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_dummy_server,9005));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
sthread.detach();
tthread.detach();
sleep(1); // give the server thread some time to start
test_deadline_timer deadline(10);
run_client(c, "http://localhost:9005");
}
@@ -439,8 +462,8 @@ BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) {
websocketpp::error::open_handshake_timeout,::_1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
tthread.detach();
test_deadline_timer deadline(10);
sleep(1); // give the server thread some time to start
@@ -464,8 +487,8 @@ BOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) {
websocketpp::error::close_handshake_timeout,::_1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
tthread.detach();
test_deadline_timer deadline(10);
sleep(1); // give the server thread some time to start
@@ -498,8 +521,7 @@ BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) {
c.set_open_handler(bind(&delay,::_1,1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
tthread.detach();
test_deadline_timer deadline(10);
sleep(1); // give the server thread some time to start
@@ -511,8 +533,7 @@ BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) {
BOOST_AUTO_TEST_CASE( client_runs_out_of_work ) {
client c;
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,3));
tthread.detach();
test_deadline_timer deadline(3);
websocketpp::lib::error_code ec;
c.init_asio(ec);
@@ -578,8 +599,7 @@ BOOST_AUTO_TEST_CASE( stop_listening ) {
c.set_open_handler(bind(&close<client>,&c,::_1));
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,5));
tthread.detach();
test_deadline_timer deadline(5);
sleep(1); // give the server thread some time to start
+3
View File
@@ -88,6 +88,9 @@ namespace lib {
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
} // namespace error
} // namespace ssl
} // namespace asio
#else
@@ -46,7 +46,7 @@
namespace websocketpp {
namespace extensions {
/// Implementation of the draft permessage-deflate WebSocket extension
/// Implementation of RFC 7692, the permessage-deflate WebSocket extension
/**
* ### permessage-deflate interface
*
@@ -174,18 +174,30 @@ namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Default value for server_max_window_bits as defined by draft 17
/// Default value for server_max_window_bits as defined by RFC 7692
static uint8_t const default_server_max_window_bits = 15;
/// Minimum value for server_max_window_bits as defined by draft 17
/// Minimum value for server_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_server_max_window_bits = 8;
/// Maximum value for server_max_window_bits as defined by draft 17
/// Maximum value for server_max_window_bits as defined by RFC 7692
static uint8_t const max_server_max_window_bits = 15;
/// Default value for client_max_window_bits as defined by draft 17
/// Default value for client_max_window_bits as defined by RFC 7692
static uint8_t const default_client_max_window_bits = 15;
/// Minimum value for client_max_window_bits as defined by draft 17
/// Minimum value for client_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_client_max_window_bits = 8;
/// Maximum value for client_max_window_bits as defined by draft 17
/// Maximum value for client_max_window_bits as defined by RFC 7692
static uint8_t const max_client_max_window_bits = 15;
namespace mode {
@@ -372,7 +384,7 @@ public:
/**
* The bits setting is the base 2 logarithm of the maximum window size that
* the server must use to compress outgoing messages. The permitted range
* is 8 to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB
* is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB
* window. The default setting is 15.
*
* Mode Options:
@@ -386,6 +398,14 @@ public:
* adjusted by the server. A server may unilaterally set this value without
* client support.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
@@ -394,6 +414,12 @@ public:
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_server_max_window_bits = bits;
m_server_max_window_bits_mode = mode;
@@ -403,8 +429,8 @@ public:
/// Limit client LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the window size that the
* client must use to compress outgoing messages. The permitted range is 8
* to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB window.
* client must use to compress outgoing messages. The permitted range is 9
* to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.
* The default setting is 15.
*
* Mode Options:
@@ -417,6 +443,14 @@ public:
* outgoing window size unilaterally. A server may only limit the client's
* window size if the remote client supports that feature.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
@@ -425,6 +459,12 @@ public:
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_client_max_window_bits = bits;
m_client_max_window_bits_mode = mode;
@@ -642,11 +682,17 @@ private:
* client requested that we use.
*
* options:
* - decline (refuse to use the attribute)
* - accept (use whatever the client says)
* - largest (use largest possible value)
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
@@ -678,6 +724,11 @@ private:
ec = make_error_code(error::invalid_mode);
m_server_max_window_bits = default_server_max_window_bits;
}
// See note in doc comment
if (m_server_max_window_bits == 8) {
m_server_max_window_bits = 9;
}
}
/// Negotiate client_max_window_bits attribute
@@ -687,11 +738,17 @@ private:
* negotiation mode.
*
* options:
* - decline (refuse to use the attribute)
* - accept (use whatever the client says)
* - largest (use largest possible value)
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
@@ -727,6 +784,11 @@ private:
ec = make_error_code(error::invalid_mode);
m_client_max_window_bits = default_client_max_window_bits;
}
// See note in doc comment
if (m_client_max_window_bits == 8) {
m_client_max_window_bits = 9;
}
}
bool m_enabled;
+14 -11
View File
@@ -999,19 +999,16 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
"handle_read_frame: got invalid istate in closed state");
return;
}
} else if (ecm == transport::error::tls_short_read) {
if (m_state == session::state::closed) {
// We expect to get a TLS short read if we try to read after the
// connection is closed. If this happens ignore and exit the
// read frame path.
terminate(lib::error_code());
return;
}
echannel = log::elevel::rerror;
} else if (ecm == transport::error::action_after_shutdown) {
echannel = log::elevel::info;
} else {
// TODO: more generally should we do something different here in the
// case that m_state is cosed? Are errors after the connection is
// already closed really an rerror?
}
log_err(echannel, "handle_read_frame", ecm);
this->terminate(ecm);
return;
@@ -1222,12 +1219,18 @@ lib::error_code connection<config>::process_handshake_request() {
std::pair<lib::error_code,std::string> neg_results;
neg_results = m_processor->negotiate_extensions(m_request);
if (neg_results.first) {
if (neg_results.first == processor::error::make_error_code(processor::error::extension_parse_error)) {
// There was a fatal error in extension parsing that should result in
// a failed connection attempt.
m_alog->write(log::alevel::devel, "Bad request: " + neg_results.first.message());
m_elog->write(log::elevel::info, "Bad request: " + neg_results.first.message());
m_response.set_status(http::status_code::bad_request);
return neg_results.first;
} else if (neg_results.first) {
// There was a fatal error in extension processing that is probably our
// fault. Consider extension negotiation to have failed and continue as
// if extensions were not supported
m_elog->write(log::elevel::info,
"Extension negotiation failed: " + neg_results.first.message());
} else {
// extension negotiation succeeded, set response header accordingly
// we don't send an empty extensions header because it breaks many
+46 -24
View File
@@ -125,38 +125,60 @@ public:
http::parameter_list::const_iterator it;
// look through the list of extension requests to find the first
// one that we can accept.
if (m_permessage_deflate.is_implemented()) {
err_str_pair neg_ret;
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);
// not a permessage-deflate extension request, ignore
if (it->first != "permessage-deflate") {
continue;
}
if (neg_ret.first) {
// Figure out if this is an error that should halt all
// extension negotiations or simply cause negotiation of
// this specific extension to fail.
//std::cout << "permessage-compress negotiation failed: "
// << neg_ret.first.message() << std::endl;
} else {
// 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;
}
// 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;
}
// attempt to negotiate this offer
neg_ret = m_permessage_deflate.negotiate(it->second);
if (neg_ret.first) {
// negotiation offer failed. Do nothing. We will continue
// searching for a permessage-deflate config that succeeds
continue;
}
// Negotiation tentatively succeeded
// Actually try to initialize the extension before we
// deem negotiation complete
lib::error_code ec = m_permessage_deflate.init(base::m_server);
if (ec) {
// Negotiation succeeded but initialization failed this is
// an error that should stop negotiation of permessage
// deflate. Return the reason for the init failure
ret.first = ec;
break;
} else {
// Successfully initialized, push the negotiated response into
// the reply and stop looking for additional permessage-deflate
// extensions
ret.second += neg_ret.second;
break;
}
}
}
// support for future extensions would go here. Should check the value of
// ret.first before continuing. Might need to consider whether failure of
// negotiation of an earlier extension should stop negotiation of subsequent
// ones
return ret;
}
+4 -11
View File
@@ -1116,17 +1116,10 @@ protected:
tec = socket_con_type::translate_ec(ec);
m_tec = ec;
if (tec == transport::error::tls_short_read) {
// TLS short read at this point is somewhat expected if both
// sides try and end the connection at the same time or if
// SSLv2 is being used. In general there is nothing that can
// be done here other than a low level development log.
} else {
// all other errors are effectively pass through errors of
// some sort so print some detail on the info channel for
// library users to look up if needed.
log_err(log::elevel::info,"asio async_shutdown",ec);
}
// all other errors are effectively pass through errors of
// some sort so print some detail on the info channel for
// library users to look up if needed.
log_err(log::elevel::info,"asio async_shutdown",ec);
}
} else {
if (m_alog->static_test(log::alevel::devel)) {
+3 -15
View File
@@ -355,13 +355,9 @@ protected:
template <typename ErrorCodeType>
lib::error_code translate_ec(ErrorCodeType ec) {
if (ec.category() == lib::asio::error::get_ssl_category()) {
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
return make_error_code(transport::error::tls_short_read);
} else {
// We know it is a TLS related error, but otherwise don't know
// more. Pass through as TLS generic.
return make_error_code(transport::error::tls_error);
}
// We know it is a TLS related error, but otherwise don't know more.
// Pass through as TLS generic.
return make_error_code(transport::error::tls_error);
} else {
// We don't know any more information about this error so pass
// through
@@ -372,14 +368,6 @@ protected:
/// Overload of translate_ec to catch cases where lib::error_code is the
/// same type as lib::asio::error_code
lib::error_code translate_ec(lib::error_code ec) {
// Normalize the tls_short_read error as it is used by the library and
// needs a consistent value. All other errors pass through natively.
// TODO: how to get the SSL category from std::error?
/*if (ec.category() == lib::asio::error::get_ssl_category()) {
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
return make_error_code(transport::error::tls_short_read);
}
}*/
return ec;
}
private: