frame.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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_FRAME_HPP
  10. #define BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
  11. #include <boost/beast/core/buffer_traits.hpp>
  12. #include <boost/beast/websocket/error.hpp>
  13. #include <boost/beast/websocket/rfc6455.hpp>
  14. #include <boost/beast/websocket/detail/utf8_checker.hpp>
  15. #include <boost/beast/core/buffers_suffix.hpp>
  16. #include <boost/beast/core/flat_static_buffer.hpp>
  17. #include <boost/beast/core/static_string.hpp>
  18. #include <boost/asio/buffer.hpp>
  19. #include <boost/assert.hpp>
  20. // This is for <boost/endian/buffers.hpp>
  21. #if BOOST_WORKAROUND(BOOST_MSVC, > 0)
  22. # pragma warning (push)
  23. # pragma warning (disable: 4127) // conditional expression is constant
  24. #endif
  25. #include <boost/endian/buffers.hpp>
  26. #if BOOST_WORKAROUND(BOOST_MSVC, > 0)
  27. # pragma warning (pop)
  28. #endif
  29. #include <cstdint>
  30. namespace boost {
  31. namespace beast {
  32. namespace websocket {
  33. namespace detail {
  34. inline
  35. std::uint16_t
  36. big_uint16_to_native(void const* buf)
  37. {
  38. auto const p = static_cast<
  39. std::uint8_t const*>(buf);
  40. return (p[0]<<8) + p[1];
  41. }
  42. inline
  43. std::uint64_t
  44. big_uint64_to_native(void const* buf)
  45. {
  46. auto const p = static_cast<
  47. std::uint8_t const*>(buf);
  48. return
  49. (static_cast<std::uint64_t>(p[0])<<56) +
  50. (static_cast<std::uint64_t>(p[1])<<48) +
  51. (static_cast<std::uint64_t>(p[2])<<40) +
  52. (static_cast<std::uint64_t>(p[3])<<32) +
  53. (static_cast<std::uint64_t>(p[4])<<24) +
  54. (static_cast<std::uint64_t>(p[5])<<16) +
  55. (static_cast<std::uint64_t>(p[6])<< 8) +
  56. p[7];
  57. }
  58. inline
  59. std::uint32_t
  60. little_uint32_to_native(void const* buf)
  61. {
  62. auto const p = static_cast<
  63. std::uint8_t const*>(buf);
  64. return
  65. p[0] +
  66. (static_cast<std::uint32_t>(p[1])<< 8) +
  67. (static_cast<std::uint32_t>(p[2])<<16) +
  68. (static_cast<std::uint32_t>(p[3])<<24);
  69. }
  70. inline
  71. void
  72. native_to_little_uint32(std::uint32_t v, void* buf)
  73. {
  74. auto p = static_cast<std::uint8_t*>(buf);
  75. p[0] = v & 0xff;
  76. p[1] = (v >> 8) & 0xff;
  77. p[2] = (v >> 16) & 0xff;
  78. p[3] = (v >> 24) & 0xff;
  79. }
  80. // frame header opcodes
  81. enum class opcode : std::uint8_t
  82. {
  83. cont = 0,
  84. text = 1,
  85. binary = 2,
  86. rsv3 = 3,
  87. rsv4 = 4,
  88. rsv5 = 5,
  89. rsv6 = 6,
  90. rsv7 = 7,
  91. close = 8,
  92. ping = 9,
  93. pong = 10,
  94. crsvb = 11,
  95. crsvc = 12,
  96. crsvd = 13,
  97. crsve = 14,
  98. crsvf = 15
  99. };
  100. // Contents of a WebSocket frame header
  101. struct frame_header
  102. {
  103. std::uint64_t len;
  104. std::uint32_t key;
  105. opcode op;
  106. bool fin : 1;
  107. bool mask : 1;
  108. bool rsv1 : 1;
  109. bool rsv2 : 1;
  110. bool rsv3 : 1;
  111. };
  112. // holds the largest possible frame header
  113. using fh_buffer = flat_static_buffer<14>;
  114. // holds the largest possible control frame
  115. using frame_buffer =
  116. flat_static_buffer< 2 + 8 + 4 + 125 >;
  117. inline
  118. bool constexpr
  119. is_reserved(opcode op)
  120. {
  121. return
  122. (op >= opcode::rsv3 && op <= opcode::rsv7) ||
  123. (op >= opcode::crsvb && op <= opcode::crsvf);
  124. }
  125. inline
  126. bool constexpr
  127. is_valid(opcode op)
  128. {
  129. return op <= opcode::crsvf;
  130. }
  131. inline
  132. bool constexpr
  133. is_control(opcode op)
  134. {
  135. return op >= opcode::close;
  136. }
  137. inline
  138. bool
  139. is_valid_close_code(std::uint16_t v)
  140. {
  141. switch(v)
  142. {
  143. case close_code::normal: // 1000
  144. case close_code::going_away: // 1001
  145. case close_code::protocol_error: // 1002
  146. case close_code::unknown_data: // 1003
  147. case close_code::bad_payload: // 1007
  148. case close_code::policy_error: // 1008
  149. case close_code::too_big: // 1009
  150. case close_code::needs_extension: // 1010
  151. case close_code::internal_error: // 1011
  152. case close_code::service_restart: // 1012
  153. case close_code::try_again_later: // 1013
  154. return true;
  155. // explicitly reserved
  156. case close_code::reserved1: // 1004
  157. case close_code::no_status: // 1005
  158. case close_code::abnormal: // 1006
  159. case close_code::reserved2: // 1014
  160. case close_code::reserved3: // 1015
  161. return false;
  162. }
  163. // reserved
  164. if(v >= 1016 && v <= 2999)
  165. return false;
  166. // not used
  167. if(v <= 999)
  168. return false;
  169. return true;
  170. }
  171. //------------------------------------------------------------------------------
  172. // Write frame header to dynamic buffer
  173. //
  174. template<class DynamicBuffer>
  175. void
  176. write(DynamicBuffer& db, frame_header const& fh)
  177. {
  178. using namespace boost::endian;
  179. std::size_t n;
  180. std::uint8_t b[14];
  181. b[0] = (fh.fin ? 0x80 : 0x00) | static_cast<std::uint8_t>(fh.op);
  182. if(fh.rsv1)
  183. b[0] |= 0x40;
  184. if(fh.rsv2)
  185. b[0] |= 0x20;
  186. if(fh.rsv3)
  187. b[0] |= 0x10;
  188. b[1] = fh.mask ? 0x80 : 0x00;
  189. if(fh.len <= 125)
  190. {
  191. b[1] |= fh.len;
  192. n = 2;
  193. }
  194. else if(fh.len <= 65535)
  195. {
  196. b[1] |= 126;
  197. ::new(&b[2]) big_uint16_buf_t{
  198. (std::uint16_t)fh.len};
  199. n = 4;
  200. }
  201. else
  202. {
  203. b[1] |= 127;
  204. ::new(&b[2]) big_uint64_buf_t{fh.len};
  205. n = 10;
  206. }
  207. if(fh.mask)
  208. {
  209. native_to_little_uint32(fh.key, &b[n]);
  210. n += 4;
  211. }
  212. db.commit(net::buffer_copy(
  213. db.prepare(n), net::buffer(b)));
  214. }
  215. // Read data from buffers
  216. // This is for ping and pong payloads
  217. //
  218. template<class Buffers>
  219. void
  220. read_ping(ping_data& data, Buffers const& bs)
  221. {
  222. BOOST_ASSERT(buffer_bytes(bs) <= data.max_size());
  223. data.resize(buffer_bytes(bs));
  224. net::buffer_copy(net::mutable_buffer{
  225. data.data(), data.size()}, bs);
  226. }
  227. // Read close_reason, return true on success
  228. // This is for the close payload
  229. //
  230. template<class Buffers>
  231. void
  232. read_close(
  233. close_reason& cr,
  234. Buffers const& bs,
  235. error_code& ec)
  236. {
  237. using namespace boost::endian;
  238. auto n = buffer_bytes(bs);
  239. BOOST_ASSERT(n <= 125);
  240. if(n == 0)
  241. {
  242. cr = close_reason{};
  243. ec = {};
  244. return;
  245. }
  246. if(n == 1)
  247. {
  248. // invalid payload size == 1
  249. ec = error::bad_close_size;
  250. return;
  251. }
  252. buffers_suffix<Buffers> cb(bs);
  253. {
  254. std::uint8_t b[2];
  255. net::buffer_copy(net::buffer(b), cb);
  256. cr.code = big_uint16_to_native(&b[0]);
  257. cb.consume(2);
  258. n -= 2;
  259. if(! is_valid_close_code(cr.code))
  260. {
  261. // invalid close code
  262. ec = error::bad_close_code;
  263. return;
  264. }
  265. }
  266. if(n > 0)
  267. {
  268. cr.reason.resize(n);
  269. net::buffer_copy(
  270. net::buffer(&cr.reason[0], n), cb);
  271. if(! check_utf8(
  272. cr.reason.data(), cr.reason.size()))
  273. {
  274. // not valid utf-8
  275. ec = error::bad_close_payload;
  276. return;
  277. }
  278. }
  279. else
  280. {
  281. cr.reason = "";
  282. }
  283. ec = {};
  284. }
  285. } // detail
  286. } // websocket
  287. } // beast
  288. } // boost
  289. #endif