2 // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
8 #ifndef BEAST_WEBSOCKET_DETAIL_FRAME_HPP
9 #define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
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>
26 // Contents of a WebSocket frame header
39 // holds the largest possible frame header
41 static_streambuf_n<14>;
43 // holds the largest possible control frame
44 using frame_streambuf =
45 static_streambuf_n< 2 + 8 + 4 + 125 >;
49 is_reserved(opcode op)
52 (op >= opcode::rsv3 && op <= opcode::rsv7) ||
53 (op >= opcode::crsvb && op <= opcode::crsvf);
60 return op <= opcode::crsvf;
67 return op >= opcode::close;
72 is_valid_close_code(std::uint16_t v)
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
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
98 if(v >= 1016 && v <= 2999)
106 //------------------------------------------------------------------------------
108 // Write frame header to dynamic buffer
110 template<class DynamicBuffer>
112 write(DynamicBuffer& db, frame_header const& fh)
114 using boost::asio::buffer;
115 using boost::asio::buffer_copy;
116 using namespace boost::endian;
119 b[0] = (fh.fin ? 0x80 : 0x00) | static_cast<std::uint8_t>(fh.op);
126 b[1] = fh.mask ? 0x80 : 0x00;
132 else if(fh.len <= 65535)
135 ::new(&b[2]) big_uint16_buf_t{
136 (std::uint16_t)fh.len};
142 ::new(&b[2]) big_uint64_buf_t{fh.len};
147 native_to_little_uint32(fh.key, &b[n]);
150 db.commit(buffer_copy(
151 db.prepare(n), buffer(b)));
154 // Read data from buffers
155 // This is for ping and pong payloads
157 template<class Buffers>
159 read(ping_data& data, Buffers const& bs)
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);
170 // Read close_reason, return true on success
171 // This is for the close payload
173 template<class Buffers>
175 read(close_reason& cr,
176 Buffers const& bs, close_code& code)
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);
187 code = close_code::none;
192 code = close_code::protocol_error;
195 consuming_buffers<Buffers> cb(bs);
198 buffer_copy(buffer(b), cb);
199 cr.code = big_uint16_to_native(&b[0]);
202 if(! is_valid_close_code(cr.code))
204 code = close_code::protocol_error;
211 buffer_copy(buffer(&cr.reason[0], n), cb);
212 if(! detail::check_utf8(
213 cr.reason.data(), cr.reason.size()))
215 code = close_code::protocol_error;
223 code = close_code::none;