28 #ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP    29 #define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP    47 namespace extensions {
    87 namespace permessage_deflate {
   123         return "websocketpp.extension.permessage-deflate";
   129                 return "Generic permessage-compress error";
   131                 return "Invalid extension attributes";
   133                 return "Invalid extension attribute value";
   135                 return "Invalid permessage-deflate negotiation mode";
   137                 return "Unsupported extension attributes";
   139                 return "Invalid value for max_window_bits";
   141                 return "A zlib function returned an error";
   143                 return "Deflate extension must be initialized before use";
   145                 return "Unknown permessage-compress error";
   158     return lib::error_code(static_cast<int>(e), 
get_category());
   167 template<> 
struct is_error_code_enum
   174 namespace extensions {
   175 namespace permessage_deflate {
   204 template <
typename config>
   209       , m_server_no_context_takeover(false)
   210       , m_client_no_context_takeover(false)
   211       , m_server_max_window_bits(15)
   212       , m_client_max_window_bits(15)
   213       , m_server_max_window_bits_mode(mode::
accept)
   214       , m_client_max_window_bits_mode(mode::
accept)
   215       , m_initialized(false)
   216       , m_compress_buffer_size(16384)
   218         m_dstate.zalloc = Z_NULL;
   219         m_dstate.zfree = Z_NULL;
   220         m_dstate.opaque = Z_NULL;
   222         m_istate.zalloc = Z_NULL;
   223         m_istate.zfree = Z_NULL;
   224         m_istate.opaque = Z_NULL;
   225         m_istate.avail_in = 0;
   226         m_istate.next_in = Z_NULL;
   230         if (!m_initialized) {
   234         int ret = deflateEnd(&m_dstate);
   241         ret = inflateEnd(&m_istate);
   260     lib::error_code 
init(
bool is_server) {
   261         uint8_t deflate_bits;
   262         uint8_t inflate_bits;
   265             deflate_bits = m_server_max_window_bits;
   266             inflate_bits = m_client_max_window_bits;
   268             deflate_bits = m_client_max_window_bits;
   269             inflate_bits = m_server_max_window_bits;
   272         int ret = deflateInit2(
   274             Z_DEFAULT_COMPRESSION,
   294         m_compress_buffer.reset(
new unsigned char[m_compress_buffer_size]);
   295         if ((m_server_no_context_takeover && is_server) ||
   296             (m_client_no_context_takeover && !is_server))
   298             m_flush = Z_FULL_FLUSH;
   300             m_flush = Z_SYNC_FLUSH;
   302         m_initialized = 
true;
   303         return lib::error_code();
   349         m_server_no_context_takeover = 
true;
   368         m_client_no_context_takeover = 
true;
   394         if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
   397         m_server_max_window_bits = bits;
   398         m_server_max_window_bits_mode = mode;
   400         return lib::error_code();
   425         if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
   428         m_client_max_window_bits = bits;
   429         m_client_max_window_bits_mode = mode;
   431         return lib::error_code();
   443         return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
   455         return lib::error_code();
   470         http::attribute_list::const_iterator it;
   471         for (it = offer.begin(); it != offer.end(); ++it) {
   472             if (it->first == 
"server_no_context_takeover") {
   473                 negotiate_server_no_context_takeover(it->second,ret.first);
   474             } 
else if (it->first == 
"client_no_context_takeover") {
   475                 negotiate_client_no_context_takeover(it->second,ret.first);
   476             } 
else if (it->first == 
"server_max_window_bits") {
   477                 negotiate_server_max_window_bits(it->second,ret.first);
   478             } 
else if (it->first == 
"client_max_window_bits") {
   479                 negotiate_client_max_window_bits(it->second,ret.first);
   489         if (ret.first == lib::error_code()) {
   491             ret.second = generate_response();
   506     lib::error_code 
compress(std::string 
const & in, std::string & out) {
   507         if (!m_initialized) {
   514             uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
   515             out.append((
char *)(buf),6);
   516             return lib::error_code();
   519         m_dstate.avail_in = in.size();
   520         m_dstate.next_in = (
unsigned char *)(const_cast<char *>(in.data()));
   524             m_dstate.avail_out = m_compress_buffer_size;
   525             m_dstate.next_out = m_compress_buffer.get();
   527             deflate(&m_dstate, m_flush);
   529             output = m_compress_buffer_size - m_dstate.avail_out;
   531             out.append((
char *)(m_compress_buffer.get()),output);
   532         } 
while (m_dstate.avail_out == 0);
   534         return lib::error_code();
   544     lib::error_code 
decompress(uint8_t 
const * buf, 
size_t len, std::string &
   547         if (!m_initialized) {
   553         m_istate.avail_in = len;
   554         m_istate.next_in = 
const_cast<unsigned char *
>(buf);
   557             m_istate.avail_out = m_compress_buffer_size;
   558             m_istate.next_out = m_compress_buffer.get();
   560             ret = inflate(&m_istate, Z_SYNC_FLUSH);
   562             if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
   567                 reinterpret_cast<char *>(m_compress_buffer.get()),
   568                 m_compress_buffer_size - m_istate.avail_out
   570         } 
while (m_istate.avail_out == 0);
   572         return lib::error_code();
   579     std::string generate_response() {
   580         std::string ret = 
"permessage-deflate";
   582         if (m_server_no_context_takeover) {
   583             ret += 
"; server_no_context_takeover";
   586         if (m_client_no_context_takeover) {
   587             ret += 
"; client_no_context_takeover";
   590         if (m_server_max_window_bits < default_server_max_window_bits) {
   592             s << int(m_server_max_window_bits);
   593             ret += 
"; server_max_window_bits="+s.str();
   596         if (m_client_max_window_bits < default_client_max_window_bits) {
   598             s << int(m_client_max_window_bits);
   599             ret += 
"; client_max_window_bits="+s.str();
   610     void negotiate_server_no_context_takeover(std::string 
const & 
value,
   611         lib::error_code & ec)
   613         if (!value.empty()) {
   618         m_server_no_context_takeover = 
true;
   626     void negotiate_client_no_context_takeover(std::string 
const & value,
   627         lib::error_code & ec)
   629         if (!value.empty()) {
   634         m_client_no_context_takeover = 
true;
   653     void negotiate_server_max_window_bits(std::string 
const & value,
   654         lib::error_code & ec)
   656         uint8_t bits = uint8_t(atoi(value.c_str()));
   658         if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
   664         switch (m_server_max_window_bits_mode) {
   669                 m_server_max_window_bits = bits;
   672                 m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
   698     void negotiate_client_max_window_bits(std::string 
const & value,
   699             lib::error_code & ec)
   701         uint8_t bits = uint8_t(atoi(value.c_str()));
   705         } 
else if (bits < min_client_max_window_bits ||
   706                    bits > max_client_max_window_bits)
   713         switch (m_client_max_window_bits_mode) {
   718                 m_client_max_window_bits = bits;
   721                 m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
   733     bool m_server_no_context_takeover;
   734     bool m_client_no_context_takeover;
   735     uint8_t m_server_max_window_bits;
   736     uint8_t m_client_max_window_bits;
   742     size_t m_compress_buffer_size;
   752 #endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode)
Limit server LZ77 sliding window size. 
 
void enable_client_no_context_takeover()
Reset client's outgoing LZ77 sliding window for each new message. 
 
static uint8_t const default_server_max_window_bits
Default value for server_max_window_bits as defined by draft 17. 
 
Decline any value the remote endpoint offers. Insist on defaults. 
 
lib::error_category const & get_category()
Get a reference to a static copy of the permessage-deflate error category. 
 
Accept any value the remote endpoint offers. 
 
std::pair< lib::error_code, std::string > err_str_pair
Combination error code / string type for returning two values. 
 
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
 
Invalid value for max_window_bits. 
 
Invalid megotiation mode. 
 
Invalid extension attribute value. 
 
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_
 
lib::error_code init(bool is_server)
Initialize zlib state. 
 
Use the smallest value common to both offers. 
 
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode)
Limit client LZ77 sliding window size. 
 
lib::error_code validate_offer(http::attribute_list const &)
Validate extension response. 
 
lib::error_code decompress(uint8_t const *buf, size_t len, std::string &out)
Decompress bytes. 
 
Use the largest value common to both offers. 
 
lib::error_code make_error_code(error::value e)
Create an error code in the permessage-deflate category. 
 
static uint8_t const min_client_max_window_bits
Minimum value for client_max_window_bits as defined by draft 17. 
 
Namespace for the WebSocket++ project. 
 
static uint8_t const max_server_max_window_bits
Maximum value for server_max_window_bits as defined by draft 17. 
 
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
 
err_str_pair negotiate(http::attribute_list const &offer)
Negotiate extension. 
 
bool is_implemented() const 
Test if this object implements the permessage-deflate specification. 
 
std::map< std::string, std::string > attribute_list
The type of an HTTP attribute list. 
 
Unsupported extension attributes. 
 
bool is_enabled() const 
Test if the extension was negotiated for this connection. 
 
void enable_server_no_context_takeover()
Reset server's outgoing LZ77 sliding window for each new message. 
 
static uint8_t const min_server_max_window_bits
Minimum value for server_max_window_bits as defined by draft 17. 
 
lib::error_code compress(std::string const &in, std::string &out)
Compress bytes. 
 
std::string message(int value) const 
 
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
 
static uint8_t const max_client_max_window_bits
Maximum value for client_max_window_bits as defined by draft 17. 
 
Invalid extension attributes. 
 
boost::scoped_array< unsigned char > unique_ptr_uchar_array
 
static uint8_t const default_client_max_window_bits
Default value for client_max_window_bits as defined by draft 17. 
 
std::string generate_offer() const 
Generate extension offer. 
 
Permessage-deflate error category.