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_STREAM_BASE_HPP
9 #define BEAST_WEBSOCKET_DETAIL_STREAM_BASE_HPP
11 #include <beast/websocket/error.hpp>
12 #include <beast/websocket/option.hpp>
13 #include <beast/websocket/rfc6455.hpp>
14 #include <beast/websocket/detail/decorator.hpp>
15 #include <beast/websocket/detail/frame.hpp>
16 #include <beast/websocket/detail/invokable.hpp>
17 #include <beast/websocket/detail/mask.hpp>
18 #include <beast/websocket/detail/pmd_extension.hpp>
19 #include <beast/websocket/detail/utf8_checker.hpp>
20 #include <beast/http/message.hpp>
21 #include <beast/http/string_body.hpp>
22 #include <beast/zlib/deflate_stream.hpp>
23 #include <beast/zlib/inflate_stream.hpp>
24 #include <boost/asio/error.hpp>
25 #include <boost/assert.hpp>
33 /// Identifies the role of a WebSockets stream.
36 /// Stream is operating as a client.
39 /// Stream is operating as a server.
43 //------------------------------------------------------------------------------
48 friend class frame_test;
52 detail::maskgen maskgen_; // source of mask keys
53 decorator_type d_; // adorns http messages
54 bool keep_alive_ = false; // close on failed upgrade
55 std::size_t rd_msg_max_ =
56 16 * 1024 * 1024; // max message size
57 bool wr_autofrag_ = true; // auto fragment
58 std::size_t wr_buf_size_ = 4096; // write buffer size
59 std::size_t rd_buf_size_ = 4096; // read buffer size
60 opcode wr_opcode_ = opcode::text; // outgoing message type
61 ping_cb ping_cb_; // ping callback
62 role_type role_; // server or client
63 bool failed_; // the connection failed
65 bool wr_close_; // sent close frame
66 op* wr_block_; // op currenly writing
68 ping_data* ping_data_; // where to put the payload
69 invokable rd_op_; // read parking
70 invokable wr_op_; // write parking
71 invokable ping_op_; // ping parking
72 close_reason cr_; // set from received close frame
74 // State information for the message being received
78 // opcode of current message being read
81 // `true` if the next frame is a continuation.
84 // Checks that test messages are valid utf8
85 detail::utf8_checker utf8;
87 // Size of the current message so far.
90 // Size of the read buffer.
91 // This gets set to the read buffer size option at the
92 // beginning of sending a message, so that the option can be
93 // changed mid-send without affecting the current message.
96 // The read buffer. Used for compression and masking.
97 std::unique_ptr<std::uint8_t[]> buf;
102 // State information for the message being sent
106 // `true` if next frame is a continuation,
107 // `false` if next frame starts a new message
110 // `true` if this message should be auto-fragmented
111 // This gets set to the auto-fragment option at the beginning
112 // of sending a message, so that the option can be changed
113 // mid-send without affecting the current message.
116 // `true` if this message should be compressed.
117 // This gets set to the compress option at the beginning of
118 // of sending a message, so that the option can be changed
119 // mid-send without affecting the current message.
122 // Size of the write buffer.
123 // This gets set to the write buffer size option at the
124 // beginning of sending a message, so that the option can be
125 // changed mid-send without affecting the current message.
126 std::size_t buf_size;
128 // The write buffer. Used for compression and masking.
129 // The buffer is allocated or reallocated at the beginning of
130 // sending a message.
131 std::unique_ptr<std::uint8_t[]> buf;
136 // State information for the permessage-deflate extension
139 // `true` if current read message is compressed
142 zlib::deflate_stream zo;
143 zlib::inflate_stream zi;
146 // If not engaged, then permessage-deflate is not
147 // enabled for the currently active session.
148 std::unique_ptr<pmd_t> pmd_;
150 // Local options for permessage-deflate
151 permessage_deflate pmd_opts_;
153 // Offer for clients, negotiated result for servers
154 pmd_offer pmd_config_;
156 stream_base(stream_base&&) = default;
157 stream_base(stream_base const&) = delete;
158 stream_base& operator=(stream_base&&) = default;
159 stream_base& operator=(stream_base const&) = delete;
162 : d_(detail::default_decorator{})
166 template<class = void>
168 open(role_type role);
170 template<class = void>
174 template<class DynamicBuffer>
176 read_fh1(detail::frame_header& fh,
177 DynamicBuffer& db, close_code& code);
179 template<class DynamicBuffer>
181 read_fh2(detail::frame_header& fh,
182 DynamicBuffer& db, close_code& code);
184 // Called before receiving the first frame of each message
185 template<class = void>
189 // Called before sending the first frame of each message
191 template<class = void>
195 template<class DynamicBuffer>
197 write_close(DynamicBuffer& db, close_reason const& rc);
199 template<class DynamicBuffer>
201 write_ping(DynamicBuffer& db, opcode op, ping_data const& data);
209 // VFALCO TODO analyze and remove dupe code in reset()
214 wr_block_ = nullptr; // should be nullptr on close anyway
215 ping_data_ = nullptr; // should be nullptr on close anyway
220 if(((role_ == role_type::client && pmd_opts_.client_enable) ||
221 (role_ == role_type::server && pmd_opts_.server_enable)) &&
224 pmd_normalize(pmd_config_);
225 pmd_.reset(new pmd_t);
226 if(role_ == role_type::client)
229 pmd_config_.server_max_window_bits);
232 pmd_config_.client_max_window_bits,
234 zlib::Strategy::normal);
239 pmd_config_.client_max_window_bits);
242 pmd_config_.server_max_window_bits,
244 zlib::Strategy::normal);
259 // Read fixed frame header from buffer
260 // Requires at least 2 bytes
262 template<class DynamicBuffer>
265 read_fh1(detail::frame_header& fh,
266 DynamicBuffer& db, close_code& code)
268 using boost::asio::buffer;
269 using boost::asio::buffer_copy;
270 using boost::asio::buffer_size;
278 BOOST_ASSERT(buffer_size(db.data()) >= sizeof(b));
279 db.consume(buffer_copy(buffer(b), db.data()));
281 fh.len = b[1] & 0x7f;
284 case 126: need = 2; break;
285 case 127: need = 8; break;
289 fh.mask = (b[1] & 0x80) != 0;
292 fh.op = static_cast<opcode>(b[0] & 0x0f);
293 fh.fin = (b[0] & 0x80) != 0;
294 fh.rsv1 = (b[0] & 0x40) != 0;
295 fh.rsv2 = (b[0] & 0x20) != 0;
296 fh.rsv3 = (b[0] & 0x10) != 0;
303 // new data frame when continuation expected
304 return err(close_code::protocol_error);
306 if((fh.rsv1 && ! pmd_) ||
309 // reserved bits not cleared
310 return err(close_code::protocol_error);
313 pmd_->rd_set = fh.rsv1;
319 // continuation without an active message
320 return err(close_code::protocol_error);
322 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
324 // reserved bits not cleared
325 return err(close_code::protocol_error);
330 if(is_reserved(fh.op))
333 return err(close_code::protocol_error);
337 // fragmented control message
338 return err(close_code::protocol_error);
342 // invalid length for control message
343 return err(close_code::protocol_error);
345 if(fh.rsv1 || fh.rsv2 || fh.rsv3)
347 // reserved bits not cleared
348 return err(close_code::protocol_error);
352 // unmasked frame from client
353 if(role_ == role_type::server && ! fh.mask)
355 code = close_code::protocol_error;
358 // masked frame from server
359 if(role_ == role_type::client && fh.mask)
361 code = close_code::protocol_error;
364 code = close_code::none;
368 // Decode variable frame header from buffer
370 template<class DynamicBuffer>
373 read_fh2(detail::frame_header& fh,
374 DynamicBuffer& db, close_code& code)
376 using boost::asio::buffer;
377 using boost::asio::buffer_copy;
378 using boost::asio::buffer_size;
379 using namespace boost::endian;
385 BOOST_ASSERT(buffer_size(db.data()) >= sizeof(b));
386 db.consume(buffer_copy(buffer(b), db.data()));
387 fh.len = big_uint16_to_native(&b[0]);
388 // length not canonical
391 code = close_code::protocol_error;
399 BOOST_ASSERT(buffer_size(db.data()) >= sizeof(b));
400 db.consume(buffer_copy(buffer(b), db.data()));
401 fh.len = big_uint64_to_native(&b[0]);
402 // length not canonical
405 code = close_code::protocol_error;
414 BOOST_ASSERT(buffer_size(db.data()) >= sizeof(b));
415 db.consume(buffer_copy(buffer(b), db.data()));
416 fh.key = little_uint32_to_native(&b[0]);
420 // initialize this otherwise operator== breaks
423 if(! is_control(fh.op))
425 if(fh.op != opcode::cont)
432 if(rd_.size > (std::numeric_limits<
433 std::uint64_t>::max)() - fh.len)
435 code = close_code::too_big;
441 code = close_code::none;
449 // Maintain the read buffer
452 if(! rd_.buf || rd_.buf_size != rd_buf_size_)
454 rd_.buf_size = rd_buf_size_;
455 rd_.buf.reset(new std::uint8_t[rd_.buf_size]);
465 wr_.autofrag = wr_autofrag_;
466 wr_.compress = static_cast<bool>(pmd_);
468 // Maintain the write buffer
470 role_ == detail::role_type::client)
472 if(! wr_.buf || wr_.buf_size != wr_buf_size_)
474 wr_.buf_size = wr_buf_size_;
475 wr_.buf.reset(new std::uint8_t[wr_.buf_size]);
480 wr_.buf_size = wr_buf_size_;
485 template<class DynamicBuffer>
488 write_close(DynamicBuffer& db, close_reason const& cr)
490 using namespace boost::endian;
492 fh.op = opcode::close;
497 fh.len = cr.code == close_code::none ?
498 0 : 2 + cr.reason.size();
499 fh.mask = role_ == detail::role_type::client;
502 detail::write(db, fh);
503 if(cr.code != close_code::none)
505 detail::prepared_key key;
507 detail::prepare_key(key, fh.key);
510 ::new(&b[0]) big_uint16_buf_t{
511 (std::uint16_t)cr.code};
512 auto d = db.prepare(2);
513 boost::asio::buffer_copy(d,
514 boost::asio::buffer(b));
516 detail::mask_inplace(d, key);
519 if(! cr.reason.empty())
521 auto d = db.prepare(cr.reason.size());
522 boost::asio::buffer_copy(d,
523 boost::asio::const_buffer(
524 cr.reason.data(), cr.reason.size()));
526 detail::mask_inplace(d, key);
527 db.commit(cr.reason.size());
532 template<class DynamicBuffer>
536 DynamicBuffer& db, opcode op, ping_data const& data)
544 fh.len = data.size();
545 fh.mask = role_ == role_type::client;
548 detail::write(db, fh);
551 detail::prepared_key key;
553 detail::prepare_key(key, fh.key);
554 auto d = db.prepare(data.size());
555 boost::asio::buffer_copy(d,
556 boost::asio::const_buffers_1(
557 data.data(), data.size()));
559 detail::mask_inplace(d, key);
560 db.commit(data.size());