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_ACCEPT_IPP
11#define BOOST_BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
12
13#include <boost/beast/websocket/impl/stream_impl.hpp>
14#include <boost/beast/websocket/detail/type_traits.hpp>
15#include <boost/beast/http/empty_body.hpp>
16#include <boost/beast/http/parser.hpp>
17#include <boost/beast/http/read.hpp>
18#include <boost/beast/http/string_body.hpp>
19#include <boost/beast/http/write.hpp>
20#include <boost/beast/core/async_base.hpp>
21#include <boost/beast/core/buffer_traits.hpp>
22#include <boost/beast/core/stream_traits.hpp>
23#include <boost/beast/core/detail/buffer.hpp>
24#include <boost/beast/version.hpp>
25#include <boost/asio/coroutine.hpp>
26#include <boost/assert.hpp>
27#include <boost/throw_exception.hpp>
28#include <memory>
29#include <type_traits>
30
31namespace boost {
32namespace beast {
33namespace websocket {
34
35//------------------------------------------------------------------------------
36
37namespace detail {
38
39template<class Body, class Allocator>
40void
41impl_base<true>::
42build_response_pmd(
43 http::response<http::string_body>& res,
44 http::request<Body,
45 http::basic_fields<Allocator>> const& req)
46{
47 pmd_offer offer;
48 pmd_offer unused;
49 pmd_read(offer, req);
50 pmd_negotiate(fields&: res, config&: unused, offer, o: pmd_opts_);
51}
52
53template<class Body, class Allocator>
54void
55impl_base<false>::
56build_response_pmd(
57 http::response<http::string_body>&,
58 http::request<Body,
59 http::basic_fields<Allocator>> const&)
60{
61}
62
63} // detail
64
65template<class NextLayer, bool deflateSupported>
66template<class Body, class Allocator, class Decorator>
67response_type
68stream<NextLayer, deflateSupported>::impl_type::
69build_response(
70 http::request<Body,
71 http::basic_fields<Allocator>> const& req,
72 Decorator const& decorator,
73 error_code& result)
74{
75 auto const decorate =
76 [this, &decorator](response_type& res)
77 {
78 decorator_opt(res);
79 decorator(res);
80 if(! res.count(name: http::field::server))
81 res.set(name: http::field::server,
82 value: string_view(BOOST_BEAST_VERSION_STRING));
83 };
84 auto err =
85 [&](error e)
86 {
87 result = e;
88 response_type res;
89 res.version(req.version());
90 res.result(v: http::status::bad_request);
91 res.body() = result.message();
92 res.prepare_payload();
93 decorate(res);
94 return res;
95 };
96 if(req.version() != 11)
97 return err(error::bad_http_version);
98 if(req.method() != http::verb::get)
99 return err(error::bad_method);
100 if(! req.count(http::field::host))
101 return err(error::no_host);
102 {
103 auto const it = req.find(http::field::connection);
104 if(it == req.end())
105 return err(error::no_connection);
106 if(! http::token_list{it->value()}.exists(s: "upgrade"))
107 return err(error::no_connection_upgrade);
108 }
109 {
110 auto const it = req.find(http::field::upgrade);
111 if(it == req.end())
112 return err(error::no_upgrade);
113 if(! http::token_list{it->value()}.exists(s: "websocket"))
114 return err(error::no_upgrade_websocket);
115 }
116 string_view key;
117 {
118 auto const it = req.find(http::field::sec_websocket_key);
119 if(it == req.end())
120 return err(error::no_sec_key);
121 key = it->value();
122 if(key.size() > detail::sec_ws_key_type::static_capacity)
123 return err(error::bad_sec_key);
124 }
125 {
126 auto const it = req.find(http::field::sec_websocket_version);
127 if(it == req.end())
128 return err(error::no_sec_version);
129 if(it->value() != "13")
130 {
131 response_type res;
132 res.result(v: http::status::upgrade_required);
133 res.version(req.version());
134 res.set(name: http::field::sec_websocket_version, value: "13");
135 result = error::bad_sec_version;
136 res.body() = result.message();
137 res.prepare_payload();
138 decorate(res);
139 return res;
140 }
141 }
142
143 response_type res;
144 res.result(v: http::status::switching_protocols);
145 res.version(req.version());
146 res.set(name: http::field::upgrade, value: "websocket");
147 res.set(name: http::field::connection, value: "Upgrade");
148 {
149 detail::sec_ws_accept_type acc;
150 detail::make_sec_ws_accept(accept&: acc, key);
151 res.set(name: http::field::sec_websocket_accept, value: to_string_view(s: acc));
152 }
153 this->build_response_pmd(res, req);
154 decorate(res);
155 result = {};
156 return res;
157}
158
159//------------------------------------------------------------------------------
160
161/** Respond to an HTTP request
162*/
163template<class NextLayer, bool deflateSupported>
164template<class Handler>
165class stream<NextLayer, deflateSupported>::response_op
166 : public beast::stable_async_base<
167 Handler, beast::executor_type<stream>>
168 , public asio::coroutine
169{
170 boost::weak_ptr<impl_type> wp_;
171 error_code result_; // must come before res_
172 response_type& res_;
173 http::response<http::empty_body> res_100_;
174 bool needs_res_100_{false};
175
176public:
177 template<
178 class Handler_,
179 class Body, class Allocator,
180 class Decorator>
181 response_op(
182 Handler_&& h,
183 boost::shared_ptr<impl_type> const& sp,
184 http::request<Body,
185 http::basic_fields<Allocator>> const& req,
186 Decorator const& decorator,
187 bool cont = false)
188 : stable_async_base<Handler,
189 beast::executor_type<stream>>(
190 std::forward<Handler_>(h),
191 sp->stream().get_executor())
192 , wp_(sp)
193 , res_(beast::allocate_stable<response_type>(*this,
194 sp->build_response(req, decorator, result_)))
195 {
196 auto itr = req.find(http::field::expect);
197 if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
198 {
199 res_100_.version(value: res_.version());
200 res_100_.set(name: http::field::server, value: res_[http::field::server]);
201 res_100_.result(v: http::status::continue_);
202 res_100_.prepare_payload();
203 needs_res_100_ = true;
204 }
205 (*this)({}, 0, cont);
206 }
207
208 void operator()(
209 error_code ec = {},
210 std::size_t bytes_transferred = 0,
211 bool cont = true)
212 {
213 boost::ignore_unused(bytes_transferred);
214 auto sp = wp_.lock();
215 if(! sp)
216 {
217 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
218 return this->complete(cont, ec);
219 }
220 auto& impl = *sp;
221 BOOST_ASIO_CORO_REENTER(*this)
222 {
223 impl.change_status(status::handshake);
224 impl.update_timer(this->get_executor());
225
226 if (needs_res_100_)
227 {
228 BOOST_ASIO_CORO_YIELD
229 {
230 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "websocket::async_accept"));
231 http::async_write(
232 impl.stream(), res_100_, std::move(*this));
233 }
234 }
235
236 // Send response
237 BOOST_ASIO_CORO_YIELD
238 {
239 BOOST_ASIO_HANDLER_LOCATION((
240 __FILE__, __LINE__,
241 "websocket::async_accept"));
242
243 http::async_write(
244 impl.stream(), res_, std::move(*this));
245 }
246 if(impl.check_stop_now(ec))
247 goto upcall;
248 if(! ec)
249 {
250 BOOST_BEAST_ASSIGN_EC(ec, result_);
251 BOOST_BEAST_ASSIGN_EC(ec, result_);
252 }
253 if(! ec)
254 {
255 impl.do_pmd_config(res_);
256 impl.open(role_type::server);
257 }
258 upcall:
259 this->complete(cont, ec);
260 }
261 }
262};
263
264//------------------------------------------------------------------------------
265
266// read and respond to an upgrade request
267//
268// Cancellation: the async_accept cancellation can be terminal
269// because it will just interrupt the reading of the header.
270//
271template<class NextLayer, bool deflateSupported>
272template<class Handler, class Decorator>
273class stream<NextLayer, deflateSupported>::accept_op
274 : public beast::stable_async_base<
275 Handler, beast::executor_type<stream>>
276 , public asio::coroutine
277{
278 boost::weak_ptr<impl_type> wp_;
279 http::request_parser<http::empty_body>& p_;
280 Decorator d_;
281
282public:
283 template<class Handler_, class Buffers>
284 accept_op(
285 Handler_&& h,
286 boost::shared_ptr<impl_type> const& sp,
287 Decorator const& decorator,
288 Buffers const& buffers)
289 : stable_async_base<Handler,
290 beast::executor_type<stream>>(
291 std::forward<Handler_>(h),
292 sp->stream().get_executor())
293 , wp_(sp)
294 , p_(beast::allocate_stable<
295 http::request_parser<http::empty_body>>(*this))
296 , d_(decorator)
297 {
298 auto& impl = *sp;
299 error_code ec;
300 auto const mb =
301 beast::detail::dynamic_buffer_prepare(
302 impl.rd_buf, buffer_bytes(buffers),
303 ec, error::buffer_overflow);
304 if(! ec)
305 impl.rd_buf.commit(
306 net::buffer_copy(*mb, buffers));
307 (*this)(ec);
308 }
309
310 void operator()(
311 error_code ec = {},
312 std::size_t bytes_transferred = 0,
313 bool cont = true)
314 {
315 boost::ignore_unused(bytes_transferred);
316 auto sp = wp_.lock();
317 if(! sp)
318 {
319 BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
320 return this->complete(cont, ec);
321 }
322 auto& impl = *sp;
323 BOOST_ASIO_CORO_REENTER(*this)
324 {
325 impl.change_status(status::handshake);
326 impl.update_timer(this->get_executor());
327
328 // The constructor could have set ec
329 if(ec)
330 goto upcall;
331
332 BOOST_ASIO_CORO_YIELD
333 {
334 BOOST_ASIO_HANDLER_LOCATION((
335 __FILE__, __LINE__,
336 "websocket::async_accept"));
337
338 http::async_read(impl.stream(),
339 impl.rd_buf, p_, std::move(*this));
340 }
341 if(ec == http::error::end_of_stream)
342 {
343 BOOST_BEAST_ASSIGN_EC(ec, error::closed);
344 }
345 if(impl.check_stop_now(ec))
346 goto upcall;
347
348 {
349 // Arguments from our state must be
350 // moved to the stack before releasing
351 // the handler.
352 auto const req = p_.release();
353 auto const decorator = d_;
354
355 response_op<Handler>(
356 this->release_handler(),
357 sp, req, decorator, true);
358 return;
359 }
360
361 upcall:
362 this->complete(cont, ec);
363 }
364 }
365};
366
367template<class NextLayer, bool deflateSupported>
368struct stream<NextLayer, deflateSupported>::
369 run_response_op
370{
371 template<
372 class AcceptHandler,
373 class Body, class Allocator,
374 class Decorator>
375 void
376 operator()(
377 AcceptHandler&& h,
378 boost::shared_ptr<impl_type> const& sp,
379 http::request<Body,
380 http::basic_fields<Allocator>> const* m,
381 Decorator const& d)
382 {
383 // If you get an error on the following line it means
384 // that your handler does not meet the documented type
385 // requirements for the handler.
386
387 static_assert(
388 beast::detail::is_invocable<AcceptHandler,
389 void(error_code)>::value,
390 "AcceptHandler type requirements not met");
391
392 response_op<
393 typename std::decay<AcceptHandler>::type>(
394 std::forward<AcceptHandler>(h), sp, *m, d);
395 }
396};
397
398template<class NextLayer, bool deflateSupported>
399struct stream<NextLayer, deflateSupported>::
400 run_accept_op
401{
402 template<
403 class AcceptHandler,
404 class Decorator,
405 class Buffers>
406 void
407 operator()(
408 AcceptHandler&& h,
409 boost::shared_ptr<impl_type> const& sp,
410 Decorator const& d,
411 Buffers const& b)
412 {
413 // If you get an error on the following line it means
414 // that your handler does not meet the documented type
415 // requirements for the handler.
416
417 static_assert(
418 beast::detail::is_invocable<AcceptHandler,
419 void(error_code)>::value,
420 "AcceptHandler type requirements not met");
421
422 accept_op<
423 typename std::decay<AcceptHandler>::type,
424 Decorator>(
425 std::forward<AcceptHandler>(h),
426 sp,
427 d,
428 b);
429 }
430};
431
432//------------------------------------------------------------------------------
433
434template<class NextLayer, bool deflateSupported>
435template<class Body, class Allocator,
436 class Decorator>
437void
438stream<NextLayer, deflateSupported>::
439do_accept(
440 http::request<Body,
441 http::basic_fields<Allocator>> const& req,
442 Decorator const& decorator,
443 error_code& ec)
444{
445 impl_->change_status(status::handshake);
446
447 error_code result;
448 auto const res = impl_->build_response(req, decorator, result);
449
450 auto itr = req.find(http::field::expect);
451 if (itr != req.end() && iequals(itr->value(), "100-continue")) // do
452 {
453 http::response<http::empty_body> res_100;
454 res_100.version(res.version());
455 res_100.set(http::field::server, res[http::field::server]);
456 res_100.result(v: http::status::continue_);
457 res_100.prepare_payload();
458 http::write(impl_->stream(), res_100, ec);
459 if (ec)
460 return;
461 }
462
463 http::write(impl_->stream(), res, ec);
464 if(ec)
465 return;
466 BOOST_BEAST_ASSIGN_EC(ec, result);
467 if(ec)
468 {
469 // VFALCO TODO Respect keep alive setting, perform
470 // teardown if Connection: close.
471 return;
472 }
473 impl_->do_pmd_config(res);
474 impl_->open(role_type::server);
475}
476
477template<class NextLayer, bool deflateSupported>
478template<class Buffers, class Decorator>
479void
480stream<NextLayer, deflateSupported>::
481do_accept(
482 Buffers const& buffers,
483 Decorator const& decorator,
484 error_code& ec)
485{
486 impl_->reset();
487 auto const mb =
488 beast::detail::dynamic_buffer_prepare(
489 impl_->rd_buf, buffer_bytes(buffers), ec,
490 error::buffer_overflow);
491 if(ec)
492 return;
493 impl_->rd_buf.commit(net::buffer_copy(*mb, buffers));
494
495 http::request_parser<http::empty_body> p;
496 http::read(next_layer(), impl_->rd_buf, p, ec);
497 if(ec == http::error::end_of_stream)
498 {
499 BOOST_BEAST_ASSIGN_EC(ec, error::closed);
500 }
501 if(ec)
502 return;
503 do_accept(p.get(), decorator, ec);
504}
505
506//------------------------------------------------------------------------------
507
508template<class NextLayer, bool deflateSupported>
509void
510stream<NextLayer, deflateSupported>::
511accept()
512{
513 static_assert(is_sync_stream<next_layer_type>::value,
514 "SyncStream type requirements not met");
515 error_code ec;
516 accept(ec);
517 if(ec)
518 BOOST_THROW_EXCEPTION(system_error{ec});
519}
520
521template<class NextLayer, bool deflateSupported>
522void
523stream<NextLayer, deflateSupported>::
524accept(error_code& ec)
525{
526 static_assert(is_sync_stream<next_layer_type>::value,
527 "SyncStream type requirements not met");
528 do_accept(
529 net::const_buffer{},
530 &default_decorate_res, ec);
531}
532
533template<class NextLayer, bool deflateSupported>
534template<class ConstBufferSequence>
535typename std::enable_if<! http::detail::is_header<
536 ConstBufferSequence>::value>::type
537stream<NextLayer, deflateSupported>::
538accept(ConstBufferSequence const& buffers)
539{
540 static_assert(is_sync_stream<next_layer_type>::value,
541 "SyncStream type requirements not met");
542 static_assert(net::is_const_buffer_sequence<
543 ConstBufferSequence>::value,
544 "ConstBufferSequence type requirements not met");
545 error_code ec;
546 accept(buffers, ec);
547 if(ec)
548 BOOST_THROW_EXCEPTION(system_error{ec});
549}
550template<class NextLayer, bool deflateSupported>
551template<class ConstBufferSequence>
552typename std::enable_if<! http::detail::is_header<
553 ConstBufferSequence>::value>::type
554stream<NextLayer, deflateSupported>::
555accept(
556 ConstBufferSequence const& buffers, error_code& ec)
557{
558 static_assert(is_sync_stream<next_layer_type>::value,
559 "SyncStream type requirements not met");
560 static_assert(net::is_const_buffer_sequence<
561 ConstBufferSequence>::value,
562 "ConstBufferSequence type requirements not met");
563 do_accept(buffers, &default_decorate_res, ec);
564}
565
566
567template<class NextLayer, bool deflateSupported>
568template<class Body, class Allocator>
569void
570stream<NextLayer, deflateSupported>::
571accept(
572 http::request<Body,
573 http::basic_fields<Allocator>> const& req)
574{
575 static_assert(is_sync_stream<next_layer_type>::value,
576 "SyncStream type requirements not met");
577 error_code ec;
578 accept(req, ec);
579 if(ec)
580 BOOST_THROW_EXCEPTION(system_error{ec});
581}
582
583template<class NextLayer, bool deflateSupported>
584template<class Body, class Allocator>
585void
586stream<NextLayer, deflateSupported>::
587accept(
588 http::request<Body,
589 http::basic_fields<Allocator>> const& req,
590 error_code& ec)
591{
592 static_assert(is_sync_stream<next_layer_type>::value,
593 "SyncStream type requirements not met");
594 impl_->reset();
595 do_accept(req, &default_decorate_res, ec);
596}
597
598//------------------------------------------------------------------------------
599
600template<class NextLayer, bool deflateSupported>
601template<
602 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
603BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
604stream<NextLayer, deflateSupported>::
605async_accept(
606 AcceptHandler&& handler)
607{
608 static_assert(is_async_stream<next_layer_type>::value,
609 "AsyncStream type requirements not met");
610 impl_->reset();
611 return net::async_initiate<
612 AcceptHandler,
613 void(error_code)>(
614 run_accept_op{},
615 handler,
616 impl_,
617 &default_decorate_res,
618 net::const_buffer{});
619}
620
621template<class NextLayer, bool deflateSupported>
622template<
623 class ConstBufferSequence,
624 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
625BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
626stream<NextLayer, deflateSupported>::
627async_accept(
628 ConstBufferSequence const& buffers,
629 AcceptHandler&& handler,
630 typename std::enable_if<
631 ! http::detail::is_header<
632 ConstBufferSequence>::value>::type*
633)
634{
635 static_assert(is_async_stream<next_layer_type>::value,
636 "AsyncStream type requirements not met");
637 static_assert(net::is_const_buffer_sequence<
638 ConstBufferSequence>::value,
639 "ConstBufferSequence type requirements not met");
640 impl_->reset();
641 return net::async_initiate<
642 AcceptHandler,
643 void(error_code)>(
644 run_accept_op{},
645 handler,
646 impl_,
647 &default_decorate_res,
648 buffers);
649}
650
651template<class NextLayer, bool deflateSupported>
652template<
653 class Body, class Allocator,
654 BOOST_BEAST_ASYNC_TPARAM1 AcceptHandler>
655BOOST_BEAST_ASYNC_RESULT1(AcceptHandler)
656stream<NextLayer, deflateSupported>::
657async_accept(
658 http::request<Body, http::basic_fields<Allocator>> const& req,
659 AcceptHandler&& handler)
660{
661 static_assert(is_async_stream<next_layer_type>::value,
662 "AsyncStream type requirements not met");
663 impl_->reset();
664 return net::async_initiate<
665 AcceptHandler,
666 void(error_code)>(
667 run_response_op{},
668 handler,
669 impl_,
670 &req,
671 &default_decorate_res);
672}
673
674} // websocket
675} // beast
676} // boost
677
678#endif
679

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