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.