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