123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- //
- // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #ifndef BHO_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
- #define BHO_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
- #include <asio2/bho/beast/websocket/detail/pmd_extension.hpp>
- namespace bho {
- namespace beast {
- namespace websocket {
- namespace detail {
- int
- parse_bits(string_view s)
- {
- if(s.size() == 0)
- return -1;
- if(s.size() > 2)
- return -1;
- if(s[0] < '1' || s[0] > '9')
- return -1;
- unsigned i = 0;
- for(auto c : s)
- {
- if(c < '0' || c > '9')
- return -1;
- auto const i0 = i;
- i = 10 * i + (c - '0');
- if(i < i0)
- return -1;
- }
- return static_cast<int>(i);
- }
- // Parse permessage-deflate request fields
- //
- void
- pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
- {
- offer.accept = false;
- offer.server_max_window_bits= 0;
- offer.client_max_window_bits = 0;
- offer.server_no_context_takeover = false;
- offer.client_no_context_takeover = false;
- for(auto const& ext : list)
- {
- if(beast::iequals(ext.first, "permessage-deflate"))
- {
- for(auto const& param : ext.second)
- {
- if(beast::iequals(param.first,
- "server_max_window_bits"))
- {
- if(offer.server_max_window_bits != 0)
- {
- // The negotiation offer contains multiple
- // extension parameters with the same name.
- //
- return; // MUST decline
- }
- if(param.second.empty())
- {
- // The negotiation offer extension
- // parameter is missing the value.
- //
- return; // MUST decline
- }
- offer.server_max_window_bits =
- parse_bits(param.second);
- if( offer.server_max_window_bits < 8 ||
- offer.server_max_window_bits > 15)
- {
- // The negotiation offer contains an
- // extension parameter with an invalid value.
- //
- return; // MUST decline
- }
- }
- else if(beast::iequals(param.first,
- "client_max_window_bits"))
- {
- if(offer.client_max_window_bits != 0)
- {
- // The negotiation offer contains multiple
- // extension parameters with the same name.
- //
- return; // MUST decline
- }
- if(! param.second.empty())
- {
- offer.client_max_window_bits =
- parse_bits(param.second);
- if( offer.client_max_window_bits < 8 ||
- offer.client_max_window_bits > 15)
- {
- // The negotiation offer contains an
- // extension parameter with an invalid value.
- //
- return; // MUST decline
- }
- }
- else
- {
- offer.client_max_window_bits = -1;
- }
- }
- else if(beast::iequals(param.first,
- "server_no_context_takeover"))
- {
- if(offer.server_no_context_takeover)
- {
- // The negotiation offer contains multiple
- // extension parameters with the same name.
- //
- return; // MUST decline
- }
- if(! param.second.empty())
- {
- // The negotiation offer contains an
- // extension parameter with an invalid value.
- //
- return; // MUST decline
- }
- offer.server_no_context_takeover = true;
- }
- else if(beast::iequals(param.first,
- "client_no_context_takeover"))
- {
- if(offer.client_no_context_takeover)
- {
- // The negotiation offer contains multiple
- // extension parameters with the same name.
- //
- return; // MUST decline
- }
- if(! param.second.empty())
- {
- // The negotiation offer contains an
- // extension parameter with an invalid value.
- //
- return; // MUST decline
- }
- offer.client_no_context_takeover = true;
- }
- else
- {
- // The negotiation offer contains an extension
- // parameter not defined for use in an offer.
- //
- return; // MUST decline
- }
- }
- offer.accept = true;
- return;
- }
- }
- }
- static_string<512>
- pmd_write_impl(pmd_offer const& offer)
- {
- static_string<512> s = "permessage-deflate";
- if(offer.server_max_window_bits != 0)
- {
- if(offer.server_max_window_bits != -1)
- {
- s += "; server_max_window_bits=";
- s += to_static_string(
- offer.server_max_window_bits);
- }
- else
- {
- s += "; server_max_window_bits";
- }
- }
- if(offer.client_max_window_bits != 0)
- {
- if(offer.client_max_window_bits != -1)
- {
- s += "; client_max_window_bits=";
- s += to_static_string(
- offer.client_max_window_bits);
- }
- else
- {
- s += "; client_max_window_bits";
- }
- }
- if(offer.server_no_context_takeover)
- {
- s += "; server_no_context_takeover";
- }
- if(offer.client_no_context_takeover)
- {
- s += "; client_no_context_takeover";
- }
- return s;
- }
- static_string<512>
- pmd_negotiate_impl(
- pmd_offer& config,
- pmd_offer const& offer,
- permessage_deflate const& o)
- {
- static_string<512> s = "permessage-deflate";
- config.server_no_context_takeover =
- offer.server_no_context_takeover ||
- o.server_no_context_takeover;
- if(config.server_no_context_takeover)
- s += "; server_no_context_takeover";
- config.client_no_context_takeover =
- o.client_no_context_takeover ||
- offer.client_no_context_takeover;
- if(config.client_no_context_takeover)
- s += "; client_no_context_takeover";
- if(offer.server_max_window_bits != 0)
- config.server_max_window_bits = (std::min)(
- offer.server_max_window_bits,
- o.server_max_window_bits);
- else
- config.server_max_window_bits =
- o.server_max_window_bits;
- if(config.server_max_window_bits < 15)
- {
- // ZLib's deflateInit silently treats 8 as
- // 9 due to a bug, so prevent 8 from being used.
- //
- if(config.server_max_window_bits < 9)
- config.server_max_window_bits = 9;
- s += "; server_max_window_bits=";
- s += to_static_string(
- config.server_max_window_bits);
- }
- switch(offer.client_max_window_bits)
- {
- case -1:
- // extension parameter is present with no value
- config.client_max_window_bits =
- o.client_max_window_bits;
- if(config.client_max_window_bits < 15)
- {
- s += "; client_max_window_bits=";
- s += to_static_string(
- config.client_max_window_bits);
- }
- break;
- case 0:
- /* extension parameter is absent.
- If a received extension negotiation offer doesn't have the
- "client_max_window_bits" extension parameter, the corresponding
- extension negotiation response to the offer MUST NOT include the
- "client_max_window_bits" extension parameter.
- */
- if(o.client_max_window_bits == 15)
- config.client_max_window_bits = 15;
- else
- config.accept = false;
- break;
- default:
- // extension parameter has value in [8..15]
- config.client_max_window_bits = (std::min)(
- o.client_max_window_bits,
- offer.client_max_window_bits);
- s += "; client_max_window_bits=";
- s += to_static_string(
- config.client_max_window_bits);
- break;
- }
- return s;
- }
- void
- pmd_normalize(pmd_offer& offer)
- {
- if(offer.accept)
- {
- if( offer.server_max_window_bits == 0)
- offer.server_max_window_bits = 15;
- if( offer.client_max_window_bits == 0 ||
- offer.client_max_window_bits == -1)
- offer.client_max_window_bits = 15;
- }
- }
- } // detail
- } // websocket
- } // beast
- } // bho
- #endif // BHO_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
|