File indexing completed on 2025-01-18 09:29:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
0011 #define BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
0012
0013 #include <boost/beast/core/buffer_traits.hpp>
0014 #include <boost/beast/websocket/error.hpp>
0015 #include <boost/beast/websocket/rfc6455.hpp>
0016 #include <boost/beast/websocket/detail/utf8_checker.hpp>
0017 #include <boost/beast/core/flat_static_buffer.hpp>
0018 #include <boost/asio/buffer.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/endian/conversion.hpp>
0021 #include <cstdint>
0022
0023 namespace boost {
0024 namespace beast {
0025 namespace websocket {
0026 namespace detail {
0027
0028
0029 enum class opcode : std::uint8_t
0030 {
0031 cont = 0,
0032 text = 1,
0033 binary = 2,
0034 rsv3 = 3,
0035 rsv4 = 4,
0036 rsv5 = 5,
0037 rsv6 = 6,
0038 rsv7 = 7,
0039 close = 8,
0040 ping = 9,
0041 pong = 10,
0042 crsvb = 11,
0043 crsvc = 12,
0044 crsvd = 13,
0045 crsve = 14,
0046 crsvf = 15
0047 };
0048
0049
0050 struct frame_header
0051 {
0052 std::uint64_t len;
0053 std::uint32_t key;
0054 opcode op;
0055 bool fin : 1;
0056 bool mask : 1;
0057 bool rsv1 : 1;
0058 bool rsv2 : 1;
0059 bool rsv3 : 1;
0060 };
0061
0062
0063 using fh_buffer = flat_static_buffer<14>;
0064
0065
0066 using frame_buffer =
0067 flat_static_buffer< 2 + 8 + 4 + 125 >;
0068
0069 inline
0070 bool constexpr
0071 is_reserved(opcode op)
0072 {
0073 return
0074 (op >= opcode::rsv3 && op <= opcode::rsv7) ||
0075 (op >= opcode::crsvb && op <= opcode::crsvf);
0076 }
0077
0078 inline
0079 bool constexpr
0080 is_valid(opcode op)
0081 {
0082 return op <= opcode::crsvf;
0083 }
0084
0085 inline
0086 bool constexpr
0087 is_control(opcode op)
0088 {
0089 return op >= opcode::close;
0090 }
0091
0092 inline
0093 bool
0094 is_valid_close_code(std::uint16_t v)
0095 {
0096 switch(v)
0097 {
0098 case close_code::normal:
0099 case close_code::going_away:
0100 case close_code::protocol_error:
0101 case close_code::unknown_data:
0102 case close_code::bad_payload:
0103 case close_code::policy_error:
0104 case close_code::too_big:
0105 case close_code::needs_extension:
0106 case close_code::internal_error:
0107 case close_code::service_restart:
0108 case close_code::try_again_later:
0109 return true;
0110
0111
0112 case close_code::reserved1:
0113 case close_code::no_status:
0114 case close_code::abnormal:
0115 case close_code::reserved2:
0116 case close_code::reserved3:
0117 return false;
0118 }
0119
0120 if(v >= 1016 && v <= 2999)
0121 return false;
0122
0123 if(v <= 999)
0124 return false;
0125 return true;
0126 }
0127
0128
0129
0130
0131
0132 template<class DynamicBuffer>
0133 void
0134 write(DynamicBuffer& db, frame_header const& fh)
0135 {
0136 std::size_t n;
0137 std::uint8_t b[14];
0138 b[0] = (fh.fin ? 0x80 : 0x00) | static_cast<std::uint8_t>(fh.op);
0139 if(fh.rsv1)
0140 b[0] |= 0x40;
0141 if(fh.rsv2)
0142 b[0] |= 0x20;
0143 if(fh.rsv3)
0144 b[0] |= 0x10;
0145 b[1] = fh.mask ? 0x80 : 0x00;
0146 if(fh.len <= 125)
0147 {
0148 b[1] |= fh.len;
0149 n = 2;
0150 }
0151 else if(fh.len <= 65535)
0152 {
0153 b[1] |= 126;
0154 auto len_be = endian::native_to_big(
0155 static_cast<std::uint16_t>(fh.len));
0156 std::memcpy(&b[2], &len_be, sizeof(len_be));
0157 n = 4;
0158 }
0159 else
0160 {
0161 b[1] |= 127;
0162 auto len_be = endian::native_to_big(
0163 static_cast<std::uint64_t>(fh.len));
0164 std::memcpy(&b[2], &len_be, sizeof(len_be));
0165 n = 10;
0166 }
0167 if(fh.mask)
0168 {
0169 auto key_le = endian::native_to_little(
0170 static_cast<std::uint32_t>(fh.key));
0171 std::memcpy(&b[n], &key_le, sizeof(key_le));
0172 n += 4;
0173 }
0174 db.commit(net::buffer_copy(
0175 db.prepare(n), net::buffer(b)));
0176 }
0177
0178
0179
0180
0181 template<class Buffers>
0182 void
0183 read_ping(ping_data& data, Buffers const& bs)
0184 {
0185 BOOST_ASSERT(buffer_bytes(bs) <= data.max_size());
0186 data.resize(buffer_bytes(bs));
0187 net::buffer_copy(net::mutable_buffer{
0188 data.data(), data.size()}, bs);
0189 }
0190
0191
0192
0193
0194 template<class Buffers>
0195 void
0196 read_close(
0197 close_reason& cr,
0198 Buffers const& bs,
0199 error_code& ec)
0200 {
0201 auto const n = buffer_bytes(bs);
0202 BOOST_ASSERT(n <= 125);
0203 if(n == 0)
0204 {
0205 cr = close_reason{};
0206 ec = {};
0207 return;
0208 }
0209 if(n == 1)
0210 {
0211
0212 BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_size);
0213 return;
0214 }
0215
0216 std::uint16_t code_be;
0217 cr.reason.resize(n - 2);
0218 std::array<net::mutable_buffer, 2> out_bufs{{
0219 net::mutable_buffer(&code_be, sizeof(code_be)),
0220 net::mutable_buffer(&cr.reason[0], n - 2)}};
0221
0222 net::buffer_copy(out_bufs, bs);
0223
0224 cr.code = endian::big_to_native(code_be);
0225 if(! is_valid_close_code(cr.code))
0226 {
0227
0228 BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_code);
0229 return;
0230 }
0231
0232 if(n > 2 && !check_utf8(
0233 cr.reason.data(), cr.reason.size()))
0234 {
0235
0236 BOOST_BEAST_ASSIGN_EC(ec, error::bad_close_payload);
0237 return;
0238 }
0239 ec = {};
0240 }
0241
0242 }
0243 }
0244 }
0245 }
0246
0247 #endif