frame.hpp 5.5 KB

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