1//
2// Copyright (c) 2016-2019 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_IMPL_STREAM_HPP
11#define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_HPP
12
13#include <boost/beast/core/buffer_traits.hpp>
14#include <boost/beast/websocket/rfc6455.hpp>
15#include <boost/beast/websocket/teardown.hpp>
16#include <boost/beast/websocket/detail/hybi13.hpp>
17#include <boost/beast/websocket/detail/mask.hpp>
18#include <boost/beast/websocket/impl/stream_impl.hpp>
19#include <boost/beast/version.hpp>
20#include <boost/beast/http/read.hpp>
21#include <boost/beast/http/write.hpp>
22#include <boost/beast/http/rfc7230.hpp>
23#include <boost/beast/core/buffers_cat.hpp>
24#include <boost/beast/core/buffers_prefix.hpp>
25#include <boost/beast/core/buffers_suffix.hpp>
26#include <boost/beast/core/flat_static_buffer.hpp>
27#include <boost/beast/core/detail/clamp.hpp>
28#include <boost/asio/steady_timer.hpp>
29#include <boost/assert.hpp>
30#include <boost/make_shared.hpp>
31#include <boost/throw_exception.hpp>
32#include <algorithm>
33#include <chrono>
34#include <memory>
35#include <stdexcept>
36#include <utility>
37
38namespace boost {
39namespace beast {
40namespace websocket {
41
42template<class NextLayer, bool deflateSupported>
43stream<NextLayer, deflateSupported>::
44~stream()
45{
46 if(impl_)
47 impl_->remove();
48}
49
50template<class NextLayer, bool deflateSupported>
51template<class... Args>
52stream<NextLayer, deflateSupported>::
53stream(Args&&... args)
54 : impl_(boost::make_shared<impl_type>(
55 std::forward<Args>(args)...))
56{
57 BOOST_ASSERT(impl_->rd_buf.max_size() >=
58 max_control_frame_size);
59}
60
61template<class NextLayer, bool deflateSupported>
62template<class Other>
63stream<NextLayer, deflateSupported>::
64stream(stream<Other> && other)
65 : impl_(boost::make_shared<impl_type>(std::move(other.next_layer())))
66{
67}
68
69
70template<class NextLayer, bool deflateSupported>
71auto
72stream<NextLayer, deflateSupported>::
73get_executor() noexcept ->
74 executor_type
75{
76 return impl_->stream().get_executor();
77}
78
79template<class NextLayer, bool deflateSupported>
80auto
81stream<NextLayer, deflateSupported>::
82next_layer() noexcept ->
83 next_layer_type&
84{
85 return impl_->stream();
86}
87
88template<class NextLayer, bool deflateSupported>
89auto
90stream<NextLayer, deflateSupported>::
91next_layer() const noexcept ->
92 next_layer_type const&
93{
94 return impl_->stream();
95}
96
97template<class NextLayer, bool deflateSupported>
98bool
99stream<NextLayer, deflateSupported>::
100is_open() const noexcept
101{
102 return impl_->status_ == status::open;
103}
104
105template<class NextLayer, bool deflateSupported>
106bool
107stream<NextLayer, deflateSupported>::
108got_binary() const noexcept
109{
110 return impl_->rd_op == detail::opcode::binary;
111}
112
113template<class NextLayer, bool deflateSupported>
114bool
115stream<NextLayer, deflateSupported>::
116is_message_done() const noexcept
117{
118 return impl_->rd_done;
119}
120
121template<class NextLayer, bool deflateSupported>
122close_reason const&
123stream<NextLayer, deflateSupported>::
124reason() const noexcept
125{
126 return impl_->cr;
127}
128
129template<class NextLayer, bool deflateSupported>
130std::size_t
131stream<NextLayer, deflateSupported>::
132read_size_hint(
133 std::size_t initial_size) const
134{
135 return impl_->read_size_hint_pmd(
136 initial_size, impl_->rd_done,
137 impl_->rd_remain, impl_->rd_fh);
138}
139
140template<class NextLayer, bool deflateSupported>
141template<class DynamicBuffer, class>
142std::size_t
143stream<NextLayer, deflateSupported>::
144read_size_hint(DynamicBuffer& buffer) const
145{
146 static_assert(
147 net::is_dynamic_buffer<DynamicBuffer>::value,
148 "DynamicBuffer type requirements not met");
149 return impl_->read_size_hint_db(buffer);
150}
151
152//------------------------------------------------------------------------------
153//
154// Settings
155//
156//------------------------------------------------------------------------------
157
158// decorator
159
160template<class NextLayer, bool deflateSupported>
161void
162stream<NextLayer, deflateSupported>::
163set_option(decorator opt)
164{
165 impl_->decorator_opt = std::move(opt.d_);
166}
167
168// timeout
169
170template<class NextLayer, bool deflateSupported>
171void
172stream<NextLayer, deflateSupported>::
173get_option(timeout& opt)
174{
175 opt = impl_->timeout_opt;
176}
177
178template<class NextLayer, bool deflateSupported>
179void
180stream<NextLayer, deflateSupported>::
181set_option(timeout const& opt)
182{
183 impl_->set_option(opt);
184}
185
186//
187
188template<class NextLayer, bool deflateSupported>
189void
190stream<NextLayer, deflateSupported>::
191set_option(permessage_deflate const& o)
192{
193 impl_->set_option_pmd(o);
194}
195
196template<class NextLayer, bool deflateSupported>
197void
198stream<NextLayer, deflateSupported>::
199get_option(permessage_deflate& o)
200{
201 impl_->get_option_pmd(o);
202}
203
204template<class NextLayer, bool deflateSupported>
205void
206stream<NextLayer, deflateSupported>::
207auto_fragment(bool value)
208{
209 impl_->wr_frag_opt = value;
210}
211
212template<class NextLayer, bool deflateSupported>
213bool
214stream<NextLayer, deflateSupported>::
215auto_fragment() const
216{
217 return impl_->wr_frag_opt;
218}
219
220template<class NextLayer, bool deflateSupported>
221void
222stream<NextLayer, deflateSupported>::
223binary(bool value)
224{
225 impl_->wr_opcode = value ?
226 detail::opcode::binary :
227 detail::opcode::text;
228}
229
230template<class NextLayer, bool deflateSupported>
231bool
232stream<NextLayer, deflateSupported>::
233binary() const
234{
235 return impl_->wr_opcode == detail::opcode::binary;
236}
237
238template<class NextLayer, bool deflateSupported>
239void
240stream<NextLayer, deflateSupported>::
241control_callback(std::function<
242 void(frame_type, string_view)> cb)
243{
244 impl_->ctrl_cb = std::move(cb);
245}
246
247template<class NextLayer, bool deflateSupported>
248void
249stream<NextLayer, deflateSupported>::
250control_callback()
251{
252 impl_->ctrl_cb = {};
253}
254
255template<class NextLayer, bool deflateSupported>
256void
257stream<NextLayer, deflateSupported>::
258read_message_max(std::size_t amount)
259{
260 impl_->rd_msg_max = amount;
261}
262
263template<class NextLayer, bool deflateSupported>
264std::size_t
265stream<NextLayer, deflateSupported>::
266read_message_max() const
267{
268 return impl_->rd_msg_max;
269}
270
271template<class NextLayer, bool deflateSupported>
272void
273stream<NextLayer, deflateSupported>::
274secure_prng(bool value)
275{
276 this->impl_->secure_prng_ = value;
277}
278
279template<class NextLayer, bool deflateSupported>
280void
281stream<NextLayer, deflateSupported>::
282write_buffer_bytes(std::size_t amount)
283{
284 if(amount < 8)
285 BOOST_THROW_EXCEPTION(std::invalid_argument{
286 "write buffer size underflow"});
287 impl_->wr_buf_opt = amount;
288}
289
290template<class NextLayer, bool deflateSupported>
291std::size_t
292stream<NextLayer, deflateSupported>::
293write_buffer_bytes() const
294{
295 return impl_->wr_buf_opt;
296}
297
298template<class NextLayer, bool deflateSupported>
299void
300stream<NextLayer, deflateSupported>::
301text(bool value)
302{
303 impl_->wr_opcode = value ?
304 detail::opcode::text :
305 detail::opcode::binary;
306}
307
308template<class NextLayer, bool deflateSupported>
309bool
310stream<NextLayer, deflateSupported>::
311text() const
312{
313 return impl_->wr_opcode == detail::opcode::text;
314}
315
316template<class NextLayer, bool deflateSupported>
317void
318stream<NextLayer, deflateSupported>::
319compress(bool value)
320{
321 impl_->wr_compress_opt = value;
322}
323
324template<class NextLayer, bool deflateSupported>
325bool
326stream<NextLayer, deflateSupported>::
327compress() const
328{
329 return impl_->wr_compress_opt;
330}
331
332//------------------------------------------------------------------------------
333
334// _Fail the WebSocket Connection_
335template<class NextLayer, bool deflateSupported>
336void
337stream<NextLayer, deflateSupported>::
338do_fail(
339 std::uint16_t code, // if set, send a close frame first
340 error_code ev, // error code to use upon success
341 error_code& ec) // set to the error, else set to ev
342{
343 BOOST_ASSERT(ev);
344 impl_->change_status(status::closing);
345 if(code != close_code::none && ! impl_->wr_close)
346 {
347 impl_->wr_close = true;
348 detail::frame_buffer fb;
349 impl_->template write_close<
350 flat_static_buffer_base>(fb, code);
351 net::write(impl_->stream(), fb.data(), ec);
352 if(impl_->check_stop_now(ec))
353 return;
354 }
355 using beast::websocket::teardown;
356 teardown(impl_->role, impl_->stream(), ec);
357 if(ec == net::error::eof)
358 {
359 // Rationale:
360 // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
361 ec = {};
362 }
363 if(! ec)
364 {
365 BOOST_BEAST_ASSIGN_EC(ec, ev);
366 }
367 if(ec && ec != error::closed)
368 impl_->change_status(status::failed);
369 else
370 impl_->change_status(status::closed);
371 impl_->close();
372}
373
374} // websocket
375} // beast
376} // boost
377
378#endif
379

source code of boost/libs/beast/include/boost/beast/websocket/impl/stream.hpp