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 
38 namespace boost {
39 namespace beast {
40 namespace websocket {
41 
42 template<class NextLayer, bool deflateSupported>
43 stream<NextLayer, deflateSupported>::
~stream()44 ~stream()
45 {
46     if(impl_)
47         impl_->remove();
48 }
49 
50 template<class NextLayer, bool deflateSupported>
51 template<class... Args>
52 stream<NextLayer, deflateSupported>::
stream(Args &&...args)53 stream(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 
61 template<class NextLayer, bool deflateSupported>
62 auto
63 stream<NextLayer, deflateSupported>::
get_executor()64 get_executor() noexcept ->
65     executor_type
66 {
67     return impl_->stream().get_executor();
68 }
69 
70 template<class NextLayer, bool deflateSupported>
71 auto
72 stream<NextLayer, deflateSupported>::
next_layer()73 next_layer() noexcept ->
74     next_layer_type&
75 {
76     return impl_->stream();
77 }
78 
79 template<class NextLayer, bool deflateSupported>
80 auto
81 stream<NextLayer, deflateSupported>::
next_layer() const82 next_layer() const noexcept ->
83     next_layer_type const&
84 {
85     return impl_->stream();
86 }
87 
88 template<class NextLayer, bool deflateSupported>
89 bool
90 stream<NextLayer, deflateSupported>::
is_open() const91 is_open() const noexcept
92 {
93     return impl_->status_ == status::open;
94 }
95 
96 template<class NextLayer, bool deflateSupported>
97 bool
98 stream<NextLayer, deflateSupported>::
got_binary() const99 got_binary() const noexcept
100 {
101     return impl_->rd_op == detail::opcode::binary;
102 }
103 
104 template<class NextLayer, bool deflateSupported>
105 bool
106 stream<NextLayer, deflateSupported>::
is_message_done() const107 is_message_done() const noexcept
108 {
109     return impl_->rd_done;
110 }
111 
112 template<class NextLayer, bool deflateSupported>
113 close_reason const&
114 stream<NextLayer, deflateSupported>::
reason() const115 reason() const noexcept
116 {
117     return impl_->cr;
118 }
119 
120 template<class NextLayer, bool deflateSupported>
121 std::size_t
122 stream<NextLayer, deflateSupported>::
read_size_hint(std::size_t initial_size) const123 read_size_hint(
124     std::size_t initial_size) const
125 {
126     return impl_->read_size_hint_pmd(
127         initial_size, impl_->rd_done,
128         impl_->rd_remain, impl_->rd_fh);
129 }
130 
131 template<class NextLayer, bool deflateSupported>
132 template<class DynamicBuffer, class>
133 std::size_t
134 stream<NextLayer, deflateSupported>::
read_size_hint(DynamicBuffer & buffer) const135 read_size_hint(DynamicBuffer& buffer) const
136 {
137     static_assert(
138         net::is_dynamic_buffer<DynamicBuffer>::value,
139         "DynamicBuffer type requirements not met");
140     return impl_->read_size_hint_db(buffer);
141 }
142 
143 //------------------------------------------------------------------------------
144 //
145 // Settings
146 //
147 //------------------------------------------------------------------------------
148 
149 // decorator
150 
151 template<class NextLayer, bool deflateSupported>
152 void
153 stream<NextLayer, deflateSupported>::
set_option(decorator opt)154 set_option(decorator opt)
155 {
156     impl_->decorator_opt = std::move(opt.d_);
157 }
158 
159 // timeout
160 
161 template<class NextLayer, bool deflateSupported>
162 void
163 stream<NextLayer, deflateSupported>::
get_option(timeout & opt)164 get_option(timeout& opt)
165 {
166     opt = impl_->timeout_opt;
167 }
168 
169 template<class NextLayer, bool deflateSupported>
170 void
171 stream<NextLayer, deflateSupported>::
set_option(timeout const & opt)172 set_option(timeout const& opt)
173 {
174     impl_->set_option(opt);
175 }
176 
177 //
178 
179 template<class NextLayer, bool deflateSupported>
180 void
181 stream<NextLayer, deflateSupported>::
set_option(permessage_deflate const & o)182 set_option(permessage_deflate const& o)
183 {
184     impl_->set_option_pmd(o);
185 }
186 
187 template<class NextLayer, bool deflateSupported>
188 void
189 stream<NextLayer, deflateSupported>::
get_option(permessage_deflate & o)190 get_option(permessage_deflate& o)
191 {
192     impl_->get_option_pmd(o);
193 }
194 
195 template<class NextLayer, bool deflateSupported>
196 void
197 stream<NextLayer, deflateSupported>::
auto_fragment(bool value)198 auto_fragment(bool value)
199 {
200     impl_->wr_frag_opt = value;
201 }
202 
203 template<class NextLayer, bool deflateSupported>
204 bool
205 stream<NextLayer, deflateSupported>::
auto_fragment() const206 auto_fragment() const
207 {
208     return impl_->wr_frag_opt;
209 }
210 
211 template<class NextLayer, bool deflateSupported>
212 void
213 stream<NextLayer, deflateSupported>::
binary(bool value)214 binary(bool value)
215 {
216     impl_->wr_opcode = value ?
217         detail::opcode::binary :
218         detail::opcode::text;
219 }
220 
221 template<class NextLayer, bool deflateSupported>
222 bool
223 stream<NextLayer, deflateSupported>::
binary() const224 binary() const
225 {
226     return impl_->wr_opcode == detail::opcode::binary;
227 }
228 
229 template<class NextLayer, bool deflateSupported>
230 void
231 stream<NextLayer, deflateSupported>::
control_callback(std::function<void (frame_type,string_view)> cb)232 control_callback(std::function<
233     void(frame_type, string_view)> cb)
234 {
235     impl_->ctrl_cb = std::move(cb);
236 }
237 
238 template<class NextLayer, bool deflateSupported>
239 void
240 stream<NextLayer, deflateSupported>::
control_callback()241 control_callback()
242 {
243     impl_->ctrl_cb = {};
244 }
245 
246 template<class NextLayer, bool deflateSupported>
247 void
248 stream<NextLayer, deflateSupported>::
read_message_max(std::size_t amount)249 read_message_max(std::size_t amount)
250 {
251     impl_->rd_msg_max = amount;
252 }
253 
254 template<class NextLayer, bool deflateSupported>
255 std::size_t
256 stream<NextLayer, deflateSupported>::
read_message_max() const257 read_message_max() const
258 {
259     return impl_->rd_msg_max;
260 }
261 
262 template<class NextLayer, bool deflateSupported>
263 void
264 stream<NextLayer, deflateSupported>::
secure_prng(bool value)265 secure_prng(bool value)
266 {
267     this->impl_->secure_prng_ = value;
268 }
269 
270 template<class NextLayer, bool deflateSupported>
271 void
272 stream<NextLayer, deflateSupported>::
write_buffer_bytes(std::size_t amount)273 write_buffer_bytes(std::size_t amount)
274 {
275     if(amount < 8)
276         BOOST_THROW_EXCEPTION(std::invalid_argument{
277             "write buffer size underflow"});
278     impl_->wr_buf_opt = amount;
279 }
280 
281 template<class NextLayer, bool deflateSupported>
282 std::size_t
283 stream<NextLayer, deflateSupported>::
write_buffer_bytes() const284 write_buffer_bytes() const
285 {
286     return impl_->wr_buf_opt;
287 }
288 
289 template<class NextLayer, bool deflateSupported>
290 void
291 stream<NextLayer, deflateSupported>::
text(bool value)292 text(bool value)
293 {
294     impl_->wr_opcode = value ?
295         detail::opcode::text :
296         detail::opcode::binary;
297 }
298 
299 template<class NextLayer, bool deflateSupported>
300 bool
301 stream<NextLayer, deflateSupported>::
text() const302 text() const
303 {
304     return impl_->wr_opcode == detail::opcode::text;
305 }
306 
307 //------------------------------------------------------------------------------
308 
309 // _Fail the WebSocket Connection_
310 template<class NextLayer, bool deflateSupported>
311 void
312 stream<NextLayer, deflateSupported>::
do_fail(std::uint16_t code,error_code ev,error_code & ec)313 do_fail(
314     std::uint16_t code,         // if set, send a close frame first
315     error_code ev,              // error code to use upon success
316     error_code& ec)             // set to the error, else set to ev
317 {
318     BOOST_ASSERT(ev);
319     impl_->change_status(status::closing);
320     if(code != close_code::none && ! impl_->wr_close)
321     {
322         impl_->wr_close = true;
323         detail::frame_buffer fb;
324         impl_->template write_close<
325             flat_static_buffer_base>(fb, code);
326         net::write(impl_->stream(), fb.data(), ec);
327         if(impl_->check_stop_now(ec))
328             return;
329     }
330     using beast::websocket::teardown;
331     teardown(impl_->role, impl_->stream(), ec);
332     if(ec == net::error::eof)
333     {
334         // Rationale:
335         // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
336         ec = {};
337     }
338     if(! ec)
339         ec = ev;
340     if(ec && ec != error::closed)
341         impl_->change_status(status::failed);
342     else
343         impl_->change_status(status::closed);
344     impl_->close();
345 }
346 
347 } // websocket
348 } // beast
349 } // boost
350 
351 #endif
352