add basic compression/decompression implimentation

This commit is contained in:
Peter Thorson
2013-07-03 06:19:08 -05:00
parent dbd0fc5372
commit 6bd1bfd4f2
4 changed files with 184 additions and 7 deletions

View File

@@ -10,7 +10,7 @@ Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
BOOST_LIBS = boostlibs(['unit_test_framework','system','regex'],env) + [platform_libs]
BOOST_LIBS = boostlibs(['unit_test_framework','system','regex'],env) + [platform_libs] + ['z']
objs = env.Object('extension_boost.o', ["extension.cpp"], LIBS = BOOST_LIBS)
objs += env.Object('permessage_deflate_boost.o', ["permessage_deflate.cpp"], LIBS = BOOST_LIBS)
@@ -18,7 +18,7 @@ prgs = env.Program('test_extension_boost', ["extension_boost.o"], LIBS = BOOST_L
prgs += env.Program('test_permessage_deflate_boost', ["permessage_deflate_boost.o"], LIBS = BOOST_LIBS)
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
objs += env_cpp11.Object('extension_stl.o', ["extension.cpp"], LIBS = BOOST_LIBS_CPP11)
objs += env_cpp11.Object('permessage_deflate_stl.o', ["permessage_deflate.cpp"], LIBS = BOOST_LIBS_CPP11)
prgs += env_cpp11.Program('test_extension_stl', ["extension_stl.o"], LIBS = BOOST_LIBS_CPP11)

View File

@@ -36,6 +36,9 @@
#include <string>
#include <websocketpp/utilities.hpp>
#include <iostream>
class config {};
typedef websocketpp::extensions::permessage_deflate::enabled<config> enabled_type;
@@ -495,3 +498,46 @@ BOOST_AUTO_TEST_CASE( negotiate_four_client_initiated ) {
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");
}
// Compression
/*
BOOST_AUTO_TEST_CASE( compress_data ) {
ext_vars v;
std::string in = "Hello";
std::string out;
std::string in2;
std::string out2;
v.exts.init();
v.ec = v.exts.compress(in,out);
std::cout << "in : " << websocketpp::utility::to_hex(in) << std::endl;
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);
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_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;
v.exts.init();
v.ec = v.exts.decompress(in,12,out);
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
BOOST_CHECK( false );
}
*/

View File

@@ -10,7 +10,7 @@ Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs]
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs] + ['z']
objs = env.Object('test_processor_boost.o', ["processor.cpp"], LIBS = BOOST_LIBS)
objs += env.Object('test_hybi13_boost.o', ["hybi13.cpp"], LIBS = BOOST_LIBS)
@@ -27,7 +27,7 @@ prgs += env.Program('test_hybi00_boost', ["test_hybi00_boost.o"], LIBS = BOOST_L
prgs += env.Program('test_extension_permessage_compress_boost', ["test_extension_permessage_compress_boost.o"], LIBS = BOOST_LIBS + ['z'])
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
# no C++11 features are used in processor so there are no C++11 versions of
# these tests.
objs += env_cpp11.Object('test_processor_stl.o', ["processor.cpp"], LIBS = BOOST_LIBS_CPP11)

View File

@@ -205,7 +205,85 @@ public:
, 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_c2s_max_window_bits_mode(mode::accept)
, m_initialized(false)
, m_compress_buffer_size(16384)
{
m_dstate.zalloc = Z_NULL;
m_dstate.zfree = Z_NULL;
m_dstate.opaque = Z_NULL;
m_istate.zalloc = Z_NULL;
m_istate.zfree = Z_NULL;
m_istate.opaque = Z_NULL;
m_istate.avail_in = 0;
m_istate.next_in = Z_NULL;
}
~enabled() {
if (!m_initialized) {
return;
}
int ret = deflateEnd(&m_dstate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib compression state"
// << std::endl;
}
ret = inflateEnd(&m_istate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib decompression state"
// << std::endl;
}
}
/// Initialize zlib state
/**
*
* @todo memory level, strategy, etc are hardcoded
* @todo server detection is hardcoded
*/
lib::error_code init() {
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;
} else {
deflate_bits = m_c2s_max_window_bits;
inflate_bits = m_s2c_max_window_bits;
}
int ret = deflateInit2(
&m_dstate,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
-1*deflate_bits,
8, // memory level 1-9
/*Z_DEFAULT_STRATEGY*/Z_FIXED
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
ret = inflateInit2(
&m_istate,
-1*inflate_bits
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
m_initialized = true;
return lib::error_code();
}
/// Test if this object impliments the permessage-deflate specification
/**
@@ -404,7 +482,29 @@ public:
* @return Error or status code
*/
lib::error_code compress(std::string const & in, std::string & out) {
return make_error_code(error::uninitialized);
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
size_t output;
int ret;
m_dstate.avail_out = m_compress_buffer_size;
m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
do {
// Output to local buffer
m_dstate.avail_out = m_compress_buffer_size;
m_dstate.next_out = m_compress_buffer.get();
ret = deflate(&m_dstate, Z_SYNC_FLUSH);
output = m_compress_buffer_size - m_dstate.avail_out;
out.append((char *)(m_compress_buffer.get()),output);
} while (m_dstate.avail_out == 0);
return lib::error_code();
}
/// Decompress bytes
@@ -417,7 +517,32 @@ public:
lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
out)
{
return make_error_code(error::uninitialized);
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
int ret;
m_istate.avail_in = len;
m_istate.next_in = const_cast<unsigned char *>(buf);
do {
m_istate.avail_out = m_compress_buffer_size;
m_istate.next_out = m_compress_buffer.get();
ret = inflate(&m_istate, Z_SYNC_FLUSH);
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
return make_error_code(error::zlib_error);
}
out.append(
reinterpret_cast<char *>(m_compress_buffer.get()),
m_compress_buffer_size - m_istate.avail_out
);
} while (m_istate.avail_out == 0);
return lib::error_code();
}
private:
/// Generate negotiation response
@@ -584,6 +709,12 @@ private:
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_initialized;
size_t m_compress_buffer_size;
lib::unique_ptr_uchar_array m_compress_buffer;
z_stream m_dstate;
z_stream m_istate;
};
} // namespace permessage_deflate