WebSocket++ 0.8.2
C++ websocket client/server library
Loading...
Searching...
No Matches
enabled.hpp
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
32#include <websocketpp/common/cpp11.hpp>
33#include <websocketpp/common/memory.hpp>
34#include <websocketpp/common/platforms.hpp>
35#include <websocketpp/common/stdint.hpp>
36#include <websocketpp/common/system_error.hpp>
37#include <websocketpp/error.hpp>
38
39#include <websocketpp/extensions/extension.hpp>
40
41#include "zlib.h"
42
43#include <algorithm>
44#include <string>
45#include <vector>
46
47namespace websocketpp {
48namespace extensions {
49
50/// Implementation of RFC 7692, the permessage-deflate WebSocket extension
51/**
52 * ### permessage-deflate interface
53 *
54 * **init**\n
55 * `lib::error_code init(bool is_server)`\n
56 * Performs initialization
57 *
58 * **is_implimented**\n
59 * `bool is_implimented()`\n
60 * Returns whether or not the object impliments the extension or not
61 *
62 * **is_enabled**\n
63 * `bool is_enabled()`\n
64 * Returns whether or not the extension was negotiated for the current
65 * connection
66 *
67 * **generate_offer**\n
68 * `std::string generate_offer() const`\n
69 * Create an extension offer string based on local policy
70 *
71 * **validate_response**\n
72 * `lib::error_code validate_response(http::attribute_list const & response)`\n
73 * Negotiate the parameters of extension use
74 *
75 * **negotiate**\n
76 * `err_str_pair negotiate(http::attribute_list const & attributes)`\n
77 * Negotiate the parameters of extension use
78 *
79 * **compress**\n
80 * `lib::error_code compress(std::string const & in, std::string & out)`\n
81 * Compress the bytes in `in` and append them to `out`
82 *
83 * **decompress**\n
84 * `lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
85 * out)`\n
86 * Decompress `len` bytes from `buf` and append them to string `out`
87 */
88namespace permessage_deflate {
89
90/// Permessage deflate error values
91namespace error {
92enum value {
93 /// Catch all
94 general = 1,
95
96 /// Invalid extension attributes
98
99 /// Invalid extension attribute value
101
102 /// Invalid megotiation mode
104
105 /// Unsupported extension attributes
107
108 /// Invalid value for max_window_bits
110
111 /// ZLib Error
113
114 /// Uninitialized
116};
117
118/// Permessage-deflate error category
119class category : public lib::error_category {
120public:
121 category() {}
122
123 char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
124 return "websocketpp.extension.permessage-deflate";
125 }
126
127 std::string message(int value) const {
128 switch(value) {
129 case general:
130 return "Generic permessage-compress error";
132 return "Invalid extension attributes";
134 return "Invalid extension attribute value";
135 case invalid_mode:
136 return "Invalid permessage-deflate negotiation mode";
138 return "Unsupported extension attributes";
140 return "Invalid value for max_window_bits";
141 case zlib_error:
142 return "A zlib function returned an error";
143 case uninitialized:
144 return "Deflate extension must be initialized before use";
145 default:
146 return "Unknown permessage-compress error";
147 }
148 }
149};
150
151/// Get a reference to a static copy of the permessage-deflate error category
152inline lib::error_category const & get_category() {
153 static category instance;
154 return instance;
155}
156
157/// Create an error code in the permessage-deflate category
158inline lib::error_code make_error_code(error::value e) {
159 return lib::error_code(static_cast<int>(e), get_category());
160}
161
162} // namespace error
163} // namespace permessage_deflate
164} // namespace extensions
165} // namespace websocketpp
166
168template<> struct is_error_code_enum
170{
171 static bool const value = true;
172};
174namespace websocketpp {
175namespace extensions {
176namespace permessage_deflate {
177
178/// Default value for server_max_window_bits as defined by RFC 7692
179static uint8_t const default_server_max_window_bits = 15;
180/// Minimum value for server_max_window_bits as defined by RFC 7692
181/**
182 * NOTE: A value of 8 is not actually supported by zlib, the deflate
183 * library that WebSocket++ uses. To preserve backwards compatibility
184 * with RFC 7692 and previous versions of the library a value of 8
185 * is accepted by the library but will always be negotiated as 9.
186 */
187static uint8_t const min_server_max_window_bits = 8;
188/// Maximum value for server_max_window_bits as defined by RFC 7692
189static uint8_t const max_server_max_window_bits = 15;
190
191/// Default value for client_max_window_bits as defined by RFC 7692
192static uint8_t const default_client_max_window_bits = 15;
193/// Minimum value for client_max_window_bits as defined by RFC 7692
194/**
195 * NOTE: A value of 8 is not actually supported by zlib, the deflate
196 * library that WebSocket++ uses. To preserve backwards compatibility
197 * with RFC 7692 and previous versions of the library a value of 8
198 * is accepted by the library but will always be negotiated as 9.
199 */
200static uint8_t const min_client_max_window_bits = 8;
201/// Maximum value for client_max_window_bits as defined by RFC 7692
202static uint8_t const max_client_max_window_bits = 15;
203
204namespace mode {
205enum value {
206 /// Accept any value the remote endpoint offers
207 accept = 1,
208 /// Decline any value the remote endpoint offers. Insist on defaults.
209 decline,
210 /// Use the largest value common to both offers
211 largest,
212 /// Use the smallest value common to both offers
213 smallest
214};
215} // namespace mode
216
217template <typename config>
218class enabled {
219public:
220 enabled()
221 : m_enabled(false)
222 , m_server_no_context_takeover(false)
223 , m_client_no_context_takeover(false)
224 , m_server_max_window_bits(15)
225 , m_client_max_window_bits(15)
226 , m_server_max_window_bits_mode(mode::accept)
227 , m_client_max_window_bits_mode(mode::accept)
228 , m_initialized(false)
229 , m_compress_buffer_size(8192)
230 {
231 m_dstate.zalloc = Z_NULL;
232 m_dstate.zfree = Z_NULL;
233 m_dstate.opaque = Z_NULL;
234
235 m_istate.zalloc = Z_NULL;
236 m_istate.zfree = Z_NULL;
237 m_istate.opaque = Z_NULL;
238 m_istate.avail_in = 0;
239 m_istate.next_in = Z_NULL;
240 }
241
242 ~enabled() {
243 if (!m_initialized) {
244 return;
245 }
246
247 int ret = deflateEnd(&m_dstate);
248
249 if (ret != Z_OK) {
250 //std::cout << "error cleaning up zlib compression state"
251 // << std::endl;
252 }
253
254 ret = inflateEnd(&m_istate);
255
256 if (ret != Z_OK) {
257 //std::cout << "error cleaning up zlib decompression state"
258 // << std::endl;
259 }
260 }
261
262 /// Initialize zlib state
263 /**
264 * Note: this should be called *after* the negotiation methods. It will use
265 * information from the negotiation to determine how to initialize the zlib
266 * data structures.
267 *
268 * @todo memory level, strategy, etc are hardcoded
269 *
270 * @param is_server True to initialize as a server, false for a client.
271 * @return A code representing the error that occurred, if any
272 */
273 lib::error_code init(bool is_server) {
274 uint8_t deflate_bits;
275 uint8_t inflate_bits;
276
277 if (is_server) {
278 deflate_bits = m_server_max_window_bits;
279 inflate_bits = m_client_max_window_bits;
280 } else {
281 deflate_bits = m_client_max_window_bits;
282 inflate_bits = m_server_max_window_bits;
283 }
284
285 int ret = deflateInit2(
286 &m_dstate,
287 Z_DEFAULT_COMPRESSION,
288 Z_DEFLATED,
289 -1*deflate_bits,
290 4, // memory level 1-9
291 Z_DEFAULT_STRATEGY
292 );
293
294 if (ret != Z_OK) {
296 }
297
298 ret = inflateInit2(
299 &m_istate,
300 -1*inflate_bits
301 );
302
303 if (ret != Z_OK) {
305 }
306
307 m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
308 m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]);
309 if ((m_server_no_context_takeover && is_server) ||
310 (m_client_no_context_takeover && !is_server))
311 {
312 m_flush = Z_FULL_FLUSH;
313 } else {
314 m_flush = Z_SYNC_FLUSH;
315 }
316 m_initialized = true;
317 return lib::error_code();
318 }
319
320 /// Test if this object implements the permessage-deflate specification
321 /**
322 * Because this object does implieent it, it will always return true.
323 *
324 * @return Whether or not this object implements permessage-deflate
325 */
326 bool is_implemented() const {
327 return true;
328 }
329
330 /// Test if the extension was negotiated for this connection
331 /**
332 * Retrieves whether or not this extension is in use based on the initial
333 * handshake extension negotiations.
334 *
335 * @return Whether or not the extension is in use
336 */
337 bool is_enabled() const {
338 return m_enabled;
339 }
340
341 /// Reset server's outgoing LZ77 sliding window for each new message
342 /**
343 * Enabling this setting will cause the server's compressor to reset the
344 * compression state (the LZ77 sliding window) for every message. This
345 * means that the compressor will not look back to patterns in previous
346 * messages to improve compression. This will reduce the compression
347 * efficiency for large messages somewhat and small messages drastically.
348 *
349 * This option may reduce server compressor memory usage and client
350 * decompressor memory usage.
351 * @todo Document to what extent memory usage will be reduced
352 *
353 * For clients, this option is dependent on server support. Enabling it
354 * via this method does not guarantee that it will be successfully
355 * negotiated, only that it will be requested.
356 *
357 * For servers, no client support is required. Enabling this option on a
358 * server will result in its use. The server will signal to clients that
359 * the option will be in use so they can optimize resource usage if they
360 * are able.
361 */
363 m_server_no_context_takeover = true;
364 }
365
366 /// Reset client's outgoing LZ77 sliding window for each new message
367 /**
368 * Enabling this setting will cause the client's compressor to reset the
369 * compression state (the LZ77 sliding window) for every message. This
370 * means that the compressor will not look back to patterns in previous
371 * messages to improve compression. This will reduce the compression
372 * efficiency for large messages somewhat and small messages drastically.
373 *
374 * This option may reduce client compressor memory usage and server
375 * decompressor memory usage.
376 * @todo Document to what extent memory usage will be reduced
377 *
378 * This option is supported by all compliant clients and servers. Enabling
379 * it via either endpoint should be sufficient to ensure it is used.
380 */
382 m_client_no_context_takeover = true;
383 }
384
385 /// Limit server LZ77 sliding window size
386 /**
387 * The bits setting is the base 2 logarithm of the maximum window size that
388 * the server must use to compress outgoing messages. The permitted range
389 * is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB
390 * window. The default setting is 15.
391 *
392 * Mode Options:
393 * - accept: Accept whatever the remote endpoint offers.
394 * - decline: Decline any offers to deviate from the defaults
395 * - largest: Accept largest window size acceptable to both endpoints
396 * - smallest: Accept smallest window size acceptiable to both endpoints
397 *
398 * This setting is dependent on server support. A client requesting this
399 * setting may be rejected by the server or have the exact value used
400 * adjusted by the server. A server may unilaterally set this value without
401 * client support.
402 *
403 * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
404 * Prior to version 0.8.0 a value of 8 was also allowed by this library.
405 * zlib, the deflate compression library that WebSocket++ uses has always
406 * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
407 * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
408 * continues to perform the 8->9 conversion for backwards compatibility
409 * purposes but this should be considered deprecated functionality.
410 *
411 * @param bits The size to request for the outgoing window size
412 * @param mode The mode to use for negotiating this parameter
413 * @return A status code
414 */
415 lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
418 }
419
420 // See note in doc comment above about what is happening here
421 if (bits == 8) {
422 bits = 9;
423 }
424
425 m_server_max_window_bits = bits;
426 m_server_max_window_bits_mode = mode;
427
428 return lib::error_code();
429 }
430
431 /// Limit client LZ77 sliding window size
432 /**
433 * The bits setting is the base 2 logarithm of the window size that the
434 * client must use to compress outgoing messages. The permitted range is 9
435 * to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.
436 * The default setting is 15.
437 *
438 * Mode Options:
439 * - accept: Accept whatever the remote endpoint offers.
440 * - decline: Decline any offers to deviate from the defaults
441 * - largest: Accept largest window size acceptable to both endpoints
442 * - smallest: Accept smallest window size acceptiable to both endpoints
443 *
444 * This setting is dependent on client support. A client may limit its own
445 * outgoing window size unilaterally. A server may only limit the client's
446 * window size if the remote client supports that feature.
447 *
448 * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
449 * Prior to version 0.8.0 a value of 8 was also allowed by this library.
450 * zlib, the deflate compression library that WebSocket++ uses has always
451 * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
452 * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
453 * continues to perform the 8->9 conversion for backwards compatibility
454 * purposes but this should be considered deprecated functionality.
455 *
456 * @param bits The size to request for the outgoing window size
457 * @param mode The mode to use for negotiating this parameter
458 * @return A status code
459 */
460 lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
463 }
464
465 // See note in doc comment above about what is happening here
466 if (bits == 8) {
467 bits = 9;
468 }
469
470 m_client_max_window_bits = bits;
471 m_client_max_window_bits_mode = mode;
472
473 return lib::error_code();
474 }
475
476 /// Generate extension offer
477 /**
478 * Creates an offer string to include in the Sec-WebSocket-Extensions
479 * header of outgoing client requests.
480 *
481 * @return A WebSocket extension offer string for this extension
482 */
483 std::string generate_offer() const {
484 // TODO: this should be dynamically generated based on user settings
485 return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
486 }
487
488 /// Validate extension response
489 /**
490 * Confirm that the server has negotiated settings compatible with our
491 * original offer and apply those settings to the extension state.
492 *
493 * @param response The server response attribute list to validate
494 * @return Validation error or 0 on success
495 */
496 lib::error_code validate_offer(http::attribute_list const &) {
497 return lib::error_code();
498 }
499
500 /// Negotiate extension
501 /**
502 * Confirm that the client's extension negotiation offer has settings
503 * compatible with local policy. If so, generate a reply and apply those
504 * settings to the extension state.
505 *
506 * @param offer Attribute from client's offer
507 * @return Status code and value to return to remote endpoint
508 */
509 err_str_pair negotiate(http::attribute_list const & offer) {
510 err_str_pair ret;
511
512 http::attribute_list::const_iterator it;
513 for (it = offer.begin(); it != offer.end(); ++it) {
514 if (it->first == "server_no_context_takeover") {
515 negotiate_server_no_context_takeover(it->second,ret.first);
516 } else if (it->first == "client_no_context_takeover") {
517 negotiate_client_no_context_takeover(it->second,ret.first);
518 } else if (it->first == "server_max_window_bits") {
519 negotiate_server_max_window_bits(it->second,ret.first);
520 } else if (it->first == "client_max_window_bits") {
521 negotiate_client_max_window_bits(it->second,ret.first);
522 } else {
524 }
525
526 if (ret.first) {
527 break;
528 }
529 }
530
531 if (ret.first == lib::error_code()) {
532 m_enabled = true;
533 ret.second = generate_response();
534 }
535
536 return ret;
537 }
538
539 /// Compress bytes
540 /**
541 * @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames
542 * on 64 bit machines.
543 *
544 * @param [in] in String to compress
545 * @param [out] out String to append compressed bytes to
546 * @return Error or status code
547 */
548 lib::error_code compress(std::string const & in, std::string & out) {
549 if (!m_initialized) {
551 }
552
553 size_t output;
554
555 if (in.empty()) {
556 uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
557 out.append((char *)(buf),6);
558 return lib::error_code();
559 }
560
561 m_dstate.avail_in = in.size();
562 m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
563
564 do {
565 // Output to local buffer
566 m_dstate.avail_out = m_compress_buffer_size;
567 m_dstate.next_out = m_compress_buffer.get();
568
569 deflate(&m_dstate, m_flush);
570
571 output = m_compress_buffer_size - m_dstate.avail_out;
572
573 out.append((char *)(m_compress_buffer.get()),output);
574 } while (m_dstate.avail_out == 0);
575
576 return lib::error_code();
577 }
578
579 /// Decompress bytes
580 /**
581 * @param buf Byte buffer to decompress
582 * @param len Length of buf
583 * @param out String to append decompressed bytes to
584 * @return Error or status code
585 */
586 lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
587 out)
588 {
589 if (!m_initialized) {
591 }
592
593 int ret;
594
595 m_istate.avail_in = len;
596 m_istate.next_in = const_cast<unsigned char *>(buf);
597
598 do {
599 m_istate.avail_out = m_compress_buffer_size;
600 m_istate.next_out = m_decompress_buffer.get();
601
602 ret = inflate(&m_istate, Z_SYNC_FLUSH);
603
604 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
606 }
607
608 out.append(
609 reinterpret_cast<char *>(m_decompress_buffer.get()),
610 m_compress_buffer_size - m_istate.avail_out
611 );
612 } while (m_istate.avail_out == 0);
613
614 return lib::error_code();
615 }
616private:
617 /// Generate negotiation response
618 /**
619 * @return Generate extension negotiation reponse string to send to client
620 */
621 std::string generate_response() {
622 std::string ret = "permessage-deflate";
623
624 if (m_server_no_context_takeover) {
625 ret += "; server_no_context_takeover";
626 }
627
628 if (m_client_no_context_takeover) {
629 ret += "; client_no_context_takeover";
630 }
631
632 if (m_server_max_window_bits < default_server_max_window_bits) {
633 std::stringstream s;
634 s << int(m_server_max_window_bits);
635 ret += "; server_max_window_bits="+s.str();
636 }
637
638 if (m_client_max_window_bits < default_client_max_window_bits) {
639 std::stringstream s;
640 s << int(m_client_max_window_bits);
641 ret += "; client_max_window_bits="+s.str();
642 }
643
644 return ret;
645 }
646
647 /// Negotiate server_no_context_takeover attribute
648 /**
649 * @param [in] value The value of the attribute from the offer
650 * @param [out] ec A reference to the error code to return errors via
651 */
652 void negotiate_server_no_context_takeover(std::string const & value,
653 lib::error_code & ec)
654 {
655 if (!value.empty()) {
657 return;
658 }
659
660 m_server_no_context_takeover = true;
661 }
662
663 /// Negotiate client_no_context_takeover attribute
664 /**
665 * @param [in] value The value of the attribute from the offer
666 * @param [out] ec A reference to the error code to return errors via
667 */
668 void negotiate_client_no_context_takeover(std::string const & value,
669 lib::error_code & ec)
670 {
671 if (!value.empty()) {
673 return;
674 }
675
676 m_client_no_context_takeover = true;
677 }
678
679 /// Negotiate server_max_window_bits attribute
680 /**
681 * When this method starts, m_server_max_window_bits will contain the server's
682 * preferred value and m_server_max_window_bits_mode will contain the mode the
683 * server wants to use to for negotiation. `value` contains the value the
684 * client requested that we use.
685 *
686 * options:
687 * - decline (ignore value, offer our default instead)
688 * - accept (use the value requested by the client)
689 * - largest (use largest value acceptable to both)
690 * - smallest (use smallest possible value)
691 *
692 * NOTE: As a value of 8 is no longer explicitly supported by zlib but might
693 * be requested for negotiation by an older client/server, if the result of
694 * the negotiation would be to send a value of 8, a value of 9 is offered
695 * instead. This ensures that WebSocket++ will only ever negotiate connections
696 * with compression settings explicitly supported by zlib.
697 *
698 * @param [in] value The value of the attribute from the offer
699 * @param [out] ec A reference to the error code to return errors via
700 */
701 void negotiate_server_max_window_bits(std::string const & value,
702 lib::error_code & ec)
703 {
704 uint8_t bits = uint8_t(atoi(value.c_str()));
705
708 m_server_max_window_bits = default_server_max_window_bits;
709 return;
710 }
711
712 switch (m_server_max_window_bits_mode) {
713 case mode::decline:
714 m_server_max_window_bits = default_server_max_window_bits;
715 break;
716 case mode::accept:
717 m_server_max_window_bits = bits;
718 break;
719 case mode::largest:
720 m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
721 break;
722 case mode::smallest:
723 m_server_max_window_bits = min_server_max_window_bits;
724 break;
725 default:
727 m_server_max_window_bits = default_server_max_window_bits;
728 }
729
730 // See note in doc comment
731 if (m_server_max_window_bits == 8) {
732 m_server_max_window_bits = 9;
733 }
734 }
735
736 /// Negotiate client_max_window_bits attribute
737 /**
738 * When this method starts, m_client_max_window_bits and m_c2s_max_window_mode
739 * will contain the server's preferred values for window size and
740 * negotiation mode.
741 *
742 * options:
743 * - decline (ignore value, offer our default instead)
744 * - accept (use the value requested by the client)
745 * - largest (use largest value acceptable to both)
746 * - smallest (use smallest possible value)
747 *
748 * NOTE: As a value of 8 is no longer explicitly supported by zlib but might
749 * be requested for negotiation by an older client/server, if the result of
750 * the negotiation would be to send a value of 8, a value of 9 is offered
751 * instead. This ensures that WebSocket++ will only ever negotiate connections
752 * with compression settings explicitly supported by zlib.
753 *
754 * @param [in] value The value of the attribute from the offer
755 * @param [out] ec A reference to the error code to return errors via
756 */
757 void negotiate_client_max_window_bits(std::string const & value,
758 lib::error_code & ec)
759 {
760 uint8_t bits = uint8_t(atoi(value.c_str()));
761
762 if (value.empty()) {
764 } else if (bits < min_client_max_window_bits ||
766 {
768 m_client_max_window_bits = default_client_max_window_bits;
769 return;
770 }
771
772 switch (m_client_max_window_bits_mode) {
773 case mode::decline:
774 m_client_max_window_bits = default_client_max_window_bits;
775 break;
776 case mode::accept:
777 m_client_max_window_bits = bits;
778 break;
779 case mode::largest:
780 m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
781 break;
782 case mode::smallest:
783 m_client_max_window_bits = min_client_max_window_bits;
784 break;
785 default:
787 m_client_max_window_bits = default_client_max_window_bits;
788 }
789
790 // See note in doc comment
791 if (m_client_max_window_bits == 8) {
792 m_client_max_window_bits = 9;
793 }
794 }
795
796 bool m_enabled;
797 bool m_server_no_context_takeover;
798 bool m_client_no_context_takeover;
799 uint8_t m_server_max_window_bits;
800 uint8_t m_client_max_window_bits;
801 mode::value m_server_max_window_bits_mode;
802 mode::value m_client_max_window_bits_mode;
803
804 bool m_initialized;
805 int m_flush;
806 size_t m_compress_buffer_size;
807 lib::unique_ptr_uchar_array m_compress_buffer;
808 lib::unique_ptr_uchar_array m_decompress_buffer;
809 z_stream m_dstate;
810 z_stream m_istate;
811};
812
813} // namespace permessage_deflate
814} // namespace extensions
815} // namespace websocketpp
816
817#endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
lib::error_code init(bool is_server)
Initialize zlib state.
Definition enabled.hpp:273
void enable_client_no_context_takeover()
Reset client's outgoing LZ77 sliding window for each new message.
Definition enabled.hpp:381
lib::error_code compress(std::string const &in, std::string &out)
Compress bytes.
Definition enabled.hpp:548
bool is_enabled() const
Test if the extension was negotiated for this connection.
Definition enabled.hpp:337
lib::error_code decompress(uint8_t const *buf, size_t len, std::string &out)
Decompress bytes.
Definition enabled.hpp:586
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode)
Limit client LZ77 sliding window size.
Definition enabled.hpp:460
bool is_implemented() const
Test if this object implements the permessage-deflate specification.
Definition enabled.hpp:326
void enable_server_no_context_takeover()
Reset server's outgoing LZ77 sliding window for each new message.
Definition enabled.hpp:362
err_str_pair negotiate(http::attribute_list const &offer)
Negotiate extension.
Definition enabled.hpp:509
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode)
Limit server LZ77 sliding window size.
Definition enabled.hpp:415
lib::error_code validate_offer(http::attribute_list const &)
Validate extension response.
Definition enabled.hpp:496
std::string generate_offer() const
Generate extension offer.
Definition enabled.hpp:483
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
Definition cpp11.hpp:113
Permessage deflate error values.
Definition enabled.hpp:91
@ unsupported_attributes
Unsupported extension attributes.
Definition enabled.hpp:106
@ invalid_max_window_bits
Invalid value for max_window_bits.
Definition enabled.hpp:109
@ invalid_attribute_value
Invalid extension attribute value.
Definition enabled.hpp:100
@ invalid_attributes
Invalid extension attributes.
Definition enabled.hpp:97
lib::error_category const & get_category()
Get a reference to a static copy of the permessage-deflate error category.
Definition enabled.hpp:152
lib::error_code make_error_code(error::value e)
Create an error code in the permessage-deflate category.
Definition enabled.hpp:158
Implementation of RFC 7692, the permessage-deflate WebSocket extension.
Definition disabled.hpp:44
static uint8_t const default_client_max_window_bits
Default value for client_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:192
static uint8_t const default_server_max_window_bits
Default value for server_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:179
static uint8_t const max_client_max_window_bits
Maximum value for client_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:202
static uint8_t const min_client_max_window_bits
Minimum value for client_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:200
static uint8_t const min_server_max_window_bits
Minimum value for server_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:187
static uint8_t const max_server_max_window_bits
Maximum value for server_max_window_bits as defined by RFC 7692.
Definition enabled.hpp:189
Namespace for the WebSocket++ project.
std::pair< lib::error_code, std::string > err_str_pair
Combination error code / string type for returning two values.
Definition error.hpp:41
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_