frame.hpp 7.0 KB

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