Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:33

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
0011 #define BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
0012 
0013 #include <boost/beast/websocket/detail/pmd_extension.hpp>
0014 
0015 namespace boost {
0016 namespace beast {
0017 namespace websocket {
0018 namespace detail {
0019 
0020 int
0021 parse_bits(string_view s)
0022 {
0023     if(s.size() == 0)
0024         return -1;
0025     if(s.size() > 2)
0026         return -1;
0027     if(s[0] < '1' || s[0] > '9')
0028         return -1;
0029     unsigned i = 0;
0030     for(auto c : s)
0031     {
0032         if(c < '0' || c > '9')
0033             return -1;
0034         auto const i0 = i;
0035         i = 10 * i + (c - '0');
0036         if(i < i0)
0037             return -1;
0038     }
0039     return static_cast<int>(i);
0040 }
0041 
0042 // Parse permessage-deflate request fields
0043 //
0044 void
0045 pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
0046 {
0047     offer.accept = false;
0048     offer.server_max_window_bits= 0;
0049     offer.client_max_window_bits = 0;
0050     offer.server_no_context_takeover = false;
0051     offer.client_no_context_takeover = false;
0052 
0053     for(auto const& ext : list)
0054     {
0055         if(beast::iequals(ext.first, "permessage-deflate"))
0056         {
0057             for(auto const& param : ext.second)
0058             {
0059                 if(beast::iequals(param.first,
0060                     "server_max_window_bits"))
0061                 {
0062                     if(offer.server_max_window_bits != 0)
0063                     {
0064                         // The negotiation offer contains multiple
0065                         // extension parameters with the same name.
0066                         //
0067                         return; // MUST decline
0068                     }
0069                     if(param.second.empty())
0070                     {
0071                         // The negotiation offer extension
0072                         // parameter is missing the value.
0073                         //
0074                         return; // MUST decline
0075                     }
0076                     offer.server_max_window_bits =
0077                         parse_bits(param.second);
0078                     if( offer.server_max_window_bits < 8 ||
0079                         offer.server_max_window_bits > 15)
0080                     {
0081                         // The negotiation offer contains an
0082                         // extension parameter with an invalid value.
0083                         //
0084                         return; // MUST decline
0085                     }
0086                 }
0087                 else if(beast::iequals(param.first,
0088                     "client_max_window_bits"))
0089                 {
0090                     if(offer.client_max_window_bits != 0)
0091                     {
0092                         // The negotiation offer contains multiple
0093                         // extension parameters with the same name.
0094                         //
0095                         return; // MUST decline
0096                     }
0097                     if(! param.second.empty())
0098                     {
0099                         offer.client_max_window_bits =
0100                             parse_bits(param.second);
0101                         if( offer.client_max_window_bits < 8 ||
0102                             offer.client_max_window_bits > 15)
0103                         {
0104                             // The negotiation offer contains an
0105                             // extension parameter with an invalid value.
0106                             //
0107                             return; // MUST decline
0108                         }
0109                     }
0110                     else
0111                     {
0112                         offer.client_max_window_bits = -1;
0113                     }
0114                 }
0115                 else if(beast::iequals(param.first,
0116                     "server_no_context_takeover"))
0117                 {
0118                     if(offer.server_no_context_takeover)
0119                     {
0120                         // The negotiation offer contains multiple
0121                         // extension parameters with the same name.
0122                         //
0123                         return; // MUST decline
0124                     }
0125                     if(! param.second.empty())
0126                     {
0127                         // The negotiation offer contains an
0128                         // extension parameter with an invalid value.
0129                         //
0130                         return; // MUST decline
0131                     }
0132                     offer.server_no_context_takeover = true;
0133                 }
0134                 else if(beast::iequals(param.first,
0135                     "client_no_context_takeover"))
0136                 {
0137                     if(offer.client_no_context_takeover)
0138                     {
0139                         // The negotiation offer contains multiple
0140                         // extension parameters with the same name.
0141                         //
0142                         return; // MUST decline
0143                     }
0144                     if(! param.second.empty())
0145                     {
0146                         // The negotiation offer contains an
0147                         // extension parameter with an invalid value.
0148                         //
0149                         return; // MUST decline
0150                     }
0151                     offer.client_no_context_takeover = true;
0152                 }
0153                 else
0154                 {
0155                     // The negotiation offer contains an extension
0156                     // parameter not defined for use in an offer.
0157                     //
0158                     return; // MUST decline
0159                 }
0160             }
0161             offer.accept = true;
0162             return;
0163         }
0164     }
0165 }
0166 
0167 static_string<512>
0168 pmd_write_impl(pmd_offer const& offer)
0169 {
0170     static_string<512> s = "permessage-deflate";
0171     if(offer.server_max_window_bits != 0)
0172     {
0173         if(offer.server_max_window_bits != -1)
0174         {
0175             s += "; server_max_window_bits=";
0176             s += to_static_string(
0177                 offer.server_max_window_bits);
0178         }
0179         else
0180         {
0181             s += "; server_max_window_bits";
0182         }
0183     }
0184     if(offer.client_max_window_bits != 0)
0185     {
0186         if(offer.client_max_window_bits != -1)
0187         {
0188             s += "; client_max_window_bits=";
0189             s += to_static_string(
0190                 offer.client_max_window_bits);
0191         }
0192         else
0193         {
0194             s += "; client_max_window_bits";
0195         }
0196     }
0197     if(offer.server_no_context_takeover)
0198     {
0199         s += "; server_no_context_takeover";
0200     }
0201     if(offer.client_no_context_takeover)
0202     {
0203         s += "; client_no_context_takeover";
0204     }
0205 
0206     return s;
0207 }
0208 
0209 static_string<512>
0210 pmd_negotiate_impl(
0211     pmd_offer& config,
0212     pmd_offer const& offer,
0213     permessage_deflate const& o)
0214 {
0215     static_string<512> s = "permessage-deflate";
0216 
0217     config.server_no_context_takeover =
0218         offer.server_no_context_takeover ||
0219             o.server_no_context_takeover;
0220     if(config.server_no_context_takeover)
0221         s += "; server_no_context_takeover";
0222 
0223     config.client_no_context_takeover =
0224         o.client_no_context_takeover ||
0225             offer.client_no_context_takeover;
0226     if(config.client_no_context_takeover)
0227         s += "; client_no_context_takeover";
0228 
0229     if(offer.server_max_window_bits != 0)
0230         config.server_max_window_bits = (std::min)(
0231             offer.server_max_window_bits,
0232                 o.server_max_window_bits);
0233     else
0234         config.server_max_window_bits =
0235             o.server_max_window_bits;
0236     if(config.server_max_window_bits < 15)
0237     {
0238         // ZLib's deflateInit silently treats 8 as
0239         // 9 due to a bug, so prevent 8 from being used.
0240         //
0241         if(config.server_max_window_bits < 9)
0242             config.server_max_window_bits = 9;
0243 
0244         s += "; server_max_window_bits=";
0245         s += to_static_string(
0246             config.server_max_window_bits);
0247     }
0248 
0249     switch(offer.client_max_window_bits)
0250     {
0251     case -1:
0252         // extension parameter is present with no value
0253         config.client_max_window_bits =
0254             o.client_max_window_bits;
0255         if(config.client_max_window_bits < 15)
0256         {
0257             s += "; client_max_window_bits=";
0258             s += to_static_string(
0259                 config.client_max_window_bits);
0260         }
0261         break;
0262 
0263     case 0:
0264         /*  extension parameter is absent.
0265 
0266             If a received extension negotiation offer doesn't have the
0267             "client_max_window_bits" extension parameter, the corresponding
0268             extension negotiation response to the offer MUST NOT include the
0269             "client_max_window_bits" extension parameter.
0270         */
0271         if(o.client_max_window_bits == 15)
0272             config.client_max_window_bits = 15;
0273         else
0274             config.accept = false;
0275         break;
0276 
0277     default:
0278         // extension parameter has value in [8..15]
0279         config.client_max_window_bits = (std::min)(
0280             o.client_max_window_bits,
0281                 offer.client_max_window_bits);
0282         s += "; client_max_window_bits=";
0283         s += to_static_string(
0284             config.client_max_window_bits);
0285         break;
0286     }
0287 
0288     return s;
0289 }
0290 
0291 void
0292 pmd_normalize(pmd_offer& offer)
0293 {
0294     if(offer.accept)
0295     {
0296         if( offer.server_max_window_bits == 0)
0297             offer.server_max_window_bits = 15;
0298 
0299         if( offer.client_max_window_bits ==  0 ||
0300             offer.client_max_window_bits == -1)
0301             offer.client_max_window_bits = 15;
0302     }
0303 }
0304 
0305 } // detail
0306 } // websocket
0307 } // beast
0308 } // boost
0309 
0310 #endif // BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP