ゴミ箱
frame.hpp
Go to the documentation of this file.
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 
10 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
11 #define BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
12 
18 #include <boost/asio/buffer.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/endian/buffers.hpp>
21 #include <cstdint>
22 
23 namespace boost {
24 namespace beast {
25 namespace websocket {
26 namespace detail {
27 
28 inline
29 std::uint16_t
30 big_uint16_to_native(void const* buf)
31 {
32  auto const p = reinterpret_cast<
33  std::uint8_t const*>(buf);
34  return (p[0]<<8) + p[1];
35 }
36 
37 inline
38 std::uint64_t
39 big_uint64_to_native(void const* buf)
40 {
41  auto const p = reinterpret_cast<
42  std::uint8_t const*>(buf);
43  return
44  (static_cast<std::uint64_t>(p[0])<<56) +
45  (static_cast<std::uint64_t>(p[1])<<48) +
46  (static_cast<std::uint64_t>(p[2])<<40) +
47  (static_cast<std::uint64_t>(p[3])<<32) +
48  (static_cast<std::uint64_t>(p[4])<<24) +
49  (static_cast<std::uint64_t>(p[5])<<16) +
50  (static_cast<std::uint64_t>(p[6])<< 8) +
51  p[7];
52 }
53 
54 inline
55 std::uint32_t
56 little_uint32_to_native(void const* buf)
57 {
58  auto const p = reinterpret_cast<
59  std::uint8_t const*>(buf);
60  return
61  p[0] +
62  (static_cast<std::uint32_t>(p[1])<< 8) +
63  (static_cast<std::uint32_t>(p[2])<<16) +
64  (static_cast<std::uint32_t>(p[3])<<24);
65 }
66 
67 inline
68 void
69 native_to_little_uint32(std::uint32_t v, void* buf)
70 {
71  auto p = reinterpret_cast<std::uint8_t*>(buf);
72  p[0] = v & 0xff;
73  p[1] = (v >> 8) & 0xff;
74  p[2] = (v >> 16) & 0xff;
75  p[3] = (v >> 24) & 0xff;
76 }
77 
79 enum class opcode : std::uint8_t
80 {
81  cont = 0,
82  text = 1,
83  binary = 2,
84  rsv3 = 3,
85  rsv4 = 4,
86  rsv5 = 5,
87  rsv6 = 6,
88  rsv7 = 7,
89  close = 8,
90  ping = 9,
91  pong = 10,
92  crsvb = 11,
93  crsvc = 12,
94  crsvd = 13,
95  crsve = 14,
96  crsvf = 15
97 };
98 
99 // Contents of a WebSocket frame header
101 {
102  std::uint64_t len;
103  std::uint32_t key;
105  bool fin : 1;
106  bool mask : 1;
107  bool rsv1 : 1;
108  bool rsv2 : 1;
109  bool rsv3 : 1;
110 };
111 
112 // holds the largest possible frame header
113 using fh_buffer =
115 
116 // holds the largest possible control frame
117 using frame_buffer =
119 
120 inline
121 bool constexpr
123 {
124  return
125  (op >= opcode::rsv3 && op <= opcode::rsv7) ||
126  (op >= opcode::crsvb && op <= opcode::crsvf);
127 }
128 
129 inline
130 bool constexpr
132 {
133  return op <= opcode::crsvf;
134 }
135 
136 inline
137 bool constexpr
139 {
140  return op >= opcode::close;
141 }
142 
143 inline
144 bool
145 is_valid_close_code(std::uint16_t v)
146 {
147  switch(v)
148  {
149  case close_code::normal: // 1000
150  case close_code::going_away: // 1001
151  case close_code::protocol_error: // 1002
152  case close_code::unknown_data: // 1003
153  case close_code::bad_payload: // 1007
154  case close_code::policy_error: // 1008
155  case close_code::too_big: // 1009
156  case close_code::needs_extension: // 1010
157  case close_code::internal_error: // 1011
158  case close_code::service_restart: // 1012
159  case close_code::try_again_later: // 1013
160  return true;
161 
162  // explicitly reserved
163  case close_code::reserved1: // 1004
164  case close_code::no_status: // 1005
165  case close_code::abnormal: // 1006
166  case close_code::reserved2: // 1014
167  case close_code::reserved3: // 1015
168  return false;
169  }
170  // reserved
171  if(v >= 1016 && v <= 2999)
172  return false;
173  // not used
174  if(v <= 999)
175  return false;
176  return true;
177 }
178 
179 //------------------------------------------------------------------------------
180 
181 // Write frame header to dynamic buffer
182 //
183 template<class DynamicBuffer>
184 void
185 write(DynamicBuffer& db, frame_header const& fh)
186 {
187  using boost::asio::buffer;
188  using boost::asio::buffer_copy;
189  using namespace boost::endian;
190  std::size_t n;
191  std::uint8_t b[14];
192  b[0] = (fh.fin ? 0x80 : 0x00) | static_cast<std::uint8_t>(fh.op);
193  if(fh.rsv1)
194  b[0] |= 0x40;
195  if(fh.rsv2)
196  b[0] |= 0x20;
197  if(fh.rsv3)
198  b[0] |= 0x10;
199  b[1] = fh.mask ? 0x80 : 0x00;
200  if(fh.len <= 125)
201  {
202  b[1] |= fh.len;
203  n = 2;
204  }
205  else if(fh.len <= 65535)
206  {
207  b[1] |= 126;
208  ::new(&b[2]) big_uint16_buf_t{
209  (std::uint16_t)fh.len};
210  n = 4;
211  }
212  else
213  {
214  b[1] |= 127;
215  ::new(&b[2]) big_uint64_buf_t{fh.len};
216  n = 10;
217  }
218  if(fh.mask)
219  {
220  native_to_little_uint32(fh.key, &b[n]);
221  n += 4;
222  }
223  db.commit(buffer_copy(
224  db.prepare(n), buffer(b)));
225 }
226 
227 // Read data from buffers
228 // This is for ping and pong payloads
229 //
230 template<class Buffers>
231 void
232 read_ping(ping_data& data, Buffers const& bs)
233 {
234  using boost::asio::buffer_copy;
235  using boost::asio::buffer_size;
236  using boost::asio::mutable_buffers_1;
237  BOOST_ASSERT(buffer_size(bs) <= data.max_size());
238  data.resize(buffer_size(bs));
239  buffer_copy(mutable_buffers_1{
240  data.data(), data.size()}, bs);
241 }
242 
243 // Read close_reason, return true on success
244 // This is for the close payload
245 //
246 template<class Buffers>
247 void
249  Buffers const& bs, close_code& code)
250 {
251  using boost::asio::buffer;
252  using boost::asio::buffer_copy;
253  using boost::asio::buffer_size;
254  using namespace boost::endian;
255  auto n = buffer_size(bs);
256  BOOST_ASSERT(n <= 125);
257  if(n == 0)
258  {
259  cr = close_reason{};
260  code = close_code::none;
261  return;
262  }
263  if(n == 1)
264  {
266  return;
267  }
269  {
270  std::uint8_t b[2];
271  buffer_copy(buffer(b), cb);
272  cr.code = big_uint16_to_native(&b[0]);
273  cb.consume(2);
274  n -= 2;
275  if(! is_valid_close_code(cr.code))
276  {
278  return;
279  }
280  }
281  if(n > 0)
282  {
283  cr.reason.resize(n);
284  buffer_copy(buffer(&cr.reason[0], n), cb);
285  if(! check_utf8(
286  cr.reason.data(), cr.reason.size()))
287  {
289  return;
290  }
291  }
292  else
293  {
294  cr.reason = "";
295  }
296  code = close_code::none;
297 }
298 
299 } // detail
300 } // websocket
301 } // beast
302 } // boost
303 
304 #endif
bool constexpr is_control(opcode op)
Definition: frame.hpp:138
The endpoint is going away, either because of a server failure or because the browser is navigating a...
Definition: rfc6455.hpp:73
bool rsv3
Definition: frame.hpp:109
The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is c...
Definition: rfc6455.hpp:100
reason_string reason
The optional utf8-encoded reason string.
Definition: rfc6455.hpp:166
Definition: async_result.hpp:20
bool rsv1
Definition: frame.hpp:107
size_type constexpr max_size() const
Returns the maximum number of characters that can be stored, excluding the null terminator.
Definition: static_string.hpp:470
bool is_valid_close_code(std::uint16_t v)
Definition: frame.hpp:145
void read_close(close_reason &cr, Buffers const &bs, close_code &code)
Definition: frame.hpp:248
The connection is being terminated because the endpoint received data of a type it cannot accept (for...
Definition: rfc6455.hpp:79
opcode op
Definition: frame.hpp:104
Definition: rfc6455.hpp:129
void write(DynamicBuffer &db, frame_header const &fh)
Definition: frame.hpp:185
std::uint32_t key
Definition: frame.hpp:103
Definition: rfc6455.hpp:160
The server is terminating the connection because it is restarting.
Definition: rfc6455.hpp:97
bool rsv2
Definition: frame.hpp:108
Definition: rfc6455.hpp:111
size_type size() const
Returns the number of characters, excluding the null terminator.
Definition: static_string.hpp:456
std::uint16_t code
The close code.
Definition: rfc6455.hpp:163
The server is terminating the connection because it encountered an unexpected condition that prevente...
Definition: rfc6455.hpp:94
The client is terminating the connection because it expected the server to negotiate one or more exte...
Definition: rfc6455.hpp:91
bool constexpr is_valid(opcode op)
Definition: frame.hpp:131
void resize(std::size_t n)
Definition: static_string.ipp:461
void read_ping(ping_data &data, Buffers const &bs)
Definition: frame.hpp:232
The endpoint is terminating the connection because it received a message that violates its policy...
Definition: rfc6455.hpp:85
std::uint16_t big_uint16_to_native(void const *buf)
Definition: frame.hpp:30
std::uint64_t big_uint64_to_native(void const *buf)
Definition: frame.hpp:39
bool constexpr is_reserved(opcode op)
Definition: frame.hpp:122
The endpoint is terminating the connection because a message was received that contained inconsistent...
Definition: rfc6455.hpp:82
close_code
Definition: rfc6455.hpp:67
Definition: rfc6455.hpp:141
Definition: rfc6455.hpp:123
The endpoint is terminating the connection because a data frame was received that is too large...
Definition: rfc6455.hpp:88
std::uint32_t little_uint32_to_native(void const *buf)
Definition: frame.hpp:56
void native_to_little_uint32(std::uint32_t v, void *buf)
Definition: frame.hpp:69
The endpoint is terminating the connection due to a protocol error.
Definition: rfc6455.hpp:76
Normal closure; the connection successfully completed whatever purpose for which it was created...
Definition: rfc6455.hpp:70
Definition: static_string.hpp:44
Definition: rfc6455.hpp:135
Definition: rfc6455.hpp:117
void consume(std::size_t amount)
Definition: consuming_buffers.ipp:219
opcode
Definition: frame.hpp:79
std::uint64_t len
Definition: frame.hpp:102
CharT * data()
Returns a pointer to the first character of a string.
Definition: static_string.hpp:329
bool check_utf8(char const *p, std::size_t n)
Definition: utf8_checker.hpp:334
bool mask
Definition: frame.hpp:106