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