Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
enabled.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Peter Thorson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of the WebSocket++ Project nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
29#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
30
31
36#include <websocketpp/error.hpp>
37
39
40#include "zlib.h"
41
42#include <algorithm>
43#include <string>
44#include <vector>
45
46namespace websocketpp {
47namespace extensions {
48
50
87namespace permessage_deflate {
88
90namespace error {
116
118class category : public lib::error_category {
119public:
121
122 char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
123 return "websocketpp.extension.permessage-deflate";
124 }
125
126 std::string message(int value) const {
127 switch(value) {
128 case general:
129 return "Generic permessage-compress error";
131 return "Invalid extension attributes";
133 return "Invalid extension attribute value";
134 case invalid_mode:
135 return "Invalid permessage-deflate negotiation mode";
137 return "Unsupported extension attributes";
139 return "Invalid value for max_window_bits";
140 case zlib_error:
141 return "A zlib function returned an error";
142 case uninitialized:
143 return "Deflate extension must be initialized before use";
144 default:
145 return "Unknown permessage-compress error";
146 }
147 }
148};
149
151inline lib::error_category const & get_category() {
152 static category instance;
153 return instance;
154}
155
157inline lib::error_code make_error_code(error::value e) {
158 return lib::error_code(static_cast<int>(e), get_category());
159}
160
161} // namespace error
162} // namespace permessage_deflate
163} // namespace extensions
164} // namespace websocketpp
165
167template<> struct is_error_code_enum
168 <websocketpp::extensions::permessage_deflate::error::value>
169{
170 static bool const value = true;
171};
173namespace websocketpp {
174namespace extensions {
175namespace permessage_deflate {
176
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;
183
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;
190
191namespace mode {
202} // namespace mode
203
204template <typename config>
205class enabled {
206public:
208 : m_enabled(false)
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)
217 {
218 m_dstate.zalloc = Z_NULL;
219 m_dstate.zfree = Z_NULL;
220 m_dstate.opaque = Z_NULL;
221
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;
227 }
228
230 if (!m_initialized) {
231 return;
232 }
233
234 int ret = deflateEnd(&m_dstate);
235
236 if (ret != Z_OK) {
237 //std::cout << "error cleaning up zlib compression state"
238 // << std::endl;
239 }
240
241 ret = inflateEnd(&m_istate);
242
243 if (ret != Z_OK) {
244 //std::cout << "error cleaning up zlib decompression state"
245 // << std::endl;
246 }
247 }
248
250
260 lib::error_code init(bool is_server) {
261 uint8_t deflate_bits;
262 uint8_t inflate_bits;
263
264 if (is_server) {
265 deflate_bits = m_server_max_window_bits;
266 inflate_bits = m_client_max_window_bits;
267 } else {
268 deflate_bits = m_client_max_window_bits;
269 inflate_bits = m_server_max_window_bits;
270 }
271
272 int ret = deflateInit2(
273 &m_dstate,
274 Z_DEFAULT_COMPRESSION,
275 Z_DEFLATED,
276 -1*deflate_bits,
277 4, // memory level 1-9
278 Z_DEFAULT_STRATEGY
279 );
280
281 if (ret != Z_OK) {
282 return make_error_code(error::zlib_error);
283 }
284
285 ret = inflateInit2(
286 &m_istate,
287 -1*inflate_bits
288 );
289
290 if (ret != Z_OK) {
291 return make_error_code(error::zlib_error);
292 }
293
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))
297 {
298 m_flush = Z_FULL_FLUSH;
299 } else {
300 m_flush = Z_SYNC_FLUSH;
301 }
302 m_initialized = true;
303 return lib::error_code();
304 }
305
307
312 bool is_implemented() const {
313 return true;
314 }
315
317
323 bool is_enabled() const {
324 return m_enabled;
325 }
326
328
349 m_server_no_context_takeover = true;
350 }
351
353
368 m_client_no_context_takeover = true;
369 }
370
372
393 lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
394 if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
396 }
397 m_server_max_window_bits = bits;
398 m_server_max_window_bits_mode = mode;
399
400 return lib::error_code();
401 }
402
404
424 lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
425 if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
427 }
428 m_client_max_window_bits = bits;
429 m_client_max_window_bits_mode = mode;
430
431 return lib::error_code();
432 }
433
435
441 std::string generate_offer() const {
442 // TODO: this should be dynamically generated based on user settings
443 return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
444 }
445
447
454 lib::error_code validate_offer(http::attribute_list const &) {
455 return lib::error_code();
456 }
457
459
467 err_str_pair negotiate(http::attribute_list const & offer) {
469
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);
480 } else {
481 ret.first = make_error_code(error::invalid_attributes);
482 }
483
484 if (ret.first) {
485 break;
486 }
487 }
488
489 if (ret.first == lib::error_code()) {
490 m_enabled = true;
491 ret.second = generate_response();
492 }
493
494 return ret;
495 }
496
498
506 lib::error_code compress(std::string const & in, std::string & out) {
507 if (!m_initialized) {
508 return make_error_code(error::uninitialized);
509 }
510
511 size_t output;
512
513 if (in.empty()) {
514 uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
515 out.append((char *)(buf),6);
516 return lib::error_code();
517 }
518
519 m_dstate.avail_in = in.size();
520 m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
521
522 do {
523 // Output to local buffer
524 m_dstate.avail_out = m_compress_buffer_size;
525 m_dstate.next_out = m_compress_buffer.get();
526
527 deflate(&m_dstate, m_flush);
528
529 output = m_compress_buffer_size - m_dstate.avail_out;
530
531 out.append((char *)(m_compress_buffer.get()),output);
532 } while (m_dstate.avail_out == 0);
533
534 return lib::error_code();
535 }
536
538
544 lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
545 out)
546 {
547 if (!m_initialized) {
548 return make_error_code(error::uninitialized);
549 }
550
551 int ret;
552
553 m_istate.avail_in = len;
554 m_istate.next_in = const_cast<unsigned char *>(buf);
555
556 do {
557 m_istate.avail_out = m_compress_buffer_size;
558 m_istate.next_out = m_compress_buffer.get();
559
560 ret = inflate(&m_istate, Z_SYNC_FLUSH);
561
562 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
563 return make_error_code(error::zlib_error);
564 }
565
566 out.append(
567 reinterpret_cast<char *>(m_compress_buffer.get()),
568 m_compress_buffer_size - m_istate.avail_out
569 );
570 } while (m_istate.avail_out == 0);
571
572 return lib::error_code();
573 }
574private:
576
579 std::string generate_response() {
580 std::string ret = "permessage-deflate";
581
582 if (m_server_no_context_takeover) {
583 ret += "; server_no_context_takeover";
584 }
585
586 if (m_client_no_context_takeover) {
587 ret += "; client_no_context_takeover";
588 }
589
590 if (m_server_max_window_bits < default_server_max_window_bits) {
591 std::stringstream s;
592 s << int(m_server_max_window_bits);
593 ret += "; server_max_window_bits="+s.str();
594 }
595
596 if (m_client_max_window_bits < default_client_max_window_bits) {
597 std::stringstream s;
598 s << int(m_client_max_window_bits);
599 ret += "; client_max_window_bits="+s.str();
600 }
601
602 return ret;
603 }
604
606
610 void negotiate_server_no_context_takeover(std::string const & value,
611 lib::error_code & ec)
612 {
613 if (!value.empty()) {
614 ec = make_error_code(error::invalid_attribute_value);
615 return;
616 }
617
618 m_server_no_context_takeover = true;
619 }
620
622
626 void negotiate_client_no_context_takeover(std::string const & value,
627 lib::error_code & ec)
628 {
629 if (!value.empty()) {
630 ec = make_error_code(error::invalid_attribute_value);
631 return;
632 }
633
634 m_client_no_context_takeover = true;
635 }
636
638
653 void negotiate_server_max_window_bits(std::string const & value,
654 lib::error_code & ec)
655 {
656 uint8_t bits = uint8_t(atoi(value.c_str()));
657
658 if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
659 ec = make_error_code(error::invalid_attribute_value);
660 m_server_max_window_bits = default_server_max_window_bits;
661 return;
662 }
663
664 switch (m_server_max_window_bits_mode) {
665 case mode::decline:
666 m_server_max_window_bits = default_server_max_window_bits;
667 break;
668 case mode::accept:
669 m_server_max_window_bits = bits;
670 break;
671 case mode::largest:
672 m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
673 break;
674 case mode::smallest:
675 m_server_max_window_bits = min_server_max_window_bits;
676 break;
677 default:
678 ec = make_error_code(error::invalid_mode);
679 m_server_max_window_bits = default_server_max_window_bits;
680 }
681 }
682
684
698 void negotiate_client_max_window_bits(std::string const & value,
699 lib::error_code & ec)
700 {
701 uint8_t bits = uint8_t(atoi(value.c_str()));
702
703 if (value.empty()) {
704 bits = default_client_max_window_bits;
705 } else if (bits < min_client_max_window_bits ||
706 bits > max_client_max_window_bits)
707 {
708 ec = make_error_code(error::invalid_attribute_value);
709 m_client_max_window_bits = default_client_max_window_bits;
710 return;
711 }
712
713 switch (m_client_max_window_bits_mode) {
714 case mode::decline:
715 m_client_max_window_bits = default_client_max_window_bits;
716 break;
717 case mode::accept:
718 m_client_max_window_bits = bits;
719 break;
720 case mode::largest:
721 m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
722 break;
723 case mode::smallest:
724 m_client_max_window_bits = min_client_max_window_bits;
725 break;
726 default:
727 ec = make_error_code(error::invalid_mode);
728 m_client_max_window_bits = default_client_max_window_bits;
729 }
730 }
731
732 bool m_enabled;
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;
737 mode::value m_server_max_window_bits_mode;
738 mode::value m_client_max_window_bits_mode;
739
740 bool m_initialized;
741 int m_flush;
742 size_t m_compress_buffer_size;
743 lib::unique_ptr_uchar_array m_compress_buffer;
744 z_stream m_dstate;
745 z_stream m_istate;
746};
747
748} // namespace permessage_deflate
749} // namespace extensions
750} // namespace websocketpp
751
752#endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
lib::error_code init(bool is_server)
Initialize zlib state.
Definition enabled.hpp:260
void enable_client_no_context_takeover()
Reset client's outgoing LZ77 sliding window for each new message.
Definition enabled.hpp:367
lib::error_code compress(std::string const &in, std::string &out)
Compress bytes.
Definition enabled.hpp:506
bool is_enabled() const
Test if the extension was negotiated for this connection.
Definition enabled.hpp:323
lib::error_code decompress(uint8_t const *buf, size_t len, std::string &out)
Decompress bytes.
Definition enabled.hpp:544
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode)
Limit client LZ77 sliding window size.
Definition enabled.hpp:424
bool is_implemented() const
Test if this object implements the permessage-deflate specification.
Definition enabled.hpp:312
void enable_server_no_context_takeover()
Reset server's outgoing LZ77 sliding window for each new message.
Definition enabled.hpp:348
err_str_pair negotiate(http::attribute_list const &offer)
Negotiate extension.
Definition enabled.hpp:467
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode)
Limit server LZ77 sliding window size.
Definition enabled.hpp:393
lib::error_code validate_offer(http::attribute_list const &)
Validate extension response.
Definition enabled.hpp:454
std::string generate_offer() const
Generate extension offer.
Definition enabled.hpp:441
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_
Definition enabled.hpp:122
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
Definition cpp11.hpp:113
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.
Definition enabled.hpp:105
@ invalid_max_window_bits
Invalid value for max_window_bits.
Definition enabled.hpp:108
@ invalid_attribute_value
Invalid extension attribute value.
Definition enabled.hpp:99
@ invalid_attributes
Invalid extension attributes.
Definition enabled.hpp:96
lib::error_category const & get_category()
Get a reference to a static copy of the permessage-deflate error category.
Definition enabled.hpp:151
lib::error_code make_error_code(error::value e)
Create an error code in the permessage-deflate category.
Definition enabled.hpp:157
@ accept
Accept any value the remote endpoint offers.
Definition enabled.hpp:194
@ smallest
Use the smallest value common to both offers.
Definition enabled.hpp:200
@ largest
Use the largest value common to both offers.
Definition enabled.hpp:198
@ decline
Decline any value the remote endpoint offers. Insist on defaults.
Definition enabled.hpp:196
boost::scoped_array< unsigned char > unique_ptr_uchar_array
Definition memory.hpp:83
Namespace for the WebSocket++ project.
Definition base64.hpp:41
std::pair< lib::error_code, std::string > err_str_pair
Combination error code / string type for returning two values.
Definition error.hpp:41
#define value
Definition pkcs11.h:157
unsigned char uint8_t
Definition stdint.h:124
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
CK_RV ret
char * s
size_t len
uint8_t buf[2048]