28#ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
29#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
87namespace 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());
167template<>
struct is_error_code_enum
168 <
websocketpp::extensions::permessage_deflate::error::value>
174namespace extensions {
175namespace permessage_deflate {
178static uint8_t const default_server_max_window_bits = 15;
180static uint8_t const min_server_max_window_bits = 8;
182static uint8_t const max_server_max_window_bits = 15;
185static uint8_t const default_client_max_window_bits = 15;
187static uint8_t const min_client_max_window_bits = 8;
189static uint8_t const max_client_max_window_bits = 15;
204template <
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) {
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();
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)
658 if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
660 m_server_max_window_bits = default_server_max_window_bits;
664 switch (m_server_max_window_bits_mode) {
666 m_server_max_window_bits = default_server_max_window_bits;
669 m_server_max_window_bits = bits;
672 m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
675 m_server_max_window_bits = min_server_max_window_bits;
679 m_server_max_window_bits = default_server_max_window_bits;
698 void negotiate_client_max_window_bits(std::string
const &
value,
699 lib::error_code & ec)
704 bits = default_client_max_window_bits;
705 }
else if (bits < min_client_max_window_bits ||
706 bits > max_client_max_window_bits)
709 m_client_max_window_bits = default_client_max_window_bits;
713 switch (m_client_max_window_bits_mode) {
715 m_client_max_window_bits = default_client_max_window_bits;
718 m_client_max_window_bits = bits;
721 m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
724 m_client_max_window_bits = min_client_max_window_bits;
728 m_client_max_window_bits = default_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;
lib::error_code init(bool is_server)
Initialize zlib state.
void enable_client_no_context_takeover()
Reset client's outgoing LZ77 sliding window for each new message.
lib::error_code compress(std::string const &in, std::string &out)
Compress bytes.
bool is_enabled() const
Test if the extension was negotiated for this connection.
lib::error_code decompress(uint8_t const *buf, size_t len, std::string &out)
Decompress bytes.
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode)
Limit client LZ77 sliding window size.
bool is_implemented() const
Test if this object implements the permessage-deflate specification.
void enable_server_no_context_takeover()
Reset server's outgoing LZ77 sliding window for each new message.
err_str_pair negotiate(http::attribute_list const &offer)
Negotiate extension.
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode)
Limit server LZ77 sliding window size.
lib::error_code validate_offer(http::attribute_list const &)
Validate extension response.
std::string generate_offer() const
Generate extension offer.
Permessage-deflate error category.
std::string message(int value) const
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension Error decompressing transaction Transaction should have at least one required authority Expired Transaction Invalid Reference Block Duplicate deferred transaction The transaction can not be found Transaction is too big Invalid transaction extension Transaction includes disallowed extensions(invalid block)" ) FC_DECLARE_DERIVED_EXCEPTION( tx_resource_exhaustion
@ unsupported_attributes
Unsupported extension attributes.
@ invalid_max_window_bits
Invalid value for max_window_bits.
@ invalid_attribute_value
Invalid extension attribute value.
@ uninitialized
Uninitialized.
@ invalid_attributes
Invalid extension attributes.
@ invalid_mode
Invalid megotiation mode.
lib::error_category const & get_category()
Get a reference to a static copy of the permessage-deflate error category.
lib::error_code make_error_code(error::value e)
Create an error code in the permessage-deflate category.
@ accept
Accept any value the remote endpoint offers.
@ smallest
Use the smallest value common to both offers.
@ largest
Use the largest value common to both offers.
@ decline
Decline any value the remote endpoint offers. Insist on defaults.
boost::scoped_array< unsigned char > unique_ptr_uchar_array
Namespace for the WebSocket++ project.
std::pair< lib::error_code, std::string > err_str_pair
Combination error code / string type for returning two values.
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_