pmd_extension.ipp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
  10. #define BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
  11. #include <boost/beast/websocket/detail/pmd_extension.hpp>
  12. namespace boost {
  13. namespace beast {
  14. namespace websocket {
  15. namespace detail {
  16. int
  17. parse_bits(string_view s)
  18. {
  19. if(s.size() == 0)
  20. return -1;
  21. if(s.size() > 2)
  22. return -1;
  23. if(s[0] < '1' || s[0] > '9')
  24. return -1;
  25. unsigned i = 0;
  26. for(auto c : s)
  27. {
  28. if(c < '0' || c > '9')
  29. return -1;
  30. auto const i0 = i;
  31. i = 10 * i + (c - '0');
  32. if(i < i0)
  33. return -1;
  34. }
  35. return static_cast<int>(i);
  36. }
  37. // Parse permessage-deflate request fields
  38. //
  39. void
  40. pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
  41. {
  42. offer.accept = false;
  43. offer.server_max_window_bits= 0;
  44. offer.client_max_window_bits = 0;
  45. offer.server_no_context_takeover = false;
  46. offer.client_no_context_takeover = false;
  47. for(auto const& ext : list)
  48. {
  49. if(beast::iequals(ext.first, "permessage-deflate"))
  50. {
  51. for(auto const& param : ext.second)
  52. {
  53. if(beast::iequals(param.first,
  54. "server_max_window_bits"))
  55. {
  56. if(offer.server_max_window_bits != 0)
  57. {
  58. // The negotiation offer contains multiple
  59. // extension parameters with the same name.
  60. //
  61. return; // MUST decline
  62. }
  63. if(param.second.empty())
  64. {
  65. // The negotiation offer extension
  66. // parameter is missing the value.
  67. //
  68. return; // MUST decline
  69. }
  70. offer.server_max_window_bits =
  71. parse_bits(param.second);
  72. if( offer.server_max_window_bits < 8 ||
  73. offer.server_max_window_bits > 15)
  74. {
  75. // The negotiation offer contains an
  76. // extension parameter with an invalid value.
  77. //
  78. return; // MUST decline
  79. }
  80. }
  81. else if(beast::iequals(param.first,
  82. "client_max_window_bits"))
  83. {
  84. if(offer.client_max_window_bits != 0)
  85. {
  86. // The negotiation offer contains multiple
  87. // extension parameters with the same name.
  88. //
  89. return; // MUST decline
  90. }
  91. if(! param.second.empty())
  92. {
  93. offer.client_max_window_bits =
  94. parse_bits(param.second);
  95. if( offer.client_max_window_bits < 8 ||
  96. offer.client_max_window_bits > 15)
  97. {
  98. // The negotiation offer contains an
  99. // extension parameter with an invalid value.
  100. //
  101. return; // MUST decline
  102. }
  103. }
  104. else
  105. {
  106. offer.client_max_window_bits = -1;
  107. }
  108. }
  109. else if(beast::iequals(param.first,
  110. "server_no_context_takeover"))
  111. {
  112. if(offer.server_no_context_takeover)
  113. {
  114. // The negotiation offer contains multiple
  115. // extension parameters with the same name.
  116. //
  117. return; // MUST decline
  118. }
  119. if(! param.second.empty())
  120. {
  121. // The negotiation offer contains an
  122. // extension parameter with an invalid value.
  123. //
  124. return; // MUST decline
  125. }
  126. offer.server_no_context_takeover = true;
  127. }
  128. else if(beast::iequals(param.first,
  129. "client_no_context_takeover"))
  130. {
  131. if(offer.client_no_context_takeover)
  132. {
  133. // The negotiation offer contains multiple
  134. // extension parameters with the same name.
  135. //
  136. return; // MUST decline
  137. }
  138. if(! param.second.empty())
  139. {
  140. // The negotiation offer contains an
  141. // extension parameter with an invalid value.
  142. //
  143. return; // MUST decline
  144. }
  145. offer.client_no_context_takeover = true;
  146. }
  147. else
  148. {
  149. // The negotiation offer contains an extension
  150. // parameter not defined for use in an offer.
  151. //
  152. return; // MUST decline
  153. }
  154. }
  155. offer.accept = true;
  156. return;
  157. }
  158. }
  159. }
  160. static_string<512>
  161. pmd_write_impl(pmd_offer const& offer)
  162. {
  163. static_string<512> s = "permessage-deflate";
  164. if(offer.server_max_window_bits != 0)
  165. {
  166. if(offer.server_max_window_bits != -1)
  167. {
  168. s += "; server_max_window_bits=";
  169. s += to_static_string(
  170. offer.server_max_window_bits);
  171. }
  172. else
  173. {
  174. s += "; server_max_window_bits";
  175. }
  176. }
  177. if(offer.client_max_window_bits != 0)
  178. {
  179. if(offer.client_max_window_bits != -1)
  180. {
  181. s += "; client_max_window_bits=";
  182. s += to_static_string(
  183. offer.client_max_window_bits);
  184. }
  185. else
  186. {
  187. s += "; client_max_window_bits";
  188. }
  189. }
  190. if(offer.server_no_context_takeover)
  191. {
  192. s += "; server_no_context_takeover";
  193. }
  194. if(offer.client_no_context_takeover)
  195. {
  196. s += "; client_no_context_takeover";
  197. }
  198. return s;
  199. }
  200. static_string<512>
  201. pmd_negotiate_impl(
  202. pmd_offer& config,
  203. pmd_offer const& offer,
  204. permessage_deflate const& o)
  205. {
  206. static_string<512> s = "permessage-deflate";
  207. config.server_no_context_takeover =
  208. offer.server_no_context_takeover ||
  209. o.server_no_context_takeover;
  210. if(config.server_no_context_takeover)
  211. s += "; server_no_context_takeover";
  212. config.client_no_context_takeover =
  213. o.client_no_context_takeover ||
  214. offer.client_no_context_takeover;
  215. if(config.client_no_context_takeover)
  216. s += "; client_no_context_takeover";
  217. if(offer.server_max_window_bits != 0)
  218. config.server_max_window_bits = (std::min)(
  219. offer.server_max_window_bits,
  220. o.server_max_window_bits);
  221. else
  222. config.server_max_window_bits =
  223. o.server_max_window_bits;
  224. if(config.server_max_window_bits < 15)
  225. {
  226. // ZLib's deflateInit silently treats 8 as
  227. // 9 due to a bug, so prevent 8 from being used.
  228. //
  229. if(config.server_max_window_bits < 9)
  230. config.server_max_window_bits = 9;
  231. s += "; server_max_window_bits=";
  232. s += to_static_string(
  233. config.server_max_window_bits);
  234. }
  235. switch(offer.client_max_window_bits)
  236. {
  237. case -1:
  238. // extension parameter is present with no value
  239. config.client_max_window_bits =
  240. o.client_max_window_bits;
  241. if(config.client_max_window_bits < 15)
  242. {
  243. s += "; client_max_window_bits=";
  244. s += to_static_string(
  245. config.client_max_window_bits);
  246. }
  247. break;
  248. case 0:
  249. /* extension parameter is absent.
  250. If a received extension negotiation offer doesn't have the
  251. "client_max_window_bits" extension parameter, the corresponding
  252. extension negotiation response to the offer MUST NOT include the
  253. "client_max_window_bits" extension parameter.
  254. */
  255. if(o.client_max_window_bits == 15)
  256. config.client_max_window_bits = 15;
  257. else
  258. config.accept = false;
  259. break;
  260. default:
  261. // extension parameter has value in [8..15]
  262. config.client_max_window_bits = (std::min)(
  263. o.client_max_window_bits,
  264. offer.client_max_window_bits);
  265. s += "; client_max_window_bits=";
  266. s += to_static_string(
  267. config.client_max_window_bits);
  268. break;
  269. }
  270. return s;
  271. }
  272. void
  273. pmd_normalize(pmd_offer& offer)
  274. {
  275. if(offer.accept)
  276. {
  277. if( offer.server_max_window_bits == 0)
  278. offer.server_max_window_bits = 15;
  279. if( offer.client_max_window_bits == 0 ||
  280. offer.client_max_window_bits == -1)
  281. offer.client_max_window_bits = 15;
  282. }
  283. }
  284. } // detail
  285. } // websocket
  286. } // beast
  287. } // boost
  288. #endif // BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP